Skip to content

Commit 5efdf91

Browse files
authored
Symfony: detect callback constraints (#180)
1 parent 0c989a4 commit 5efdf91

File tree

2 files changed

+41
-0
lines changed

2 files changed

+41
-0
lines changed

src/Provider/SymfonyUsageProvider.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,10 @@ protected function shouldMarkAsUsed(ReflectionMethod $method): ?string
326326
return 'Route method via #[Route] attribute';
327327
}
328328

329+
if ($this->isMethodWithCallbackConstraintAttribute($method)) {
330+
return 'Callback constraint method via #[Assert\Callback] attribute';
331+
}
332+
329333
if ($this->isProbablySymfonyListener($method)) {
330334
return 'Probable listener method';
331335
}
@@ -461,6 +465,23 @@ protected function isMethodWithRouteAttribute(ReflectionMethod $method): bool
461465
|| $this->hasAttribute($method, 'Symfony\Component\Routing\Annotation\Route', $isInstanceOf);
462466
}
463467

468+
protected function isMethodWithCallbackConstraintAttribute(ReflectionMethod $method): bool
469+
{
470+
$attributes = $method->getDeclaringClass()->getAttributes('Symfony\Component\Validator\Constraints\Callback');
471+
472+
foreach ($attributes as $attribute) {
473+
$arguments = $attribute->getArguments();
474+
475+
$callback = $arguments['callback'] ?? $arguments[0] ?? null;
476+
477+
if ($callback === $method->getName()) {
478+
return true;
479+
}
480+
}
481+
482+
return $this->hasAttribute($method, 'Symfony\Component\Validator\Constraints\Callback');
483+
}
484+
464485
/**
465486
* Ideally, we would need to parse DIC xml to know this for sure just like phpstan-symfony does.
466487
*/
@@ -502,6 +523,7 @@ private function isSymfonyInstalled(): bool
502523
|| InstalledVersions::isInstalled('symfony/contracts')
503524
|| InstalledVersions::isInstalled('symfony/console')
504525
|| InstalledVersions::isInstalled('symfony/http-kernel')
526+
|| InstalledVersions::isInstalled('symfony/validator')
505527
|| InstalledVersions::isInstalled('symfony/dependency-injection');
506528
}
507529

tests/Rule/data/providers/symfony.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
1717
use Symfony\Component\Routing\Attribute\Route;
1818
use Symfony\Contracts\Service\Attribute\Required;
19+
use Symfony\Component\Validator\Constraints as Assert;
1920

2021
class SomeController {
2122

@@ -115,3 +116,21 @@ public function create(): self {
115116
class Sftp {
116117
const RETRY_LIMIT = 3; // used in yaml via !php/const
117118
}
119+
120+
class ModelValidator
121+
{
122+
public static function validate(): void {}
123+
}
124+
125+
#[Assert\Callback([ModelValidator::class, 'validate'])]
126+
#[Assert\Callback('validateBar')]
127+
#[Assert\Callback(callback: 'validateBaz')]
128+
class ValidatedModel
129+
{
130+
#[Assert\Callback]
131+
public function validateFoo(): void {}
132+
133+
public function validateBar(): void {}
134+
135+
public function validateBaz(): void {}
136+
}

0 commit comments

Comments
 (0)