Skip to content

Commit

Permalink
Merge pull request #8455 from kenjis/feat-Model-updateOnlyChanged
Browse files Browse the repository at this point in the history
feat: [Model] add option $updateOnlyChanged
  • Loading branch information
kenjis authored Feb 4, 2024
2 parents 437ce02 + f2cb81b commit 01d8280
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 29 deletions.
67 changes: 39 additions & 28 deletions system/BaseModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ abstract class BaseModel
*/
public $pager;

/**
* Database Connection
*
* @var BaseConnection
*/
protected $db;

/**
* Last insert ID
*
Expand All @@ -89,13 +96,20 @@ abstract class BaseModel
protected $returnType = 'array';

/**
* If this model should use "softDeletes" and
* simply set a date when rows are deleted, or
* do hard deletes.
* Used by asArray() and asObject() to provide
* temporary overrides of model default.
*
* @var string
*/
protected $tempReturnType;

/**
* Whether we should limit fields in inserts
* and updates to those available in $allowedFields or not.
*
* @var bool
*/
protected $useSoftDeletes = false;
protected $protectFields = true;

/**
* An array of field names that are allowed
Expand Down Expand Up @@ -137,6 +151,15 @@ abstract class BaseModel
*/
protected $updatedField = 'updated_at';

/**
* If this model should use "softDeletes" and
* simply set a date when rows are deleted, or
* do hard deletes.
*
* @var bool
*/
protected $useSoftDeletes = false;

/**
* Used by withDeleted to override the
* model's softDelete setting.
Expand All @@ -153,27 +176,14 @@ abstract class BaseModel
protected $deletedField = 'deleted_at';

/**
* Used by asArray and asObject to provide
* temporary overrides of model default.
*
* @var string
*/
protected $tempReturnType;

/**
* Whether we should limit fields in inserts
* and updates to those available in $allowedFields or not.
*
* @var bool
* Whether to allow inserting empty data.
*/
protected $protectFields = true;
protected bool $allowEmptyInserts = false;

/**
* Database Connection
*
* @var BaseConnection
* Whether to update Entity's only changed data.
*/
protected $db;
protected bool $updateOnlyChanged = true;

/**
* Rules used to validate data in insert, update, and save methods.
Expand Down Expand Up @@ -327,11 +337,6 @@ abstract class BaseModel
*/
protected $afterDelete = [];

/**
* Whether to allow inserting empty data.
*/
protected bool $allowEmptyInserts = false;

public function __construct(?ValidationInterface $validation = null)
{
$this->tempReturnType = $this->returnType;
Expand Down Expand Up @@ -1794,9 +1799,15 @@ protected function transformDataToArray($row, string $type): array
// properties representing the collection elements, we need to grab
// them as an array.
if (is_object($row) && ! $row instanceof stdClass) {
if ($type === 'update' && ! $this->updateOnlyChanged) {
$onlyChanged = false;
}
// If it validates with entire rules, all fields are needed.
$onlyChanged = ($this->skipValidation === false && $this->cleanValidationRules === false)
? false : ($type === 'update');
elseif ($this->skipValidation === false && $this->cleanValidationRules === false) {
$onlyChanged = false;
} else {
$onlyChanged = ($type === 'update');
}

$row = $this->objectToArray($row, $onlyChanged, true);
}
Expand Down
1 change: 1 addition & 0 deletions system/Commands/Generators/Views/model.tpl.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class {class} extends Model
protected $allowedFields = [];

protected bool $allowEmptyInserts = false;
protected bool $updateOnlyChanged = true;

// Dates
protected $useTimestamps = false;
Expand Down
22 changes: 22 additions & 0 deletions tests/system/Models/UpdateModelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
use Config\Database;
use InvalidArgumentException;
use stdClass;
use Tests\Support\Entity\User;
use Tests\Support\Entity\UUID;
use Tests\Support\Models\EventModel;
use Tests\Support\Models\JobModel;
use Tests\Support\Models\SecondaryModel;
use Tests\Support\Models\UserModel;
use Tests\Support\Models\UserTimestampModel;
use Tests\Support\Models\UUIDPkeyModel;
use Tests\Support\Models\ValidModel;
use Tests\Support\Models\WithoutAutoIncrementModel;
Expand Down Expand Up @@ -535,4 +537,24 @@ public static function provideUpdateThrowDatabaseExceptionWithoutWhereClause():
],
];
}

public function testUpdateEntityUpdateOnlyChangedFalse(): void
{
$model = new class () extends UserTimestampModel {
protected $returnType = User::class;
protected bool $updateOnlyChanged = false;
};

$user = $model->find(1);
$updateAtBefore = $user->updated_at;

// updates the Entity without changes.
$result = $model->update(1, $user);

$user = $model->find(1);
$updateAtAfter = $user->updated_at;

$this->assertTrue($result);
$this->assertNotSame($updateAtBefore, $updateAtAfter);
}
}
11 changes: 11 additions & 0 deletions user_guide_src/source/changelogs/v4.5.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,17 @@ findAll(0) Behavior
- If you disable this flag, you need to change code like ``findAll(0, $offset)``
to ``findAll(null, $offset)``.

$updateOnlyChanged
------------------

Added a property ``$updateOnlyChanged`` whether to update
:doc:`Entity <../models/entities>`'s only changed fields. If you set this property
to ``false``, when you are updating an Entity, ``DataException``
"There is no data to update" will not raise even if the values in the Entity have
not changed.

See :ref:`Using CodeIgniter’s Model <model-update-only-changed>` for details.

Libraries
=========

Expand Down
17 changes: 16 additions & 1 deletion user_guide_src/source/models/model.rst
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,26 @@ $allowEmptyInserts
.. versionadded:: 4.3.0

Whether to allow inserting empty data. The default value is ``false``, meaning
that if you try to insert empty data, an exception with
that if you try to insert empty data, ``DataException`` with
"There is no data to insert." will raise.

You may also change this setting with the :ref:`model-allow-empty-inserts` method.

.. _model-update-only-changed:

$updateOnlyChanged
------------------

.. versionadded:: 4.5.0

Whether to update :doc:`Entity <./entities>`'s only changed fields. The default
value is ``true``, meaning that only changed field data is used when updating to
the database. So if you try to update an Entity without changes, ``DataException``
with "There is no data to update." will raise.

Setting this property to ``false`` will ensure that all allowed fields of an Entity
are submitted to the database and updated at any time.

Dates
-----

Expand Down
1 change: 1 addition & 0 deletions user_guide_src/source/models/model/005.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class UserModel extends Model
protected $allowedFields = ['name', 'email'];

protected bool $allowEmptyInserts = false;
protected bool $updateOnlyChanged = true;

// Dates
protected $useTimestamps = false;
Expand Down

0 comments on commit 01d8280

Please sign in to comment.