Skip to content

Commit baba622

Browse files
committed
chore(cs): fix all phpstan errors, increase level
1 parent 0b08f64 commit baba622

File tree

5 files changed

+203
-77
lines changed

5 files changed

+203
-77
lines changed

src/Codeception/Lib/Connector/Yii2.php

Lines changed: 63 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Codeception\Lib\Connector;
66

77
use Codeception\Exception\ConfigurationException;
8+
use Codeception\Exception\ModuleConfigException;
89
use Codeception\Lib\Connector\Yii2\Logger;
910
use Codeception\Lib\Connector\Yii2\TestMailer;
1011
use Codeception\Util\Debug;
@@ -13,11 +14,15 @@
1314
use Symfony\Component\BrowserKit\Cookie;
1415
use Symfony\Component\BrowserKit\CookieJar;
1516
use Symfony\Component\BrowserKit\History;
17+
use Symfony\Component\BrowserKit\Request as BrowserkitRequest;
1618
use Symfony\Component\BrowserKit\Response;
1719
use Yii;
20+
use yii\base\Component;
21+
use yii\base\Event;
1822
use yii\base\ExitException;
1923
use yii\base\Security;
2024
use yii\base\UserException;
25+
use yii\mail\BaseMessage;
2126
use yii\mail\MessageInterface;
2227
use yii\web\Application;
2328
use yii\web\ErrorHandler;
@@ -26,6 +31,10 @@
2631
use yii\web\Response as YiiResponse;
2732
use yii\web\User;
2833

34+
35+
/**
36+
* @extends Client<BrowserkitRequest, Response>
37+
*/
2938
class Yii2 extends Client
3039
{
3140
use Shared\PhpSuperGlobalsConverter;
@@ -98,18 +107,29 @@ class Yii2 extends Client
98107
public string|null $applicationClass = null;
99108

100109

110+
/**
111+
* @var list<BaseMessage>
112+
*/
101113
private array $emails = [];
102114

103115
/**
104-
* @deprecated since 2.5, will become protected in 3.0. Directly access to \Yii::$app if you need to interact with it.
105116
* @internal
106117
*/
107-
public function getApplication(): \yii\base\Application
118+
protected function getApplication(): \yii\base\Application
108119
{
109120
if (!isset(Yii::$app)) {
110121
$this->startApp();
111122
}
112-
return Yii::$app;
123+
return Yii::$app ?? throw new \RuntimeException('Failed to create Yii2 application');
124+
}
125+
126+
private function getWebRequest(): Request
127+
{
128+
$request = $this->getApplication()->request;
129+
if (!$request instanceof Request) {
130+
throw new \RuntimeException('Request component is not of type ' . Request::class);
131+
}
132+
return $request;
113133
}
114134

115135
public function resetApplication(bool $closeSession = true): void
@@ -120,9 +140,7 @@ public function resetApplication(bool $closeSession = true): void
120140
}
121141
Yii::$app = null;
122142
\yii\web\UploadedFile::reset();
123-
if (method_exists(\yii\base\Event::class, 'offAll')) {
124-
\yii\base\Event::offAll();
125-
}
143+
Event::offAll();
126144
Yii::setLogger(null);
127145
// This resolves an issue with database connections not closing properly.
128146
gc_collect_cycles();
@@ -161,23 +179,27 @@ public function findAndLoginUser(int|string|IdentityInterface $user): void
161179
* @param string $value The value of the cookie
162180
* @return string The value to send to the browser
163181
*/
164-
public function hashCookieData($name, $value): string
182+
public function hashCookieData(string $name, string $value): string
165183
{
166184
$app = $this->getApplication();
167-
if (!$app->request->enableCookieValidation) {
185+
$request = $app->getRequest();
186+
if (!$request instanceof Request) {
187+
throw new \RuntimeException("Can't do cookie operations on non-web requests");
188+
}
189+
if (!$request->enableCookieValidation) {
168190
return $value;
169191
}
170-
return $app->security->hashData(serialize([$name, $value]), $app->request->cookieValidationKey);
192+
return $app->security->hashData(serialize([$name, $value]), $request->cookieValidationKey);
171193
}
172194

173195
/**
174196
* @internal
175-
* @return array List of regex patterns for recognized domain names
197+
* @return non-empty-list<string> List of regex patterns for recognized domain names
176198
*/
177199
public function getInternalDomains(): array
178200
{
179-
/** @var \yii\web\UrlManager $urlManager */
180201
$urlManager = $this->getApplication()->urlManager;
202+
181203
$domains = [$this->getDomainRegex($urlManager->hostInfo)];
182204
if ($urlManager->enablePrettyUrl) {
183205
foreach ($urlManager->rules as $rule) {
@@ -187,12 +209,12 @@ public function getInternalDomains(): array
187209
}
188210
}
189211
}
190-
return array_unique($domains);
212+
return array_values(array_unique($domains));
191213
}
192214

