diff --git a/system/Model.php b/system/Model.php index f6b125260398..700cada5cabf 100644 --- a/system/Model.php +++ b/system/Model.php @@ -558,6 +558,14 @@ public function exists(bool $reset = true, bool $test = false) return $this->builder()->testMode($test)->exists($reset); } + /** + * Determines whether the given primary key value exists. + */ + public function existsById(int|string $id): bool + { + return $this->where($this->table . '.' . $this->primaryKey, $id)->exists(); + } + /** * Determines whether the current Model query would not return any rows. * diff --git a/tests/system/Models/ExistsModelTest.php b/tests/system/Models/ExistsModelTest.php index 1dc617e40bc3..a6671261c52c 100644 --- a/tests/system/Models/ExistsModelTest.php +++ b/tests/system/Models/ExistsModelTest.php @@ -14,6 +14,7 @@ namespace CodeIgniter\Models; use PHPUnit\Framework\Attributes\Group; +use Tests\Support\Models\EventModel; use Tests\Support\Models\UserModel; /** @@ -22,6 +23,46 @@ #[Group('DatabaseLive')] final class ExistsModelTest extends LiveModelTestCase { + public function testExistsByIdReturnsTrueForExistingPrimaryKey(): void + { + $this->createModel(UserModel::class); + + $this->assertTrue($this->model->existsById(1)); + } + + public function testExistsByIdReturnsFalseForMissingPrimaryKey(): void + { + $this->createModel(UserModel::class); + + $this->assertFalse($this->model->existsById(999)); + } + + public function testExistsByIdRespectsSoftDeletes(): void + { + $this->createModel(UserModel::class); + $this->model->delete(1); + + $this->assertFalse($this->model->existsById(1)); + $this->assertTrue($this->model->withDeleted()->existsById(1)); + } + + public function testExistsByIdWorksWithCurrentModelQuery(): void + { + $this->createModel(UserModel::class); + + $this->assertTrue($this->model->where('country', 'US')->existsById(1)); + $this->assertFalse($this->model->where('country', 'UK')->existsById(1)); + } + + public function testExistsByIdDoesNotTriggerFindCallbacks(): void + { + $model = $this->createModel(EventModel::class); + + $this->assertTrue($model->existsById(1)); + $this->assertFalse($model->hasToken('beforeFind')); + $this->assertFalse($model->hasToken('afterFind')); + } + public function testExistsRespectsSoftDeletes(): void { $this->createModel(UserModel::class); diff --git a/user_guide_src/source/changelogs/v4.8.0.rst b/user_guide_src/source/changelogs/v4.8.0.rst index 359448aa83b5..80621561df9c 100644 --- a/user_guide_src/source/changelogs/v4.8.0.rst +++ b/user_guide_src/source/changelogs/v4.8.0.rst @@ -247,6 +247,7 @@ Model ===== - Added new ``chunkRows()`` method to ``CodeIgniter\Model`` for processing large datasets in smaller chunks. +- Added new ``existsById()`` method to ``CodeIgniter\Model`` to check whether a row exists for a primary key without fetching it. See :ref:`model-exists-by-id`. - Added new ``firstOrInsert()`` method to ``CodeIgniter\Model`` that finds the first row matching the given attributes or inserts a new one. See :ref:`model-first-or-insert`. Libraries diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index 800ae304f117..9ef6e193d087 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -509,6 +509,23 @@ of just one: .. note:: If ``find()`` is called without parameters or with ``null``, it will return all rows in that model's table, effectively acting like ``findAll()``, though less explicit. +.. _model-exists-by-id: + +existsById() +------------ + +.. versionadded:: 4.8.0 + +Checks whether a row exists where the model's `$primaryKey`_ matches the +given value, without fetching or hydrating the row: + +.. literalinclude:: model/068.php + +This method respects soft deletes. Use ``withDeleted()`` first if you need to +check deleted rows. It can also be combined with Query Builder methods like +``where()``. For condition-based existence checks that are not tied to a +primary key, use ``exists()`` or ``doesntExist()``. + findColumn() ------------ diff --git a/user_guide_src/source/models/model/068.php b/user_guide_src/source/models/model/068.php new file mode 100644 index 000000000000..e50af3b1bd06 --- /dev/null +++ b/user_guide_src/source/models/model/068.php @@ -0,0 +1,4 @@ +existsById($userId); +$activeUserExists = $userModel->where('active', 1)->existsById($userId);