Skip to content

Commit 5be8f82

Browse files
[injection] If parent class has dependency via promoted property, but its private, add a new one to child class deps (#7996)
* kick off fix * [ci-review] Rector Rectify --------- Co-authored-by: GitHub Action <actions@github.com>
1 parent 27c0087 commit 5be8f82

1 file changed

Lines changed: 26 additions & 6 deletions

File tree

src/NodeManipulator/ClassDependencyManipulator.php

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44

55
namespace Rector\NodeManipulator;
66

7+
use PhpParser\Modifiers;
78
use PhpParser\Node\Arg;
89
use PhpParser\Node\Expr\Assign;
910
use PhpParser\Node\Expr\StaticCall;
1011
use PhpParser\Node\Expr\Variable;
1112
use PhpParser\Node\Name;
13+
use PhpParser\Node\Param;
1214
use PhpParser\Node\Stmt;
1315
use PhpParser\Node\Stmt\Class_;
1416
use PhpParser\Node\Stmt\ClassLike;
@@ -248,13 +250,31 @@ private function addPromotedProperty(
248250
$param = $this->nodeFactory->createPromotedPropertyParam($propertyMetadata);
249251

250252
if ($constructClassMethod instanceof ClassMethod) {
251-
// parameter is already added
252-
if ($this->hasMethodParameter($constructClassMethod, $propertyMetadata->getName())) {
253+
$hasOwnConstruct = $class->getMethod(MethodName::CONSTRUCT) instanceof ClassMethod;
254+
$matchedParam = $this->matchMethodParameter($constructClassMethod, $propertyMetadata->getName());
255+
256+
if ($matchedParam instanceof Param) {
257+
// own constructor already has this param → nothing to do
258+
if ($hasOwnConstruct) {
259+
return;
260+
}
261+
262+
// parent constructor has a same-named param; if it is a private promoted
263+
// property, the child cannot access it via $this — add a fresh constructor
264+
// on the child instead of trying to extend the parent signature
265+
if (($matchedParam->flags & Modifiers::PRIVATE) !== 0) {
266+
$childConstructClassMethod = $this->nodeFactory->createPublicMethod(MethodName::CONSTRUCT);
267+
$childConstructClassMethod->params[] = $param;
268+
$this->classInsertManipulator->addAsFirstMethod($class, $childConstructClassMethod);
269+
return;
270+
}
271+
272+
// parent's matching param is protected/public — accessible from child, no add needed
253273
return;
254274
}
255275

256276
// found construct, but only on parent, add to current class
257-
if (! $class->getMethod(MethodName::CONSTRUCT) instanceof ClassMethod) {
277+
if (! $hasOwnConstruct) {
258278
$parentArgs = [];
259279

260280
foreach ($constructClassMethod->params as $originalParam) {
@@ -334,15 +354,15 @@ private function hasClassPropertyAndDependency(Class_ $class, PropertyMetadata $
334354
return $property instanceof Property;
335355
}
336356

337-
private function hasMethodParameter(ClassMethod $classMethod, string $name): bool
357+
private function matchMethodParameter(ClassMethod $classMethod, string $name): ?Param
338358
{
339359
foreach ($classMethod->params as $param) {
340360
if ($this->nodeNameResolver->isName($param->var, $name)) {
341-
return true;
361+
return $param;
342362
}
343363
}
344364

345-
return false;
365+
return null;
346366
}
347367

348368
private function shouldAddPromotedProperty(Class_ $class, PropertyMetadata $propertyMetadata): bool

0 commit comments

Comments
 (0)