ILIAS  release_8 Revision v8.24
DICDependencyManipulator.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
23use PhpParser\Node\Stmt;
24use PhpParser\Node\Stmt\ClassMethod;
25use PhpParser\Node\Expr\Variable;
26use Rector\PostRector\Collector\NodesToAddCollector;
27use Rector\Transform\Rector\StaticCall\StaticCallToMethodCallRector;
28use PhpParser\Node\Expr\Assign;
29use PhpParser\Node\Scalar\String_;
30use PhpParser\Comment\Doc;
31use Rector\Core\Exception\ShouldNotHappenException;
32
34{
35 public const DIC = 'DIC';
36 private \Rector\Core\PhpParser\Node\NodeFactory $nodeFactory;
37 private \Rector\Core\NodeManipulator\StmtsManipulator $stmtsManipulator;
38 private \Rector\NodeNameResolver\NodeNameResolver $nodeNameResolver;
39 private \Rector\Core\PhpParser\Comparing\NodeComparator $nodeComparator;
40 private NodesToAddCollector $nodesToAddCollector;
41 private \Rector\Core\NodeDecorator\CreatedByRuleDecorator $createdByRuleDecorator;
42 private array $duplicate_checker = [];
43 private \Rector\Core\PhpParser\Node\BetterNodeFinder $betterNodeFinder;
44 private array $added_constructors = [];
45 private \Rector\Core\Contract\Console\OutputStyleInterface $outputStyle;
46
47 public function __construct(
48 \Rector\Core\PhpParser\Node\NodeFactory $nodeFactory,
49 \Rector\Core\NodeManipulator\StmtsManipulator $stmtsManipulator,
50 \Rector\NodeNameResolver\NodeNameResolver $nodeNameResolver,
51 \Rector\Core\PhpParser\Comparing\NodeComparator $nodeComparator,
52 NodesToAddCollector $nodesToAddCollector,
53 \Rector\Core\PhpParser\Node\BetterNodeFinder $betterNodeFinder,
54 \Rector\Core\Contract\Console\OutputStyleInterface $outputStyle
55 ) {
56 $this->nodeFactory = $nodeFactory;
57 $this->stmtsManipulator = $stmtsManipulator;
58 $this->nodeNameResolver = $nodeNameResolver;
59 $this->nodeComparator = $nodeComparator;
60 $this->nodesToAddCollector = $nodesToAddCollector;
61 $this->betterNodeFinder = $betterNodeFinder;
62 $this->outputStyle = $outputStyle;
63 }
64
68 private function getDICVariable(): Variable
69 {
70 return new Variable(self::DIC);
71 }
72
76 private function getGlobalDIC(): Stmt\Global_
77 {
78 return new Stmt\Global_([$this->getDICVariable()]);
79 }
80
82 ClassMethod $classMethod,
83 Stmt\Class_ $class,
84 Stmt $stmt
85 ): void {
86 $class_method_string = $class->name->name . '::' . $classMethod->name->name;
87 $stmt_string = $this->nodeComparator->printWithoutComments($stmt);
88 if (isset($this->duplicate_checker[$class_method_string][$stmt_string])
89 && $this->duplicate_checker[$class_method_string][$stmt_string] === true) {
90 return;
91 }
92 $stmts = $this->stmtsManipulator->filterOutExistingStmts(
93 $classMethod,
94 [$stmt]
95 );
96 // all stmts are already there → skip
97 if ($stmts === []) {
98 return;
99 }
100 $first = null;
101 foreach ($classMethod->getStmts() as $inner_statement) {
102 if ($inner_statement->getAttributes() === []) {
103 continue;
104 }
105 $first = $inner_statement;
106 break;
107 }
108 if ($first !== null) {
109 $this->nodesToAddCollector->addNodeBeforeNode($stmt, $first);
110 } else {
111 $classMethod->stmts[] = $stmt;
112 }
113 $this->duplicate_checker[$class_method_string][$stmt_string] = true;
114 }
115
116 private function createConstructor(
117 \PhpParser\Node\Stmt\Class_ $class
118 ): ClassMethod {
119 if (isset($this->added_constructors[$class->name->name])) {
120 return $this->added_constructors[$class->name->name];
121 }
122 $classMethod = $this->nodeFactory->createPublicMethod(
123 \Rector\Core\ValueObject\MethodName::CONSTRUCT
124 );
125 // implement parent constructor call
126 if ($this->hasClassParentClassMethod(
127 $class,
128 \Rector\Core\ValueObject\MethodName::CONSTRUCT
129 )) {
130 $classMethod->stmts[] = $this->createParentClassMethodCall(
131 \Rector\Core\ValueObject\MethodName::CONSTRUCT
132 );
133 }
134 $first_class_method = array_filter($class->stmts, function (\PhpParser\Node $n): bool {
135 return $n instanceof ClassMethod;
136 });
137 $first_class_method = array_shift($first_class_method);
138 if ($first_class_method !== null) {
139 $this->nodesToAddCollector->addNodeBeforeNode($classMethod, $first_class_method);
140 } else {
141 array_unshift($class->stmts, $classMethod);
142 }
143 $this->outputStyle->newline();
144 $this->outputStyle->warning(
145 'created constructor for ' . $class->name->name . '. Please check the parent-call for missing parameters!'
146 );
147 $this->outputStyle->newline();
148
149
150 $this->added_constructors[$class->name->name] = $classMethod;
151
152 return $classMethod;
153 }
154
156 \PhpParser\Node\Stmt\Class_ $class,
157 Stmt $stmt
158 ): void {
159 $classMethod = $class->getMethod(
160 \Rector\Core\ValueObject\MethodName::CONSTRUCT
161 );
162 if (!$classMethod instanceof \PhpParser\Node\Stmt\ClassMethod) {
163 $classMethod = $this->createConstructor($class);
164 }
165 $this->addStmtToMethodIfNotThereYetAtFirstPosition(
166 $classMethod,
167 $class,
168 $stmt
169 );
170 }
171
172 public function ensureGlobalDICinConstructor(Stmt\Class_ $class): void
173 {
174 $stmt = $this->getGlobalDIC();
175 $this->addStmtToConstructorIfNotThereYetAtFirstPosition(
176 $class,
177 $stmt
178 );
179 $this->duplicate_checker[$class->name->name][$this->nodeComparator->printWithoutComments($stmt)] = true;
180 }
181
182 public function ensureGlobalDICinMethod(ClassMethod $classMethod, Stmt\Class_ $class): Variable
183 {
184 $this->addStmtToMethodIfNotThereYetAtFirstPosition(
185 $classMethod,
186 $class,
187 $this->getGlobalDIC()
188 );
189 return $this->getDICVariable();
190 }
191
193 ClassMethod $classMethod,
194 Stmt\Class_ $class,
195 Stmt $stmt
196 ) {
197 $class_method_string = $class->name->name . '::' . $classMethod->name->name;
198 $statement_string = $this->nodeComparator->printWithoutComments($stmt);
199 if (isset($this->duplicate_checker[$class_method_string][$statement_string])
200 && $this->duplicate_checker[$class_method_string][$statement_string] === true) {
201 return;
202 }
203 $stmts = $this->stmtsManipulator->filterOutExistingStmts(
204 $classMethod,
205 [$stmt]
206 );
207 // all stmts are already there → skip
208 if ($stmts === []) {
209 return;
210 }
211
212 $existing_dic = $this->betterNodeFinder->findFirst($classMethod->stmts, function (\PhpParser\Node $n): bool {
213 if (!$n instanceof Stmt\Global_) {
214 return false;
215 }
216 foreach ($n->vars as $var) {
217 if (isset($var->name) && $var->name === self::DIC) {
218 return true;
219 }
220 }
221 return false;
222 });
223 $dic_statement_string = $this->nodeComparator->printWithoutComments($this->getGlobalDIC());
224 if ($existing_dic === null
225 && !isset($this->duplicate_checker[$class_method_string][$dic_statement_string]) // we already added global $DIC in this run
226 && !$this->duplicate_checker[$class_method_string][$dic_statement_string] === true
227 ) {
228 throw new ShouldNotHappenException(
229 'no dic found: ' . $class_method_string . ' (' . $statement_string . ') '
230 );
231 }
232
233 // get first existing statement
234 $first_existing = array_filter($classMethod->stmts, function (\PhpParser\Node $n): bool {
235 if ($n->getAttributes() === []) {
236 return false;
237 }
238 return !$n instanceof Stmt\Global_;
239 });
240 $first_existing = array_shift($first_existing);
241 if ($first_existing !== null) {
242 $this->nodesToAddCollector->addNodeBeforeNode($stmt, $first_existing);
243 } else {
244 // we use a fallback to add the element in first place.
245 // the nodesToAddCollector does not work here, becaue there are only
246 // "new" nodes without position
247 $classMethod->stmts[] = $stmt;
248 }
249 $this->duplicate_checker[$class_method_string][$statement_string] = true;
250 }
251
253 \PhpParser\Node\Stmt\Class_ $class,
254 Stmt $stmt
255 ): void {
256 $classMethod = $class->getMethod(
257 \Rector\Core\ValueObject\MethodName::CONSTRUCT
258 );
259 if (!$classMethod instanceof \PhpParser\Node\Stmt\ClassMethod) {
260 $classMethod = $this->createConstructor($class);
261 }
262 $this->addStmtToMethodIfNotThereAfterGlobalDIC(
263 $classMethod,
264 $class,
265 $stmt
266 );
267 }
268
270 \PhpParser\Node\Stmt\Class_ $class,
271 string $methodName
272 ): bool {
273 $scope = $class->getAttribute(
274 \Rector\NodeTypeResolver\Node\AttributeKey::SCOPE
275 );
276 if (!$scope instanceof \PHPStan\Analyser\Scope) {
277 return \false;
278 }
279 $classReflection = $scope->getClassReflection();
280 if (!$classReflection instanceof \PHPStan\Reflection\ClassReflection) {
281 return \false;
282 }
283 foreach ($classReflection->getParents() as $parentClassReflection) {
284 if ($parentClassReflection->hasMethod($methodName)) {
286 }
287 }
288 return \false;
289 }
290
292 string $methodName
293 ): \PhpParser\Node\Stmt\Expression {
294 $staticCall = new \PhpParser\Node\Expr\StaticCall(
295 new \PhpParser\Node\Name(
296 \Rector\Core\Enum\ObjectReference::PARENT()->getValue()
297 ),
298 $methodName
299 );
300
301 // append arguments
302
303
304 return new \PhpParser\Node\Stmt\Expression($staticCall);
305 }
306
307 private function isParamInConstructor(
308 \PhpParser\Node\Stmt\Class_ $class,
309 string $propertyName
310 ): bool {
311 $constructClassMethod = $class->getMethod(
312 \Rector\Core\ValueObject\MethodName::CONSTRUCT
313 );
314 if (!$constructClassMethod instanceof \PhpParser\Node\Stmt\ClassMethod) {
315 return \false;
316 }
317 foreach ($constructClassMethod->params as $param) {
318 if ($this->nodeNameResolver->isName($param, $propertyName)) {
320 }
321 }
322 return \false;
323 }
324
325 private function hasMethodParameter(
326 \PhpParser\Node\Stmt\ClassMethod $classMethod,
327 string $name
328 ): bool {
329 foreach ($classMethod->params as $param) {
330 if ($this->nodeNameResolver->isName($param->var, $name)) {
332 }
333 }
334 return \false;
335 }
336}
static return function(ContainerConfigurator $containerConfigurator)
Definition: basic_rector.php:9
Rector Core NodeManipulator StmtsManipulator $stmtsManipulator
Rector Core Contract Console OutputStyleInterface $outputStyle
addStmtToMethodIfNotThereAfterGlobalDIC(ClassMethod $classMethod, Stmt\Class_ $class, Stmt $stmt)
Rector Core PhpParser Comparing NodeComparator $nodeComparator
hasClassParentClassMethod(\PhpParser\Node\Stmt\Class_ $class, string $methodName)
hasMethodParameter(\PhpParser\Node\Stmt\ClassMethod $classMethod, string $name)
createConstructor(\PhpParser\Node\Stmt\Class_ $class)
Rector Core PhpParser Node BetterNodeFinder $betterNodeFinder
Rector Core NodeDecorator CreatedByRuleDecorator $createdByRuleDecorator
addStmtToMethodIfNotThereYetAtFirstPosition(ClassMethod $classMethod, Stmt\Class_ $class, Stmt $stmt)
addStmtToConstructorIfNotThereYetAtFirstPosition(\PhpParser\Node\Stmt\Class_ $class, Stmt $stmt)
__construct(\Rector\Core\PhpParser\Node\NodeFactory $nodeFactory, \Rector\Core\NodeManipulator\StmtsManipulator $stmtsManipulator, \Rector\NodeNameResolver\NodeNameResolver $nodeNameResolver, \Rector\Core\PhpParser\Comparing\NodeComparator $nodeComparator, NodesToAddCollector $nodesToAddCollector, \Rector\Core\PhpParser\Node\BetterNodeFinder $betterNodeFinder, \Rector\Core\Contract\Console\OutputStyleInterface $outputStyle)
isParamInConstructor(\PhpParser\Node\Stmt\Class_ $class, string $propertyName)
Rector NodeNameResolver NodeNameResolver $nodeNameResolver
Rector Core PhpParser Node NodeFactory $nodeFactory
addStmtToConstructorIfNotThereAfterGlobalDIC(\PhpParser\Node\Stmt\Class_ $class, Stmt $stmt)
ensureGlobalDICinMethod(ClassMethod $classMethod, Stmt\Class_ $class)
return true
if(!file_exists(getcwd() . '/ilias.ini.php'))
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: confirmReg.php:20
$scope
Definition: ltiregstart.php:53
if($format !==null) $name
Definition: metadata.php:247
getValue()
Get the value that is displayed in the input client side.
Definition: Group.php:47
$param
Definition: xapitoken.php:46