From b5eb98c5916e5e116d387768933755217750a5be Mon Sep 17 00:00:00 2001 From: Oliver Stark Date: Tue, 18 Jan 2022 23:43:10 +0100 Subject: [PATCH 01/14] Test for DefaultHasher --- src/Queue/DefaultHasher.php | 16 +++++++++------- tests/Unit/DefaultHasherTest.php | 30 ++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 tests/Unit/DefaultHasherTest.php diff --git a/src/Queue/DefaultHasher.php b/src/Queue/DefaultHasher.php index edfa3fb..2fe5fc4 100644 --- a/src/Queue/DefaultHasher.php +++ b/src/Queue/DefaultHasher.php @@ -8,16 +8,15 @@ class DefaultHasher implements Hasher { - public int $seconds = 600; + public int $precisionInMinutes = 10; public SerializerInterface $serializer; - public function __construct(SerializerInterface $serializer, int $seconds = 600) + public function __construct(SerializerInterface $serializer, int $minutes = 10) { $this->serializer = $serializer; - $this->seconds = $seconds; + $this->precisionInMinutes = $minutes; } - /** * @param \yii\queue\JobInterface|string $job * @@ -27,11 +26,14 @@ public function hash($job): string { $hash = md5($this->serializer->serialize($job)); - return sprintf("%s__%d", $hash, $this->roundedTimestamp()); + return sprintf("%s__%s", $hash, $this->timeSuffix()); } - private function roundedTimestamp(): int + private function timeSuffix(string $format = 'Ymd.His'): string { - return (int) round(time() / $this->seconds) * $this->seconds; + $precision = $this->precisionInMinutes * 60; + $rounded = (int) ceil(time() / $precision) * $precision; + + return date($format, $rounded); } } diff --git a/tests/Unit/DefaultHasherTest.php b/tests/Unit/DefaultHasherTest.php new file mode 100644 index 0000000..ff30269 --- /dev/null +++ b/tests/Unit/DefaultHasherTest.php @@ -0,0 +1,30 @@ +hash(new DummyJob()); + [$md5, $suffix] = explode($separator, $result, 2); + + expect($md5)->toHaveLength(32); + expect($suffix)->toEndWith('00'); +}); + + + +class DummyJob implements \craft\queue\JobInterface +{ + public int $prop = 1; + + public function getDescription() + { + return 'dummy'; + } + + public function execute($queue) + { + + } +} From 8d4499ca3e237defefad45d6bd75e9757e08245b Mon Sep 17 00:00:00 2001 From: Oliver Stark Date: Tue, 18 Jan 2022 23:49:48 +0100 Subject: [PATCH 02/14] Test for DefaultHasher --- tests/Unit/DefaultHasherTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Unit/DefaultHasherTest.php b/tests/Unit/DefaultHasherTest.php index ff30269..81b6174 100644 --- a/tests/Unit/DefaultHasherTest.php +++ b/tests/Unit/DefaultHasherTest.php @@ -8,6 +8,7 @@ $result = $hasher->hash(new DummyJob()); [$md5, $suffix] = explode($separator, $result, 2); + expect(mb_strlen($result))->toBeLessThanOrEqual(64); expect($md5)->toHaveLength(32); expect($suffix)->toEndWith('00'); }); From 7a923481e5f8cdda3fc386dfac08ba6bac372018 Mon Sep 17 00:00:00 2001 From: Oliver Stark Date: Fri, 11 Feb 2022 11:47:37 +0100 Subject: [PATCH 03/14] Test the job hash --- composer.json | 8 +++++--- src/Queue/DefaultHasher.php | 3 ++- tests/Unit/DefaultHasherTest.php | 8 ++++++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index b35087f..02c5b22 100644 --- a/composer.json +++ b/composer.json @@ -23,16 +23,18 @@ "docs": "https://github.com/ostark/craft-relax/blob/main/README.md" }, "require": { - "php": "^7.4 | ^8.0", + "php": "^7.4||^8.0", "craftcms/cms": "^3.7.20", "treeware/plant": "*", "yiisoft/yii2-queue": "^2.3.3" }, "require-dev": { + "friendsofphp/php-cs-fixer": "^3.0", "nunomaduro/collision": "^5.10", - "phpstan/phpstan": "^1.0", + "ostark/craft-mockery": "dev-master", "pestphp/pest": "^1.2", - "friendsofphp/php-cs-fixer": "^3.0" + "pestphp/pest-plugin-parallel": "^1.0", + "phpstan/phpstan": "^1.0" }, "autoload": { "psr-4": { diff --git a/src/Queue/DefaultHasher.php b/src/Queue/DefaultHasher.php index 2fe5fc4..f65920e 100644 --- a/src/Queue/DefaultHasher.php +++ b/src/Queue/DefaultHasher.php @@ -17,6 +17,7 @@ public function __construct(SerializerInterface $serializer, int $minutes = 10) $this->serializer = $serializer; $this->precisionInMinutes = $minutes; } + /** * @param \yii\queue\JobInterface|string $job * @@ -32,7 +33,7 @@ public function hash($job): string private function timeSuffix(string $format = 'Ymd.His'): string { $precision = $this->precisionInMinutes * 60; - $rounded = (int) ceil(time() / $precision) * $precision; + $rounded = (int) ceil(time() / $precision) * $precision; return date($format, $rounded); } diff --git a/tests/Unit/DefaultHasherTest.php b/tests/Unit/DefaultHasherTest.php index 81b6174..64d3ec8 100644 --- a/tests/Unit/DefaultHasherTest.php +++ b/tests/Unit/DefaultHasherTest.php @@ -1,5 +1,7 @@ hash(new DummyJob()); [$md5, $suffix] = explode($separator, $result, 2); + // Not more than 64 chars to fit in the db column expect(mb_strlen($result))->toBeLessThanOrEqual(64); + expect(mb_strlen($result))->toBeGreaterThan(40); + + // Expected format: {md5}__{Ymd.His} expect($md5)->toHaveLength(32); expect($suffix)->toEndWith('00'); }); - class DummyJob implements \craft\queue\JobInterface { public int $prop = 1; @@ -26,6 +31,5 @@ public function getDescription() public function execute($queue) { - } } From c348898f9b6c09dd569ff1bdd1ef4418c5b52eef Mon Sep 17 00:00:00 2001 From: Oliver Stark Date: Fri, 11 Feb 2022 12:52:04 +0100 Subject: [PATCH 04/14] Remove pest boilerplate --- tests/ExampleTest.php | 7 ------- tests/Pest.php | 6 ------ 2 files changed, 13 deletions(-) delete mode 100644 tests/ExampleTest.php diff --git a/tests/ExampleTest.php b/tests/ExampleTest.php deleted file mode 100644 index 57349d9..0000000 --- a/tests/ExampleTest.php +++ /dev/null @@ -1,7 +0,0 @@ -toBeTrue(); -}); diff --git a/tests/Pest.php b/tests/Pest.php index f3cabe7..9b5eb1d 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -41,9 +41,3 @@ | */ -function mockCraftApp() -{ - // $mockApp = \craft\test\TestSetup::getMockApp($test); - // \Craft::$app = $mockApp; - // \Yii::$app = $mockApp; -} From 99c916856e661aa9746b7bb4ad7d9fa6fe0fffb9 Mon Sep 17 00:00:00 2001 From: ostark Date: Thu, 5 May 2022 16:07:43 +0000 Subject: [PATCH 05/14] Fix styling --- tests/Pest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Pest.php b/tests/Pest.php index 9b5eb1d..12ad555 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -40,4 +40,3 @@ | global functions to help you to reduce the number of lines of code in your test files. | */ - From 9fa489ac72c7a83bc9e950c4febab8422d21dd5e Mon Sep 17 00:00:00 2001 From: Oliver Stark Date: Thu, 5 May 2022 18:12:33 +0200 Subject: [PATCH 06/14] Pest --- tests/Pest.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/Pest.php b/tests/Pest.php index 12ad555..c3abb9d 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -26,9 +26,6 @@ | */ -expect()->extend('toBeOne', function () { - return $this->toBe(1); -}); /* |-------------------------------------------------------------------------- @@ -40,3 +37,11 @@ | global functions to help you to reduce the number of lines of code in your test files. | */ + +function disableCustomFields(): void { + $class = '\craft\behaviors\CustomFieldBehavior'; + if (Yii::$container->has($class)) { + spl_autoload_unregister([Craft::class, 'autoload']); + Yii::$container->set($class, new \yii\base\Behavior()); + } +} From 46fd074b6fe8104d89229ac981f436ac540ad935 Mon Sep 17 00:00:00 2001 From: ostark Date: Thu, 5 May 2022 16:12:56 +0000 Subject: [PATCH 07/14] Fix styling --- tests/Pest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Pest.php b/tests/Pest.php index c3abb9d..a636a07 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -38,7 +38,8 @@ | */ -function disableCustomFields(): void { +function disableCustomFields(): void +{ $class = '\craft\behaviors\CustomFieldBehavior'; if (Yii::$container->has($class)) { spl_autoload_unregister([Craft::class, 'autoload']); From 35676ed7e45e76ffacaeed1a91ca2450cd4c5ffb Mon Sep 17 00:00:00 2001 From: Oliver Stark Date: Thu, 5 May 2022 18:17:55 +0200 Subject: [PATCH 08/14] Github action - tests with PHP 8.0 and 8.1 --- .github/workflows/run-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 6eaebfc..2e81bb0 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -9,7 +9,7 @@ jobs: fail-fast: true matrix: os: [ubuntu-latest] - php: [7.4, 8.0] + php: [8.0, 8.1] stability: [prefer-stable] name: P${{ matrix.php }} From 464b7baf063b9fa494f765297246b96c24b15ef2 Mon Sep 17 00:00:00 2001 From: Oliver Stark Date: Mon, 9 May 2022 15:28:21 +0200 Subject: [PATCH 09/14] Prepare for Craft 4 --- composer.json | 11 ++++++----- phpstan.neon | 11 +++++------ src/Plugin.php | 7 ++++--- src/Queue/HashedJobQueue.php | 8 ++++---- src/SearchIndex/SearchIndexCommand.php | 4 ++-- tests/Unit/DefaultHasherTest.php | 4 ++-- 6 files changed, 23 insertions(+), 22 deletions(-) diff --git a/composer.json b/composer.json index 02c5b22..8745ade 100644 --- a/composer.json +++ b/composer.json @@ -24,17 +24,17 @@ }, "require": { "php": "^7.4||^8.0", - "craftcms/cms": "^3.7.20", + "craftcms/cms": "^4.0.0", "treeware/plant": "*", "yiisoft/yii2-queue": "^2.3.3" }, "require-dev": { + "craftcms/phpstan": "*", + "craftcms/rector": "dev-main", "friendsofphp/php-cs-fixer": "^3.0", "nunomaduro/collision": "^5.10", - "ostark/craft-mockery": "dev-master", "pestphp/pest": "^1.2", - "pestphp/pest-plugin-parallel": "^1.0", - "phpstan/phpstan": "^1.0" + "pestphp/pest-plugin-parallel": "^1.0" }, "autoload": { "psr-4": { @@ -64,5 +64,6 @@ "changelogUrl": "https://raw.githubusercontent.com/ostark/craft-relax/main/CHANGELOG.md", "class": "ostark\\Relax\\Plugin" }, - "prefer-stable": true + "prefer-stable": true, + "minimum-stability": "dev" } diff --git a/phpstan.neon b/phpstan.neon index ba9fbdb..be0a203 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,12 +1,11 @@ +includes: + - vendor/craftcms/phpstan/phpstan.neon parameters: level: 6 paths: - src - scanFiles: - - vendor/yiisoft/yii2/Yii.php - - vendor/craftcms/cms/src/Craft.php - stubFiles: - - vendor/craftcms/cms/stubs/BaseYii.stub + - tests tmpDir: build/phpstan checkMissingIterableValueType: false - + ignoreErrors: + - "#Unable to resolve the template type T in call to method static method#" diff --git a/src/Plugin.php b/src/Plugin.php index 14582a1..a4399ea 100755 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -9,6 +9,7 @@ use ostark\Relax\Handlers\DeprecationServiceHandler; use ostark\Relax\Handlers\QueueServiceHandler; use ostark\Relax\Handlers\SearchServiceHandler; +use phpDocumentor\Reflection\Types\Boolean; use yii\base\Event; /** @@ -16,9 +17,9 @@ */ final class Plugin extends BasePlugin { - public $schemaVersion = '1.0.0'; - public $hasCpSettings = false; - public $hasCpSection = false; + public string $schemaVersion = '1.0.0'; + public bool $hasCpSettings = false; + public bool $hasCpSection = false; public function init(): void { diff --git a/src/Queue/HashedJobQueue.php b/src/Queue/HashedJobQueue.php index 8a0a7c8..859a9e3 100644 --- a/src/Queue/HashedJobQueue.php +++ b/src/Queue/HashedJobQueue.php @@ -53,10 +53,10 @@ public function push($job): ?string * @param int $delay * @param mixed $priority * - * @return string|null + * @return string * @throws \yii\db\Exception */ - protected function pushMessage($message, $ttr, $delay, $priority): ?string + protected function pushMessage($message, $ttr, $delay, $priority): string { $hash = $this->hasher->hash($message); $found = (new Query()) @@ -65,7 +65,7 @@ protected function pushMessage($message, $ttr, $delay, $priority): ?string ->count('*', $this->db); if ($found) { - return null; + return '1'; } $data = [ @@ -78,7 +78,7 @@ protected function pushMessage($message, $ttr, $delay, $priority): ?string self::HASH_COLUMN => $hash, ]; - Db::insert($this->tableName, $data, false, $this->db); + Db::insert($this->tableName, $data, $this->db); return $this->db->getLastInsertID($this->tableName); } diff --git a/src/SearchIndex/SearchIndexCommand.php b/src/SearchIndex/SearchIndexCommand.php index fe0882f..8f54822 100644 --- a/src/SearchIndex/SearchIndexCommand.php +++ b/src/SearchIndex/SearchIndexCommand.php @@ -14,7 +14,7 @@ class SearchIndexCommand extends Command */ public array $filters = []; - public function insert($table, $columns, $includeAuditColumns = true) + public function insert($table, $columns): Command { if ($table === Table::SEARCHINDEX) { if ($this->applyFilters($columns)) { @@ -22,7 +22,7 @@ public function insert($table, $columns, $includeAuditColumns = true) } } - return parent::insert($table, $columns, $includeAuditColumns); + return parent::insert($table, $columns); } protected function applyFilters(array $columns): bool diff --git a/tests/Unit/DefaultHasherTest.php b/tests/Unit/DefaultHasherTest.php index 64d3ec8..7a41de0 100644 --- a/tests/Unit/DefaultHasherTest.php +++ b/tests/Unit/DefaultHasherTest.php @@ -24,12 +24,12 @@ class DummyJob implements \craft\queue\JobInterface { public int $prop = 1; - public function getDescription() + public function getDescription(): string { return 'dummy'; } - public function execute($queue) + public function execute($queue): void { } } From c2e6b982f2e631c45e897f58794b8a0befa80b64 Mon Sep 17 00:00:00 2001 From: ostark Date: Wed, 11 May 2022 12:16:03 +0000 Subject: [PATCH 10/14] Fix styling --- src/Plugin.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Plugin.php b/src/Plugin.php index a4399ea..60f6a42 100755 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -9,7 +9,6 @@ use ostark\Relax\Handlers\DeprecationServiceHandler; use ostark\Relax\Handlers\QueueServiceHandler; use ostark\Relax\Handlers\SearchServiceHandler; -use phpDocumentor\Reflection\Types\Boolean; use yii\base\Event; /** From e3a6a46d3d71a373cdf1136e80ad43ef779985d9 Mon Sep 17 00:00:00 2001 From: Oliver Stark Date: Thu, 12 May 2022 14:21:57 +0200 Subject: [PATCH 11/14] Bullet proof migration --- src/migrations/Install.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/migrations/Install.php b/src/migrations/Install.php index fb3cd6b..51aacda 100644 --- a/src/migrations/Install.php +++ b/src/migrations/Install.php @@ -14,6 +14,7 @@ public function safeUp(): bool { // Same schema as the `queue` table, but with an additional `job_hash` column // to prevent duplicated queue messages + $this->dropTableIfExists(HashedJobQueue::TABLE); $this->createTable(HashedJobQueue::TABLE, [ 'id' => $this->primaryKey(), 'channel' => $this->string()->notNull()->defaultValue('queue'), @@ -43,7 +44,7 @@ public function safeUp(): bool public function safeDown(): bool { - $this->dropTable(HashedJobQueue::TABLE); + $this->dropTableIfExists(HashedJobQueue::TABLE); return true; } From 002274b65a26809c1ce613336736733bc5b30b99 Mon Sep 17 00:00:00 2001 From: Oliver Stark Date: Thu, 19 May 2022 13:45:44 +0200 Subject: [PATCH 12/14] Feedme queue support --- src/Handlers/QueueServiceHandler.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Handlers/QueueServiceHandler.php b/src/Handlers/QueueServiceHandler.php index 1a965bb..8437948 100644 --- a/src/Handlers/QueueServiceHandler.php +++ b/src/Handlers/QueueServiceHandler.php @@ -43,5 +43,10 @@ public function __invoke(): void if (isset(Craft::$app->controllerMap['queue']['queue'])) { Craft::$app->controllerMap['queue']['queue'] = $queue; } + + // Extrawurst for feed-me + if ($feedMe = Craft::$app->getPlugins()->getPlugin('feed-me')) { + $feedMe->queue = $queue; + }; } } From dfa05812b41d9cc654046416b1ee520dfd474847 Mon Sep 17 00:00:00 2001 From: Oliver Stark Date: Thu, 19 May 2022 13:49:47 +0200 Subject: [PATCH 13/14] Happy phpstan --- src/Handlers/QueueServiceHandler.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Handlers/QueueServiceHandler.php b/src/Handlers/QueueServiceHandler.php index 8437948..bcd209a 100644 --- a/src/Handlers/QueueServiceHandler.php +++ b/src/Handlers/QueueServiceHandler.php @@ -46,6 +46,7 @@ public function __invoke(): void // Extrawurst for feed-me if ($feedMe = Craft::$app->getPlugins()->getPlugin('feed-me')) { + /** @phpstan-ignore-next-line */ $feedMe->queue = $queue; }; } From 0edcb395bcfafab36deee042bae0e66f2878d64d Mon Sep 17 00:00:00 2001 From: Oliver Stark Date: Thu, 19 May 2022 14:09:59 +0200 Subject: [PATCH 14/14] Prepare 2.0 --- CHANGELOG.md | 6 ++++++ README.md | 1 + 2 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9b8903..b7e4b80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes will be documented in this file. +## 2.0.0 - 2022-05-19 + +- Craft 4 support +- Feed Me plugin support +- Bulletproof database migration + ## 1.0.1 - 2022-01-18 - Fixed phpstan (1.4) level 6 diff --git a/README.md b/README.md index 26e6fb8..bae3434 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ The first time plugin is installed, a config file `config/relax.php` is created. composer test ``` + ## Changelog Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.