diff --git a/composer.json b/composer.json index a447850..8cb1f78 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,8 @@ "codemix/yii2-localeurls": "^1.7", "codeception/module-asserts": ">= 3.0", "codeception/module-filesystem": "> 3.0", - "phpstan/phpstan": "^1.10" + "phpstan/phpstan": "^1.10", + "rector/rector": "^1.2" }, "autoload":{ "classmap": ["src/"] diff --git a/phpstan.neon b/phpstan.neon index efda0f0..7019dd5 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -9,12 +9,11 @@ parameters: paths: - src checkMaybeUndefinedVariables: true - checkGenericClassInNonGenericObjectType: false ignoreErrors: # All Yii setters accept `null` but their phpdoc is incorrect. - message: '~^Parameter #1 \$(.+) of method yii\\web\\Request::set(.+)\(\) expects (.+), null given.$~' path: 'src/' - - message: '~^Variable \$_COOKIE in isset\(\) always exists and is not nullable.$~' - path: 'src/' + # If you want to ignore missing generics errors in the future, you can add: + # - identifier: missingType.generics stubFiles: - tests/Yii.stub diff --git a/src/Codeception/Lib/Connector/Yii2.php b/src/Codeception/Lib/Connector/Yii2.php index 890ab45..b7df1d5 100644 --- a/src/Codeception/Lib/Connector/Yii2.php +++ b/src/Codeception/Lib/Connector/Yii2.php @@ -8,6 +8,7 @@ use Codeception\Lib\Connector\Yii2\Logger; use Codeception\Lib\Connector\Yii2\TestMailer; use Codeception\Util\Debug; +use InvalidArgumentException; use Symfony\Component\BrowserKit\AbstractBrowser as Client; use Symfony\Component\BrowserKit\Cookie; use Symfony\Component\BrowserKit\CookieJar; @@ -114,7 +115,7 @@ public function getApplication(): \yii\base\Application public function resetApplication(bool $closeSession = true): void { codecept_debug('Destroying application'); - if (true === $closeSession) { + if ($closeSession) { $this->closeSession(); } Yii::$app = null; @@ -141,13 +142,13 @@ public function findAndLoginUser(int|string|IdentityInterface $user): void throw new ConfigurationException('The user component is not configured'); } - if ($user instanceof \yii\web\IdentityInterface) { + if ($user instanceof IdentityInterface) { $identity = $user; } else { // class name implementing IdentityInterface $identityClass = $userComponent->identityClass; - $identity = call_user_func([$identityClass, 'findIdentity'], $user); - if (!isset($identity)) { + $identity = $identityClass::findIdentity($user); + if ($identity === null) { throw new \RuntimeException('User not found'); } } @@ -181,7 +182,7 @@ public function getInternalDomains(): array if ($urlManager->enablePrettyUrl) { foreach ($urlManager->rules as $rule) { /** @var \yii\web\UrlRule $rule */ - if (isset($rule->host)) { + if ($rule->host !== null) { $domains[] = $this->getDomainRegex($rule->host); } } @@ -228,12 +229,12 @@ private function getDomainRegex(string $template): string $template = $matches[1]; } $parameters = []; - if (strpos($template, '<') !== false) { + if (str_contains($template, '<')) { $template = preg_replace_callback( '/<(?:\w+):?([^>]+)?>/u', - function ($matches) use (&$parameters) { + function ($matches) use (&$parameters): string { $key = '__' . count($parameters) . '__'; - $parameters[$key] = isset($matches[1]) ? $matches[1] : '\w+'; + $parameters[$key] = $matches[1] ?? '\w+'; return $key; }, $template @@ -258,24 +259,18 @@ public function startApp(?\yii\log\Logger $logger = null): void codecept_debug('Starting application'); $config = require($this->configFile); if (!isset($config['class'])) { - if (null !== $this->applicationClass) { - $config['class'] = $this->applicationClass; - } else { - $config['class'] = 'yii\web\Application'; - } + $config['class'] = $this->applicationClass ?? \yii\web\Application::class; } - if (isset($config['container'])) - { + if (isset($config['container'])) { Yii::configure(Yii::$container, $config['container']); unset($config['container']); } $config = $this->mockMailer($config); - /** @var \yii\base\Application $app */ Yii::$app = Yii::createObject($config); - if ($logger !== null) { + if ($logger instanceof \yii\log\Logger) { Yii::setLogger($logger); } else { Yii::setLogger(new Logger()); @@ -326,9 +321,6 @@ public function doRequest(object $request): \Symfony\Component\BrowserKit\Respon $target->enabled = false; } - - - $yiiRequest = $app->getRequest(); if ($request->getContent() !== null) { $yiiRequest->setRawBody($request->getContent()); @@ -441,7 +433,7 @@ protected function mockMailer(array $config): array $mailerConfig = [ 'class' => TestMailer::class, - 'callback' => function (MessageInterface $message) { + 'callback' => function (MessageInterface $message): void { $this->emails[] = $message; } ]; @@ -474,7 +466,7 @@ public function getContext(): array { return [ 'cookieJar' => $this->cookieJar, - 'history' => $this->history, + 'history' => $this->history, ]; } @@ -509,11 +501,12 @@ protected function resetResponse(Application $app): void { $method = $this->responseCleanMethod; // First check the current response object. - if (($app->response->hasEventHandlers(\yii\web\Response::EVENT_BEFORE_SEND) - || $app->response->hasEventHandlers(\yii\web\Response::EVENT_AFTER_SEND) - || $app->response->hasEventHandlers(\yii\web\Response::EVENT_AFTER_PREPARE) - || count($app->response->getBehaviors()) > 0 - ) && $method === self::CLEAN_RECREATE + if ( + ($app->response->hasEventHandlers(YiiResponse::EVENT_BEFORE_SEND) + || $app->response->hasEventHandlers(YiiResponse::EVENT_AFTER_SEND) + || $app->response->hasEventHandlers(YiiResponse::EVENT_AFTER_PREPARE) + || count($app->response->getBehaviors()) > 0) + && $method === self::CLEAN_RECREATE ) { Debug::debug(<<set('response', $app->getComponents()['response']); - break; - case self::CLEAN_CLEAR: - $app->response->clear(); - break; - case self::CLEAN_MANUAL: - break; - } + match ($method) { + self::CLEAN_FORCE_RECREATE, self::CLEAN_RECREATE => $app->set('response', $app->getComponents()['response']), + self::CLEAN_CLEAR => $app->response->clear(), + self::CLEAN_MANUAL => null, + default => throw new InvalidArgumentException("Unknown method: $method"), + }; } protected function resetRequest(Application $app): void @@ -555,12 +543,9 @@ protected function resetRequest(Application $app): void $method = self::CLEAN_CLEAR; } - switch ($method) { - case self::CLEAN_FORCE_RECREATE: - case self::CLEAN_RECREATE: - $app->set('request', $app->getComponents()['request']); - break; - case self::CLEAN_CLEAR: + match ($method) { + self::CLEAN_FORCE_RECREATE, self::CLEAN_RECREATE => $app->set('request', $app->getComponents()['request']), + self::CLEAN_CLEAR => (function () use ($request): void { $request->getHeaders()->removeAll(); $request->setBaseUrl(null); $request->setHostInfo(null); @@ -572,11 +557,10 @@ protected function resetRequest(Application $app): void $request->setSecurePort(0); $request->setAcceptableContentTypes(null); $request->setAcceptableLanguages(null); - - break; - case self::CLEAN_MANUAL: - break; - } + })(), + self::CLEAN_MANUAL => null, + default => throw new InvalidArgumentException("Unknown method: $method"), + }; } /** diff --git a/src/Codeception/Lib/Connector/Yii2/ConnectionWatcher.php b/src/Codeception/Lib/Connector/Yii2/ConnectionWatcher.php index aa92f7f..1240662 100644 --- a/src/Codeception/Lib/Connector/Yii2/ConnectionWatcher.php +++ b/src/Codeception/Lib/Connector/Yii2/ConnectionWatcher.php @@ -4,6 +4,9 @@ namespace Codeception\Lib\Connector\Yii2; +use Closure; +use JsonSerializable; +use ReflectionClass; use yii\base\Event; use yii\db\Connection; @@ -14,14 +17,14 @@ */ class ConnectionWatcher { - private \Closure $handler; + private Closure $handler; /** @var Connection[] */ private array $connections = []; public function __construct() { - $this->handler = function (Event $event) { + $this->handler = function (Event $event): void { if ($event->sender instanceof Connection) { $this->connectionOpened($event->sender); } @@ -55,10 +58,10 @@ public function closeAll(): void } } - protected function debug($message): void + protected function debug(string|array|JsonSerializable $message): void { - $title = (new \ReflectionClass($this))->getShortName(); - if (is_array($message) or is_object($message)) { + $title = (new ReflectionClass($this))->getShortName(); + if (is_array($message) || is_object($message)) { $message = stripslashes(json_encode($message)); } codecept_debug("[$title] $message"); diff --git a/src/Codeception/Lib/Connector/Yii2/FixturesStore.php b/src/Codeception/Lib/Connector/Yii2/FixturesStore.php index 71c490e..cb46a77 100644 --- a/src/Codeception/Lib/Connector/Yii2/FixturesStore.php +++ b/src/Codeception/Lib/Connector/Yii2/FixturesStore.php @@ -11,25 +11,24 @@ class FixturesStore { use FixtureTrait; - protected $data; - /** * Expects fixtures config * * FixturesStore constructor. - * @param $data */ - public function __construct($data) + public function __construct(protected mixed $data) { - $this->data = $data; } - public function fixtures() + public function fixtures(): mixed { return $this->data; } - public function globalFixtures() + /** + * @return array{initDbFixture: array{class: class-string}} + */ + public function globalFixtures(): array { return [ 'initDbFixture' => [ diff --git a/src/Codeception/Lib/Connector/Yii2/Logger.php b/src/Codeception/Lib/Connector/Yii2/Logger.php index 0a2501f..820e4ba 100644 --- a/src/Codeception/Lib/Connector/Yii2/Logger.php +++ b/src/Codeception/Lib/Connector/Yii2/Logger.php @@ -5,13 +5,15 @@ namespace Codeception\Lib\Connector\Yii2; use Codeception\Util\Debug; +use yii\base\Exception as YiiException; use yii\helpers\VarDumper; +use yii\log\Logger as YiiLogger; -class Logger extends \yii\log\Logger +class Logger extends YiiLogger { private \SplQueue $logQueue; - public function __construct(private int $maxLogItems = 5, $config = []) + public function __construct(private int $maxLogItems = 5, array $config = []) { parent::__construct($config); $this->logQueue = new \SplQueue(); @@ -23,33 +25,28 @@ public function init(): void } /** - * @param string|array|\yii\base\Exception $message - * @param $level - * @param $category - * @return void + * @param string|array|YiiException $message + * @param self::LEVEL_INFO|self::LEVEL_WARNING|self::LEVEL_ERROR $level + * @param string $category */ public function log($message, $level, $category = 'application'): void { if (!in_array($level, [ - \yii\log\Logger::LEVEL_INFO, - \yii\log\Logger::LEVEL_WARNING, - \yii\log\Logger::LEVEL_ERROR, - ])) { + self::LEVEL_INFO, + self::LEVEL_WARNING, + self::LEVEL_ERROR, + ], true)) { return; } if (str_starts_with($category, 'yii\db\Command')) { return; // don't log queries } - // https://github.com/Codeception/Codeception/issues/3696 - if ($message instanceof \yii\base\Exception) { + if ($message instanceof YiiException) { $message = $message->__toString(); } - $logMessage = "[$category] " . VarDumper::export($message); - Debug::debug($logMessage); - $this->logQueue->enqueue($logMessage); if ($this->logQueue->count() > $this->maxLogItems) { $this->logQueue->dequeue(); @@ -58,12 +55,8 @@ public function log($message, $level, $category = 'application'): void public function getAndClearLog(): string { - $completeStr = ''; - foreach ($this->logQueue as $item) { - $completeStr .= $item . PHP_EOL; - } + $logs = iterator_to_array($this->logQueue); $this->logQueue = new \SplQueue(); - - return $completeStr; + return implode(PHP_EOL, $logs) . PHP_EOL; } } diff --git a/src/Codeception/Lib/Connector/Yii2/TestMailer.php b/src/Codeception/Lib/Connector/Yii2/TestMailer.php index c6276a4..230e15a 100644 --- a/src/Codeception/Lib/Connector/Yii2/TestMailer.php +++ b/src/Codeception/Lib/Connector/Yii2/TestMailer.php @@ -4,26 +4,24 @@ namespace Codeception\Lib\Connector\Yii2; +use Closure; use yii\mail\BaseMailer; class TestMailer extends BaseMailer { public $messageClass = \yii\symfonymailer\Message::class; - /** - * @var \Closure - */ - public $callback; + public Closure $callback; - protected function sendMessage($message) + protected function sendMessage(mixed $message): bool { - call_user_func($this->callback, $message); + ($this->callback)($message); return true; } - - protected function saveMessage($message) + + protected function saveMessage(mixed $message): bool { - call_user_func($this->callback, $message); + ($this->callback)($message); return true; } } diff --git a/src/Codeception/Lib/Connector/Yii2/TransactionForcer.php b/src/Codeception/Lib/Connector/Yii2/TransactionForcer.php index 7c2588a..350411a 100644 --- a/src/Codeception/Lib/Connector/Yii2/TransactionForcer.php +++ b/src/Codeception/Lib/Connector/Yii2/TransactionForcer.php @@ -5,7 +5,6 @@ namespace Codeception\Lib\Connector\Yii2; use Codeception\Util\Debug; -use yii\base\Event; use yii\db\Connection; use yii\db\Transaction; @@ -16,22 +15,15 @@ */ class TransactionForcer extends ConnectionWatcher { - private $ignoreCollidingDSN; + private array $pdoCache = []; + private array $dsnCache = []; + private array $transactions = []; - private $pdoCache = []; - - private $dsnCache; - - private $transactions = []; - - public function __construct( - $ignoreCollidingDSN - ) { + public function __construct(private bool $ignoreCollidingDSN) + { parent::__construct(); - $this->ignoreCollidingDSN = $ignoreCollidingDSN; } - protected function connectionOpened(Connection $connection): void { parent::connectionOpened($connection); @@ -47,9 +39,8 @@ protected function connectionOpened(Connection $connection): void 'pass' => $connection->password, 'attributes' => $connection->attributes, 'emulatePrepare' => $connection->emulatePrepare, - 'charset' => $connection->charset + 'charset' => $connection->charset, ])); - /* * If keys match we assume connections are "similar enough". */ @@ -58,7 +49,6 @@ protected function connectionOpened(Connection $connection): void } else { $this->pdoCache[$key] = $connection->pdo; } - if (isset($this->dsnCache[$connection->dsn]) && $this->dsnCache[$connection->dsn] !== $key && !$this->ignoreCollidingDSN @@ -72,12 +62,10 @@ protected function connectionOpened(Connection $connection): void ); Debug::pause(); } - if (isset($this->transactions[$key])) { $this->debug('Reusing PDO, so no need for a new transaction'); return; } - $this->debug('Transaction started for: ' . $connection->dsn); $this->transactions[$key] = $connection->beginTransaction(); } @@ -91,7 +79,6 @@ public function rollbackAll(): void $this->debug('Transaction cancelled; all changes reverted.'); } } - $this->transactions = []; $this->pdoCache = []; $this->dsnCache = []; diff --git a/src/Codeception/Module/Yii2.php b/src/Codeception/Module/Yii2.php index 99a3a2d..fdd47b8 100644 --- a/src/Codeception/Module/Yii2.php +++ b/src/Codeception/Module/Yii2.php @@ -16,7 +16,9 @@ use Codeception\Lib\Interfaces\MultiSession; use Codeception\Lib\Interfaces\PartedModule; use Codeception\TestInterface; -use Symfony\Component\DomCrawler\Crawler as SymfonyCrawler; +use ReflectionClass; +use RuntimeException; +use Symfony\Component\BrowserKit\AbstractBrowser; use Yii; use yii\base\Security; use yii\db\ActiveQueryInterface; @@ -44,7 +46,7 @@ * interaction. * * You may use multiple database connections, each will use a separate * transaction; to prevent accidental mistakes we will warn you if you try to - * connect to the same database twice but we cannot reuse the same connection. + * connect to the same database twice, but we cannot reuse the same connection. * * ## Config * @@ -97,7 +99,7 @@ * * ## Parts * - * By default all available methods are loaded, but you can also use the `part` + * By default, all available methods are loaded, but you can also use the `part` * option to select only the needed actions and to avoid conflicts. The * available parts are: * @@ -123,7 +125,7 @@ * configFile: 'config/test.php' * part: [orm, route] # allow to use AR methods and route method * transaction: false # don't wrap test in transaction - * cleanup: false # don't cleanup the fixtures + * cleanup: false # don't clean up the fixtures * entryScript: index-test.php * ``` * @@ -173,7 +175,6 @@ class Yii2 extends Framework implements ActiveRecord, MultiSession, PartedModule { /** * Application config file must be set. - * @var array */ protected array $config = [ 'fixturesMethod' => '_fixtures', @@ -216,10 +217,13 @@ class Yii2 extends Framework implements ActiveRecord, MultiSession, PartedModule private Logger $yiiLogger; - private function getClient(): \Codeception\Lib\Connector\Yii2|null + private function getClient(): Yii2Connector { - if (isset($this->client) && !$this->client instanceof \Codeception\Lib\Connector\Yii2) { - throw new \RuntimeException('The Yii2 module must be used with the Yii2 browser client'); + if (!isset($this->client)) { + throw new RuntimeException('Browser not initialized'); + } + if (!$this->client instanceof Yii2Connector) { + throw new RuntimeException('The Yii2 module must be used with the Yii2 browser client'); } return $this->client; } @@ -235,7 +239,6 @@ public function _initialize(): void $this->initServerGlobal(); } - /** * Module configuration changed inside a test. * We always re-create the application. @@ -256,42 +259,40 @@ protected function onReconfigure(): void */ private function initServerGlobal(): void { - $entryUrl = $this->config['entryUrl']; + $parsedUrl = parse_url($entryUrl); $entryFile = $this->config['entryScript'] ?: basename($entryUrl); - $entryScript = $this->config['entryScript'] ?: parse_url($entryUrl, PHP_URL_PATH); + $entryScript = $this->config['entryScript'] ?: ($parsedUrl['path'] ?? ''); $_SERVER = array_merge($_SERVER, [ 'SCRIPT_FILENAME' => $entryFile, 'SCRIPT_NAME' => $entryScript, - 'SERVER_NAME' => parse_url($entryUrl, PHP_URL_HOST), - 'SERVER_PORT' => parse_url($entryUrl, PHP_URL_PORT) ?: '80', - 'HTTPS' => parse_url($entryUrl, PHP_URL_SCHEME) === 'https' + 'SERVER_NAME' => $parsedUrl['host'] ?? '', + 'SERVER_PORT' => $parsedUrl['port'] ?? '80', + 'HTTPS' => isset($parsedUrl['scheme']) && $parsedUrl['scheme'] === 'https' ]); } protected function validateConfig(): void { parent::validateConfig(); - $pathToConfig = codecept_absolute_path($this->config['configFile']); if (!is_file($pathToConfig)) { throw new ModuleConfigException( - __CLASS__, + self::class, "The application config file does not exist: " . $pathToConfig ); } - - if (!in_array($this->config['responseCleanMethod'], Yii2Connector::CLEAN_METHODS)) { + $validMethods = implode(", ", Yii2Connector::CLEAN_METHODS); + if (!in_array($this->config['responseCleanMethod'], Yii2Connector::CLEAN_METHODS, true)) { throw new ModuleConfigException( - __CLASS__, - "The response clean method must be one of: " . implode(", ", Yii2Connector::CLEAN_METHODS) + self::class, + "The response clean method must be one of: " . $validMethods ); } - - if (!in_array($this->config['requestCleanMethod'], Yii2Connector::CLEAN_METHODS)) { + if (!in_array($this->config['requestCleanMethod'], Yii2Connector::CLEAN_METHODS, true)) { throw new ModuleConfigException( - __CLASS__, - "The response clean method must be one of: " . implode(", ", Yii2Connector::CLEAN_METHODS) + self::class, + "The request clean method must be one of: " . $validMethods ); } } @@ -299,7 +300,6 @@ protected function validateConfig(): void protected function configureClient(array $settings): void { $settings['configFile'] = codecept_absolute_path($settings['configFile']); - foreach ($settings as $key => $value) { if (property_exists($this->client, $key)) { $this->getClient()->$key = $value; @@ -314,17 +314,16 @@ protected function configureClient(array $settings): void protected function recreateClient(): void { $entryUrl = $this->config['entryUrl']; + $parsedUrl = parse_url($entryUrl); $entryFile = $this->config['entryScript'] ?: basename($entryUrl); - $entryScript = $this->config['entryScript'] ?: parse_url($entryUrl, PHP_URL_PATH); - + $entryScript = $this->config['entryScript'] ?: ($parsedUrl['path'] ?? ''); $this->client = new Yii2Connector([ 'SCRIPT_FILENAME' => $entryFile, 'SCRIPT_NAME' => $entryScript, - 'SERVER_NAME' => parse_url($entryUrl, PHP_URL_HOST), - 'SERVER_PORT' => parse_url($entryUrl, PHP_URL_PORT) ?: '80', - 'HTTPS' => parse_url($entryUrl, PHP_URL_SCHEME) === 'https' + 'SERVER_NAME' => $parsedUrl['host'] ?? '', + 'SERVER_PORT' => $parsedUrl['port'] ?? '80', + 'HTTPS' => isset($parsedUrl['scheme']) && $parsedUrl['scheme'] === 'https' ]); - $this->configureClient($this->config); } @@ -346,7 +345,6 @@ public function _before(TestInterface $test): void $this->loadFixtures($test); } - $this->startTransactions(); } @@ -356,7 +354,7 @@ public function _before(TestInterface $test): void private function loadFixtures(object $test): void { $this->debugSection('Fixtures', 'Loading fixtures'); - if (empty($this->loadedFixtures) + if ($this->loadedFixtures === [] && method_exists($test, $this->_getConfig('fixturesMethod')) ) { $connectionWatcher = new ConnectionWatcher(); @@ -386,7 +384,7 @@ public function _after(TestInterface $test): void $this->loadedFixtures = []; } - $this->getClient()?->resetApplication(); + $this->getClient()->resetApplication(); if (isset($this->connectionWatcher)) { $this->connectionWatcher->stop(); @@ -426,7 +424,7 @@ protected function rollbackTransactions(): void public function _parts(): array { - return ['orm', 'init', 'fixtures', 'email','route']; + return ['orm', 'init', 'fixtures', 'email', 'route']; } /** @@ -449,10 +447,8 @@ public function _parts(): array public function amLoggedInAs(int|string|IdentityInterface $user): void { try { - $this->getClient()?->findAndLoginUser($user); - } catch (ConfigurationException $e) { - throw new ModuleException($this, $e->getMessage()); - } catch (\RuntimeException $e) { + $this->getClient()->findAndLoginUser($user); + } catch (ConfigurationException|RuntimeException $e) { throw new ModuleException($this, $e->getMessage()); } } @@ -509,23 +505,17 @@ public function haveFixtures($fixtures): void * Array of fixture instances * * @part fixtures - * @return array */ public function grabFixtures() { - if (!$this->loadedFixtures) { + if ($this->loadedFixtures === []) { return []; } - return call_user_func_array( - 'array_merge', - array_map( // merge all fixtures from all fixture stores - function ($fixturesStore) { - return $fixturesStore->getFixtures(); - }, - $this->loadedFixtures - ) - ); + return array_merge(...array_map( + fn($fixturesStore) => $fixturesStore->getFixtures(), + $this->loadedFixtures + )); } /** @@ -556,13 +546,11 @@ public function grabFixture($name, $index = null) throw new ModuleException($this, "Fixture $name is not loaded"); } $fixture = $fixtures[$name]; - if ($index === null) { - return $fixture; - } - if ($fixture instanceof \yii\test\BaseActiveFixture) { - return $fixture->getModel($index); - } - throw new ModuleException($this, "Fixture $name is not an instance of ActiveFixture and can't be loaded with second parameter"); + return match (true) { + $index === null => $fixture, + $fixture instanceof \yii\test\BaseActiveFixture => $fixture->getModel($index), + default => throw new ModuleException($this, "Fixture $name is not an instance of ActiveFixture and can't be loaded with second parameter") + }; } /** @@ -576,12 +564,11 @@ public function grabFixture($name, $index = null) * @template T of \yii\db\ActiveRecord * @param class-string $model * @param array $attributes - * @return mixed * @part orm */ public function haveRecord(string $model, $attributes = []): mixed { - /** @var T $record **/ + /** @var T $record */ $record = \Yii::createObject($model); $record->setAttributes($attributes, false); $res = $record->save(false); @@ -594,7 +581,7 @@ public function haveRecord(string $model, $attributes = []): mixed /** * Checks that a record exists in the database. * - * ``` php + * ```php * $I->seeRecord('app\models\User', array('name' => 'davert')); * ``` * @@ -614,7 +601,7 @@ public function seeRecord(string $model, array $attributes = []): void /** * Checks that a record does not exist in the database. * - * ``` php + * ```php * $I->dontSeeRecord('app\models\User', array('name' => 'davert')); * ``` * @@ -634,7 +621,7 @@ public function dontSeeRecord(string $model, array $attributes = []): void /** * Retrieves a record from the database * - * ``` php + * ```php * $category = $I->grabRecord('app\models\User', array('name' => 'davert')); * ``` * @@ -651,12 +638,12 @@ public function grabRecord(string $model, array $attributes = []): \yii\db\Activ * @param class-string<\yii\db\ActiveRecord> $model Class name * @param array $attributes */ - protected function findRecord(string $model, array $attributes = []): \yii\db\ActiveRecord | null | array + protected function findRecord(string $model, array $attributes = []): \yii\db\ActiveRecord|null|array { if (!class_exists($model)) { - throw new \RuntimeException("Class $model does not exist"); + throw new RuntimeException("Class $model does not exist"); } - $rc = new \ReflectionClass($model); + $rc = new ReflectionClass($model); if ($rc->hasMethod('find') /** @phpstan-ignore-next-line */ && ($findMethod = $rc->getMethod('find')) @@ -668,10 +655,9 @@ protected function findRecord(string $model, array $attributes = []): \yii\db\Ac if ($activeQuery instanceof ActiveQueryInterface) { return $activeQuery->andWhere($attributes)->one(); } - - throw new \RuntimeException("$model::find() must return an instance of yii\db\QueryInterface"); + throw new RuntimeException("$model::find() must return an instance of yii\db\QueryInterface"); } - throw new \RuntimeException("Class $model does not have a public static find() method without required parameters"); + throw new RuntimeException("Class $model does not have a public static find() method without required parameters"); } /** @@ -683,14 +669,14 @@ protected function findRecord(string $model, array $attributes = []): \yii\db\Ac * * @param string $route A route * @param array $params Additional route parameters - * @part route + * @part route */ public function amOnRoute(string $route, array $params = []): void { if (Yii::$app->controller === null) { $route = "/{$route}"; } - + array_unshift($params, $route); $this->amOnPage(Url::to($params)); } @@ -728,7 +714,6 @@ public function grabComponent(string $component): null|object * $I->seeEmailIsSent(3); * ``` * - * @param int|null $num * @throws \Codeception\Exception\ModuleException * @part email */ @@ -764,7 +749,6 @@ public function dontSeeEmailIsSent(): void * ``` * * @part email - * @return array * @throws \Codeception\Exception\ModuleException */ public function grabSentEmails(): array @@ -794,12 +778,8 @@ public function grabLastSentEmail(): object return end($messages); } - - /** * Returns a list of regex patterns for recognized domain names - * - * @return array */ public function getInternalDomains(): array { @@ -808,9 +788,9 @@ public function getInternalDomains(): array private function defineConstants(): void { - defined('YII_DEBUG') or define('YII_DEBUG', true); - defined('YII_ENV') or define('YII_ENV', 'test'); - defined('YII_ENABLE_ERROR_HANDLER') or define('YII_ENABLE_ERROR_HANDLER', false); + defined('YII_DEBUG') || define('YII_DEBUG', true); + defined('YII_ENV') || define('YII_ENV', 'test'); + defined('YII_ENABLE_ERROR_HANDLER') || define('YII_ENABLE_ERROR_HANDLER', false); } /** @@ -868,14 +848,14 @@ public function _backupSession(): array return [ 'clientContext' => $this->getClient()->getContext(), 'headers' => $this->headers, - 'cookie' => isset($_COOKIE) ? $_COOKIE : [], - 'session' => isset($_SESSION) ? $_SESSION : [], + 'cookie' => $_COOKIE ?? [], + 'session' => $_SESSION ?? [], ]; } /** * Restore a session. Implements MultiSession. - * @param array $session output of _backupSession() + * @param array $session output of _backupSession() */ public function _loadSession($session): void { @@ -883,14 +863,10 @@ public function _loadSession($session): void $this->headers = $session['headers']; $_SESSION = $session['session']; $_COOKIE = $session['cookie']; - - // reset Yii::$app->user - if (isset(Yii::$app)) { - $app = Yii::$app; - $definitions = $app->getComponents(true); - if ($app->has('user', true)) { - $app->set('user', $definitions['user']); - } + $app = Yii::$app; + if ($app?->has('user', true)) { + $definitions = $app->getComponents(); + $app->set('user', $definitions['user']); } }