1: <?php
2:
3: declare(strict_types=1);
4:
5: namespace Atk4\Data\Persistence\Sql;
6:
7: use Atk4\Data\Model;
8: use Atk4\Data\Persistence;
9:
10: class Join extends Model\Join
11: {
12: /**
13: * By default we create ON expression ourselves, but it can be specific explicitly.
14: *
15: * @var Expressionable|string|null
16: */
17: protected $on;
18:
19: #[\Override]
20: protected function init(): void
21: {
22: parent::init();
23:
24: // TODO thus mutates the owner model!
25: $this->getOwner()->persistenceData['use_table_prefixes'] = true;
26:
27: // our short name will be unique
28: // TODO this should be removed, short name is not guaranteed to be unique with nested model/query
29: if ($this->foreignAlias === null) {
30: $this->foreignAlias = ($this->getOwner()->tableAlias ?? '') . '_' . (str_starts_with($this->shortName, '#join-') ? substr($this->shortName, 6) : $this->shortName);
31: }
32:
33: // TODO thus mutates the owner model/joins!
34: if (!$this->reverse && !$this->getOwner()->hasField($this->masterField)) {
35: $owner = $this->hasJoin() ? $this->getJoin() : $this->getOwner();
36: $field = $owner->addField($this->masterField, ['type' => 'integer', 'system' => true, 'readOnly' => true]);
37: $this->masterField = $field->shortName; // TODO thus mutates the join!
38: } elseif ($this->reverse && !$this->getOwner()->hasField($this->foreignField) && $this->hasJoin()) {
39: $owner = $this->getJoin();
40: $field = $owner->addField($this->foreignField, ['type' => 'integer', 'system' => true, 'readOnly' => true, 'actual' => $this->masterField]);
41: $this->foreignField = $field->shortName; // TODO thus mutates the join!
42: }
43: }
44:
45: #[\Override]
46: protected function initJoinHooks(): void
47: {
48: parent::initJoinHooks();
49:
50: $this->onHookToOwnerBoth(Persistence\Sql::HOOK_INIT_SELECT_QUERY, \Closure::fromCallable([$this, 'initSelectQuery']));
51: }
52:
53: /**
54: * Before query is executed, this method will be called.
55: */
56: protected function initSelectQuery(Model $model, Query $query): void
57: {
58: if ($this->on) {
59: $onExpr = $this->on instanceof Expressionable ? $this->on : $this->getOwner()->expr($this->on);
60: } else {
61: $onExpr = $this->getOwner()->expr('{{}}.{} = {}', [
62: $this->foreignAlias ?? $this->foreignTable,
63: $this->foreignField,
64: $this->hasJoin()
65: ? $this->getOwner()->expr('{}.{}', [$this->getJoin()->foreignAlias, $this->masterField])
66: : $this->getOwner()->getField($this->masterField),
67: ]);
68: }
69:
70: $query->join(
71: $this->foreignTable,
72: $onExpr,
73: $this->kind,
74: $this->foreignAlias
75: );
76: }
77: }
78: