Skip to content

Commit 49393a4

Browse files
authored
feat: Merge pull request #119 from TavoNiievez/php_features
Implement new PHP features up to 8.2
2 parents 833a9e6 + 93c9135 commit 49393a4

File tree

9 files changed

+144
-204
lines changed

9 files changed

+144
-204
lines changed

composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
"codemix/yii2-localeurls": "^1.7",
3030
"codeception/module-asserts": ">= 3.0",
3131
"codeception/module-filesystem": "> 3.0",
32-
"phpstan/phpstan": "^1.10"
32+
"phpstan/phpstan": "^1.10",
33+
"rector/rector": "^1.2"
3334
},
3435
"autoload":{
3536
"classmap": ["src/"]

phpstan.neon

+2-3
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@ parameters:
99
paths:
1010
- src
1111
checkMaybeUndefinedVariables: true
12-
checkGenericClassInNonGenericObjectType: false
1312
ignoreErrors:
1413
# All Yii setters accept `null` but their phpdoc is incorrect.
1514
- message: '~^Parameter #1 \$(.+) of method yii\\web\\Request::set(.+)\(\) expects (.+), null given.$~'
1615
path: 'src/'
17-
- message: '~^Variable \$_COOKIE in isset\(\) always exists and is not nullable.$~'
18-
path: 'src/'
16+
# If you want to ignore missing generics errors in the future, you can add:
17+
# - identifier: missingType.generics
1918
stubFiles:
2019
- tests/Yii.stub

src/Codeception/Lib/Connector/Yii2.php

+33-49
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Codeception\Lib\Connector\Yii2\Logger;
99
use Codeception\Lib\Connector\Yii2\TestMailer;
1010
use Codeception\Util\Debug;
11+
use InvalidArgumentException;
1112
use Symfony\Component\BrowserKit\AbstractBrowser as Client;
1213
use Symfony\Component\BrowserKit\Cookie;
1314
use Symfony\Component\BrowserKit\CookieJar;
@@ -114,7 +115,7 @@ public function getApplication(): \yii\base\Application
114115
public function resetApplication(bool $closeSession = true): void
115116
{
116117
codecept_debug('Destroying application');
117-
if (true === $closeSession) {
118+
if ($closeSession) {
118119
$this->closeSession();
119120
}
120121
Yii::$app = null;
@@ -141,13 +142,13 @@ public function findAndLoginUser(int|string|IdentityInterface $user): void
141142
throw new ConfigurationException('The user component is not configured');
142143
}
143144

144-
if ($user instanceof \yii\web\IdentityInterface) {
145+
if ($user instanceof IdentityInterface) {
145146
$identity = $user;
146147
} else {
147148
// class name implementing IdentityInterface
148149
$identityClass = $userComponent->identityClass;
149-
$identity = call_user_func([$identityClass, 'findIdentity'], $user);
150-
if (!isset($identity)) {
150+
$identity = $identityClass::findIdentity($user);
151+
if ($identity === null) {
151152
throw new \RuntimeException('User not found');
152153
}
153154
}
@@ -181,7 +182,7 @@ public function getInternalDomains(): array
181182
if ($urlManager->enablePrettyUrl) {
182183
foreach ($urlManager->rules as $rule) {
183184
/** @var \yii\web\UrlRule $rule */
184-
if (isset($rule->host)) {
185+
if ($rule->host !== null) {
185186
$domains[] = $this->getDomainRegex($rule->host);
186187
}
187188
}
@@ -228,12 +229,12 @@ private function getDomainRegex(string $template): string
228229
$template = $matches[1];
229230
}
230231
$parameters = [];
231-
if (strpos($template, '<') !== false) {
232+
if (str_contains($template, '<')) {
232233
$template = preg_replace_callback(
233234
'/<(?:\w+):?([^>]+)?>/u',
234-
function ($matches) use (&$parameters) {
235+
function ($matches) use (&$parameters): string {
235236
$key = '__' . count($parameters) . '__';
236-
$parameters[$key] = isset($matches[1]) ? $matches[1] : '\w+';
237+
$parameters[$key] = $matches[1] ?? '\w+';
237238
return $key;
238239
},
239240
$template
@@ -258,24 +259,18 @@ public function startApp(?\yii\log\Logger $logger = null): void
258259
codecept_debug('Starting application');
259260
$config = require($this->configFile);
260261
if (!isset($config['class'])) {
261-
if (null !== $this->applicationClass) {
262-
$config['class'] = $this->applicationClass;
263-
} else {
264-
$config['class'] = 'yii\web\Application';
265-
}
262+
$config['class'] = $this->applicationClass ?? \yii\web\Application::class;
266263
}
267264

268-
if (isset($config['container']))
269-
{
265+
if (isset($config['container'])) {
270266
Yii::configure(Yii::$container, $config['container']);
271267
unset($config['container']);
272268
}
273269

274270
$config = $this->mockMailer($config);
275-
/** @var \yii\base\Application $app */
276271
Yii::$app = Yii::createObject($config);
277272

278-
if ($logger !== null) {
273+
if ($logger instanceof \yii\log\Logger) {
279274
Yii::setLogger($logger);
280275
} else {
281276
Yii::setLogger(new Logger());
@@ -326,9 +321,6 @@ public function doRequest(object $request): \Symfony\Component\BrowserKit\Respon
326321
$target->enabled = false;
327322
}
328323

329-
330-
331-
332324
$yiiRequest = $app->getRequest();
333325
if ($request->getContent() !== null) {
334326
$yiiRequest->setRawBody($request->getContent());
@@ -441,7 +433,7 @@ protected function mockMailer(array $config): array
441433

442434
$mailerConfig = [
443435
'class' => TestMailer::class,
444-
'callback' => function (MessageInterface $message) {
436+
'callback' => function (MessageInterface $message): void {
445437
$this->emails[] = $message;
446438
}
447439
];
@@ -474,7 +466,7 @@ public function getContext(): array
474466
{
475467
return [
476468
'cookieJar' => $this->cookieJar,
477-
'history' => $this->history,
469+
'history' => $this->history,
478470
];
479471
}
480472

@@ -509,11 +501,12 @@ protected function resetResponse(Application $app): void
509501
{
510502
$method = $this->responseCleanMethod;
511503
// First check the current response object.
512-
if (($app->response->hasEventHandlers(\yii\web\Response::EVENT_BEFORE_SEND)
513-
|| $app->response->hasEventHandlers(\yii\web\Response::EVENT_AFTER_SEND)
514-
|| $app->response->hasEventHandlers(\yii\web\Response::EVENT_AFTER_PREPARE)
515-
|| count($app->response->getBehaviors()) > 0
516-
) && $method === self::CLEAN_RECREATE
504+
if (
505+
($app->response->hasEventHandlers(YiiResponse::EVENT_BEFORE_SEND)
506+
|| $app->response->hasEventHandlers(YiiResponse::EVENT_AFTER_SEND)
507+
|| $app->response->hasEventHandlers(YiiResponse::EVENT_AFTER_PREPARE)
508+
|| count($app->response->getBehaviors()) > 0)
509+
&& $method === self::CLEAN_RECREATE
517510
) {
518511
Debug::debug(<<<TEXT
519512
[WARNING] You are attaching event handlers or behaviors to the response object. But the Yii2 module is configured to recreate
@@ -525,17 +518,12 @@ protected function resetResponse(Application $app): void
525518
$method = self::CLEAN_CLEAR;
526519
}
527520

528-
switch ($method) {
529-
case self::CLEAN_FORCE_RECREATE:
530-
case self::CLEAN_RECREATE:
531-
$app->set('response', $app->getComponents()['response']);
532-
break;
533-
case self::CLEAN_CLEAR:
534-
$app->response->clear();
535-
break;
536-
case self::CLEAN_MANUAL:
537-
break;
538-
}
521+
match ($method) {
522+
self::CLEAN_FORCE_RECREATE, self::CLEAN_RECREATE => $app->set('response', $app->getComponents()['response']),
523+
self::CLEAN_CLEAR => $app->response->clear(),
524+
self::CLEAN_MANUAL => null,
525+
default => throw new InvalidArgumentException("Unknown method: $method"),
526+
};
539527
}
540528

541529
protected function resetRequest(Application $app): void
@@ -555,12 +543,9 @@ protected function resetRequest(Application $app): void
555543
$method = self::CLEAN_CLEAR;
556544
}
557545

558-
switch ($method) {
559-
case self::CLEAN_FORCE_RECREATE:
560-
case self::CLEAN_RECREATE:
561-
$app->set('request', $app->getComponents()['request']);
562-
break;
563-
case self::CLEAN_CLEAR:
546+
match ($method) {
547+
self::CLEAN_FORCE_RECREATE, self::CLEAN_RECREATE => $app->set('request', $app->getComponents()['request']),
548+
self::CLEAN_CLEAR => (function () use ($request): void {
564549
$request->getHeaders()->removeAll();
565550
$request->setBaseUrl(null);
566551
$request->setHostInfo(null);
@@ -572,11 +557,10 @@ protected function resetRequest(Application $app): void
572557
$request->setSecurePort(0);
573558
$request->setAcceptableContentTypes(null);
574559
$request->setAcceptableLanguages(null);
575-
576-
break;
577-
case self::CLEAN_MANUAL:
578-
break;
579-
}
560+
})(),
561+
self::CLEAN_MANUAL => null,
562+
default => throw new InvalidArgumentException("Unknown method: $method"),
563+
};
580564
}
581565

582566
/**

src/Codeception/Lib/Connector/Yii2/ConnectionWatcher.php

+8-5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
namespace Codeception\Lib\Connector\Yii2;
66

7+
use Closure;
8+
use JsonSerializable;
9+
use ReflectionClass;
710
use yii\base\Event;
811
use yii\db\Connection;
912

@@ -14,14 +17,14 @@
1417
*/
1518
class ConnectionWatcher
1619
{
17-
private \Closure $handler;
20+
private Closure $handler;
1821

1922
/** @var Connection[] */
2023
private array $connections = [];
2124

2225
public function __construct()
2326
{
24-
$this->handler = function (Event $event) {
27+
$this->handler = function (Event $event): void {
2528
if ($event->sender instanceof Connection) {
2629
$this->connectionOpened($event->sender);
2730
}
@@ -55,10 +58,10 @@ public function closeAll(): void
5558
}
5659
}
5760

58-
protected function debug($message): void
61+
protected function debug(string|array|JsonSerializable $message): void
5962
{
60-
$title = (new \ReflectionClass($this))->getShortName();
61-
if (is_array($message) or is_object($message)) {
63+
$title = (new ReflectionClass($this))->getShortName();
64+
if (is_array($message) || is_object($message)) {
6265
$message = stripslashes(json_encode($message));
6366
}
6467
codecept_debug("[$title] $message");

src/Codeception/Lib/Connector/Yii2/FixturesStore.php

+6-7
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,24 @@ class FixturesStore
1111
{
1212
use FixtureTrait;
1313

14-
protected $data;
15-
1614
/**
1715
* Expects fixtures config
1816
*
1917
* FixturesStore constructor.
20-
* @param $data
2118
*/
22-
public function __construct($data)
19+
public function __construct(protected mixed $data)
2320
{
24-
$this->data = $data;
2521
}
2622

27-
public function fixtures()
23+
public function fixtures(): mixed
2824
{
2925
return $this->data;
3026
}
3127

32-
public function globalFixtures()
28+
/**
29+
* @return array{initDbFixture: array{class: class-string}}
30+
*/
31+
public function globalFixtures(): array
3332
{
3433
return [
3534
'initDbFixture' => [

src/Codeception/Lib/Connector/Yii2/Logger.php

+14-21
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
namespace Codeception\Lib\Connector\Yii2;
66

77
use Codeception\Util\Debug;
8+
use yii\base\Exception as YiiException;
89
use yii\helpers\VarDumper;
10+
use yii\log\Logger as YiiLogger;
911

10-
class Logger extends \yii\log\Logger
12+
class Logger extends YiiLogger
1113
{
1214
private \SplQueue $logQueue;
1315

14-
public function __construct(private int $maxLogItems = 5, $config = [])
16+
public function __construct(private int $maxLogItems = 5, array $config = [])
1517
{
1618
parent::__construct($config);
1719
$this->logQueue = new \SplQueue();
@@ -23,33 +25,28 @@ public function init(): void
2325
}
2426

2527
/**
26-
* @param string|array<mixed>|\yii\base\Exception $message
27-
* @param $level
28-
* @param $category
29-
* @return void
28+
* @param string|array|YiiException $message
29+
* @param self::LEVEL_INFO|self::LEVEL_WARNING|self::LEVEL_ERROR $level
30+
* @param string $category
3031
*/
3132
public function log($message, $level, $category = 'application'): void
3233
{
3334
if (!in_array($level, [
34-
\yii\log\Logger::LEVEL_INFO,
35-
\yii\log\Logger::LEVEL_WARNING,
36-
\yii\log\Logger::LEVEL_ERROR,
37-
])) {
35+
self::LEVEL_INFO,
36+
self::LEVEL_WARNING,
37+
self::LEVEL_ERROR,
38+
], true)) {
3839
return;
3940
}
4041
if (str_starts_with($category, 'yii\db\Command')) {
4142
return; // don't log queries
4243
}
43-
4444
// https://github.com/Codeception/Codeception/issues/3696
45-
if ($message instanceof \yii\base\Exception) {
45+
if ($message instanceof YiiException) {
4646
$message = $message->__toString();
4747
}
48-
4948
$logMessage = "[$category] " . VarDumper::export($message);
50-
5149
Debug::debug($logMessage);
52-
5350
$this->logQueue->enqueue($logMessage);
5451
if ($this->logQueue->count() > $this->maxLogItems) {
5552
$this->logQueue->dequeue();
@@ -58,12 +55,8 @@ public function log($message, $level, $category = 'application'): void
5855

5956
public function getAndClearLog(): string
6057
{
61-
$completeStr = '';
62-
foreach ($this->logQueue as $item) {
63-
$completeStr .= $item . PHP_EOL;
64-
}
58+
$logs = iterator_to_array($this->logQueue);
6559
$this->logQueue = new \SplQueue();
66-
67-
return $completeStr;
60+
return implode(PHP_EOL, $logs) . PHP_EOL;
6861
}
6962
}

src/Codeception/Lib/Connector/Yii2/TestMailer.php

+7-9
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,24 @@
44

55
namespace Codeception\Lib\Connector\Yii2;
66

7+
use Closure;
78
use yii\mail\BaseMailer;
89

910
class TestMailer extends BaseMailer
1011
{
1112
public $messageClass = \yii\symfonymailer\Message::class;
1213

13-
/**
14-
* @var \Closure
15-
*/
16-
public $callback;
14+
public Closure $callback;
1715

18-
protected function sendMessage($message)
16+
protected function sendMessage(mixed $message): bool
1917
{
20-
call_user_func($this->callback, $message);
18+
($this->callback)($message);
2119
return true;
2220
}
23-
24-
protected function saveMessage($message)
21+
22+
protected function saveMessage(mixed $message): bool
2523
{
26-
call_user_func($this->callback, $message);
24+
($this->callback)($message);
2725
return true;
2826
}
2927
}

0 commit comments

Comments
 (0)