Commit 043fe543 authored by Karamel's avatar Karamel
Browse files

Automatically set id for embedded records when possible, fixes deleting and adding the record.

parent bbaca06e
......@@ -44,7 +44,7 @@ class CashSessionCatTax extends DoctrineModel // Embedded class
return [
[
'name' => 'cashSession',
'class' => '\Pasteque\Server\Model\CashSessionCat',
'class' => '\Pasteque\Server\Model\CashSession',
'null' => true // because embedded
],
[
......
......@@ -136,7 +136,7 @@ class CashSessionPayment extends DoctrineModel // Embedded class
$payment->setAmount($struct['amount']);
$payment->setCurrencyAmount($struct['currencyAmount']);
$currencyField = $payment->getAssociationFields()[2];
$payment->setCurrency(static::readAssociationValue($struct, $dao, $currencyField));
$payment->setCurrency($payment->readAssociationValue($struct, $dao, $currencyField));
$search = $dao->search(\Pasteque\Server\Model\PaymentMode::class,
new DAOCondition('reference', '=', $struct['type']));
if (count($search) > 0) {
......
......@@ -220,8 +220,8 @@ class PaymentMode extends DoctrineModel
return $struct;
}
public static function fromStruct($struct, $dao, $embedded = false) {
$model = parent::fromStruct($struct, $dao, $embedded);
public static function fromStruct($struct, $dao, $parent = null) {
$model = parent::fromStruct($struct, $dao, $parent);
// Set reference from code for compatibility
if (!empty($struct['code']) && $model->getReference() === null) {
$model->setReference($struct['code']);
......
......@@ -134,7 +134,7 @@ class TicketPayment extends DoctrineModel // Embedded class
$this->currencyAmount = round($currencyAmount, 5);
}
public static function fromStruct($struct, $dao, $embedded = false) {
public static function fromStruct($struct, $dao, $parent = null) {
// This is the old desktop compatibility mode
// which doesn't use PaymentMode.
if (!empty($struct['desktop'])) {
......@@ -143,7 +143,7 @@ class TicketPayment extends DoctrineModel // Embedded class
$payment->setAmount($struct['amount']);
$payment->setCurrencyAmount($struct['currencyAmount']);
$currencyField = $payment->getAssociationFields()[2];
$payment->setCurrency(static::readAssociationValue($struct, $dao, $currencyField));
$payment->setCurrency($payment->readAssociationValue($struct, $dao, $currencyField));
$search = $dao->search(\Pasteque\Server\Model\PaymentMode::class,
new DAOCondition('reference', '=', $struct['type']));
if (count($search) > 0) {
......@@ -154,7 +154,7 @@ class TicketPayment extends DoctrineModel // Embedded class
return $payment;
}
// And this is the normal case
return parent::fromStruct($struct, $dao, $embedded);
return parent::fromStruct($struct, $dao, $parent);
}
public function toStruct() {
......
......@@ -152,17 +152,66 @@ abstract class DoctrineModel
/** Build an instance from struct. If id is set, it will ask the DAO to set
* the current values. If not a new instance is created and returned.
* @throws \UnexpectedValueException If id is set but no data is found. */
protected static function instanceFromStruct($struct, $dao, $embedded = false) {
protected static function instanceFromStruct($struct, $dao, $parent = null) {
$model = null;
if (isset($struct['id'])) {
$model = $dao->read(static::class, $struct['id']);
if ($model === null && !$embedded) {
if ($model === null && $parent === null) {
// Embedded classes don't have their own id, so it's ok
// not to find them: it's a new instance.
throw new \UnexpectedValueException('No data found with this Id');
}
} else {
$model = new static();
/* Maybe the id was not set, because that doesn't make sense
* to do it for an embedded data. */
if ($parent !== null && $parent->getId() != null) {
/* Try to rebuild the id automatically and look for the record
* when updating an existing parent record.
* This is necessary because Doctrine will fail to write it
* because of the unbound already existing record.
* Unity constraint violation exception is raised in that case. */
$autoId = [];
$idFields = $dao->getEntityManager()->getClassMetadata(static::class)->getIdentifier();
if (count($idFields) == 1 && $idFields[0] == 'id') {
// Stand-alone embedded record
$model = new static();
} else {
foreach ($idFields as $idField) {
// Look for a direct field, that is surely set.
foreach (static::getDirectFieldNames() as $field) {
if ($idField == $field) {
$autoId[$field] = $struct[$field];
break;
}
}
if (!empty($autoId[$idField])) {
// Found in direct fields.
continue;
}
/* Look for an associative field.
* It can be the parent (embedded)
* or an other inner field. */
foreach (static::getAssociationFields() as $field) {
if ($idField == $field['name']) {
if ($field['class'] == "\\" . get_class($parent)) {
$autoId[$field['name']] = $parent->getId();
break;
} elseif (array_key_exists($field['name'], $struct)) {
$autoId[$field['name']] = $struct[$field['name']];
}
}
}
}
}
// Now that the Id is recovered, try to read it.
if ($model === null) {
$model = $dao->read(static::class, $autoId);
}
}
// If nothing was found, it is a new record.
if ($model === null) {
$model = new static();
}
}
return $model;
}
......@@ -182,13 +231,13 @@ abstract class DoctrineModel
}
}
protected static function readAssociationValue($struct, $dao, $field) {
protected function readAssociationValue($struct, $dao, $field) {
if (!empty($field['array'])) {
$submodels = new \Doctrine\Common\Collections\ArrayCollection();
foreach ($struct[$field['name']] as $content) {
if (!empty($field['embedded'])) {
$fromStruct = new \ReflectionMethod($field['class'], 'fromStruct');
$submodel = $fromStruct->invoke(null, $content, $dao, true);
$submodel = $fromStruct->invoke(null, $content, $dao, $this);
} else {
$submodel = $dao->read($field['class'], $content['id']);
if ($submodel === null) {
......@@ -202,7 +251,7 @@ abstract class DoctrineModel
if (!empty($field['embedded'])) {
$fromStruct = new \ReflectionMethod($field['class'], 'fromStruct');
$structId = null;
$submodel = $fromStruct->invoke(null, $struct[$field['name']], $dao, true);
$submodel = $fromStruct->invoke(null, $struct[$field['name']], $dao, $this);
} else {
$submodel = $dao->read($field['class'], $struct[$field['name']]);
if ($submodel === null) {
......@@ -219,11 +268,11 @@ abstract class DoctrineModel
* from struct to DoctrineModel, as it may makes Doctrine mess up with the
* ids and duplicate or delete some records.
* @param $dao The DAO to link to.
* @param $embedded Only for recursive calls, don't set it.
* @param $parent Only for recursive calls, don't set it.
* @throw \UnexpectedValueException If Id is set but not data is found.
* Or when an non nullable field is not set. */
public static function fromStruct($struct, $dao, $embedded = false) {
$model = static::instanceFromStruct($struct, $dao, $embedded);
public static function fromStruct($struct, $dao, $parent = null) {
$model = static::instanceFromStruct($struct, $dao, $parent);
$model->directFieldsFromStruct($struct, $dao);
$associationFields = $model->getAssociationFields();
foreach ($associationFields as $field) {
......@@ -242,7 +291,7 @@ abstract class DoctrineModel
}
// Get value and assign it.
if (!empty($struct[$fieldName])) {
$value = static::readAssociationValue($struct, $dao, $field);
$value = $model->readAssociationValue($struct, $dao, $field);
if (!empty($field['array'])) {
/* At that point the model is filled from database by Doctrine.
* We must remove records that are not listed in struct
......
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