Skip to content

Commit

Permalink
Refactor delete...() methods
Browse files Browse the repository at this point in the history
  • Loading branch information
Tigrov committed Dec 29, 2023
1 parent 6d9864b commit 3b2de6c
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 73 deletions.
47 changes: 2 additions & 45 deletions src/ActiveRecord.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public function attributes(): array
return $this->getTableSchema()->getColumnNames();
}

public function delete(): false|int
public function delete(): int
{
if (!$this->isTransactional(self::OP_DELETE)) {
return $this->deleteInternal();
Expand All @@ -124,11 +124,7 @@ public function delete(): false|int

try {
$result = $this->deleteInternal();
if ($result === false) {
$transaction->rollBack();
} else {
$transaction->commit();
}
$transaction->commit();

return $result;
} catch (Throwable $e) {
Expand Down Expand Up @@ -346,45 +342,6 @@ public function update(array $attributeNames = null): false|int
}
}

/**
* Deletes an ActiveRecord without considering transaction.
*
* Note that it is possible the number of rows deleted is 0, even though the deletion execution is successful.
*
* @throws Exception
* @throws StaleObjectException
* @throws Throwable
*
* @return false|int The number of rows deleted, or `false` if the deletion is unsuccessful for some reason.
*/
protected function deleteInternal(): false|int
{
/**
* We do not check the return value of deleteAll() because it's possible the record is already deleted in the
* database and thus the method will return 0.
*/
$condition = $this->getOldPrimaryKey(true);
$lock = $this->optimisticLock();

if (is_array($condition) === false) {
return false;
}

if ($lock !== null) {
$condition[$lock] = $this->$lock;
}

$result = $this->deleteAll($condition);

if ($lock !== null && !$result) {
throw new StaleObjectException('The object being deleted is outdated.');
}

$this->setOldAttributes();

return $result;
}

/**
* Valid column names are table column names or column names prefixed with table name or table alias.
*
Expand Down
4 changes: 2 additions & 2 deletions src/ActiveRecordInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ public function attributes(): array;
* is outdated.
* @throws Throwable In case delete failed.
*
* @return false|int The number of rows deleted, or `false` if the deletion is unsuccessful for some reason.
* @return int The number of rows deleted.
*
* Note that it's possible the number of rows deleted is 0, even though the deletion execution is successful.
*/
public function delete(): false|int;
public function delete(): int;

/**
* Deletes rows in the table using the provided conditions.
Expand Down
63 changes: 37 additions & 26 deletions src/BaseActiveRecord.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,33 +60,9 @@ public function __construct(
) {
}

public function delete(): false|int
public function delete(): int
{
/**
* We do not check the return value of deleteAll() because it's possible the record is already deleted in
* the database and thus the method will return 0
*/
$condition = $this->getOldPrimaryKey(true);

if (is_array($condition) === false) {
return false;
}

$lock = $this->optimisticLock();

if ($lock !== null) {
$condition[$lock] = $lock;
}

$result = $this->deleteAll($condition);

if ($lock !== null && !$result) {
throw new StaleObjectException('The object being deleted is outdated.');
}

$this->oldAttributes = null;

return $result;
return $this->deleteInternal();
}

public function deleteAll(array $condition = [], array $params = []): int
Expand Down Expand Up @@ -1128,6 +1104,41 @@ protected function createRelationQuery(string $arClass, array $link, bool $multi
return $this->instantiateQuery($arClass)->primaryModel($this)->link($link)->multiple($multiple);
}

/**
* {@see delete()}
*
* @throws Exception
* @throws StaleObjectException
* @throws Throwable
*
* @return int The number of rows deleted.
*/
protected function deleteInternal(): int
{
/**
* We do not check the return value of deleteAll() because it's possible the record is already deleted in
* the database and thus the method will return 0
*/
$condition = $this->getOldPrimaryKey(true);
$lock = $this->optimisticLock();

if ($lock !== null) {
$condition[$lock] = $this->getAttribute($lock);

Check failure on line 1126 in src/BaseActiveRecord.php

View workflow job for this annotation

GitHub Actions / PHP 8-ubuntu-latest

InvalidArrayOffset: Cannot access value on variable $condition[$lock] using a string offset, expecting int

$result = $this->deleteAll($condition);

Check failure on line 1128 in src/BaseActiveRecord.php

View workflow job for this annotation

GitHub Actions / PHP 8-ubuntu-latest

PossiblyInvalidArgument: Argument 1 of Yiisoft\ActiveRecord\BaseActiveRecord::deleteAll expects array<array-key, mixed>, but possibly different type non-empty-array<array-key, mixed>|string provided

if ($result === 0) {
throw new StaleObjectException('The object being deleted is outdated.');
}
} else {
$result = $this->deleteAll($condition);

Check failure on line 1134 in src/BaseActiveRecord.php

View workflow job for this annotation

GitHub Actions / PHP 8-ubuntu-latest

PossiblyInvalidArgument: Argument 1 of Yiisoft\ActiveRecord\BaseActiveRecord::deleteAll expects array<array-key, mixed>, but possibly different type array<array-key, mixed>|null|string provided
}

$this->setOldAttributes();

return $result;
}

/**
* Repopulates this active record with the latest data from a newly fetched instance.
*
Expand Down
30 changes: 30 additions & 0 deletions tests/ActiveQueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2005,6 +2005,36 @@ public function testOptimisticLock(): void
$record->save();
}

public function testOptimisticLockOnDelete(): void
{
$this->checkFixture($this->db, 'document');

$documentQuery = new ActiveQuery(Document::class, $this->db);
$document = $documentQuery->findOne(1);

$this->assertSame(0, $document->version);

$document->version = 1;

$this->expectException(StaleObjectException::class);
$document->delete();
}

public function testOptimisticLockAfterDelete(): void
{
$this->checkFixture($this->db, 'document');

$documentQuery = new ActiveQuery(Document::class, $this->db);
$document = $documentQuery->findOne(1);

$this->assertSame(0, $document->version);
$this->assertSame(1, $document->delete());
$this->assertTrue($document->getIsNewRecord());

$this->expectException(StaleObjectException::class);
$document->delete();
}

/**
* {@see https://github.com/yiisoft/yii2/issues/9006}
*/
Expand Down

0 comments on commit 3b2de6c

Please sign in to comment.