diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index 0306651b2e85..9223e4beb162 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -1587,6 +1587,18 @@ public function countAllResults(bool $reset = true, bool $test = false) return (int) $row->numrows; } + //-------------------------------------------------------------------- + /** + * Get compiled 'where' condition string + * + * Compiles the set conditions and returns the sql statement + * + * @return string + */ + public function getCompiledQBWhere() + { + return $this->QBWhere; + } //-------------------------------------------------------------------- /** diff --git a/system/Model.php b/system/Model.php index 2842ec3271c4..8705276576d0 100644 --- a/system/Model.php +++ b/system/Model.php @@ -48,6 +48,7 @@ use CodeIgniter\Database\ConnectionInterface; use CodeIgniter\Validation\ValidationInterface; use CodeIgniter\Database\Exceptions\DataException; +use CodeIgniter\Database\Exceptions\DatabaseException; use ReflectionClass; use ReflectionProperty; use stdClass; @@ -714,13 +715,13 @@ public function insert($data = null, bool $returnID = true) $result = $this->builder() ->set($data['data'], '', $escape) ->insert(); - + // If insertion succeeded then save the insert ID if ($result) { $this->insertID = $this->db->insertID(); } - + $this->trigger('afterInsert', ['data' => $originalData, 'result' => $result]); // If insertion failed, get out of here @@ -913,6 +914,14 @@ public function delete($id = null, bool $purge = false) if ($this->useSoftDeletes && ! $purge) { + if (empty($builder->getCompiledQBWhere())) + { + if (CI_DEBUG) + { + throw new DatabaseException('Deletes are not allowed unless they contain a "where" or "like" clause.'); + } + return false; + } $set[$this->deletedField] = $this->setDate(); if ($this->useTimestamps && ! empty($this->updatedField)) @@ -948,8 +957,8 @@ public function purgeDeleted() } return $this->builder() - ->where($this->table . '.' . $this->deletedField . ' IS NOT NULL') - ->delete(); + ->where($this->table . '.' . $this->deletedField . ' IS NOT NULL') + ->delete(); } //-------------------------------------------------------------------- @@ -982,7 +991,7 @@ public function onlyDeleted() $this->tempUseSoftDeletes = false; $this->builder() - ->where($this->table . '.' . $this->deletedField . ' IS NOT NULL'); + ->where($this->table . '.' . $this->deletedField . ' IS NOT NULL'); return $this; } diff --git a/tests/system/Database/Live/ModelTest.php b/tests/system/Database/Live/ModelTest.php index 72b62e0a13fc..e4101caf8659 100644 --- a/tests/system/Database/Live/ModelTest.php +++ b/tests/system/Database/Live/ModelTest.php @@ -486,9 +486,62 @@ public function testOnlyDeleted() $this->assertCount(1, $users); } + /** + * If where condition is set, beyond the value was empty (0,'', NULL, etc.), + * Exception should not be thrown because condition was explicity set + * + * @dataProvider emptyPkValues + * @return void + */ + public function testDontThrowExceptionWhenSoftDeleteConditionIsSetWithEmptyValue($emptyValue) + { + $model = new UserModel(); + $this->seeInDatabase('user', ['name' => 'Derek Jones', 'deleted_at IS NULL' => null]); + $model->where('id', $emptyValue)->delete(); + $this->seeInDatabase('user', ['name' => 'Derek Jones', 'deleted_at IS NULL' => null]); + unset($model); + } //-------------------------------------------------------------------- + + /** + * @expectedException \CodeIgniter\Database\Exceptions\DatabaseException + * @expectedExceptionMessage Deletes are not allowed unless they contain a "where" or "like" clause. + * @dataProvider emptyPkValues + * @return void + */ + public function testThrowExceptionWhenSoftDeleteParamIsEmptyValue($emptyValue) + { + $model = new UserModel(); + $this->seeInDatabase('user', ['name' => 'Derek Jones', 'deleted_at IS NULL' => null]); + $model->delete($emptyValue); + } //-------------------------------------------------------------------- + /** + * @expectedException \CodeIgniter\Database\Exceptions\DatabaseException + * @expectedExceptionMessage Deletes are not allowed unless they contain a "where" or "like" clause. + * @dataProvider emptyPkValues + * @return void + */ + public function testDontDeleteRowsWhenSoftDeleteParamIsEmpty($emptyValue) + { + $model = new UserModel(); + $this->seeInDatabase('user', ['name' => 'Derek Jones', 'deleted_at IS NULL' => null]); + $model->delete($emptyValue); + $this->seeInDatabase('user', ['name' => 'Derek Jones', 'deleted_at IS NULL' => null]); + unset($model); + } + + public function emptyPkValues() + { + return [ + [0], + [null], + ['0'], + ]; + } + //-------------------------------------------------------------------- + public function testChunk() { $model = new UserModel();