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
|
* Saves multiple individual records for a single model; Also works with a single record, as well as
|
||||||
* all its associated records.
|
* all its associated records.
|
||||||
*
|
*
|
||||||
|
@ -1612,7 +1615,7 @@ class Model extends Object {
|
||||||
* Should be set to false if database/table does not support transactions.
|
* Should be set to false if database/table does not support transactions.
|
||||||
* - fieldList: Equivalent to the $fieldList parameter in Model::save()
|
* - fieldList: Equivalent to the $fieldList parameter in Model::save()
|
||||||
*
|
*
|
||||||
* @param array $data Record data to save. This can be either a numerically-indexed array (for saving multiple
|
* @param array $data Record data to save. This can be either a numerically-indexed array (for saving multiple
|
||||||
* records of the same type), or an array indexed by association name.
|
* records of the same type), or an array indexed by association name.
|
||||||
* @param array $options Options to use when saving record data, See $options above.
|
* @param array $options Options to use when saving record data, See $options above.
|
||||||
* @return mixed If atomic: True on success, or false on failure.
|
* @return mixed If atomic: True on success, or false on failure.
|
||||||
|
@ -1623,210 +1626,284 @@ class Model extends Object {
|
||||||
* @link http://book.cakephp.org/view/1031/Saving-Your-Data
|
* @link http://book.cakephp.org/view/1031/Saving-Your-Data
|
||||||
*/
|
*/
|
||||||
public function saveAll($data = null, $options = array()) {
|
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)) {
|
if (empty($data)) {
|
||||||
$data = $this->data;
|
$data = $this->data;
|
||||||
}
|
}
|
||||||
$db = $this->getDataSource();
|
|
||||||
|
|
||||||
$options = array_merge(array('validate' => 'first', 'atomic' => true), $options);
|
$options = array_merge(array('validate' => 'first', 'atomic' => true), $options);
|
||||||
$this->validationErrors = $validationErrors = array();
|
$this->validationErrors = $validationErrors = array();
|
||||||
$validates = true;
|
|
||||||
$return = array();
|
|
||||||
|
|
||||||
if (empty($data) && $options['validate'] !== false) {
|
if (empty($data) && $options['validate'] !== false) {
|
||||||
$result = $this->save($data, $options);
|
$result = $this->save($data, $options);
|
||||||
return !empty($result);
|
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);
|
$transactionBegun = $db->begin($this);
|
||||||
}
|
}
|
||||||
|
$return = array();
|
||||||
if (Set::numeric(array_keys($data))) {
|
foreach ($data as $key => $record) {
|
||||||
while ($validates) {
|
$validates = ($this->create(null) !== null && $this->save($record, $options));
|
||||||
$return = array();
|
if (!$validates) {
|
||||||
foreach ($data as $key => $record) {
|
$validationErrors[$key] = $this->validationErrors;
|
||||||
if (!$currentValidates = $this->__save($record, $options)) {
|
|
||||||
$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) {
|
|
||||||
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 ($validates) {
|
|
||||||
if ($transactionBegun) {
|
|
||||||
return $db->commit($this) !== false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$db->rollback($this);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return $return;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($options['atomic'] && !$validates) {
|
|
||||||
$db->rollback($this);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return $return;
|
|
||||||
}
|
|
||||||
$associations = $this->getAssociated();
|
|
||||||
|
|
||||||
while ($validates) {
|
|
||||||
foreach ($data as $association => $values) {
|
|
||||||
if (isset($associations[$association])) {
|
|
||||||
switch ($associations[$association]) {
|
|
||||||
case 'belongsTo':
|
|
||||||
if ($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)) {
|
|
||||||
$validationErrors[$this->alias] = $this->validationErrors;
|
|
||||||
$validates = false;
|
|
||||||
}
|
}
|
||||||
if (!$options['atomic']) {
|
if (!$options['atomic']) {
|
||||||
$return[$this->alias] = $validates;
|
$return[] = $validates;
|
||||||
}
|
} elseif (!$validates) {
|
||||||
$validating = ($options['validate'] === 'only' || $options['validate'] === 'first');
|
|
||||||
|
|
||||||
foreach ($data as $association => $values) {
|
|
||||||
if (!$validates && !$validating) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (isset($associations[$association])) {
|
|
||||||
$type = $associations[$association];
|
|
||||||
switch ($type) {
|
|
||||||
case 'hasOne':
|
|
||||||
$values[$this->{$type}[$association]['foreignKey']] = $this->id;
|
|
||||||
if (!$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))) {
|
|
||||||
$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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->validationErrors = $validationErrors;
|
|
||||||
|
|
||||||
if (isset($validationErrors[$this->alias])) {
|
|
||||||
$this->validationErrors = $validationErrors[$this->alias];
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (true) {
|
|
||||||
case ($options['validate'] === 'only'):
|
|
||||||
return ($options['atomic'] ? $validates : $return);
|
|
||||||
break;
|
break;
|
||||||
case ($options['validate'] === 'first'):
|
|
||||||
$options['validate'] = true;
|
|
||||||
$return = array();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if ($options['atomic']) {
|
|
||||||
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;
|
$this->validationErrors = $validationErrors;
|
||||||
|
|
||||||
|
if (!$options['atomic']) {
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
if ($validates) {
|
||||||
|
if ($transactionBegun) {
|
||||||
|
return $db->commit($this) !== false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$db->rollback($this);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private helper method used by saveAll.
|
* Validates multiple individual records for a single model
|
||||||
*
|
*
|
||||||
* @return boolean Success
|
* #### Options
|
||||||
* @access private
|
*
|
||||||
* @see Model::saveAll()
|
* - 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
|
||||||
*/
|
*/
|
||||||
private function __save($data, $options) {
|
public function validateMany($data, $options = array()) {
|
||||||
if ($options['validate'] === 'first' || $options['validate'] === 'only') {
|
$options = array_merge(array('atomic' => true), $options);
|
||||||
if (!($this->create($data) && $this->validates($options))) {
|
$this->validationErrors = $validationErrors = $return = array();
|
||||||
return false;
|
foreach ($data as $key => $record) {
|
||||||
|
$validates = $this->create($record) && $this->validates($options);
|
||||||
|
if (!$validates) {
|
||||||
|
$validationErrors[$key] = $this->validationErrors;
|
||||||
}
|
}
|
||||||
} elseif (!($this->create(null) !== null && $this->save($data, $options))) {
|
$return[] = $validates;
|
||||||
|
}
|
||||||
|
$this->validationErrors = $validationErrors;
|
||||||
|
if (!$options['atomic']) {
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
if (empty($this->validationErrors)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
$return = array();
|
||||||
|
$validates = true;
|
||||||
|
foreach ($data as $association => $values) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
$return[$association][] = $validates;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($validates && !($this->create(null) !== null && $this->save($data, $options))) {
|
||||||
|
$validationErrors[$this->alias] = $this->validationErrors;
|
||||||
|
$validates = false;
|
||||||
|
}
|
||||||
|
$return[$this->alias] = $validates;
|
||||||
|
|
||||||
|
foreach ($data as $association => $values) {
|
||||||
|
if (!$validates) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (isset($associations[$association])) {
|
||||||
|
$type = $associations[$association];
|
||||||
|
switch ($type) {
|
||||||
|
case 'hasOne':
|
||||||
|
$values[$this->{$type}[$association]['foreignKey']] = $this->id;
|
||||||
|
if (!($this->{$association}->create(null) !== null && $this->{$association}->save($values, $options))) {
|
||||||
|
$validationErrors[$association] = $this->{$association}->validationErrors;
|
||||||
|
$validates = false;
|
||||||
|
}
|
||||||
|
$return[$association][] = $validates;
|
||||||
|
break;
|
||||||
|
case 'hasMany':
|
||||||
|
foreach ($values as $i => $value) {
|
||||||
|
$values[$i][$this->{$type}[$association]['foreignKey']] = $this->id;
|
||||||
|
}
|
||||||
|
$_return = $this->{$association}->saveMany($values, array_merge($options, array('atomic' => false)));
|
||||||
|
if (in_array(false, $_return, true)) {
|
||||||
|
$validationErrors[$association] = $this->{$association}->validationErrors;
|
||||||
|
$validates = false;
|
||||||
|
}
|
||||||
|
$return[$association] = $_return;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->validationErrors = $validationErrors;
|
||||||
|
|
||||||
|
if (isset($validationErrors[$this->alias])) {
|
||||||
|
$this->validationErrors = $validationErrors[$this->alias];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$options['atomic']) {
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
if ($validates) {
|
||||||
|
if ($transactionBegun) {
|
||||||
|
return $db->commit($this) !== false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$db->rollback($this);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates a single record, as well as all its directly associated records.
|
||||||
|
*
|
||||||
|
* #### 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
|
||||||
|
*/
|
||||||
|
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))) {
|
||||||
|
$validationErrors[$this->alias] = $this->validationErrors;
|
||||||
|
$return[$this->alias] = false;
|
||||||
|
} else {
|
||||||
|
$return[$this->alias] = true;
|
||||||
|
}
|
||||||
|
$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 false;
|
||||||
}
|
}
|
||||||
return true;
|
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
|
* TestModel class
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in a new issue