Skip to content

Commit 0e7a603

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

16 files changed

+811
-666
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 --memory-limit=1G
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: 58 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -5,44 +5,46 @@
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\KernelInterface;
1717
use Symfony\Component\HttpKernel\Profiler\Profiler;
18-
use function array_keys;
18+
1919
use function codecept_debug;
2020

21+
/**
22+
* @property KernelInterface $kernel
23+
*/
2124
class Symfony extends HttpKernelBrowser
2225
{
26+
private ContainerInterface $container;
2327
private bool $hasPerformedRequest = false;
24-
private ?ContainerInterface $container;
2528

29+
/**
30+
* @param Kernel $kernel
31+
* @param array<string, object> $persistentServices
32+
*/
2633
public function __construct(
27-
Kernel $kernel,
34+
$kernel,
2835
public array $persistentServices = [],
29-
private readonly bool $rebootable = true
36+
private bool $reboot = true
3037
) {
3138
parent::__construct($kernel);
3239
$this->followRedirects();
33-
$this->container = $this->getContainer();
40+
$this->container = $this->resolveContainer();
3441
$this->rebootKernel();
3542
}
3643

37-
/** @param Request $request */
3844
protected function doRequest(object $request): Response
3945
{
40-
if ($this->rebootable) {
41-
if ($this->hasPerformedRequest) {
42-
$this->rebootKernel();
43-
} else {
44-
$this->hasPerformedRequest = true;
45-
}
46+
if ($this->reboot) {
47+
$this->hasPerformedRequest ? $this->rebootKernel() : $this->hasPerformedRequest = true;
4648
}
4749

4850
return parent::doRequest($request);
@@ -57,30 +59,27 @@ protected function doRequest(object $request): Response
5759
*/
5860
public function rebootKernel(): void
5961
{
60-
if ($this->container) {
61-
foreach (array_keys($this->persistentServices) as $serviceName) {
62-
if ($service = $this->getService($serviceName)) {
63-
$this->persistentServices[$serviceName] = $service;
64-
}
62+
foreach (array_keys($this->persistentServices) as $service) {
63+
if ($this->container->has($service)) {
64+
$this->persistentServices[$service] = $this->container->get($service);
6565
}
6666
}
6767

6868
$this->persistDoctrineConnections();
69-
$this->ensureKernelShutdown();
70-
$this->kernel->boot();
71-
$this->container = $this->getContainer();
72-
73-
foreach ($this->persistentServices as $serviceName => $service) {
69+
if ($this->kernel instanceof Kernel) {
70+
$this->ensureKernelShutdown();
71+
$this->kernel->boot();
72+
}
73+
$this->container = $this->resolveContainer();
74+
foreach ($this->persistentServices as $name => $service) {
7475
try {
75-
$this->container->set($serviceName, $service);
76+
$this->container->set($name, $service);
7677
} catch (InvalidArgumentException $e) {
77-
codecept_debug("[Symfony] Can't set persistent service {$serviceName}: " . $e->getMessage());
78+
codecept_debug("[Symfony] Can't set persistent service {$name}: {$e->getMessage()}");
7879
}
7980
}
8081

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

8685
protected function ensureKernelShutdown(): void
@@ -89,27 +88,25 @@ protected function ensureKernelShutdown(): void
8988
$this->kernel->shutdown();
9089
}
9190

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

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

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

115112
private function persistDoctrineConnections(): void
@@ -119,20 +116,27 @@ private function persistDoctrineConnections(): void
119116
}
120117

121118
if ($this->container instanceof TestContainer) {
122-
$reflectedTestContainer = new ReflectionMethod($this->container, 'getPublicContainer');
123-
$reflectedTestContainer->setAccessible(true);
124-
$publicContainer = $reflectedTestContainer->invoke($this->container);
119+
$method = new ReflectionMethod($this->container, 'getPublicContainer');
120+
$publicContainer = $method->invoke($this->container);
125121
} else {
126122
$publicContainer = $this->container;
127123
}
128124

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

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);
138+
$params = (array) $prop->getValue($target);
139+
unset($params['doctrine.connections']);
140+
$prop->setValue($target, $params);
137141
}
138142
}

0 commit comments

Comments
 (0)