Commit ac83e3ef authored by Karamel's avatar Karamel
Browse files

Split DoctrineModel->merge with two functions

parent 2200d216
......@@ -181,125 +181,150 @@ abstract class DoctrineModel
}
/**
* Merge the values from $struct into this record.
* Merge the field value from $struct into this record.
* Fields that are not explicitely present in $struct are left untouched.
* Id and hasImage are reserved fields and are never merged.
* @param $struct The associative array of values to merge.
* @param $dao The dao to use to look for associations.
*/
protected function mergeDirectField($struct, $field, $dao) {
if ($field == 'id' || $field == 'hasImage') {
// Doctrine loads the id
// and image cannot be altered outside imageAPI
return;
}
if (array_key_exists($field, $struct)) {
$value = $struct[$field];
$setter = $this->findMethodNameOrThrow('set', $field);
call_user_func([$this, $setter], $struct[$field]);
}
}
/**
* Merge association values from $struct into this record.
* Fields that are not explicitely present in $struct are left untouched,
* arrays are replaced.
* Id and hasImage are reserved fields and are never merged.
* @param $struct The associative array of values to merge.
* @param $dao The dao to use to look for associations.
* @throws InvalidFieldException When trying to assign a null value
* to a non-null association field (constraint NOT_NULL) or when an
* association was not found (constraint ASSOCIATION_NOT_FOUND). The key
* is not set, subclasses should set it.
* association was not found (constraint ASSOCIATION_NOT_FOUND).
*/
public function merge($struct, $dao) {
// Merge direct fields.
foreach (static::getDirectFieldNames() as $field) {
if ($field == 'id' || $field == 'hasImage') {
// Doctrine loads the id
// and image cannot be altered outside imageAPI
continue;
}
if (array_key_exists($field, $struct)) {
$value = $struct[$field];
$setter = $this->findMethodNameOrThrow('set', $field);
call_user_func([$this, $setter], $struct[$field]);
}
protected function mergeAssociationField($struct, $field, $dao) {
if (!empty($field['internal'])
|| (!array_key_exists($field['name'], $struct))) {
// Internal fields cannot come from external data.
// Values non explicitely set are left untouched.
return;
}
// Merge association fields
$associationFields = static::getAssociationFields();
foreach ($associationFields as $field) {
if (!empty($field['internal'])
|| (!array_key_exists($field['name'], $struct))) {
// Internal fields cannot come from external data.
// Values non explicitely set are left untouched.
continue;
}
$fieldName = $field['name'];
// Check for required (not null) and type
if (empty($field['null'])
&& $struct[$fieldName] === null) {
throw new InvalidFieldException(InvalidFieldException::NOT_NULL,
static::class, $field['name'],
$struct[], null);
$fieldName = $field['name'];
// Check for required (not null) and type
if (empty($field['null'])
&& $struct[$fieldName] === null) {
throw new InvalidFieldException(InvalidFieldException::NOT_NULL,
static::class, $field['name'],
$struct[], null);
}
if (!empty($field['array']) && !is_array($struct[$fieldName])) {
$ref = $this->getReference();
if (array_key_exists(static::getReferenceKey(), $struct)) {
$ref = $struct[static::getReferenceKey()];
}
if (!empty($field['array']) && !is_array($struct[$fieldName])) {
$ref = $this->getReference();
if (array_key_exists(static::getReferenceKey(), $struct)) {
$ref = $struct[static::getReferenceKey()];
throw new InvalidFieldException(InvalidFieldException::ARRAY,
static::class, $field['name'],
$ref, null);
}
// Get value and assign it.
$arrayField = !empty($field['array']);
if ($struct[$fieldName] !== null) {
$value = $this->readAssociationValue($struct, $dao, $field);
if ($arrayField && count($struct[$fieldName]) == 0) {
$clr = $this->findMethodNameOrThrow('clear', $fieldName);
call_user_func([$this, $clr], null);
} else if ($arrayField) { // Non empty array
/* At that point we must remove records that are not listed
* in struct and add those that are new.
* Unbind/rebind doesn't work because it makes Doctrine
* ignore the id. */
$toAdd = [];
$toRemove = [];
// Look for records to remove
$getter = $this->findMethodNameOrThrow('get', $fieldName);
$dbValues = call_user_func([$this, $getter]);
foreach ($dbValues as $dbv) {
$found = false;
foreach ($value as $v) {
if ($dbv->idEquals($v)) {
$found = true;
continue;
}
}
if (!$found) {
$toRemove[] = $dbv;
}
}
throw new InvalidFieldException(InvalidFieldException::ARRAY,
static::class, $field['name'],
$ref, null);
}
// Get value and assign it.
$arrayField = !empty($field['array']);
if ($struct[$fieldName] !== null) {
$value = $this->readAssociationValue($struct, $dao, $field);
if ($arrayField && count($struct[$fieldName]) == 0) {
$clr = $this->findMethodNameOrThrow('clear', $fieldName);
call_user_func([$this, $clr], null);
} else if ($arrayField) { // Non empty array
/* At that point we must remove records that are not listed
* in struct and add those that are new.
* Unbind/rebind doesn't work because it makes Doctrine
* ignore the id. */
$toAdd = [];
$toRemove = [];
// Look for records to remove
$getter = $this->findMethodNameOrThrow('get', $fieldName);
$dbValues = call_user_func([$this, $getter]);
foreach ($dbValues as $dbv) {
// Look for records to add
foreach ($value as $v) {
$id = $v->getId();
if ($id == null) { // New record, add it.
$toAdd[] = $v;
continue;
} else {
// For non-incremental id, check if the record
// is already loaded or not. Add it if new.
$found = false;
foreach ($value as $v) {
foreach ($dbValues as $dbv) {
if ($dbv->idEquals($v)) {
$found = true;
continue;
break;
}
}
if (!$found) {
$toRemove[] = $dbv;
}
}
// Look for records to add
foreach ($value as $v) {
$id = $v->getId();
if ($id == null) { // New record, add it.
$toAdd[] = $v;
continue;
} else {
// For non-incremental id, check if the record
// is already loaded or not. Add it if new.
$found = false;
foreach ($dbValues as $dbv) {
if ($dbv->idEquals($v)) {
$found = true;
break;
}
}
if (!$found) {
$toAdd[] = $v;
}
}
}
// Add and remove
$remover = $this->findMethodNameOrThrow('remove',
$fieldName);
foreach ($toRemove as $rm) {
call_user_func([$this, $remover], $rm);
}
$adder = $this->findMethodNameOrThrow('add', $fieldName);
foreach ($toAdd as $add) {
call_user_func([$this, $adder], $add);
}
} else { // Non null single record association
$setter = $this->findMethodNameOrThrow('set', $fieldName);
call_user_func([$this, $setter], $value);
}
} else { // $struct[$fieldName] is null
// Add and remove
$remover = $this->findMethodNameOrThrow('remove',
$fieldName);
foreach ($toRemove as $rm) {
call_user_func([$this, $remover], $rm);
}
$adder = $this->findMethodNameOrThrow('add', $fieldName);
foreach ($toAdd as $add) {
call_user_func([$this, $adder], $add);
}
} else { // Non null single record association
$setter = $this->findMethodNameOrThrow('set', $fieldName);
call_user_func([$this, $setter], null);
call_user_func([$this, $setter], $value);
}
} else { // $struct[$fieldName] is null
$setter = $this->findMethodNameOrThrow('set', $fieldName);
call_user_func([$this, $setter], null);
}
}
/**
* Merge the values from $struct into this record.
* Fields that are not explicitely present in $struct are left untouched,
* arrays are replaced.
* Id and hasImage are reserved fields and are never merged.
* @param $struct The associative array of values to merge.
* @param $dao The dao to use to look for associations.
* @throws InvalidFieldException When trying to assign a null value
* to a non-null association field (constraint NOT_NULL) or when an
* association was not found (constraint ASSOCIATION_NOT_FOUND). The key
* is not set, subclasses should set it.
*/
public function merge($struct, $dao) {
// Merge direct fields.
foreach (static::getDirectFieldNames() as $field) {
$this->mergeDirectField($struct, $field, $dao);
}
// Merge association fields
$associationFields = static::getAssociationFields();
foreach ($associationFields as $field) {
$this->mergeAssociationField($struct, $field, $dao);
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment