1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* This file is part of slick/orm package |
5
|
|
|
* |
6
|
|
|
* For the full copyright and license information, please view the LICENSE |
7
|
|
|
* file that was distributed with this source code. |
8
|
|
|
*/ |
9
|
|
|
|
10
|
|
|
namespace Slick\Orm\Mapper\Relation; |
11
|
|
|
|
12
|
|
|
use Slick\Common\Utils\Text; |
13
|
|
|
use Slick\Database\Sql; |
14
|
|
|
use Slick\Orm\Entity\EntityCollection; |
15
|
|
|
use Slick\Orm\EntityInterface; |
16
|
|
|
use Slick\Orm\Event\Delete; |
17
|
|
|
use Slick\Orm\Event\Select; |
18
|
|
|
use Slick\Orm\Orm; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* HasOne (one-to-one) relation |
22
|
|
|
* |
23
|
|
|
* @package Slick\Orm\Mapper\Relation |
24
|
|
|
* @author Filipe Silva <[email protected]> |
25
|
|
|
*/ |
26
|
|
|
class HasOne extends BelongsTo |
27
|
|
|
{ |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* Handles the before select callback |
31
|
|
|
* |
32
|
|
|
* @param Select $event |
33
|
|
|
*/ |
34
|
|
View Code Duplication |
public function beforeSelect(Select $event) |
|
|
|
|
35
|
|
|
{ |
36
|
|
|
if ($this->isLazyLoaded()) { |
37
|
|
|
return; |
38
|
|
|
} |
39
|
|
|
|
40
|
|
|
$fields = $this->getFieldsPrefixed(); |
41
|
|
|
$table = $this->entityDescriptor->getTableName(); |
42
|
|
|
$relateTable = $this->getParentTableName(); |
43
|
|
|
$pmk = $this->entityDescriptor->getPrimaryKey()->getField(); |
44
|
|
|
|
45
|
|
|
$onClause = "{$table}.{$pmk} = ". |
46
|
|
|
"{$relateTable}.{$this->getForeignKey()}"; |
47
|
|
|
|
48
|
|
|
$query = $event->getQuery(); |
49
|
|
|
$query->join($relateTable, $onClause, $fields, $relateTable); |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Gets the foreign key field name |
54
|
|
|
* |
55
|
|
|
* @return string |
56
|
|
|
*/ |
57
|
|
View Code Duplication |
public function getForeignKey() |
|
|
|
|
58
|
|
|
{ |
59
|
|
|
if (is_null($this->foreignKey)) { |
60
|
|
|
$name = $this->getEntityDescriptor()->getTableName(); |
61
|
|
|
$name = Text::singular(strtolower($name)); |
62
|
|
|
$this->foreignKey = "{$name}_id"; |
63
|
|
|
} |
64
|
|
|
return $this->foreignKey; |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* Loads the entity or entity collection for this relation |
69
|
|
|
* |
70
|
|
|
* @param EntityInterface $entity |
71
|
|
|
* |
72
|
|
|
* @return null|EntityInterface |
73
|
|
|
*/ |
74
|
|
|
public function load(EntityInterface $entity) |
75
|
|
|
{ |
76
|
|
|
$adapter = $this->getAdapter(); |
77
|
|
|
$relTable = $this->getParentTableName(); |
78
|
|
|
$pmk = $this->getEntityDescriptor()->getPrimaryKey(); |
79
|
|
|
$fnk = $this->getForeignKey(); |
80
|
|
|
|
81
|
|
|
$data = Sql::createSql($adapter) |
82
|
|
|
->select($relTable) |
83
|
|
|
->where([ |
|
|
|
|
84
|
|
|
"{$relTable}.{$fnk} = :id" => [ |
85
|
|
|
':id' => $entity->{$pmk->name} |
86
|
|
|
] |
87
|
|
|
]) |
88
|
|
|
->first(); |
89
|
|
|
|
90
|
|
|
$relEntity = $this->getParentEntityMapper()->createFrom($data); |
91
|
|
|
|
92
|
|
|
return null == $relEntity ? null :$this->registerEntity($relEntity); |
|
|
|
|
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* Deletes the related entity for before deleting current entity |
97
|
|
|
* |
98
|
|
|
* @param Delete $event |
99
|
|
|
*/ |
100
|
|
|
public function beforeDelete(Delete $event) |
101
|
|
|
{ |
102
|
|
|
$parent = $event->getEntity()->{$this->propertyName}; |
103
|
|
|
if ($parent instanceof EntityInterface) { |
104
|
|
|
$parent->delete(); |
105
|
|
|
} |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* Registers the listener for before select event |
110
|
|
|
*/ |
111
|
|
|
protected function registerListeners() |
112
|
|
|
{ |
113
|
|
|
Orm::addListener( |
114
|
|
|
$this->entityDescriptor->className(), |
115
|
|
|
Select::ACTION_BEFORE_SELECT, |
116
|
|
|
[$this, 'beforeSelect'] |
117
|
|
|
); |
118
|
|
|
|
119
|
|
|
Orm::addListener( |
120
|
|
|
$this->entityDescriptor->className(), |
121
|
|
|
Select::ACTION_AFTER_SELECT, |
122
|
|
|
[$this, 'afterSelect'] |
123
|
|
|
); |
124
|
|
|
|
125
|
|
|
Orm::addListener( |
126
|
|
|
$this->entityDescriptor->className(), |
127
|
|
|
Delete::ACTION_BEFORE_DELETE, |
128
|
|
|
[$this, 'beforeDelete'] |
129
|
|
|
); |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* Check if entity is already loaded and uses it. |
134
|
|
|
* |
135
|
|
|
* If not loaded the entity will be created and loaded to the repository's |
136
|
|
|
* identity map so that it can be reused next time. |
137
|
|
|
* |
138
|
|
|
* @param array $dataRow |
139
|
|
|
* |
140
|
|
|
* @return null|EntityCollection|EntityInterface|EntityInterface[] |
141
|
|
|
*/ |
142
|
|
|
protected function getFromMap($dataRow) |
143
|
|
|
{ |
144
|
|
|
$tableName = $this->getParentTableName(); |
145
|
|
|
$pmk = $this->getParentPrimaryKey(); |
146
|
|
|
$index = "{$tableName}_{$pmk}"; |
147
|
|
|
$entity = $this->getParentRepository() |
148
|
|
|
->getIdentityMap() |
149
|
|
|
->get($dataRow[$index], false); |
150
|
|
|
|
151
|
|
|
if (false === $entity) { |
152
|
|
|
$entity = $this->map($dataRow); |
153
|
|
|
} |
154
|
|
|
return $entity; |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
} |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.