Skip to content

Commit

Permalink
Update ComponentModel\Container stub for component-model 3.1.0
Browse files Browse the repository at this point in the history
That version changes the return type to array when `$deep` argument is `false` (default):
nette/component-model@7f613ee

It also deprecates the arguments but we cannot add deprecated annotation to those.
nette/component-model@4e0946a
  • Loading branch information
jtojnar committed Jan 14, 2025
1 parent 200d192 commit 3b24c68
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 2 deletions.
6 changes: 5 additions & 1 deletion extension.neon
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ parameters:
- stubs/Application/UI/Presenter.stub
- stubs/Caching/Cache.stub
- stubs/ComponentModel/Component.stub
- stubs/ComponentModel/Container.stub
- stubs/ComponentModel/IComponent.stub
- stubs/ComponentModel/IContainer.stub
- stubs/Database/ResultSet.stub
Expand Down Expand Up @@ -127,3 +126,8 @@ services:
class: PHPStan\Type\Nette\StringsReplaceCallbackClosureTypeExtension
tags:
- phpstan.staticMethodParameterClosureTypeExtension

-
class: PHPStan\Stubs\Nette\StubFilesExtensionLoader
tags:
- phpstan.stubFilesExtension
47 changes: 47 additions & 0 deletions src/Stubs/Nette/StubFilesExtensionLoader.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php declare(strict_types = 1);

namespace PHPStan\Stubs\Nette;

use Composer\InstalledVersions;
use OutOfBoundsException;
use PHPStan\PhpDoc\StubFilesExtension;
use function class_exists;
use function dirname;
use function version_compare;

class StubFilesExtensionLoader implements StubFilesExtension
{

public function getFiles(): array
{
$stubsDir = dirname(dirname(dirname(__DIR__))) . '/stubs';
$path = $stubsDir;

$files = [];

$componentModelVersion = self::getInstalledVersion('nette/component-model');
if ($componentModelVersion !== null && version_compare($componentModelVersion, '3.1.0', '>=')) {
$files[] = $path . '/ComponentModel/Container_3_1.stub';
} else {
$files[] = $path . '/ComponentModel/Container.stub';
}

return $files;
}

private static function getInstalledVersion(string $package): ?string
{
if (!class_exists(InstalledVersions::class)) {
return null;
}

try {
$installedVersion = InstalledVersions::getVersion($package);
} catch (OutOfBoundsException $e) {
return null;
}

return $installedVersion;
}

}
2 changes: 1 addition & 1 deletion stubs/ComponentModel/Container.stub
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class Container extends Component implements IContainer
* @phpstan-param null|class-string<T> $filterType
* @phpstan-return ($filterType is null ? \Iterator<int|string, \Nette\ComponentModel\IComponent> : \Iterator<int|string, T>)
*/
public function getComponents(bool $deep = false, string $filterType = null): \Iterator
public function getComponents(bool $deep = false, ?string $filterType = null): \Iterator
{
// nothing
}
Expand Down
21 changes: 21 additions & 0 deletions stubs/ComponentModel/Container_3_1.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Nette\ComponentModel;

class Container extends Component implements IContainer
{

/**
* @template T of \Nette\ComponentModel\IComponent
* @phpstan-param null|class-string<T> $filterType
* @phpstan-return (
* $deep is false
* ? ($filterType is null ? array<int|string, \Nette\ComponentModel\IComponent> : array<int|string, T>)
* : ($filterType is null ? \Iterator<int|string, \Nette\ComponentModel\IComponent> : \Iterator<int|string, T>)
* )
*/
public function getComponents(bool $deep = false, ?string $filterType = null): iterable
{
// nothing
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php declare(strict_types = 1);

namespace PHPStan\Type\Nette;

use Composer\InstalledVersions;
use OutOfBoundsException;
use PHPStan\Testing\TypeInferenceTestCase;
use function class_exists;
use function version_compare;

class ComponentModelContainerDynamicReturnTypeExtensionTest extends TypeInferenceTestCase
{

/**
* @return iterable<string, mixed[]>
*/
public function dataFileAsserts(): iterable
{
$componentModelVersion = self::getInstalledVersion('nette/component-model');

$suffix = $componentModelVersion !== null && version_compare($componentModelVersion, '3.1.0', '>=') ? '31' : '';

yield from self::gatherAssertTypes(__DIR__ . "/data/componentModelContainer{$suffix}.php");
}

/**
* @dataProvider dataFileAsserts
* @param mixed ...$args
*/
public function testFileAsserts(
string $assertType,
string $file,
...$args
): void
{
$this->assertFileAsserts($assertType, $file, ...$args);
}

public static function getAdditionalConfigFiles(): array
{
return [
__DIR__ . '/phpstan.neon',
];
}

private static function getInstalledVersion(string $package): ?string
{
if (!class_exists(InstalledVersions::class)) {
return null;
}

try {
$installedVersion = InstalledVersions::getVersion($package);
} catch (OutOfBoundsException $e) {
return null;
}

return $installedVersion;
}

}
20 changes: 20 additions & 0 deletions tests/Type/Nette/data/componentModelContainer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace PHPStan\Type\Nette\Data\ComponentModel;

use Nette\Application\UI\Form;
use Nette\Forms\Container;
use function PHPStan\Testing\assertType;

class SomeForm extends Form {
}

$bool = rand(0, 1) ? true : false;

$someForm = new SomeForm();

assertType('Iterator<int|string, Nette\ComponentModel\IComponent>', $someForm->getComponents(false));
assertType('Iterator<int|string, Nette\Forms\Container>', $someForm->getComponents(false, Container::class));
assertType('Iterator<int|string, Nette\ComponentModel\IComponent>', $someForm->getComponents(true));
assertType('Iterator<int|string, Nette\Forms\Container>', $someForm->getComponents(true, Container::class));
assertType('Iterator<int|string, Nette\ComponentModel\IComponent>', $someControl->getComponents($bool));
20 changes: 20 additions & 0 deletions tests/Type/Nette/data/componentModelContainer31.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace PHPStan\Type\Nette\Data\ComponentModel;

use Nette\Application\UI\Form;
use Nette\Forms\Container;
use function PHPStan\Testing\assertType;

class SomeForm extends Form {
}

$bool = rand(0, 1) ? true : false;

$someForm = new SomeForm();

assertType('array<int|string, Nette\ComponentModel\IComponent>', $someForm->getComponents(false));
assertType('array<int|string, Nette\Forms\Container>', $someForm->getComponents(false, Container::class));
assertType('Iterator<int|string, Nette\ComponentModel\IComponent>', $someForm->getComponents(true));
assertType('Iterator<int|string, Nette\Forms\Container>', $someForm->getComponents(true, Container::class));
assertType('array<int|string, Nette\ComponentModel\IComponent>|Iterator<int|string, Nette\ComponentModel\IComponent>', $someControl->getComponents($bool));

0 comments on commit 3b24c68

Please sign in to comment.