diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3444b18..1b40453 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,9 +13,9 @@ permissions: jobs: testsuite: - uses: cakephp/.github/.github/workflows/testsuite-with-db.yml@5.x - secrets: inherit + uses: ADmad/.github/.github/workflows/testsuite-with-db.yml@master + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} cs-stan: - uses: cakephp/.github/.github/workflows/cs-stan.yml@5.x - secrets: inherit + uses: ADmad/.github/.github/workflows/cs-stan.yml@master diff --git a/.phive/phars.xml b/.phive/phars.xml deleted file mode 100644 index 9aa6dfe..0000000 --- a/.phive/phars.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/phpstan.neon b/phpstan.neon index 99081e7..1d3456a 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,8 +1,8 @@ parameters: - level: 6 - checkMissingIterableValueType: false - checkGenericClassInNonGenericObjectType: false + level: 8 paths: - src/ ignoreErrors: - '#Call to an undefined method Cake\\ORM\\Table::cascadingRestoreTrash\(\)#' + - identifier: missingType.iterableValue + - identifier: missingType.generics diff --git a/src/Model/Behavior/TrashBehavior.php b/src/Model/Behavior/TrashBehavior.php index 609983a..3b6eb82 100644 --- a/src/Model/Behavior/TrashBehavior.php +++ b/src/Model/Behavior/TrashBehavior.php @@ -9,8 +9,6 @@ use Cake\Database\Expression\BetweenExpression; use Cake\Database\Expression\ComparisonExpression; use Cake\Database\Expression\IdentifierExpression; -use Cake\Database\Expression\QueryExpression; -use Cake\Database\Expression\UnaryExpression; use Cake\Database\Query\SelectQuery; use Cake\Datasource\EntityInterface; use Cake\Event\EventInterface; @@ -18,7 +16,6 @@ use Cake\ORM\Association; use Cake\ORM\Behavior; use Cake\ORM\Table; -use Closure; use InvalidArgumentException; use function Cake\Core\pluginSplit; @@ -56,7 +53,7 @@ class TrashBehavior extends Behavior */ public function initialize(array $config): void { - if (!empty($config['events'])) { + if (isset($config['events']) && $config['events'] !== []) { $this->setConfig('events', $config['events'], false); } } @@ -70,10 +67,12 @@ public function initialize(array $config): void public function implementedEvents(): array { $events = []; - if ($this->getConfig('events') === false) { + $config = $this->getConfig('events'); + if ($config === false) { return $events; } - foreach ((array)$this->getConfig('events') as $eventKey => $event) { + + foreach ((array)$config as $eventKey => $event) { if (is_numeric($eventKey)) { $eventKey = $event; $event = null; @@ -84,13 +83,16 @@ public function implementedEvents(): array if (!is_array($event)) { throw new InvalidArgumentException('Event should be string or array'); } - $priority = $this->getConfig('priority'); + if (!array_key_exists('callable', $event) || $event['callable'] === null) { [, $event['callable']] = pluginSplit($eventKey); } + + $priority = $this->getConfig('priority'); if ($priority && !array_key_exists('priority', $event)) { $event['priority'] = $priority; } + $events[$eventKey] = $event; } @@ -108,7 +110,7 @@ public function implementedEvents(): array */ public function beforeDelete(EventInterface $event, EntityInterface $entity, ArrayObject $options): void { - if ($options->offsetExists('purge') && $options['purge'] === true) { + if (isset($options['purge']) && $options['purge'] === true) { return; } @@ -159,14 +161,9 @@ public function trash(EntityInterface $entity, array $options = []): bool } } - $data = [$this->getTrashField(false) => new DateTime()]; - $entity->set($data, ['guard' => false]); - - if ($this->_table->save($entity, $options)) { - return true; - } + $entity->set($this->getTrashField(false), new DateTime()); - return false; + return (bool)$this->_table->save($entity, $options); } /** @@ -238,7 +235,7 @@ public function findOnlyTrashed(SelectQuery $query, array $options): SelectQuery { return $query ->applyOptions(['skipAddTrashCondition' => true]) - ->andWhere($query->newExpr()->isNotNull($this->getTrashField())); + ->andWhere([$this->getTrashField() . ' IS NOT' => null]); } /** @@ -250,9 +247,7 @@ public function findOnlyTrashed(SelectQuery $query, array $options): SelectQuery */ public function findWithTrashed(SelectQuery $query, array $options = []): SelectQuery { - return $query->applyOptions([ - 'skipAddTrashCondition' => true, - ]); + return $query->applyOptions(['skipAddTrashCondition' => true]); } /** @@ -277,7 +272,7 @@ public function trashAll(mixed $conditions): int */ public function emptyTrash(): int { - return $this->_table->deleteAll($this->_getUnaryExpression()); + return $this->_table->deleteAll([$this->getTrashField(false) . ' IS NOT' => null]); } /** @@ -300,7 +295,7 @@ public function restoreTrash(?EntityInterface $entity = null, array $options = [ return $this->_table->save($entity, $options); } - return $this->_table->updateAll($data, $this->_getUnaryExpression()); + return $this->_table->updateAll($data, [$this->getTrashField(false) . ' IS NOT' => null]); } /** @@ -346,21 +341,6 @@ public function cascadingRestoreTrash( return $result; } - /** - * Returns a unary expression for bulk record manipulation. - * - * @return \Closure - */ - protected function _getUnaryExpression(): Closure - { - return fn (QueryExpression $queryExpression): QueryExpression => $queryExpression - ->add(new UnaryExpression( - 'IS NOT NULL', - $this->getTrashField(false), - UnaryExpression::POSTFIX - )); - } - /** * Returns the table's field used to mark a `trashed` row. * @@ -371,7 +351,7 @@ public function getTrashField(bool $aliased = true): string { $field = $this->getConfig('field'); - if (empty($field)) { + if ($field === null) { $columns = $this->_table->getSchema()->columns(); foreach (['deleted', 'trashed'] as $name) { if (in_array($name, $columns, true)) { @@ -380,12 +360,9 @@ public function getTrashField(bool $aliased = true): string } } - /** @psalm-suppress RedundantCondition */ - if (empty($field)) { - $field = Configure::read('Muffin/Trash.field'); - } + $field ??= Configure::read('Muffin/Trash.field'); - if (empty($field)) { + if ($field === null) { throw new CakeException('TrashBehavior: "field" config needs to be provided.'); } diff --git a/tests/TestCase/Model/Behavior/TrashBehaviorTest.php b/tests/TestCase/Model/Behavior/TrashBehaviorTest.php index e3f886d..665e2bd 100644 --- a/tests/TestCase/Model/Behavior/TrashBehaviorTest.php +++ b/tests/TestCase/Model/Behavior/TrashBehaviorTest.php @@ -874,7 +874,7 @@ public function testGetTrashFieldUsesConfiguredValue() */ public function testGetTrashFieldFallbackToDefault() { - $trash = new TrashBehavior($this->Articles, ['field' => '']); + $trash = new TrashBehavior($this->Articles); $this->assertEmpty($trash->getConfig('field')); $this->assertEquals('Articles.trashed', $trash->getTrashField());