From 9c014fbd0e1ee74cd88533591ea145ef735a25ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20=C5=BDelezn=C3=BD?= Date: Mon, 8 Dec 2025 10:59:28 +0100 Subject: [PATCH] Nette\Application\UI\Multiplier factory can return null --- extension.neon | 6 ++- .../Application/StubFilesExtensionLoader.php | 38 +++++++++++++++++++ stubs/Application/UI/Multiplier1.stub | 19 ++++++++++ tests/Type/Nette/MultiplierTest.php | 18 ++++++++- .../Nette/data/multiplierApplication325.php | 25 ++++++++++++ 5 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 src/Stubs/Nette/Application/StubFilesExtensionLoader.php create mode 100644 stubs/Application/UI/Multiplier1.stub create mode 100644 tests/Type/Nette/data/multiplierApplication325.php diff --git a/extension.neon b/extension.neon index 91a738a..31eb67c 100644 --- a/extension.neon +++ b/extension.neon @@ -7,7 +7,6 @@ parameters: stubFiles: - stubs/Application/Routers/RouteList.stub - stubs/Application/UI/Component.stub - - stubs/Application/UI/Multiplier.stub - stubs/Application/UI/Presenter.stub - stubs/Caching/Cache.stub - stubs/ComponentModel/Component.stub @@ -52,6 +51,11 @@ parameters: - forward services: + - + class: PHPStan\Stubs\Nette\Application\StubFilesExtensionLoader + tags: + - phpstan.stubFilesExtension + - class: PHPStan\Reflection\Nette\HtmlClassReflectionExtension tags: diff --git a/src/Stubs/Nette/Application/StubFilesExtensionLoader.php b/src/Stubs/Nette/Application/StubFilesExtensionLoader.php new file mode 100644 index 0000000..1ecad2b --- /dev/null +++ b/src/Stubs/Nette/Application/StubFilesExtensionLoader.php @@ -0,0 +1,38 @@ +=')) { + $files[] = $path . '/Application/UI/Multiplier1.stub'; + } else { + $files[] = $path . '/Application/UI/Multiplier.stub'; + } + + return $files; + } + +} diff --git a/stubs/Application/UI/Multiplier1.stub b/stubs/Application/UI/Multiplier1.stub new file mode 100644 index 0000000..fa6c449 --- /dev/null +++ b/stubs/Application/UI/Multiplier1.stub @@ -0,0 +1,19 @@ +) : (T|null) $factory + */ + public function __construct(callable $factory); + + /** + * @return T|null + */ + protected function createComponent(string $name): ?\Nette\ComponentModel\IComponent; +} diff --git a/tests/Type/Nette/MultiplierTest.php b/tests/Type/Nette/MultiplierTest.php index 8f762ec..4eb04ad 100644 --- a/tests/Type/Nette/MultiplierTest.php +++ b/tests/Type/Nette/MultiplierTest.php @@ -2,14 +2,30 @@ namespace PHPStan\Type\Nette; +use Composer\InstalledVersions; +use OutOfBoundsException; use PHPStan\Testing\TypeInferenceTestCase; +use function class_exists; +use function version_compare; class MultiplierTest extends TypeInferenceTestCase { public function dataFileAsserts(): iterable { - yield from self::gatherAssertTypes(__DIR__ . '/data/multiplier.php'); + try { + $applicationVersion = class_exists(InstalledVersions::class) + ? InstalledVersions::getVersion('nette/application') + : null; + } catch (OutOfBoundsException $e) { + $applicationVersion = null; + } + + if ($applicationVersion !== null && version_compare($applicationVersion, '3.2.5', '>=')) { + yield from self::gatherAssertTypes(__DIR__ . '/data/multiplierApplication325.php'); + } else { + yield from self::gatherAssertTypes(__DIR__ . '/data/multiplier.php'); + } } /** diff --git a/tests/Type/Nette/data/multiplierApplication325.php b/tests/Type/Nette/data/multiplierApplication325.php new file mode 100644 index 0000000..638e07a --- /dev/null +++ b/tests/Type/Nette/data/multiplierApplication325.php @@ -0,0 +1,25 @@ + $multiplier */ +$multiplier = new Multiplier(function (string $name): ?Form { + if($name === 'foo') { + return new Form(); + } else { + return null; + } +}); + +assertType('Nette\Application\UI\Multiplier', $multiplier); + +$form = $multiplier->createComponent('foo'); + +assertType(Form::class . '|null', $form); + +$notSupportedForm = $multiplier->createComponent('notSupported'); + +assertType(Form::class . '|null', $notSupportedForm);