193215
/**
194216
* @internal
195-
* @return array List of sent emails
217+
* @return list<BaseMessage> List of sent emails
196218
*/
197219
public function getEmails(): array
198220
{
@@ -211,13 +233,14 @@ public function clearEmails(): void
211233
/**
212234
* @internal
213235
*/
214-
public function getComponent($name)
236+
public function getComponent(string $name): object|null
215237
{
216238
$app = $this->getApplication();
217-
if (!$app->has($name)) {
239+
$result = $app->get($name, false);
240+
if (!isset($result)) {
218241
throw new ConfigurationException("Component $name is not available in current application");
219242
}
220-
return $app->get($name);
243+
return $result;
221244
}
222245

223246
/**
@@ -240,6 +263,9 @@ function ($matches) use (&$parameters): string {
240263
$template
241264
);
242265
}
266+
if ($template === null) {
267+
throw new \RuntimeException("Failed to parse domain regex");
268+
}
243269
$template = preg_quote($template);
244270
$template = strtr($template, $parameters);
245271
return '/^' . $template . '$/u';
@@ -251,7 +277,7 @@ function ($matches) use (&$parameters): string {
251277
*/
252278
public function getCsrfParamName(): string
253279
{
254-
return $this->getApplication()->request->csrfParam;
280+
return $this->getWebRequest()->csrfParam;
255281
}
256282

257283
public function startApp(?\yii\log\Logger $logger = null): void
@@ -268,7 +294,11 @@ public function startApp(?\yii\log\Logger $logger = null): void
268294
}
269295

270296
$config = $this->mockMailer($config);
271-
Yii::$app = Yii::createObject($config);
297+
$app = Yii::createObject($config);
298+
if (!$app instanceof \yii\base\Application) {
299+
throw new ModuleConfigException($this, "Failed to initialize Yii2 app");
300+
}
301+
\Yii::$app = $app;
272302

273303
if ($logger instanceof \yii\log\Logger) {
274304
Yii::setLogger($logger);
@@ -278,9 +308,9 @@ public function startApp(?\yii\log\Logger $logger = null): void
278308
}
279309

280310
/**
281-
* @param \Symfony\Component\BrowserKit\Request $request
311+
* @param BrowserkitRequest $request
282312
*/
283-
public function doRequest(object $request): \Symfony\Component\BrowserKit\Response
313+
public function doRequest(object $request): Response
284314
{
285315
$_COOKIE = $request->getCookies();
286316
$_SERVER = $request->getServer();
@@ -362,18 +392,13 @@ public function doRequest(object $request): \Symfony\Component\BrowserKit\Respon
362392
$content = ob_get_clean();
363393
if (empty($content) && !empty($response->content) && !isset($response->stream)) {
364394
throw new \Exception('No content was sent from Yii application');
395+
} elseif ($content === false) {
396+
throw new \Exception('Failed to get output buffer');
365397
}
366398

367399
return new Response($content, $response->statusCode, $response->getHeaders()->toArray());
368400
}
369401

370-
protected function revertErrorHandler()
371-
{
372-
$handler = new ErrorHandler();
373-
set_error_handler([$handler, 'errorHandler']);
374-
}
375-
376-
377402
/**
378403
* Encodes the cookies and adds them to the headers.
379404
* @throws \yii\base\InvalidConfigException
@@ -433,11 +458,19 @@ protected function mockMailer(array $config): array
433458

434459
$mailerConfig = [
435460
'class' => TestMailer::class,
436-
'callback' => function (MessageInterface $message): void {
461+
'callback' => function (BaseMessage $message): void {
437462
$this->emails[] = $message;
438463
}
439464
];
440465

466+
if (isset($config['components'])) {
467+
if (!is_array($config['components'])) {
468+
throw new ModuleConfigException($this,
469+
"Yii2 config does not contain components key is not of type array");
470+
}
471+
} else {
472+
$config['components'] = [];
473+
}
441474
if (isset($config['components']['mailer']) && is_array($config['components']['mailer'])) {
442475
foreach ($config['components']['mailer'] as $name => $value) {
443476
if (in_array($name, $allowedOptions, true)) {
@@ -511,8 +544,8 @@ protected function resetResponse(Application $app): void
511544
Debug::debug(<<<TEXT
512545
[WARNING] You are attaching event handlers or behaviors to the response object. But the Yii2 module is configured to recreate
513546
the response object, this means any behaviors or events that are not attached in the component config will be lost.
514-
We will fall back to clearing the response. If you are certain you want to recreate it, please configure
515-
responseCleanMethod = 'force_recreate' in the module.
547+
We will fall back to clearing the response. If you are certain you want to recreate it, please configure
548+
responseCleanMethod = 'force_recreate' in the module.
516549
TEXT
517550
);
518551
$method = self::CLEAN_CLEAR;

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,15 @@ public function closeAll(): void
5858
}
5959
}
6060

61+
/**
62+
* @param string|array<mixed>|JsonSerializable $message
63+
* @return void
64+
*/
6165
protected function debug(string|array|JsonSerializable $message): void
6266
{
6367
$title = (new ReflectionClass($this))->getShortName();
6468
if (is_array($message) || is_object($message)) {
65-
$message = stripslashes(json_encode($message));
69+
$message = stripslashes(json_encode($message, JSON_THROW_ON_ERROR));
6670
}
6771
codecept_debug("[$title] $message");
6872
}

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,16 @@
1111

1212
class Logger extends YiiLogger
1313
{
14+
/**
15+
* @var \SplQueue<string>
16+
*/
1417
private \SplQueue $logQueue;
1518

16-
public function __construct(private int $maxLogItems = 5, array $config = [])
19+
/**
20+
* @param int $maxLogItems
21+
* @param array<string, mixed> $config
22+
*/
23+
public function __construct(private readonly int $maxLogItems = 5, array $config = [])
1724
{
1825
parent::__construct($config);
1926
$this->logQueue = new \SplQueue();
@@ -25,7 +32,7 @@ public function init(): void
2532
}
2633

2734
/**
28-
* @param string|array|YiiException $message
35+
* @param string|array<mixed>|YiiException $message
2936
* @param self::LEVEL_INFO|self::LEVEL_WARNING|self::LEVEL_ERROR $level
3037
* @param string $category
3138
*/

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,17 @@
1515
*/
1616
class TransactionForcer extends ConnectionWatcher
1717
{
18+
/**
19+
* @var array<string, \PDO>
20+
*/
1821
private array $pdoCache = [];
22+
/**
23+
* @var array<string, string>
24+
*/
1925
private array $dsnCache = [];
26+
/**
27+
* @var array<string, Transaction>
28+
*/
2029
private array $transactions = [];
2130

2231
public function __construct(private bool $ignoreCollidingDSN)
@@ -40,13 +49,13 @@ protected function connectionOpened(Connection $connection): void
4049
'attributes' => $connection->attributes,
4150
'emulatePrepare' => $connection->emulatePrepare,
4251
'charset' => $connection->charset,
43-
]));
52+
], JSON_THROW_ON_ERROR));
4453
/*
4554
* If keys match we assume connections are "similar enough".
4655
*/
4756
if (isset($this->pdoCache[$key])) {
4857
$connection->pdo = $this->pdoCache[$key];
49-
} else {
58+
} elseif(isset($connection->pdo)) {
5059
$this->pdoCache[$key] = $connection->pdo;
5160
}
5261
if (isset($this->dsnCache[$connection->dsn])

0 commit comments

Comments
 (0)