Further modules included.
[yaffs-website] / web / modules / contrib / drupalmoduleupgrader / src / Utility / FormConverter.php
1 <?php
2
3 namespace Drupal\drupalmoduleupgrader\Utility;
4
5 use Drupal\drupalmoduleupgrader\RewriterInterface;
6 use Drupal\drupalmoduleupgrader\TargetInterface;
7 use Pharborist\Filter;
8 use Pharborist\Functions\FunctionCallNode;
9 use Pharborist\Functions\FunctionDeclarationNode;
10 use Pharborist\Functions\ParameterNode;
11 use Pharborist\Objects\ClassMethodNode;
12 use Pharborist\Objects\ClassNode;
13 use Pharborist\Parser;
14 use Pharborist\Token;
15 use Pharborist\TokenNode;
16
17 /**
18  * Converts a form from a set of callback functions to a class implementing
19  * \Drupal\Core\Form\FormInterface.
20  */
21 class FormConverter {
22
23   use StringTransformTrait;
24
25   /**
26    * @var \Drupal\drupalmoduleupgrader\TargetInterface
27    */
28   protected $target;
29
30   /**
31    * @var string
32    */
33   protected $formID;
34
35   /**
36    * @var \Pharborist\Functions\FunctionDeclarationNode
37    */
38   protected $builder;
39
40   /**
41    * @var \Pharborist\Functions\FunctionDeclarationNode
42    */
43   protected $validator;
44
45   /**
46    * @var \Pharborist\Functions\FunctionDeclarationNode
47    */
48   protected $submitHandler;
49
50   /**
51    * @var boolean
52    */
53   protected $isConfig;
54
55   /**
56    * @var \Drupal\drupalmoduleupgrader\RewriterInterface
57    */
58   protected $formStateRewriter;
59
60   /**
61    * @var \Pharborist\Objects\ClassNode
62    */
63   protected $controller;
64
65   public function __construct(TargetInterface $target, $form_id, RewriterInterface $rewriter) {
66     $indexer = $target->getIndexer('function');
67
68     $this->target = $target;
69     $this->formID = $form_id;
70
71     $this->builder = $indexer->get($form_id);
72
73     $validator = $form_id . '_validate';
74     if ($indexer->has($validator)) {
75       $this->validator = $indexer->get($validator);
76     }
77     $submit_handler = $form_id . '_submit';
78     if ($indexer->has($submit_handler)) {
79       $this->submitHandler = $indexer->get($submit_handler);
80     }
81
82     $this->isConfig = $this->builder->has(Filter::isFunctionCall('system_settings_form'));
83     $this->formStateRewriter = $rewriter;
84   }
85
86   /**
87    * @return \Pharborist\Objects\ClassNode
88    */
89   public function render() {
90     if (empty($this->controller)) {
91       $render = [
92         '#theme' => 'dmu_form',
93         '#module' => $this->target->id(),
94         '#form_id' => $this->formID,
95         '#class' => $this->toTitleCase($this->formID),
96         '#config' => $this->isConfig,
97       ];
98       $source = \Drupal::service('renderer')->renderPlain($render);
99       $this->controller = Parser::parseSource($source)
100         ->find(Filter::isClass($render['#class']))->get(0);
101     }
102     return $this->controller;
103   }
104
105   /**
106    * @return \Pharborist\Objects\ClassNode
107    */
108   public function build() {
109     $controller = $this->render();
110
111     $builder = $this->addMethod($this->builder, $controller, 'buildForm');
112     if ($this->isConfig) {
113       $builder
114         ->find(Filter::isFunctionCall('system_settings_form'))
115         ->each(function(FunctionCallNode $call) {
116           $call
117             ->setName('parent::buildForm')
118             ->appendArgument(Token::variable('$form_state'));
119         });
120     }
121
122     if ($this->validator) {
123       $this
124         ->addMethod($this->validator, $controller, 'validateForm')
125         ->getParameterAtIndex(0)
126         ->setReference(TRUE)
127         ->setTypeHint('array');
128     }
129     if ($this->submitHandler) {
130       $this
131         ->addMethod($this->submitHandler, $controller, ($this->isConfig ? '_submitForm' : 'submitForm'))
132         ->getParameterAtIndex(0)
133         ->setReference(TRUE)
134         ->setTypeHint('array');
135     }
136
137     return $controller;
138   }
139
140   /**
141    * @return \Pharborist\Objects\ClassMethodNode
142    */
143   protected function addMethod(FunctionDeclarationNode $function, ClassNode $class, $alias = NULL) {
144     $method = ClassMethodNode::fromFunction($function);
145     if ($alias) {
146       $method->setName($alias);
147     }
148     $class->appendMethod($method);
149
150     // Add the parameters required for FormInterface conformance.
151     $parameters = $method->getParameters()->toArray();
152     if (empty($parameters)) {
153       $parameters[0] = ParameterNode::create('$form');
154       $method->appendParameter($parameters[0]);
155     }
156     if (sizeof($parameters) == 1) {
157       $parameters[1] = ParameterNode::create('$form_state');
158       $method->appendParameter($parameters[1]);
159     }
160
161     // The $form parameter must have the array type hint.
162     $parameters[0]->setTypeHint('array');
163
164     // The form state is never passed by reference.
165     $parameters[1]->setReference(FALSE);
166
167     // Additional parameters MUST have a default value of NULL in order to conform
168     // to FormInterface.
169     for ($i = 2; $i < sizeof($parameters); $i++) {
170       $parameters[$i]->setValue(new TokenNode(T_STRING, 'NULL'));
171     }
172
173     $this->formStateRewriter->rewrite($parameters[1]);
174
175     return $method;
176   }
177
178 }