From c35a2f5cd0bce3ffe952b4eb1d0d2c794440c704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Sun, 16 Jan 2022 02:32:46 +0100 Subject: [PATCH] accept model or an with/CTE alias for join --- src/Model.php | 2 +- src/Model/Join.php | 37 +++++++++++++++++++++++++++---------- src/Model/JoinsTrait.php | 7 +++++-- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/Model.php b/src/Model.php index 75e2da3aee..046fa802f0 100644 --- a/src/Model.php +++ b/src/Model.php @@ -1074,7 +1074,7 @@ public function withId($id) */ public function addWith(self $model, string $alias, array $mapping = [], bool $recursive = false) { - if (isset($this->with[$alias])) { + if ($alias === $this->table || $alias === $this->table_alias || isset($this->with[$alias])) { throw (new Exception('With cursor already set with given alias')) ->addMoreInfo('alias', $alias); } diff --git a/src/Model/Join.php b/src/Model/Join.php index f5da760d3e..961f88dd00 100644 --- a/src/Model/Join.php +++ b/src/Model/Join.php @@ -31,10 +31,9 @@ class Join } /** - * Name of the table (or collection) that can be used to retrieve data from. - * For SQL, This can also be an expression or sub-select. + * Foreign model or WITH/CTE alias when used with SQL persistence. * - * @var string + * @var Model|string */ protected $foreign_table; @@ -120,18 +119,32 @@ class Join /** @var array> Data indexed by spl_object_id(entity) which is populated here as the save/insert progresses. */ private $saveBufferByOid = []; - public function __construct(string $foreign_table = null) + /** + * @param Model|string $foreignTable + */ + public function __construct($foreignTable = null) { - $this->foreign_table = $foreign_table; + $this->foreign_table = $foreignTable; // handle foreign table containing a dot - that will be reverse join - if (strpos($this->foreign_table, '.') !== false) { + if (is_string($this->foreign_table) && strpos($this->foreign_table, '.') !== false) { // split by LAST dot in foreign_table name [$this->foreign_table, $this->foreign_field] = preg_split('~\.+(?=[^.]+$)~', $this->foreign_table); $this->reverse = true; } } + public function getForeignModel(): Model + { + if (is_string($this->foreign_table)) { + return $this->getOwner()->with[$this->foreign_table]['model']; + } + + $this->foreign_table->assertIsModel(); + + return $this->foreign_table; + } + /** * @param Model $owner * @@ -203,6 +216,8 @@ protected function init(): void { $this->_init(); + $this->getForeignModel(); // assert valid foreign_table + // owner model should have id_field set $id_field = $this->getOwner()->id_field; if (!$id_field) { @@ -278,25 +293,27 @@ public function addFields(array $fields = [], array $defaults = []) /** * Another join will be attached to a current join. * + * @param Model|string $foreignTable * @param array $defaults */ - public function join(string $foreign_table, array $defaults = []): self + public function join($foreignTable, array $defaults = []): self { $defaults['joinName'] = $this->short_name; - return $this->getOwner()->join($foreign_table, $defaults); + return $this->getOwner()->join($foreignTable, $defaults); } /** * Another leftJoin will be attached to a current join. * + * @param Model|string $foreignTable * @param array $defaults */ - public function leftJoin(string $foreign_table, array $defaults = []): self + public function leftJoin($foreignTable, array $defaults = []): self { $defaults['joinName'] = $this->short_name; - return $this->getOwner()->leftJoin($foreign_table, $defaults); + return $this->getOwner()->leftJoin($foreignTable, $defaults); } /** diff --git a/src/Model/JoinsTrait.php b/src/Model/JoinsTrait.php index 02ed7d7127..ead134f8a6 100644 --- a/src/Model/JoinsTrait.php +++ b/src/Model/JoinsTrait.php @@ -5,6 +5,7 @@ namespace Atk4\Data\Model; use Atk4\Data\Exception; +use Atk4\Data\Model; /** * Provides native Model methods for join functionality. @@ -21,9 +22,10 @@ trait JoinsTrait * join will also query $foreignTable in order to find additional fields. When inserting * the record will be also added inside $foreignTable and relationship will be maintained. * + * @param Model|string $foreignTable * @param array $defaults */ - public function join(string $foreignTable, array $defaults = []): Join + public function join($foreignTable, array $defaults = []): Join { $this->assertIsModel(); @@ -47,9 +49,10 @@ public function join(string $foreignTable, array $defaults = []): Join * * @see join() * + * @param Model|string $foreignTable * @param array $defaults */ - public function leftJoin(string $foreignTable, array $defaults = []): Join + public function leftJoin($foreignTable, array $defaults = []): Join { $defaults['weak'] = true;