Skip to content

Commit bfd6d64

Browse files
committed
Module code adapted for PHPStan
1 parent c2adb5c commit bfd6d64

16 files changed

+804
-662
lines changed

.github/workflows/main.yml

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
uses: shivammathur/setup-php@v2
1818
with:
1919
php-version: ${{ matrix.php }}
20-
tools: composer:v2
20+
tools: composer:v2, phpstan
2121
extensions: ctype, iconv, intl, json, mbstring, pdo, pdo_sqlite
2222
coverage: none
2323

@@ -56,39 +56,38 @@ jobs:
5656
uses: actions/cache@v3
5757
with:
5858
path: ${{ steps.composer-cache.outputs.dir }}
59-
key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json', 'composer.lock') }}
59+
key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.{json,lock}') }}
6060
restore-keys: ${{ runner.os }}-php-${{ matrix.php }}-composer-
6161

6262
- name: Install PHPUnit 10
63-
run: composer require --dev --no-update "phpunit/phpunit=^10.0"
63+
run: composer require --dev --no-update phpunit/phpunit:^10.0
6464

6565
- name: Install dependencies
6666
env:
6767
MATRIX_SYMFONY: ${{ matrix.symfony }}
6868
run: |
69-
composer require symfony/finder=${{ env.COMP_SYMFONY }} --no-update
70-
composer require symfony/yaml=${{ env.COMP_SYMFONY }} --no-update
71-
composer require symfony/console=${{ env.COMP_SYMFONY }} --no-update
72-
composer require symfony/event-dispatcher=${{ env.COMP_SYMFONY }} --no-update
73-
composer require symfony/css-selector=${{ env.COMP_SYMFONY }} --no-update
74-
composer require symfony/dom-crawler=${{ env.COMP_SYMFONY }} --no-update
75-
composer require symfony/browser-kit=${{ env.COMP_SYMFONY }} --no-update
76-
composer require vlucas/phpdotenv --no-update
77-
composer require codeception/module-asserts="3.*" --no-update
78-
composer require codeception/module-doctrine="3.*" --no-update
69+
composer require --no-update \
70+
symfony/{finder,yaml,console,event-dispatcher,css-selector,dom-crawler,browser-kit}:${{ env.COMP_SYMFONY }} \
71+
vlucas/phpdotenv \
72+
codeception/module-asserts:"3.*" \
73+
codeception/module-doctrine:"3.*"
7974
8075
if [[ "$MATRIX_SYMFONY" == "6.4wApi" ]]; then
8176
composer require codeception/module-rest="3.*" --no-update
8277
fi
8378
84-
composer update --prefer-dist --no-progress --no-dev
79+
composer update --prefer-dist --no-progress
80+
81+
- name: Run PHPStan (max)
82+
if: ${{ matrix.symfony == '7.2.*' }}
83+
run: phpstan analyse src --level=max --no-progress --error-format=github
8584

8685
- name: Validate Composer files
8786
run: composer validate --strict
8887
working-directory: framework-tests
8988

9089
- name: Install PHPUnit in framework-tests
91-
run: composer require --dev --no-update "phpunit/phpunit=^10.0"
90+
run: composer require --dev --no-update phpunit/phpunit:^10.0
9291
working-directory: framework-tests
9392

9493
- name: Prepare Symfony sample

src/Codeception/Lib/Connector/Symfony.php

Lines changed: 59 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -5,44 +5,47 @@
55
namespace Codeception\Lib\Connector;
66

77
use InvalidArgumentException;
8-
use ReflectionClass;
8+
use LogicException;
99
use ReflectionMethod;
1010
use ReflectionProperty;
1111
use Symfony\Bundle\FrameworkBundle\Test\TestContainer;
1212
use Symfony\Component\DependencyInjection\ContainerInterface;
13-
use Symfony\Component\HttpFoundation\Request;
1413
use Symfony\Component\HttpFoundation\Response;
1514
use Symfony\Component\HttpKernel\HttpKernelBrowser;
1615
use Symfony\Component\HttpKernel\Kernel;
16+
use Symfony\Component\HttpKernel\HttpKernelInterface;
17+
use Symfony\Component\HttpKernel\KernelInterface;
1718
use Symfony\Component\HttpKernel\Profiler\Profiler;
18-
use function array_keys;
19+
1920
use function codecept_debug;
2021

