Skip to content

Commit 3b24c68

Browse files
committed
Update ComponentModel\Container stub for component-model 3.1.0
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
1 parent 200d192 commit 3b24c68

7 files changed

+175
-2
lines changed

Diff for: extension.neon

+5-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ parameters:
1111
- stubs/Application/UI/Presenter.stub
1212
- stubs/Caching/Cache.stub
1313
- stubs/ComponentModel/Component.stub
14-
- stubs/ComponentModel/Container.stub
1514
- stubs/ComponentModel/IComponent.stub
1615
- stubs/ComponentModel/IContainer.stub
1716
- stubs/Database/ResultSet.stub
@@ -127,3 +126,8 @@ services:
127126
class: PHPStan\Type\Nette\StringsReplaceCallbackClosureTypeExtension
128127
tags:
129128
- phpstan.staticMethodParameterClosureTypeExtension
129+
130+
-
131+
class: PHPStan\Stubs\Nette\StubFilesExtensionLoader
132+
tags:
133+
- phpstan.stubFilesExtension

Diff for: src/Stubs/Nette/StubFilesExtensionLoader.php

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Stubs\Nette;
4+
5+
use Composer\InstalledVersions;
6+
use OutOfBoundsException;
7+
use PHPStan\PhpDoc\StubFilesExtension;
8+
use function class_exists;
9+
use function dirname;
10+
use function version_compare;
11+
12+
class StubFilesExtensionLoader implements StubFilesExtension
13+
{
14+
15+
public function getFiles(): array
16+
{
17+
$stubsDir = dirname(dirname(dirname(__DIR__))) . '/stubs';
18+
$path = $stubsDir;
19+
20+
$files = [];
21+
22+
$componentModelVersion = self::getInstalledVersion('nette/component-model');
23+
if ($componentModelVersion !== null && version_compare($componentModelVersion, '3.1.0', '>=')) {
24+
$files[] = $path . '/ComponentModel/Container_3_1.stub';
25+
} else {
26+
$files[] = $path . '/ComponentModel/Container.stub';
27+
}
28+
29+
return $files;
30+
}
31+
32+
private static function getInstalledVersion(string $package): ?string
33+
{
34+
if (!class_exists(InstalledVersions::class)) {
35+
return null;
36+
}
37+
38+
try {
39+
$installedVersion = InstalledVersions::getVersion($package);
40+
} catch (OutOfBoundsException $e) {
41+
return null;
42+
}
43+
44+
return $installedVersion;
45+
}
46+
47+
}

Diff for: stubs/ComponentModel/Container.stub

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class Container extends Component implements IContainer
1010
* @phpstan-param null|class-string<T> $filterType
1111
* @phpstan-return ($filterType is null ? \Iterator<int|string, \Nette\ComponentModel\IComponent> : \Iterator<int|string, T>)
1212
*/
13-
public function getComponents(bool $deep = false, string $filterType = null): \Iterator
13+
public function getComponents(bool $deep = false, ?string $filterType = null): \Iterator
1414
{
1515
// nothing
1616
}

