Skip to content

Commit 8231645

Browse files
author
Daria Prusova
committed
[orm] add recalculated objects
1 parent 4b5aa0a commit 8231645

5 files changed

Lines changed: 171 additions & 62 deletions

File tree

library/orm/collection/BaseCollection.php

Lines changed: 109 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use umi\orm\manager\TObjectManagerAware;
2424
use umi\orm\metadata\field\IField;
2525
use umi\orm\metadata\field\relation\ManyToManyRelationField;
26+
use umi\orm\metadata\field\special\FormulaField;
2627
use umi\orm\metadata\IMetadata;
2728
use umi\orm\metadata\IObjectType;
2829
use umi\orm\object\IObject;
@@ -414,81 +415,46 @@ public function persistNewObject(IObject $object)
414415
/**
415416
* {@inheritdoc}
416417
*/
417-
public function persistModifiedObject(IObject $object)
418+
public function persistRecalculatedObject(IObject $object, array $formulaProperties)
418419
{
419420
if (!$this->contains($object)) {
420421
throw new NotAllowedOperationException($this->translate(
421422
'Cannot persist modified object. Object from another collection given.'
422423
));
423424
}
424-
425-
$modifiedProperties = $object->getModifiedProperties();
426-
if (!count($modifiedProperties)) {
427-
return;
425+
if (count($formulaProperties)) {
426+
$this->executeUpdate($object, $formulaProperties);
428427
}
428+
}
429429

430-
$dataSource = $this->getMetadata()->getCollectionDataSource();
431-
$identifyColumnName = $this->getIdentifyField()->getColumnName();
430+
/**
431+
* {@inheritdoc}
432+
*/
433+
public function persistModifiedObject(IObject $object)
434+
{
435+
if (!$this->contains($object)) {
436+
throw new NotAllowedOperationException($this->translate(
437+
'Cannot persist modified object. Object from another collection given.'
438+
));
439+
}
432440

433-
$updateBuilder = $dataSource->update();
441+
$modifiedProperties = [];
442+
$formulaProperties = [];
434443

435-
foreach ($modifiedProperties as $property) {
436-
if ($this->getMetadata()->getFieldExists($property->getName())) {
437-
$field = $this->getMetadata()->getField($property->getName());
438-
$field->persistProperty($object, $property, $updateBuilder);
444+
foreach ($object->getModifiedProperties()as $property) {
445+
if ($property->getField() instanceof FormulaField) {
446+
$formulaProperties[] = $property;
447+
} else {
448+
$modifiedProperties[] = $property;
439449
}
440450
}
441451

442-
if ($updateBuilder->getUpdatePossible()) {
443-
444-
$versionProperty = $object->getProperty(IObject::FIELD_VERSION);
445-
$version = (int) ($versionProperty->getPersistedDbValue() ? : $versionProperty->getDbValue());
446-
$newVersion = $version + 1;
447-
$versionProperty->setValue($newVersion);
448-
449-
$versionColumnName = $this->getVersionField()->getColumnName();
450-
451-
$this->getVersionField()->persistProperty($object, $versionProperty, $updateBuilder);
452-
453-
$updateBuilder->where()
454-
->expr($identifyColumnName, '=', ':objectId');
455-
$updateBuilder->bindValue(
456-
':objectId',
457-
$object->getId(),
458-
$this->getIdentifyField()->getDataType()
459-
);
460-
461-
$updateBuilder->where()->expr($versionColumnName, '=', ':' . $versionColumnName);
462-
$updateBuilder->bindValue(':' . $versionColumnName, $version, $this->getVersionField()->getDataType());
463-
464-
$result = $updateBuilder->execute();
465-
466-
if ($result->rowCount() != 1) {
467-
468-
$selectBuilder = $dataSource->select($versionColumnName);
469-
$selectBuilder->where()
470-
->expr($identifyColumnName, '=', ':objectId');
471-
$selectBuilder->bindValue(
472-
':objectId',
473-
$object->getId(),
474-
$this->getIdentifyField()->getDataType()
475-
);
476-
477-
$selectResult = $selectBuilder->execute();
478-
$selectResultRow = $selectResult->fetch();
479-
480-
if (is_array($selectResultRow) && $selectResultRow[$versionColumnName] != $version) {
481-
throw new RuntimeException($this->translate(
482-
'Cannot modify object with id "{id}" and type "{type}". Object is out of date.',
483-
['id' => $object->getId(), 'type' => $object->getTypePath()]
484-
));
485-
}
452+
if ($formulaProperties) {
453+
$this->getObjectPersister()->storeRecalculatedObject($object, $formulaProperties);
454+
}
486455

487-
throw new RuntimeException($this->translate(
488-
'Cannot modify object with id "{id}" and type "{type}". Database row is not modified.',
489-
['id' => $object->getId(), 'type' => $object->getTypePath()]
490-
));
491-
}
456+
if (count($modifiedProperties)) {
457+
$this->executeUpdate($object, $modifiedProperties);
492458
}
493459
}
494460

@@ -542,4 +508,86 @@ protected function getRequiredField($fieldName)
542508

543509
return $this->metadata->getField($fieldName);
544510
}
511+
512+
/**
513+
* Запускает обновление объекта по указанным свойствам
514+
* @param IObject $object
515+
* @param IProperty[] $properties
516+
* @throws RuntimeException если обновление не прошло
517+
*/
518+
protected function executeUpdate(IObject $object, array $properties)
519+
{
520+
$dataSource = $this->getMetadata()->getCollectionDataSource();
521+
$identifyColumnName = $this->getIdentifyField()->getColumnName();
522+
$updateBuilder = $dataSource->update();
523+
524+
foreach ($properties as $property) {
525+
if ($this->getMetadata()->getFieldExists($property->getName())) {
526+
$field = $this->getMetadata()->getField($property->getName());
527+
$field->persistProperty($object, $property, $updateBuilder);
528+
}
529+
}
530+
531+
if ($updateBuilder->getUpdatePossible()) {
532+
533+
$versionProperty = $object->getProperty(IObject::FIELD_VERSION);
534+
$version = (int) ($versionProperty->getPersistedDbValue() ? : $versionProperty->getDbValue());
535+
$newVersion = $version + 1;
536+
$versionProperty->setValue($newVersion);
537+
538+
$versionColumnName = $this->getVersionField()
539+
->getColumnName();
540+
541+
$this->getVersionField()
542+
->persistProperty($object, $versionProperty, $updateBuilder);
543+
544+
$updateBuilder->where()
545+
->expr($identifyColumnName, '=', ':objectId');
546+
$updateBuilder->bindValue(
547+
':objectId',
548+
$object->getId(),
549+
$this->getIdentifyField()
550+
->getDataType()
551+
);
552+
553+
$updateBuilder->where()
554+
->expr($versionColumnName, '=', ':' . $versionColumnName);
555+
$updateBuilder->bindValue(
556+
':' . $versionColumnName,
557+
$version,
558+
$this->getVersionField()
559+
->getDataType()
560+
);
561+
562+
$result = $updateBuilder->execute();
563+
564+
if ($result->rowCount() != 1) {
565+
566+
$selectBuilder = $dataSource->select($versionColumnName);
567+
$selectBuilder->where()
568+
->expr($identifyColumnName, '=', ':objectId');
569+
$selectBuilder->bindValue(
570+
':objectId',
571+
$object->getId(),
572+
$this->getIdentifyField()
573+
->getDataType()
574+
);
575+
576+
$selectResult = $selectBuilder->execute();
577+
$selectResultRow = $selectResult->fetch();
578+
579+
if (is_array($selectResultRow) && $selectResultRow[$versionColumnName] != $version) {
580+
throw new RuntimeException($this->translate(
581+
'Cannot modify object with id "{id}" and type "{type}". Object is out of date.',
582+
['id' => $object->getId(), 'type' => $object->getTypePath()]
583+
));
584+
}
585+
586+
throw new RuntimeException($this->translate(
587+
'Cannot modify object with id "{id}" and type "{type}". Database row is not modified.',
588+
['id' => $object->getId(), 'type' => $object->getTypePath()]
589+
));
590+
}
591+
}
592+
}
545593
}

library/orm/collection/ICollection.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use umi\orm\metadata\IObjectType;
2323
use umi\orm\object\IHierarchicObject;
2424
use umi\orm\object\IObject;
25+
use umi\orm\object\property\IProperty;
2526
use umi\orm\selector\ISelector;
2627

2728
/**
@@ -187,6 +188,16 @@ public function persistNewObject(IObject $object);
187188
*/
188189
public function persistModifiedObject(IObject $object);
189190

191+
/**
192+
* Запускает запросы на вычисление и изменение свойст объекта коллекции,
193+
* которые должны быть вычислены после сохранения всех объектов.
194+
* @internal
195+
* @param IObject $object
196+
* @param IProperty[] $formulaProperties
197+
* @return
198+
*/
199+
public function persistRecalculatedObject(IObject $object, array $formulaProperties);
200+
190201
/**
191202
* Запускает запросы на удаление объекта коллекции.
192203
* @internal

library/orm/collection/LinkedHierarchicCollection.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,21 @@ public function persistModifiedObject(IObject $object)
8383
parent::persistModifiedObject($object);
8484
}
8585

86+
/**
87+
* {@inheritdoc}
88+
*/
89+
public function persistRecalculatedObject(IObject $object, array $formulaProperties)
90+
{
91+
if (!$this->contains($object)) {
92+
throw new NotAllowedOperationException($this->translate(
93+
'Cannot persist recalculated object. Object from another collection given.'
94+
));
95+
}
96+
$this->getCommonHierarchy()
97+
->persistRecalculatedObject($object, $formulaProperties);
98+
parent::persistRecalculatedObject($object, $formulaProperties);
99+
}
100+
86101
/**
87102
* {@inheritdoc}
88103
*/

library/orm/persister/IObjectPersister.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use umi\orm\exception\RuntimeException;
1616
use umi\orm\metadata\field\relation\BelongsToRelationField;
1717
use umi\orm\object\IObject;
18+
use umi\orm\object\property\IProperty;
1819

1920
/**
2021
* Синхронизатор объектов бизнес-транзакций с базой данных (Unit Of Work).
@@ -123,6 +124,14 @@ public function storeNewBelongsToRelation(
123124
IObject $relatedObject
124125
);
125126

127+
/**
128+
* Помечает объект для пересчета свойств после сохранения всех объектов
129+
* @internal
130+
* @param IObject $object
131+
* @param IProperty[] $properties свойства, которые необходимо пересчитать
132+
*/
133+
public function storeRecalculatedObject(IObject $object, array $properties);
134+
126135
/**
127136
* Очищает списки добавленных, модифицированных, перемещенныз и удаленных объектов.
128137
* Все изменения, которые были не применены будут утеряны.

library/orm/persister/ObjectPersister.php

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ class ObjectPersister implements IObjectPersister, ILocalizable, ILocalesAware,
5151
* @var SplObjectStorage|IObject[] $relatedObjects список зависимостей объектов
5252
*/
5353
protected $relatedObjects;
54+
/**
55+
* @var SplObjectStorage|IObject[] $needToBeRecalculatedObjects список объектов,
56+
* значения для которых должны быть высчитаны после сохранения всех других
57+
*/
58+
protected $needToBeRecalculatedObjects;
5459

5560
/**
5661
* Конструктор.
@@ -61,6 +66,7 @@ public function __construct()
6166
$this->deletedObjects = new SplObjectStorage();
6267
$this->modifiedObjects = new SplObjectStorage();
6368
$this->relatedObjects = new SplObjectStorage();
69+
$this->needToBeRecalculatedObjects = new SplObjectStorage();
6470
}
6571

6672
/**
@@ -191,6 +197,14 @@ public function storeNewBelongsToRelation(
191197
$this->relatedObjects->offsetSet($object, $data);
192198
}
193199

200+
/**
201+
* {@inheritdoc}
202+
*/
203+
public function storeRecalculatedObject(IObject $object, array $properties)
204+
{
205+
$this->needToBeRecalculatedObjects->offsetSet($object, $properties);
206+
}
207+
194208
/**
195209
* {@inheritdoc}
196210
*/
@@ -200,6 +214,7 @@ public function clearObjectsState()
200214
$this->relatedObjects->removeAll($this->relatedObjects);
201215
$this->modifiedObjects->removeAll($this->modifiedObjects);
202216
$this->deletedObjects->removeAll($this->deletedObjects);
217+
$this->needToBeRecalculatedObjects->removeAll($this->needToBeRecalculatedObjects);
203218

204219
return $this;
205220
}
@@ -213,6 +228,7 @@ public function clearObjectState(IObject $object)
213228
$this->modifiedObjects->detach($object);
214229
$this->deletedObjects->detach($object);
215230
$this->relatedObjects->detach($object);
231+
$this->needToBeRecalculatedObjects->detach($object);
216232
}
217233

