Skip to content

Commit

Permalink
Delegates the saving logic down to the schema.
Browse files Browse the repository at this point in the history
  • Loading branch information
jails committed Nov 28, 2015
1 parent a851ef6 commit c295306
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 83 deletions.
91 changes: 8 additions & 83 deletions src/Model.php
Expand Up @@ -1075,95 +1075,20 @@ public function __unset($name)
* $post->save(null, ['validate' => false]);
* }}}
*
* @param array $options Options:
* - `'validate'` _boolean_: If `false`, validation will be skipped, and the record will
* be immediately saved. Defaults to `true`.
* - `'whitelist'` _array_ : An array of fields that are allowed to be saved to this record.
* - `'locked'` _boolean_: Lock data to the schema fields.
* - `'embed'` _array_ : List of relations to save.
* @return boolean Returns `true` on a successful save operation, `false` on failure.
* @param array $options Options:
* - `'validate'` _boolean_: If `false`, validation will be skipped, and the record will
* be immediately saved. Defaults to `true`.
* - `'whitelist'` _array_ : An array of fields that are allowed to be saved to this record.
* - `'locked'` _boolean_: Lock data to the schema fields.
* - `'embed'` _array_ : List of relations to save.
* @return boolean Returns `true` on a successful save operation, `false` otherwise.
*/
public function save($options = [])
{
$schema = static::schema();

$defaults = [
'validate' => true,
'whitelist' => null,
'locked' => $schema->locked(),
'embed' => true
];
$options += $defaults;

if ($options['validate'] && !$this->validate($options)) {
return false;
}

$options['validate'] = false;
$options['embed'] = $schema->treeify($options['embed']);

if (!$this->_save('belongsTo', $options)) {
return false;
}

$hasRelations = ['hasMany', 'hasOne'];

if (!$this->modified()) {
return $this->_save($hasRelations, $options);
}

if (($whitelist = $options['whitelist']) || $options['locked']) {
$whitelist = $whitelist ?: array_keys($schema->fields());
}

$exclude = array_diff($schema->relations(false), array_keys($schema->fields()));
$values = array_diff_key($this->get(), array_fill_keys($exclude, true));

if ($this->exists() === false) {
$cursor = $schema->insert($values);
} else {
$id = $this->primaryKey();
if ($id === null) {
throw new ChaosException("Can't update an entity missing ID data.");
}
$cursor = $schema->update($values, [$schema->primaryKey() => $id]);
}

$success = !$cursor->error();

if ($this->exists() === false) {
$id = $this->primaryKey() === null ? $schema->lastInsertId() : null;
$this->sync($id, [], ['exists' => true]);
}

return $success && $this->_save($hasRelations, $options);
return $schema->save($this, $options);
}

/**
* Save relations helper.
*
* @param array $types Type of relations to save.
*/
protected function _save($types, $options = [])
{
$defaults = ['embed' => []];
$options += $defaults;
$schema = static::schema();
$types = (array) $types;

$success = true;
foreach ($types as $type) {
foreach ($options['embed'] as $relName => $value) {
if (!($rel = $schema->relation($relName)) || $rel->type() !== $type) {
continue;
}
$success = $success && $rel->save($this, ['embed' => $value] + $options);
}
}
return $success;
}


/**
* Similar to `->save()` except the direct relationship has not been saved by default.
*
Expand Down
91 changes: 91 additions & 0 deletions src/Schema.php
Expand Up @@ -970,6 +970,97 @@ public function conventions($conventions = null)
return $this->_conventions;
}

/**
* Creates and/or updates an entity and its direct relationship data in the datasource.
*
* @param array $options Options:
* - `'validate'` _boolean_: If `false`, validation will be skipped, and the record will
* be immediately saved. Defaults to `true`.
* - `'whitelist'` _array_ : An array of fields that are allowed to be saved to this record.
* - `'locked'` _boolean_: Lock data to the schema fields.
* - `'embed'` _array_ : List of relations to save.
* @return boolean Returns `true` on a successful save operation, `false` otherwise.
*/
public function save($entity, $options = [])
{
$defaults = [
'validate' => true,
'whitelist' => null,
'locked' => $this->locked(),
'embed' => true
];
$options += $defaults;

if ($options['validate'] && !$entity->validate($options)) {
return false;
}

$options['validate'] = false;
$options['embed'] = $this->treeify($options['embed']);

if (!$this->_save($entity, 'belongsTo', $options)) {
return false;
}

$hasRelations = ['hasMany', 'hasOne'];

if (!$entity->modified()) {
return $this->_save($entity, $hasRelations, $options);
}

if (($whitelist = $options['whitelist']) || $options['locked']) {
$whitelist = $whitelist ?: array_keys($this->fields());
}

$exclude = array_diff($this->relations(false), array_keys($this->fields()));
$values = array_diff_key($entity->get(), array_fill_keys($exclude, true));

if ($entity->exists() === false) {
$cursor = $this->insert($values);
} else {
$id = $entity->primaryKey();
if ($id === null) {
throw new ChaosException("Can't update an entity missing ID data.");
}
$cursor = $this->update($values, [$this->primaryKey() => $id]);
}

$success = !$cursor->error();

if ($entity->exists() === false) {
$id = $entity->primaryKey() === null ? $this->lastInsertId() : null;
$entity->sync($id, [], ['exists' => true]);
}

return $success && $this->_save($entity, $hasRelations, $options);
}

/**
* Save relations helper.
*
* @param object $entity The entity instance.
* @param array $types Type of relations to save.
* @param array $options Options array.
* @return boolean Returns `true` on a successful save operation, `false` on failure.
*/
protected function _save($entity, $types, $options = [])
{
$defaults = ['embed' => []];
$options += $defaults;
$types = (array) $types;

$success = true;
foreach ($types as $type) {
foreach ($options['embed'] as $relName => $value) {
if (!($rel = $this->relation($relName)) || $rel->type() !== $type) {
continue;
}
$success = $success && $rel->save($entity, ['embed' => $value] + $options);
}
}
return $success;
}

/**
* Returns a query to retrieve data from the connected data source.
*
Expand Down

0 comments on commit c295306

Please sign in to comment.