Diff for: stubs/ComponentModel/Container_3_1.stub

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace Nette\ComponentModel;
4+
5+
class Container extends Component implements IContainer
6+
{
7+
8+
/**
9+
* @template T of \Nette\ComponentModel\IComponent
10+
* @phpstan-param null|class-string<T> $filterType
11+
* @phpstan-return (
12+
* $deep is false
13+
* ? ($filterType is null ? array<int|string, \Nette\ComponentModel\IComponent> : array<int|string, T>)
14+
* : ($filterType is null ? \Iterator<int|string, \Nette\ComponentModel\IComponent> : \Iterator<int|string, T>)
15+
* )
16+
*/
17+
public function getComponents(bool $deep = false, ?string $filterType = null): iterable
18+
{
19+
// nothing
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Nette;
4+
5+
use Composer\InstalledVersions;
6+
use OutOfBoundsException;
7+
use PHPStan\Testing\TypeInferenceTestCase;
8+
use function class_exists;
9+
use function version_compare;
10+
11+
class ComponentModelContainerDynamicReturnTypeExtensionTest extends TypeInferenceTestCase
12+
{
13+
14+
/**
15+
* @return iterable<string, mixed[]>
16+
*/
17+
public function dataFileAsserts(): iterable
18+
{
19+
$componentModelVersion = self::getInstalledVersion('nette/component-model');
20+
21+
$suffix = $componentModelVersion !== null && version_compare($componentModelVersion, '3.1.0', '>=') ? '31' : '';
22+
23+
yield from self::gatherAssertTypes(__DIR__ . "/data/componentModelContainer{$suffix}.php");
24+
}
25+
26+
/**
27+
* @dataProvider dataFileAsserts
28+
* @param mixed ...$args
29+
*/
30+
public function testFileAsserts(
31+
string $assertType,
32+
string $file,
33+
...$args
34+
): void
35+
{
36+
$this->assertFileAsserts($assertType, $file, ...$args);
37+
}
38+
39+
public static function getAdditionalConfigFiles(): array
40+
{
41+
return [
42+
__DIR__ . '/phpstan.neon',
43+
];
44+
}
45+
46+
private static function getInstalledVersion(string $package): ?string
47+
{
48+
if (!class_exists(InstalledVersions::class)) {
49+
return null;
50+
}
51+
52+
try {
53+
$installedVersion = InstalledVersions::getVersion($package);
54+
} catch (OutOfBoundsException $e) {
55+
return null;
56+
}
57+
58+
return $installedVersion;
59+
}
60+
61+
}

Diff for: tests/Type/Nette/data/componentModelContainer.php

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace PHPStan\Type\Nette\Data\ComponentModel;
4+
5+
use Nette\Application\UI\Form;
6+
use Nette\Forms\Container;
7+
use function PHPStan\Testing\assertType;
8+
9+
class SomeForm extends Form {
10+
}
11+
12+
$bool = rand(0, 1) ? true : false;
13+
14+
$someForm = new SomeForm();
15+
16+
assertType('Iterator<int|string, Nette\ComponentModel\IComponent>', $someForm->getComponents(false));
17+
assertType('Iterator<int|string, Nette\Forms\Container>', $someForm->getComponents(false, Container::class));
18+
assertType('Iterator<int|string, Nette\ComponentModel\IComponent>', $someForm->getComponents(true));
19+
assertType('Iterator<int|string, Nette\Forms\Container>', $someForm->getComponents(true, Container::class));
20+
assertType('Iterator<int|string, Nette\ComponentModel\IComponent>', $someControl->getComponents($bool));

Diff for: tests/Type/Nette/data/componentModelContainer31.php

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace PHPStan\Type\Nette\Data\ComponentModel;
4+
5+
use Nette\Application\UI\Form;
6+
use Nette\Forms\Container;
7+
use function PHPStan\Testing\assertType;
8+
9+
class SomeForm extends Form {
10+
}
11+
12+
$bool = rand(0, 1) ? true : false;
13+
14+
$someForm = new SomeForm();
15+
16+
assertType('array<int|string, Nette\ComponentModel\IComponent>', $someForm->getComponents(false));
17+
assertType('array<int|string, Nette\Forms\Container>', $someForm->getComponents(false, Container::class));
18+
assertType('Iterator<int|string, Nette\ComponentModel\IComponent>', $someForm->getComponents(true));
19+
assertType('Iterator<int|string, Nette\Forms\Container>', $someForm->getComponents(true, Container::class));
20+
assertType('array<int|string, Nette\ComponentModel\IComponent>|Iterator<int|string, Nette\ComponentModel\IComponent>', $someControl->getComponents($bool));

0 commit comments

Comments
 (0)