218234
/**
@@ -254,6 +270,7 @@ protected function rollback(array $connections)
254270
$this->unloadStorageObjects($this->newObjects);
255271
$this->unloadStorageObjects($this->modifiedObjects);
256272
$this->unloadStorageObjects($this->deletedObjects);
273+
$this->unloadStorageObjects($this->needToBeRecalculatedObjects);
257274
$this->clearObjectsState();
258275

259276
return $this;
@@ -340,7 +357,7 @@ protected function persist()
340357
*/
341358
$calculableProperties = [];
342359
foreach ($object->getAllProperties() as $property) {
343-
if (!$property->getIsModified() && $property instanceof ICalculableProperty) {
360+
if ($property instanceof ICalculableProperty) {
344361
$calculableProperties[] = $property;
345362
}
346363
}
@@ -371,6 +388,15 @@ protected function persist()
371388
$object->setIsConsistent();
372389
}
373390

391+
foreach ($this->needToBeRecalculatedObjects as $object) {
392+
$object->getCollection()
393+
->persistRecalculatedObject($object, $this->needToBeRecalculatedObjects->getInfo());
394+
}
395+
396+
foreach ($this->needToBeRecalculatedObjects as $object) {
397+
$object->setIsConsistent();
398+
}
399+
374400
$this->unloadStorageObjects($this->deletedObjects);
375401
$this->clearObjectsState();
376402
}

0 commit comments

Comments
 (0)