mirror of
https://github.com/kamilwylegala/cakephp2-php8.git
synced 2024-11-15 11:28:25 +00:00
Merge remote-tracking branch 'origin/2.0-saveall' into 2.0
This commit is contained in:
commit
165dcf11b1
3 changed files with 1655 additions and 246 deletions
|
@ -1600,6 +1600,9 @@ class Model extends Object {
|
|||
}
|
||||
|
||||
/**
|
||||
* Backwards compatible passtrough method for:
|
||||
* saveMany(), validateMany(), saveAssociated() and validateAssociated()
|
||||
*
|
||||
* Saves multiple individual records for a single model; Also works with a single record, as well as
|
||||
* all its associated records.
|
||||
*
|
||||
|
@ -1623,62 +1626,78 @@ class Model extends Object {
|
|||
* @link http://book.cakephp.org/view/1031/Saving-Your-Data
|
||||
*/
|
||||
public function saveAll($data = null, $options = array()) {
|
||||
$options = array_merge(array('validate' => 'first'), $options);
|
||||
if (Set::numeric(array_keys($data))) {
|
||||
if ($options['validate'] === 'only') {
|
||||
return $this->validateMany($data, $options);
|
||||
}
|
||||
return $this->saveMany($data, $options);
|
||||
}
|
||||
if ($options['validate'] === 'only') {
|
||||
return $this->validateAssociated($data, $options);
|
||||
}
|
||||
return $this->saveAssociated($data, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves multiple individual records for a single model
|
||||
*
|
||||
* #### Options
|
||||
*
|
||||
* - validate: Set to false to disable validation, true to validate each record before saving,
|
||||
* 'first' to validate *all* records before any are saved (default),
|
||||
* - atomic: If true (default), will attempt to save all records in a single transaction.
|
||||
* Should be set to false if database/table does not support transactions.
|
||||
* - fieldList: Equivalent to the $fieldList parameter in Model::save()
|
||||
*
|
||||
* @param array $data Record data to save. This should be a numerically-indexed array
|
||||
* @param array $options Options to use when saving record data, See $options above.
|
||||
* @return mixed If atomic: True on success, or false on failure.
|
||||
* Otherwise: array similar to the $data array passed, but values are set to true/false
|
||||
* depending on whether each record saved successfully.
|
||||
* @access public
|
||||
*/
|
||||
public function saveMany($data = null, $options = array()) {
|
||||
if (empty($data)) {
|
||||
$data = $this->data;
|
||||
}
|
||||
$db = $this->getDataSource();
|
||||
|
||||
$options = array_merge(array('validate' => 'first', 'atomic' => true), $options);
|
||||
$this->validationErrors = $validationErrors = array();
|
||||
$validates = true;
|
||||
$return = array();
|
||||
|
||||
if (empty($data) && $options['validate'] !== false) {
|
||||
$result = $this->save($data, $options);
|
||||
return !empty($result);
|
||||
}
|
||||
|
||||
if ($options['atomic'] && $options['validate'] !== 'only') {
|
||||
if ($options['validate'] === 'first') {
|
||||
$validates = $this->validateMany($data, $options);
|
||||
if ((!$validates && $options['atomic']) || (!$options['atomic'] && in_array(false, $validates, true))) {
|
||||
return $validates;
|
||||
}
|
||||
}
|
||||
|
||||
if ($options['atomic']) {
|
||||
$db = $this->getDataSource();
|
||||
$transactionBegun = $db->begin($this);
|
||||
}
|
||||
|
||||
if (Set::numeric(array_keys($data))) {
|
||||
while ($validates) {
|
||||
$return = array();
|
||||
foreach ($data as $key => $record) {
|
||||
if (!$currentValidates = $this->__save($record, $options)) {
|
||||
$validates = ($this->create(null) !== null && $this->save($record, $options));
|
||||
if (!$validates) {
|
||||
$validationErrors[$key] = $this->validationErrors;
|
||||
}
|
||||
|
||||
if ($options['validate'] === 'only' || $options['validate'] === 'first') {
|
||||
$validating = true;
|
||||
if ($options['atomic']) {
|
||||
$validates = $validates && $currentValidates;
|
||||
} else {
|
||||
$validates = $currentValidates;
|
||||
}
|
||||
} else {
|
||||
$validating = false;
|
||||
$validates = $currentValidates;
|
||||
}
|
||||
|
||||
if (!$options['atomic']) {
|
||||
$return[] = $validates;
|
||||
} elseif (!$validates && !$validating) {
|
||||
} elseif (!$validates) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->validationErrors = $validationErrors;
|
||||
|
||||
switch (true) {
|
||||
case ($options['validate'] === 'only'):
|
||||
return ($options['atomic'] ? $validates : $return);
|
||||
break;
|
||||
case ($options['validate'] === 'first'):
|
||||
$options['validate'] = true;
|
||||
break;
|
||||
default:
|
||||
if ($options['atomic']) {
|
||||
if (!$options['atomic']) {
|
||||
return $return;
|
||||
}
|
||||
if ($validates) {
|
||||
if ($transactionBegun) {
|
||||
return $db->commit($this) !== false;
|
||||
|
@ -1689,48 +1708,106 @@ class Model extends Object {
|
|||
$db->rollback($this);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates multiple individual records for a single model
|
||||
*
|
||||
* #### Options
|
||||
*
|
||||
* - atomic: If true (default), returns boolean. If false returns array.
|
||||
* - fieldList: Equivalent to the $fieldList parameter in Model::save()
|
||||
*
|
||||
* @param array $data Record data to validate. This should be a numerically-indexed array
|
||||
* @param array $options Options to use when validating record data (see above), See also $options of validates().
|
||||
* @return boolean True on success, or false on failure.
|
||||
* @return mixed If atomic: True on success, or false on failure.
|
||||
* Otherwise: array similar to the $data array passed, but values are set to true/false
|
||||
* depending on whether each record validated successfully.
|
||||
* @access public
|
||||
*/
|
||||
public function validateMany($data, $options = array()) {
|
||||
$options = array_merge(array('atomic' => true), $options);
|
||||
$this->validationErrors = $validationErrors = $return = array();
|
||||
foreach ($data as $key => $record) {
|
||||
$validates = $this->create($record) && $this->validates($options);
|
||||
if (!$validates) {
|
||||
$validationErrors[$key] = $this->validationErrors;
|
||||
}
|
||||
$return[] = $validates;
|
||||
}
|
||||
$this->validationErrors = $validationErrors;
|
||||
if (!$options['atomic']) {
|
||||
return $return;
|
||||
break;
|
||||
}
|
||||
if (empty($this->validationErrors)) {
|
||||
return true;
|
||||
}
|
||||
if ($options['atomic'] && !$validates) {
|
||||
$db->rollback($this);
|
||||
return false;
|
||||
}
|
||||
return $return;
|
||||
|
||||
/**
|
||||
* Saves a single record, as well as all its directly associated records.
|
||||
*
|
||||
* #### Options
|
||||
*
|
||||
* - validate: Set to false to disable validation, true to validate each record before saving,
|
||||
* 'first' to validate *all* records before any are saved (default),
|
||||
* - atomic: If true (default), will attempt to save all records in a single transaction.
|
||||
* Should be set to false if database/table does not support transactions.
|
||||
* - fieldList: Equivalent to the $fieldList parameter in Model::save()
|
||||
*
|
||||
* @param array $data Record data to save. This should be an array indexed by association name.
|
||||
* @param array $options Options to use when saving record data, See $options above.
|
||||
* @return mixed If atomic: True on success, or false on failure.
|
||||
* Otherwise: array similar to the $data array passed, but values are set to true/false
|
||||
* depending on whether each record saved successfully.
|
||||
* @access public
|
||||
*/
|
||||
public function saveAssociated($data = null, $options = array()) {
|
||||
if (empty($data)) {
|
||||
$data = $this->data;
|
||||
}
|
||||
|
||||
$options = array_merge(array('validate' => true, 'atomic' => true), $options);
|
||||
$this->validationErrors = $validationErrors = array();
|
||||
|
||||
if (empty($data) && $options['validate'] !== false) {
|
||||
$result = $this->save($data, $options);
|
||||
return !empty($result);
|
||||
}
|
||||
|
||||
if ($options['validate'] === 'first') {
|
||||
$validates = $this->validateAssociated($data, $options);
|
||||
if ((!$validates && $options['atomic']) || (!$options['atomic'] && in_array(false, $validates, true))) {
|
||||
return $validates;
|
||||
}
|
||||
}
|
||||
if ($options['atomic']) {
|
||||
$db = $this->getDataSource();
|
||||
$transactionBegun = $db->begin($this);
|
||||
}
|
||||
$associations = $this->getAssociated();
|
||||
|
||||
while ($validates) {
|
||||
$return = array();
|
||||
$validates = true;
|
||||
foreach ($data as $association => $values) {
|
||||
if (isset($associations[$association])) {
|
||||
switch ($associations[$association]) {
|
||||
case 'belongsTo':
|
||||
if ($this->{$association}->__save($values, $options)) {
|
||||
if (isset($associations[$association]) && $associations[$association] === 'belongsTo') {
|
||||
if ($this->{$association}->create(null) !== null && $this->{$association}->save($values, $options)) {
|
||||
$data[$this->alias][$this->belongsTo[$association]['foreignKey']] = $this->{$association}->id;
|
||||
} else {
|
||||
$validationErrors[$association] = $this->{$association}->validationErrors;
|
||||
$validates = false;
|
||||
}
|
||||
if (!$options['atomic']) {
|
||||
$return[$association][] = $validates;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->__save($data, $options)) {
|
||||
if ($validates && !($this->create(null) !== null && $this->save($data, $options))) {
|
||||
$validationErrors[$this->alias] = $this->validationErrors;
|
||||
$validates = false;
|
||||
}
|
||||
if (!$options['atomic']) {
|
||||
$return[$this->alias] = $validates;
|
||||
}
|
||||
$validating = ($options['validate'] === 'only' || $options['validate'] === 'first');
|
||||
|
||||
foreach ($data as $association => $values) {
|
||||
if (!$validates && !$validating) {
|
||||
if (!$validates) {
|
||||
break;
|
||||
}
|
||||
if (isset($associations[$association])) {
|
||||
|
@ -1738,41 +1815,22 @@ class Model extends Object {
|
|||
switch ($type) {
|
||||
case 'hasOne':
|
||||
$values[$this->{$type}[$association]['foreignKey']] = $this->id;
|
||||
if (!$this->{$association}->__save($values, $options)) {
|
||||
if (!($this->{$association}->create(null) !== null && $this->{$association}->save($values, $options))) {
|
||||
$validationErrors[$association] = $this->{$association}->validationErrors;
|
||||
$validates = false;
|
||||
}
|
||||
if (!$options['atomic']) {
|
||||
$return[$association][] = $validates;
|
||||
}
|
||||
break;
|
||||
case 'hasMany':
|
||||
foreach ($values as $i => $value) {
|
||||
$values[$i][$this->{$type}[$association]['foreignKey']] = $this->id;
|
||||
}
|
||||
$_options = array_merge($options, array('atomic' => false));
|
||||
|
||||
if ($_options['validate'] === 'first') {
|
||||
$_options['validate'] = 'only';
|
||||
}
|
||||
$_return = $this->{$association}->saveAll($values, $_options);
|
||||
|
||||
if ($_return === false || (is_array($_return) && in_array(false, $_return, true))) {
|
||||
$_return = $this->{$association}->saveMany($values, array_merge($options, array('atomic' => false)));
|
||||
if (in_array(false, $_return, true)) {
|
||||
$validationErrors[$association] = $this->{$association}->validationErrors;
|
||||
$validates = false;
|
||||
}
|
||||
if (is_array($_return)) {
|
||||
foreach ($_return as $val) {
|
||||
if (!isset($return[$association])) {
|
||||
$return[$association] = array();
|
||||
} elseif (!is_array($return[$association])) {
|
||||
$return[$association] = array($return[$association]);
|
||||
}
|
||||
$return[$association][] = $val;
|
||||
}
|
||||
} else {
|
||||
$return[$association] = $_return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1783,50 +1841,69 @@ class Model extends Object {
|
|||
$this->validationErrors = $validationErrors[$this->alias];
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
case ($options['validate'] === 'only'):
|
||||
return ($options['atomic'] ? $validates : $return);
|
||||
break;
|
||||
case ($options['validate'] === 'first'):
|
||||
$options['validate'] = true;
|
||||
$return = array();
|
||||
break;
|
||||
default:
|
||||
if ($options['atomic']) {
|
||||
if (!$options['atomic']) {
|
||||
return $return;
|
||||
}
|
||||
if ($validates) {
|
||||
if ($transactionBegun) {
|
||||
return $db->commit($this) !== false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
$db->rollback($this);
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
break;
|
||||
}
|
||||
if ($options['atomic'] && !$validates) {
|
||||
$db->rollback($this);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private helper method used by saveAll.
|
||||
* Validates a single record, as well as all its directly associated records.
|
||||
*
|
||||
* @return boolean Success
|
||||
* @access private
|
||||
* @see Model::saveAll()
|
||||
* #### Options
|
||||
*
|
||||
* - atomic: If true (default), returns boolean. If false returns array.
|
||||
* - fieldList: Equivalent to the $fieldList parameter in Model::save()
|
||||
*
|
||||
* @param array $data Record data to validate. This should be an array indexed by association name.
|
||||
* @param array Options to use when validating record data (see above), See also $options of validates().
|
||||
* @return mixed If atomic: True on success, or false on failure.
|
||||
* Otherwise: array similar to the $data array passed, but values are set to true/false
|
||||
* depending on whether each record validated successfully.
|
||||
* @access public
|
||||
*/
|
||||
private function __save($data, $options) {
|
||||
if ($options['validate'] === 'first' || $options['validate'] === 'only') {
|
||||
public function validateAssociated($data, $options = array()) {
|
||||
$options = array_merge(array('atomic' => true), $options);
|
||||
$this->validationErrors = $validationErrors = $return = array();
|
||||
if (!($this->create($data) && $this->validates($options))) {
|
||||
return false;
|
||||
$validationErrors[$this->alias] = $this->validationErrors;
|
||||
$return[$this->alias] = false;
|
||||
} else {
|
||||
$return[$this->alias] = true;
|
||||
}
|
||||
} elseif (!($this->create(null) !== null && $this->save($data, $options))) {
|
||||
$associations = $this->getAssociated();
|
||||
$validates = true;
|
||||
foreach ($data as $association => $values) {
|
||||
if (isset($associations[$association])) {
|
||||
if (in_array($associations[$association], array('belongsTo', 'hasOne'))) {
|
||||
$validates = $this->{$association}->create($values) && $this->{$association}->validates($options);
|
||||
$return[$association][] = $validates;
|
||||
} elseif($associations[$association] === 'hasMany') {
|
||||
$validates = $this->{$association}->validateMany($values, $options);
|
||||
$return[$association] = $validates;
|
||||
}
|
||||
if (!$validates || (is_array($validates) && in_array(false, $validates, true))) {
|
||||
$validationErrors[$association] = $this->{$association}->validationErrors;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->validationErrors = $validationErrors;
|
||||
if (isset($validationErrors[$this->alias])) {
|
||||
$this->validationErrors = $validationErrors[$this->alias];
|
||||
}
|
||||
if (!$options['atomic']) {
|
||||
return $return;
|
||||
}
|
||||
if (!empty($this->validationErrors)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3449,6 +3449,18 @@ class TransactionTestModel extends CakeTestModel {
|
|||
}
|
||||
}
|
||||
|
||||
class TransactionManyTestModel extends CakeTestModel {
|
||||
var $name = 'TransactionManyTestModel';
|
||||
var $useTable = 'samples';
|
||||
|
||||
public function afterSave($created) {
|
||||
$data = array(
|
||||
array('apple_id' => 1, 'name' => 'sample6'),
|
||||
);
|
||||
$this->saveMany($data, array('atomic' => true, 'callbacks' => false));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TestModel class
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue