diff --git a/.phpstan-baseline.neon b/.phpstan-baseline.neon index 282055716c5..418f418a926 100644 --- a/.phpstan-baseline.neon +++ b/.phpstan-baseline.neon @@ -7775,116 +7775,6 @@ parameters: count: 1 path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginCategoryService.php - - - message: "#^Method Shopware\\\\Bundle\\\\PluginInstallerBundle\\\\Service\\\\PluginInstaller\\:\\:installCronjob\\(\\) has no return type specified\\.$#" - count: 1 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - - - message: "#^Method Shopware\\\\Bundle\\\\PluginInstallerBundle\\\\Service\\\\PluginInstaller\\:\\:installForm\\(\\) has no return type specified\\.$#" - count: 1 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - - - message: "#^Method Shopware\\\\Bundle\\\\PluginInstallerBundle\\\\Service\\\\PluginInstaller\\:\\:installMenu\\(\\) has no return type specified\\.$#" - count: 1 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - - - message: "#^Method Shopware\\\\Bundle\\\\PluginInstallerBundle\\\\Service\\\\PluginInstaller\\:\\:installResources\\(\\) has no return type specified\\.$#" - count: 1 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - - - message: "#^Method Shopware\\\\Bundle\\\\PluginInstallerBundle\\\\Service\\\\PluginInstaller\\:\\:installSnippets\\(\\) has no return type specified\\.$#" - count: 1 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - - - message: "#^Method Shopware\\\\Bundle\\\\PluginInstallerBundle\\\\Service\\\\PluginInstaller\\:\\:refreshPluginList\\(\\) has no return type specified\\.$#" - count: 1 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - - - message: "#^Method Shopware\\\\Bundle\\\\PluginInstallerBundle\\\\Service\\\\PluginInstaller\\:\\:removeCrontabEntries\\(\\) has no return type specified\\.$#" - count: 1 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - - - message: "#^Method Shopware\\\\Bundle\\\\PluginInstallerBundle\\\\Service\\\\PluginInstaller\\:\\:removeEmotionComponents\\(\\) has no return type specified\\.$#" - count: 1 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - - - message: "#^Method Shopware\\\\Bundle\\\\PluginInstallerBundle\\\\Service\\\\PluginInstaller\\:\\:removeEventSubscribers\\(\\) has no return type specified\\.$#" - count: 1 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - - - message: "#^Method Shopware\\\\Bundle\\\\PluginInstallerBundle\\\\Service\\\\PluginInstaller\\:\\:removeFormsAndElements\\(\\) has no return type specified\\.$#" - count: 1 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - - - message: "#^Method Shopware\\\\Bundle\\\\PluginInstallerBundle\\\\Service\\\\PluginInstaller\\:\\:removeMenuEntries\\(\\) has no return type specified\\.$#" - count: 1 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - - - message: "#^Method Shopware\\\\Bundle\\\\PluginInstallerBundle\\\\Service\\\\PluginInstaller\\:\\:removeSnippets\\(\\) has no return type specified\\.$#" - count: 1 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - - - message: "#^Method Shopware\\\\Bundle\\\\PluginInstallerBundle\\\\Service\\\\PluginInstaller\\:\\:removeTemplates\\(\\) has no return type specified\\.$#" - count: 1 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - - - message: "#^Query error\\: Column \"s_core_plugins\\.added\" expects value type string, got type DateTimeInterface$#" - count: 1 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - - - message: "#^Query error\\: Column \"s_core_plugins\\.author\" expects value type string\\|null, got type mixed$#" - count: 2 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - - - message: "#^Query error\\: Column \"s_core_plugins\\.id\" expects value type int, got type mixed$#" - count: 1 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - - - message: "#^Query error\\: Column \"s_core_plugins\\.label\" expects value type string, got type mixed$#" - count: 2 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - - - message: "#^Query error\\: Column \"s_core_plugins\\.link\" expects value type string\\|null, got type mixed$#" - count: 2 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - - - message: "#^Query error\\: Column \"s_core_plugins\\.refresh_date\" expects value type string\\|null, got type DateTimeInterface$#" - count: 2 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - - - message: "#^Query error\\: Column \"s_core_plugins\\.translations\" expects value type string\\|null, got type non\\-empty\\-string\\|false\\|null$#" - count: 2 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - - - message: "#^Query error\\: Column \"s_core_plugins\\.update_version\" expects value type string\\|null, got type mixed$#" - count: 1 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - - - message: "#^Query error\\: Column \"s_core_plugins\\.version\" expects value type string, got type mixed$#" - count: 2 - path: engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php - - message: "#^Method Shopware\\\\Bundle\\\\PluginInstallerBundle\\\\Service\\\\PluginLicenceService\\:\\:cleanupLocalLicenseInformation\\(\\) has no return type specified\\.$#" count: 1 @@ -18415,11 +18305,6 @@ parameters: count: 1 path: engine/Shopware/Components/Plugin/Namespace.php - - - message: "#^Query error\\: Column \"s_core_plugins\\.author\" expects value type string\\|null, got type mixed$#" - count: 2 - path: engine/Shopware/Components/Plugin/Namespace.php - - message: "#^Query error\\: Column \"s_core_plugins\\.capability_enable\" expects value type int, got type bool$#" count: 2 @@ -18440,11 +18325,6 @@ parameters: count: 2 path: engine/Shopware/Components/Plugin/Namespace.php - - - message: "#^Query error\\: Column \"s_core_plugins\\.copyright\" expects value type string\\|null, got type mixed$#" - count: 2 - path: engine/Shopware/Components/Plugin/Namespace.php - - message: "#^Query error\\: Column \"s_core_plugins\\.description\" expects value type string\\|null, got type mixed$#" count: 2 @@ -18465,11 +18345,6 @@ parameters: count: 2 path: engine/Shopware/Components/Plugin/Namespace.php - - - message: "#^Query error\\: Column \"s_core_plugins\\.source\" expects value type string, got type mixed$#" - count: 2 - path: engine/Shopware/Components/Plugin/Namespace.php - - message: "#^Query error\\: Column \"s_core_plugins\\.support\" expects value type string\\|null, got type mixed$#" count: 2 @@ -18490,11 +18365,6 @@ parameters: count: 2 path: engine/Shopware/Components/Plugin/Namespace.php - - - message: "#^Query error\\: Column \"s_core_plugins\\.version\" expects value type string, got type mixed$#" - count: 2 - path: engine/Shopware/Components/Plugin/Namespace.php - - message: "#^Method Shopware\\\\Components\\\\Plugin\\\\PaymentInstaller\\:\\:createOrUpdate\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#" count: 1 diff --git a/composer.json b/composer.json index 50e115030f1..c3c459920be 100644 --- a/composer.json +++ b/composer.json @@ -113,7 +113,7 @@ "friends-of-behat/mink-extension": "2.7.4", "php-parallel-lint/php-var-dump-check": "^0.5", "phpstan/extension-installer": "1.3.1", - "phpstan/phpstan": "1.10.50", + "phpstan/phpstan": "1.10.53", "phpstan/phpstan-doctrine": "1.3.53", "phpstan/phpstan-phpunit": "1.3.15", "phpstan/phpstan-symfony": "1.3.6", diff --git a/composer.lock b/composer.lock index 2130a464104..f845b0ce7f9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d18b47e38edb6a1c16f276e68d525dd7", + "content-hash": "0d1d2c76916deed03482601e18acf528", "packages": [ { "name": "aws/aws-crt-php", @@ -8394,16 +8394,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.50", + "version": "1.10.53", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4" + "reference": "0c48595cce15f67d6a7faf30e9d13c775e6e9875" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/06a98513ac72c03e8366b5a0cb00750b487032e4", - "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0c48595cce15f67d6a7faf30e9d13c775e6e9875", + "reference": "0c48595cce15f67d6a7faf30e9d13c775e6e9875", "shasum": "" }, "require": { @@ -8452,7 +8452,7 @@ "type": "tidelift" } ], - "time": "2023-12-13T10:59:42+00:00" + "time": "2024-01-05T13:55:38+00:00" }, { "name": "phpstan/phpstan-doctrine", diff --git a/engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php b/engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php index 2350d47e84b..5fab813c618 100644 --- a/engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php +++ b/engine/Shopware/Bundle/PluginInstallerBundle/Service/PluginInstaller.php @@ -1,4 +1,6 @@ em->flush($plugin); - $this->applyMigrations($pluginBootstrap, AbstractPluginMigration::MODUS_INSTALL); + $this->applyMigrations($pluginBootstrap, AbstractMigration::MODUS_INSTALL); $pluginBootstrap->install($context); @@ -186,8 +162,8 @@ public function installPlugin(Plugin $plugin) * @param bool $removeData * * @throws Exception - * @throws \Doctrine\DBAL\DBALException - * @throws \Doctrine\ORM\OptimisticLockException + * @throws DBALException + * @throws OptimisticLockException * * @return UninstallContext */ @@ -249,7 +225,7 @@ public function updatePlugin(Plugin $plugin) $this->installResources($pluginBootstrap, $plugin); - $this->applyMigrations($pluginBootstrap, AbstractPluginMigration::MODUS_UPDATE); + $this->applyMigrations($pluginBootstrap, AbstractMigration::MODUS_UPDATE); $pluginBootstrap->update($context); @@ -267,7 +243,7 @@ public function updatePlugin(Plugin $plugin) /** * @throws Exception - * @throws \Doctrine\ORM\OptimisticLockException + * @throws OptimisticLockException * * @return ActivateContext */ @@ -292,7 +268,7 @@ public function activatePlugin(Plugin $plugin) /** * @throws Exception - * @throws \Doctrine\ORM\OptimisticLockException + * @throws OptimisticLockException * * @return DeactivateContext */ @@ -315,26 +291,26 @@ public function deactivatePlugin(Plugin $plugin) /** * @throws RuntimeException + * + * @return void */ public function refreshPluginList(DateTimeInterface $refreshDate) { + $refreshDateString = $refreshDate->format('Y-m-d H:i:s'); $initializer = new PluginInitializer( $this->pdo, $this->pluginDirectories ); - $plugins = $initializer->initializePlugins(); - - foreach ($plugins as $plugin) { + foreach ($initializer->initializePlugins() as $plugin) { $pluginInfoPath = $plugin->getPath() . '/plugin.xml'; if (is_file($pluginInfoPath)) { - $xmlConfigReader = new XmlPluginReader(); - $info = $xmlConfigReader->read($pluginInfoPath); + $info = (new XmlPluginReader())->read($pluginInfoPath); } else { $info = []; } - $currentPluginInfo = $this->em->getConnection()->fetchAssoc( + $currentPluginInfo = $this->em->getConnection()->fetchAssociative( 'SELECT * FROM s_core_plugins WHERE `name` LIKE ?', [$plugin->getName()] ); @@ -351,43 +327,43 @@ public function refreshPluginList(DateTimeInterface $refreshDate) } } - $info['label'] = $info['label']['en'] ?? $plugin->getName(); + $info['label'] = (string) ($info['label']['en'] ?? $plugin->getName()); $info['description'] = $info['description']['en'] ?? null; - $info['version'] = $info['version'] ?? '0.0.1'; + $info['version'] = (string) ($info['version'] ?? '0.0.1'); $info['author'] = $info['author'] ?? null; $info['link'] = $info['link'] ?? null; $data = [ 'namespace' => $plugin->getPluginNamespace(), 'version' => $info['version'], - 'author' => $info['author'], + 'author' => $info['author'] ? (string) $info['author'] : null, 'name' => $plugin->getName(), - 'link' => $info['link'], + 'link' => $info['link'] ? (string) $info['link'] : null, 'label' => $info['label'], 'description' => $info['description'] ? (string) $info['description'] : null, 'capability_update' => 1, 'capability_install' => 1, 'capability_enable' => 1, 'capability_secure_uninstall' => 1, - 'refresh_date' => $refreshDate, - 'translations' => $translations ? json_encode($translations) : null, + 'refresh_date' => $refreshDateString, + 'translations' => $translations ? json_encode($translations, JSON_THROW_ON_ERROR) : null, 'changes' => isset($info['changelog']) ? json_encode($info['changelog'], JSON_THROW_ON_ERROR) : null, ]; if ($currentPluginInfo) { if ($this->hasInfoNewerVersion($info['version'], $currentPluginInfo['version'])) { - $data['version'] = $currentPluginInfo['version']; + $data['version'] = (string) $currentPluginInfo['version']; $data['update_version'] = $info['version']; } $this->em->getConnection()->update( 's_core_plugins', $data, - ['id' => $currentPluginInfo['id']], + ['id' => (int) $currentPluginInfo['id']], ['refresh_date' => 'datetime'] ); } else { - $data['added'] = $refreshDate; + $data['added'] = $refreshDateString; $this->em->getConnection()->insert( 's_core_plugins', $data, @@ -407,15 +383,10 @@ public function refreshPluginList(DateTimeInterface $refreshDate) */ public function getPluginPath(Plugin $plugin) { - $pluginBootstrap = $this->getPluginByName($plugin->getName()); - - return $pluginBootstrap->getPath(); + return $this->getPluginByName($plugin->getName())->getPath(); } - /** - * @param bool $removeDirty - */ - private function removeSnippets(PluginBootstrap $bootstrap, $removeDirty) + private function removeSnippets(PluginBaseClass $bootstrap, bool $removeDirty): void { $this->snippetHandler->removeFromDatabase($bootstrap->getPath() . '/Resources/snippets/', $removeDirty); } @@ -423,7 +394,7 @@ private function removeSnippets(PluginBootstrap $bootstrap, $removeDirty) /** * @throws Exception */ - private function installResources(PluginBootstrap $bootstrap, Plugin $plugin) + private function installResources(PluginBaseClass $bootstrap, Plugin $plugin): void { if (is_file($bootstrap->getPath() . '/Resources/config.xml')) { $this->installForm($plugin, $bootstrap->getPath() . '/Resources/config.xml'); @@ -442,72 +413,53 @@ private function installResources(PluginBootstrap $bootstrap, Plugin $plugin) } } - private function installSnippets(PluginBootstrap $bootstrap) + private function installSnippets(PluginBaseClass $bootstrap): void { $this->snippetHandler->loadToDatabase($bootstrap->getPath() . '/Resources/snippets/'); } /** - * @param string $file - * * @throws Exception */ - private function installForm(Plugin $plugin, $file) + private function installForm(Plugin $plugin, string $file): void { - $xmlConfigReader = new XmlConfigReader(); - $config = $xmlConfigReader->read($file); + $config = (new XmlConfigReader())->read($file); $formSynchronizer = new FormSynchronizer($this->em); $formSynchronizer->synchronize($plugin, $config); } /** - * @param string $file - * * @throws InvalidArgumentException */ - private function installMenu(Plugin $plugin, $file) + private function installMenu(Plugin $plugin, string $file): void { - $menuReader = new XmlMenuReader(); - $menu = $menuReader->read($file); + $menu = (new XmlMenuReader())->read($file); $menuSynchronizer = new MenuSynchronizer($this->em); $menuSynchronizer->synchronize($plugin, $menu); } /** - * @param string $file - * * @throws InvalidArgumentException */ - private function installCronjob(Plugin $plugin, $file) + private function installCronjob(Plugin $plugin, string $file): void { - $cronjobReader = new XmlCronjobReader(); - $cronjobs = $cronjobReader->read($file); + $cronjobs = (new XmlCronjobReader())->read($file); $cronjobSynchronizer = new CronjobSynchronizer($this->em->getConnection()); $cronjobSynchronizer->synchronize($plugin, $cronjobs); } - /** - * @param string $updateVersion - * @param string $currentVersion - * - * @return bool - */ - private function hasInfoNewerVersion($updateVersion, $currentVersion) + private function hasInfoNewerVersion(string $updateVersion, string $currentVersion): bool { return version_compare($updateVersion, $currentVersion, '>'); } /** - * @param string $pluginName - * * @throws Exception - * - * @return PluginBootstrap */ - private function getPluginByName($pluginName) + private function getPluginByName(string $pluginName): PluginBaseClass { $plugins = $this->kernel->getPlugins(); @@ -519,11 +471,9 @@ private function getPluginByName($pluginName) } /** - * @param int $pluginId - * - * @throws \Doctrine\DBAL\DBALException + * @throws DBALException */ - private function removeEmotionComponents($pluginId) + private function removeEmotionComponents(int $pluginId): void { // Remove emotion-components $sql = 'DELETE s_emotion_element_value, s_emotion_element @@ -546,11 +496,9 @@ private function removeEmotionComponents($pluginId) } /** - * @param int $pluginId - * - * @throws \Doctrine\DBAL\DBALException + * @throws DBALException */ - private function removeFormsAndElements($pluginId) + private function removeFormsAndElements(int $pluginId): void { $sql = <<connection->executeStatement($sql, [':pluginId' => $pluginId]); } /** - * @throws \Doctrine\DBAL\DBALException + * @throws DBALException */ - private function removeMenuEntries(int $pluginId) + private function removeMenuEntries(int $pluginId): void { - $builder = $this->em->getConnection()->createQueryBuilder(); - $builder->select(['id', 'controller', 'action']); - $builder->from('s_core_menu'); - $builder->andWhere('pluginID = :pluginId'); - $builder->setParameter(':pluginId', $pluginId); - - /** @var ResultStatement $statement */ - $statement = $builder->execute(); - - $menuItems = $statement->fetchAll(); + $menuItems = $this->em->getConnection()->createQueryBuilder() + ->select(['id', 'controller', 'action']) + ->from('s_core_menu') + ->andWhere('pluginID = :pluginId') + ->setParameter(':pluginId', $pluginId) + ->execute() + ->fetchAllAssociative(); if (\count($menuItems) === 0) { return; @@ -619,22 +562,18 @@ private function removeMenuEntries(int $pluginId) } /** - * @param int $pluginId - * - * @throws \Doctrine\DBAL\DBALException + * @throws DBALException */ - private function removeCrontabEntries($pluginId) + private function removeCrontabEntries(int $pluginId): void { $sql = 'DELETE FROM s_crontab WHERE pluginID = :pluginId'; $this->connection->executeStatement($sql, [':pluginId' => $pluginId]); } /** - * @param int $pluginId - * - * @throws \Doctrine\DBAL\DBALException + * @throws DBALException */ - private function removeEventSubscribers($pluginId) + private function removeEventSubscribers(int $pluginId): void { $sql = 'DELETE FROM s_core_subscribes WHERE pluginID = :pluginId'; $this->connection->executeStatement($sql, [':pluginId' => $pluginId]); @@ -643,7 +582,7 @@ private function removeEventSubscribers($pluginId) /** * @param AbstractPluginMigration::MODUS_* $mode */ - private function applyMigrations(PluginComponent $plugin, string $mode, bool $keepUserData = false): void + private function applyMigrations(PluginBaseClass $plugin, string $mode, bool $keepUserData = false): void { $manager = new PluginMigrationManager($this->pdo, $plugin, $this->logger); if (!is_dir($manager->getMigrationPath())) { diff --git a/engine/Shopware/Components/Plugin/Namespace.php b/engine/Shopware/Components/Plugin/Namespace.php index 0e26b0d23c5..7594dde5a30 100644 --- a/engine/Shopware/Components/Plugin/Namespace.php +++ b/engine/Shopware/Components/Plugin/Namespace.php @@ -181,14 +181,14 @@ public function registerPlugin(Enlight_Plugin_Bootstrap $plugin, ?DateTimeInterf 'namespace' => $this->getName(), 'name' => $plugin->getName(), 'label' => isset($info['label']) && \is_string($info['label']) ? $info['label'] : $plugin->getName(), - 'version' => $info['version'] ?? '1.0.0', - 'author' => $info['author'] ?? 'shopware AG', - 'copyright' => $info['copyright'] ?? 'Copyright © 2012, shopware AG', + 'version' => (string) ($info['version'] ?? '1.0.0'), + 'author' => (string) ($info['author'] ?? 'shopware AG'), + 'copyright' => (string) ($info['copyright'] ?? 'Copyright © 2012, shopware AG'), 'description' => $info['description'] ?? null, 'license' => $info['license'] ?? null, 'support' => $info['support'] ?? null, 'link' => $info['link'] ?? null, - 'source' => $info['source'] ?? 'Default', + 'source' => (string) ($info['source'] ?? 'Default'), 'update_date' => $info['updateDate'] ?? null, 'update_version' => $info['updateVersion'] ?? null, 'update_source' => $info['updateSource'] ?? null, diff --git a/tests/Unit/Bundle/PluginInstallerBundle/Service/PluginInstallerTest.php b/tests/Unit/Bundle/PluginInstallerBundle/Service/PluginInstallerTest.php index b05db2ac057..11e066126f6 100644 --- a/tests/Unit/Bundle/PluginInstallerBundle/Service/PluginInstallerTest.php +++ b/tests/Unit/Bundle/PluginInstallerBundle/Service/PluginInstallerTest.php @@ -44,6 +44,7 @@ class PluginInstallerTest extends TestCase public function testRefreshPluginList(): void { $dateTime = new DateTimeImmutable(); + $dateTimeString = $dateTime->format('Y-m-d H:i:s'); $expectedData = [ 'namespace' => 'ShopwarePlugins', @@ -53,18 +54,18 @@ public function testRefreshPluginList(): void 'link' => null, 'label' => 'TestPlugin', 'description' => null, - 'capability_update' => true, - 'capability_install' => true, - 'capability_enable' => true, - 'capability_secure_uninstall' => true, - 'refresh_date' => $dateTime, + 'capability_update' => 1, + 'capability_install' => 1, + 'capability_enable' => 1, + 'capability_secure_uninstall' => 1, + 'refresh_date' => $dateTimeString, 'translations' => '{"en":{"label":"TestPlugin"}}', 'changes' => null, - 'added' => $dateTime, + 'added' => $dateTimeString, ]; $connection = $this->createMock(Connection::class); - $connection->expects(static::once())->method('fetchAssoc')->willReturn(null); + $connection->expects(static::once())->method('fetchAssociative')->willReturn(null); $connection->expects(static::once())->method('insert')->with('s_core_plugins', $expectedData, [ 'added' => 'datetime', 'refresh_date' => 'datetime',