Skip to content

Commit 75a27d2

Browse files
authored
Allow to specify property values when insert() or save() (#424)
1 parent 48c7539 commit 75a27d2

File tree

5 files changed

+256
-43
lines changed

5 files changed

+256
-43
lines changed

src/AbstractActiveRecord.php

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use function array_flip;
2424
use function array_intersect;
2525
use function array_intersect_key;
26+
use function array_is_list;
2627
use function array_key_exists;
2728
use function array_keys;
2829
use function array_merge;
@@ -67,8 +68,8 @@ abstract protected function propertyValuesInternal(): array;
6768
/**
6869
* Inserts Active Record values into DB without considering transaction.
6970
*
70-
* @param array|null $propertyNames List of property names that need to be saved. Defaults to `null`, meaning all
71-
* changed property values will be saved. Only changed values will be saved.
71+
* @param array|null $properties List of property names or name-values pairs that need to be saved.
72+
* Defaults to `null`, meaning all changed property values will be saved.
7273
*
7374
* @throws Exception
7475
* @throws InvalidArgumentException
@@ -77,7 +78,7 @@ abstract protected function propertyValuesInternal(): array;
7778
*
7879
* @return bool Whether the record inserted successfully.
7980
*/
80-
abstract protected function insertInternal(array|null $propertyNames = null): bool;
81+
abstract protected function insertInternal(array|null $properties = null): bool;
8182

8283
/**
8384
* Sets the value of the named property.
@@ -347,9 +348,9 @@ public function hasOne(string|ActiveRecordInterface|Closure $class, array $link)
347348
return $this->createRelationQuery($class, $link, false);
348349
}
349350

350-
public function insert(array|null $propertyNames = null): bool
351+
public function insert(array|null $properties = null): bool
351352
{
352-
return $this->insertInternal($propertyNames);
353+
return $this->insertInternal($properties);
353354
}
354355

355356
/**
@@ -619,13 +620,13 @@ protected function retrieveRelation(string $name): ActiveRecordInterface|array|n
619620
return $this->related[$name] = $query->relatedRecords();
620621
}
621622

622-
public function save(array|null $propertyNames = null): bool
623+
public function save(array|null $properties = null): bool
623624
{
624625
if ($this->isNewRecord()) {
625-
return $this->insert($propertyNames);
626+
return $this->insert($properties);
626627
}
627628

628-
$this->update($propertyNames);
629+
$this->update($properties);
629630

630631
return true;
631632
}
@@ -1093,6 +1094,38 @@ protected function deleteInternal(): int
10931094
return $result;
10941095
}
10951096

1097+
/**
1098+
* Returns the property values that have been modified.
1099+
* You may specify the properties to be returned as list of name or name-value pairs.
1100+
* If name-value pair specified, the corresponding property values will be modified.
1101+
*
1102+
* Only the {@see newValues() changed property values} will be returned.
1103+
*
1104+
* @param array|null $properties List of property names or name-values pairs that need to be returned.
1105+
* Defaults to `null`, meaning all changed property values will be returned.
1106+
*
1107+
* @return array The changed property values (name-value pairs).
1108+
*/
1109+
protected function newPropertyValues(array|null $properties = null): array
1110+
{
1111+
if (empty($properties) || array_is_list($properties)) {
1112+
return $this->newValues($properties);
1113+
}
1114+
1115+
$names = [];
1116+
1117+
foreach ($properties as $name => $value) {
1118+
if (is_int($name)) {
1119+
$names[] = $value;
1120+
} else {
1121+
$this->set($name, $value);
1122+
$names[] = $name;
1123+
}
1124+
}
1125+
1126+
return $this->newValues($names);
1127+
}
1128+
10961129
/**
10971130
* Repopulates this active record with the latest data from a newly fetched instance.
10981131
*
@@ -1136,22 +1169,7 @@ protected function updateInternal(array|null $properties = null): int
11361169
throw new InvalidCallException('The record is new and cannot be updated.');
11371170
}
11381171

1139-
if ($properties === null) {
1140-
$names = $this->propertyNames();
1141-
} else {
1142-
$names = [];
1143-
1144-
foreach ($properties as $name => $value) {
1145-
if (is_int($name)) {
1146-
$names[] = $value;
1147-
} else {
1148-
$this->set($name, $value);
1149-
$names[] = $name;
1150-
}
1151-
}
1152-
}
1153-
1154-
$values = $this->newValues($names);
1172+
$values = $this->newPropertyValues($properties);
11551173

11561174
if (empty($values)) {
11571175
return 0;

src/ActiveRecord.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Yiisoft\Db\Constant\ColumnType;
88
use Yiisoft\Db\Exception\Exception;
9+
use Yiisoft\Db\Exception\InvalidCallException;
910
use Yiisoft\Db\Exception\InvalidConfigException;
1011
use Yiisoft\Db\Schema\TableSchemaInterface;
1112

@@ -153,9 +154,13 @@ protected function propertyValuesInternal(): array
153154
return get_object_vars($this);
154155
}
155156

156-
protected function insertInternal(array|null $propertyNames = null): bool
157+
protected function insertInternal(array|null $properties = null): bool
157158
{
158-
$values = $this->newValues($propertyNames);
159+
if (!$this->isNewRecord()) {
160+
throw new InvalidCallException('The record is not new and cannot be inserted.');
161+
}
162+
163+
$values = $this->newPropertyValues($properties);
159164
$primaryKeys = $this->db()->createCommand()->insertWithReturningPks($this->tableName(), $values);
160165

161166
if ($primaryKeys === false) {

src/ActiveRecordInterface.php

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Yiisoft\Db\Constant\ColumnType;
1010
use Yiisoft\Db\Exception\Exception;
1111
use Yiisoft\Db\Exception\InvalidArgumentException;
12+
use Yiisoft\Db\Exception\InvalidCallException;
1213
use Yiisoft\Db\Exception\InvalidConfigException;
1314

1415
interface ActiveRecordInterface
@@ -195,6 +196,8 @@ public function hasProperty(string $name): bool;
195196

196197
/**
197198
* Inserts a row into the associated database table using the property values of this record.
199+
* You may specify the properties to be inserted as list of name or name-value pairs.
200+
* If name-value pair specified, the corresponding property values will be modified.
198201
*
199202
* Only the {@see newValues() changed property values} will be inserted into a database.
200203
*
@@ -210,15 +213,22 @@ public function hasProperty(string $name): bool;
210213
* $customer->insert();
211214
* ```
212215
*
213-
* @param array|null $propertyNames List of property names that need to be saved. Defaults to `null`, meaning all
214-
* changed property values will be saved.
216+
* To insert a customer record with specific properties:
217+
*
218+
* ```php
219+
* $customer->insert(['name' => $name, 'email' => $email]);
220+
* ```
221+
*
222+
* @param array|null $properties List of property names or name-values pairs that need to be saved.
223+
* Defaults to `null`, meaning all changed property values will be saved.
215224
*
225+
* @throws InvalidCallException If the record {@see isNewRecord() is not new}.
216226
* @throws InvalidConfigException
217227
* @throws Throwable In case insert failed.
218228
*
219229
* @return bool Whether the record is inserted successfully.
220230
*/
221-
public function insert(array|null $propertyNames = null): bool;
231+
public function insert(array|null $properties = null): bool;
222232

223233
/**
224234
* Checks if any property returned by {@see propertyNames()} method has changed.
@@ -358,9 +368,13 @@ public function relationQuery(string $name): ActiveQueryInterface;
358368
public function resetRelation(string $name): void;
359369

360370
/**
361-
* Saves the current record.
371+
* Saves the changes to this active record into the associated database table.
372+
* You may specify the properties to be updated as list of name or name-value pairs.
373+
* If name-value pair specified, the corresponding property values will be modified.
362374
*
363-
* This method will call {@see insert()} when {@see isNewRecord()|isNewRecord} is true, or {@see update()} when
375+
* Only the {@see newValues() changed property values} will be saved into a database.
376+
*
377+
* This method will call {@see insert()} when {@see isNewRecord()} is true, or {@see update()} when
364378
* {@see isNewRecord()|isNewRecord} is false.
365379
*
366380
* For example, to save a customer record:
@@ -372,12 +386,18 @@ public function resetRelation(string $name): void;
372386
* $customer->save();
373387
* ```
374388
*
375-
* @param array|null $propertyNames List of property names that need to be saved. Defaults to `null`,
376-
* meaning all changed property values will be saved.
389+
* To save a customer record with specific properties:
390+
*
391+
* ```php
392+
* $customer->save(['name' => $name, 'email' => $email]);
393+
* ```
394+
*
395+
* @param array|null $properties List of property names or name-values pairs that need to be saved.
396+
* Defaults to `null`, meaning all changed property values will be saved.
377397
*
378398
* @return bool Whether the saving succeeded (that's no validation errors occurred).
379399
*/
380-
public function save(array|null $propertyNames = null): bool;
400+
public function save(array|null $properties = null): bool;
381401

382402
/**
383403
* Sets the named property value.
@@ -400,7 +420,7 @@ public function set(string $propertyName, mixed $value): void;
400420
* For example, to update a customer record:
401421
*
402422
* ```php
403-
* $customer = new Customer();
423+
* $customer = (new ActiveQuery(Customer::class))->findByPk(1);
404424
* $customer->name = $name;
405425
* $customer->email = $email;
406426
* $customer->update();
@@ -409,9 +429,8 @@ public function set(string $propertyName, mixed $value): void;
409429
* To update a customer record with specific properties:
410430
*
411431
* ```php
412-
* $customer = new Customer();
413-
* $customer->update(['name' => $name, 'email' => $email]);
414-
* ```
432+
* $customer->update(['name' => $name, 'email' => $email]);
433+
* ```
415434
*
416435
* Note that it's possible the update doesn't affect any row in the table.
417436
* In this case, this method will return 0.
@@ -428,6 +447,7 @@ public function set(string $propertyName, mixed $value): void;
428447
* @param array|null $properties List of property names or name-values pairs that need to be saved.
429448
* Defaults to `null`, meaning all changed property values will be saved.
430449
*
450+
* @throws InvalidCallException If the record {@see isNewRecord() is new}.
431451
* @throws OptimisticLockException If the instance implements {@see OptimisticLockInterface} and the data being
432452
* updated is outdated.
433453
* @throws Throwable In case update failed.

0 commit comments

Comments
 (0)