22+
/**
23+
* @property KernelInterface $kernel
24+
*/
2125
class Symfony extends HttpKernelBrowser
2226
{
27+
private ContainerInterface $container;
2328
private bool $hasPerformedRequest = false;
24-
private ?ContainerInterface $container;
2529

30+
/**
31+
* @param Kernel $kernel
32+
* @param array<string, object> $persistentServices
33+
*/
2634
public function __construct(
27-
Kernel $kernel,
35+
$kernel,
2836
public array $persistentServices = [],
29-
private readonly bool $rebootable = true
37+
private bool $reboot = true
3038
) {
3139
parent::__construct($kernel);
3240
$this->followRedirects();
33-
$this->container = $this->getContainer();
41+
$this->container = $this->resolveContainer();
3442
$this->rebootKernel();
3543
}
3644

37-
/** @param Request $request */
3845
protected function doRequest(object $request): Response
3946
{
40-
if ($this->rebootable) {
41-
if ($this->hasPerformedRequest) {
42-
$this->rebootKernel();
43-
} else {
44-
$this->hasPerformedRequest = true;
45-
}
47+
if ($this->reboot) {
48+
$this->hasPerformedRequest ? $this->rebootKernel() : $this->hasPerformedRequest = true;
4649
}
4750

4851
return parent::doRequest($request);
@@ -57,30 +60,27 @@ protected function doRequest(object $request): Response
5760
*/
5861
public function rebootKernel(): void
5962
{
60-
if ($this->container) {
61-
foreach (array_keys($this->persistentServices) as $serviceName) {
62-
if ($service = $this->getService($serviceName)) {
63-
$this->persistentServices[$serviceName] = $service;
64-
}
63+
foreach (array_keys($this->persistentServices) as $service) {
64+
if ($this->container->has($service)) {
65+
$this->persistentServices[$service] = $this->container->get($service);
6566
}
6667
}
6768

6869
$this->persistDoctrineConnections();
69-
$this->ensureKernelShutdown();
70-
$this->kernel->boot();
71-
$this->container = $this->getContainer();
72-
73-
foreach ($this->persistentServices as $serviceName => $service) {
70+
if ($this->kernel instanceof Kernel) {
71+
$this->ensureKernelShutdown();
72+
$this->kernel->boot();
73+
}
74+
$this->container = $this->resolveContainer();
75+
foreach ($this->persistentServices as $name => $service) {
7476
try {
75-
$this->container->set($serviceName, $service);
77+
$this->container->set($name, $service);
7678
} catch (InvalidArgumentException $e) {
77-
codecept_debug("[Symfony] Can't set persistent service {$serviceName}: " . $e->getMessage());
79+
codecept_debug("[Symfony] Can't set persistent service {$name}: {$e->getMessage()}");
7880
}
7981
}
8082

81-
if ($profiler = $this->getProfiler()) {
82-
$profiler->enable();
83-
}
83+
$this->getProfiler()?->enable();
8484
}
8585

8686
protected function ensureKernelShutdown(): void
@@ -89,27 +89,25 @@ protected function ensureKernelShutdown(): void
8989
$this->kernel->shutdown();
9090
}
9191

92-
private function getContainer(): ?ContainerInterface
92+
private function resolveContainer(): ContainerInterface
9393
{
94-
/** @var ContainerInterface $container */
9594
$container = $this->kernel->getContainer();
96-
return $container->has('test.service_container')
97-
? $container->get('test.service_container')
98-
: $container;
99-
}
10095

101-
private function getProfiler(): ?Profiler
102-
{
103-
return $this->container->has('profiler')
104-
? $this->container->get('profiler')
105-
: null;
96+
if ($container->has('test.service_container')) {
97+
$testContainer = $container->get('test.service_container');
98+
if (!$testContainer instanceof ContainerInterface) {
99+
throw new LogicException('Service "test.service_container" must implement ' . ContainerInterface::class);
100+
}
101+
$container = $testContainer;
102+
}
103+
104+
return $container;
106105
}
107106

108-
private function getService(string $serviceName): ?object
107+
private function getProfiler(): ?Profiler
109108
{
110-
return $this->container->has($serviceName)
111-
? $this->container->get($serviceName)
112-
: null;
109+
$profiler = $this->container->get('profiler');
110+
return $profiler instanceof Profiler ? $profiler : null;
113111
}
114112

115113
private function persistDoctrineConnections(): void
@@ -119,20 +117,27 @@ private function persistDoctrineConnections(): void
119117
}
120118

121119
if ($this->container instanceof TestContainer) {
122-
$reflectedTestContainer = new ReflectionMethod($this->container, 'getPublicContainer');
123-
$reflectedTestContainer->setAccessible(true);
124-
$publicContainer = $reflectedTestContainer->invoke($this->container);
120+
$method = new ReflectionMethod($this->container, 'getPublicContainer');
121+
$publicContainer = $method->invoke($this->container);
125122
} else {
126123
$publicContainer = $this->container;
127124
}
128125

129-
$reflectedContainer = new ReflectionClass($publicContainer);
130-
$reflectionTarget = $reflectedContainer->hasProperty('parameters') ? $publicContainer : $publicContainer->getParameterBag();
126+
if (!is_object($publicContainer) || !method_exists($publicContainer, 'getParameterBag')) {
127+
return;
128+
}
129+
130+
$target = property_exists($publicContainer, 'parameters')
131+
? $publicContainer
132+
: $publicContainer->getParameterBag();
133+
134+
if (!is_object($target) || !property_exists($target, 'parameters')) {
135+
return;
136+
}
137+
$prop = new ReflectionProperty($target, 'parameters');
131138

132-
$reflectedParameters = new ReflectionProperty($reflectionTarget, 'parameters');
133-
$reflectedParameters->setAccessible(true);
134-
$parameters = $reflectedParameters->getValue($reflectionTarget);
135-
unset($parameters['doctrine.connections']);
136-
$reflectedParameters->setValue($reflectionTarget, $parameters);
139+
$params = (array) $prop->getValue($target);
140+
unset($params['doctrine.connections']);
141+
$prop->setValue($target, $params);
137142
}
138143
}

0 commit comments

Comments
 (0)