From ec9b7258f6cc6f32b128b05a9728ebc2ba342030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Sun, 16 Jan 2022 16:02:05 +0100 Subject: [PATCH] Use Model for Join write operations --- src/Model/Join.php | 27 +++++++++++++ src/Persistence/Sql/Join.php | 74 ++++++++++++++++-------------------- 2 files changed, 60 insertions(+), 41 deletions(-) diff --git a/src/Model/Join.php b/src/Model/Join.php index 961f88dd00..d062d8a1b6 100644 --- a/src/Model/Join.php +++ b/src/Model/Join.php @@ -134,9 +134,36 @@ public function __construct($foreignTable = null) } } + /** + * Create fake foreign model, in the future, this method should be removed + * in favor of always requiring an object model. + */ + protected function createFakeForeignModel(): Model + { + $fakeModel = new Model($this->getOwner()->persistence, [ + 'table' => $this->foreign_table, + 'id_field' => $this->foreign_field, + ]); + foreach ($this->getOwner()->getFields() as $ownerField) { + if ($ownerField->hasJoin() && $ownerField->getJoin()->short_name === $this->short_name) { + $fakeModel->addField($ownerField->short_name, [ + 'actual' => $ownerField->actual, + 'type' => $ownerField->type, + ]); + } + } + + return $fakeModel; + } + public function getForeignModel(): Model { if (is_string($this->foreign_table)) { + // TODO this should be removed in the future + if (!isset($this->getOwner()->with[$this->foreign_table])) { + return $this->createFakeForeignModel(); + } + return $this->getOwner()->with[$this->foreign_table]['model']; } diff --git a/src/Persistence/Sql/Join.php b/src/Persistence/Sql/Join.php index 8a0ed7e536..e8b59c50a7 100644 --- a/src/Persistence/Sql/Join.php +++ b/src/Persistence/Sql/Join.php @@ -71,16 +71,6 @@ protected function init(): void } } - /** - * Returns DSQL query. - */ - public function dsql(): Query - { - $dsql = $this->getOwner()->persistence->initQuery($this->getOwner()); - - return $dsql->reset('table')->table($this->foreign_table, $this->foreign_alias); - } - /** * Before query is executed, this method will be called. */ @@ -137,17 +127,18 @@ public function beforeInsert(Model $entity, array &$data): void $model = $this->getOwner(); - // The value for the master_field is set, so we are going to use existing record anyway - if ($model->hasField($this->master_field) && $entity->get($this->master_field)) { + // the value for the master_field is set, so we are going to use existing record anyway + if ($model->hasField($this->master_field) && $entity->get($this->master_field) !== null) { return; } - $query = $this->dsql(); - $query->mode('insert'); - $query->setMulti($model->persistence->typecastSaveRow($model, $this->getAndUnsetSaveBuffer($entity))); - // $query->set($this->foreign_field, null); - $query->mode('insert')->execute(); // TODO IMPORTANT migrate to Model insert - $this->setId($entity, $model->persistence->lastInsertId(new Model($model->persistence, ['table' => $this->foreign_table]))); + $foreignModel = $this->getForeignModel(); + $foreignEntity = $foreignModel->createEntity() + ->setMulti($this->getAndUnsetSaveBuffer($entity)) + /*->set($this->foreign_field, null)*/; + $foreignEntity->save(); + + $this->setId($entity, $foreignEntity->getId()); if ($this->hasJoin()) { $this->getJoin()->setSaveBufferValue($entity, $this->master_field, $this->getId($entity)); @@ -162,18 +153,13 @@ public function afterInsert(Model $entity): void return; } - $model = $this->getOwner(); + $foreignModel = $this->getForeignModel(); + $foreignEntity = $foreignModel->createEntity() + ->setMulti($this->getAndUnsetSaveBuffer($entity)) + ->set($this->foreign_field, $this->hasJoin() ? $this->getJoin()->getId($entity) : $entity->getId()); + $foreignEntity->save(); - $query = $this->dsql(); - $query->setMulti($model->persistence->typecastSaveRow($model, $this->getAndUnsetSaveBuffer($entity))); - $query->set($this->foreign_field, $this->hasJoin() ? $this->getJoin()->getId($entity) : $entity->getId()); - $query->mode('insert')->execute(); // TODO IMPORTANT migrate to Model insert - $modelForLastInsertId = $model; - while (is_object($modelForLastInsertId->table)) { - $modelForLastInsertId = $modelForLastInsertId->table; - } - // assumes same ID field across all nested models (not needed once migrated to Model insert) - $this->setId($entity, $model->persistence->lastInsertId($modelForLastInsertId)); + $this->setId($entity, $entity->getId()); // TODO why is this here? it seems to be not needed } public function beforeUpdate(Model $entity, array &$data): void @@ -186,14 +172,16 @@ public function beforeUpdate(Model $entity, array &$data): void return; } - $model = $this->getOwner(); - - $query = $this->dsql(); - $query->setMulti($model->persistence->typecastSaveRow($model, $this->getAndUnsetSaveBuffer($entity))); - - $id = $this->reverse ? $entity->getId() : $entity->get($this->master_field); - - $query->where($this->foreign_field, $id)->mode('update')->execute(); // TODO IMPORTANT migrate to Model update + $foreignModel = $this->getForeignModel(); + $foreignId = $this->reverse ? $entity->getId() : $entity->get($this->master_field); + $saveBuffer = $this->getAndUnsetSaveBuffer($entity); + $foreignModel->atomic(function () use ($foreignModel, $foreignId, $saveBuffer) { + $foreignModel = (clone $foreignModel)->addCondition($this->foreign_field, $foreignId); + foreach ($foreignModel as $foreignEntity) { + $foreignEntity->setMulti($saveBuffer); + $foreignEntity->save(); + } + }); } public function doDelete(Model $entity): void @@ -202,9 +190,13 @@ public function doDelete(Model $entity): void return; } - $query = $this->dsql(); - $id = $this->reverse ? $entity->getId() : $entity->get($this->master_field); - - $query->where($this->foreign_field, $id)->mode('delete')->execute(); // TODO IMPORTANT migrate to Model delete + $foreignModel = $this->getForeignModel(); + $foreignId = $this->reverse ? $entity->getId() : $entity->get($this->master_field); + $foreignModel->atomic(function () use ($foreignModel, $foreignId) { + $foreignModel = (clone $foreignModel)->addCondition($this->foreign_field, $foreignId); + foreach ($foreignModel as $foreignEntity) { + $foreignEntity->delete(); + } + }); } }