1
|
|
|
<?php |
2
|
|
|
namespace Ajir\RabbitMqSqlBundle\Persister; |
3
|
|
|
|
4
|
|
|
use Exception; |
5
|
|
|
use Ajir\RabbitMqSqlBundle\DataMapper\DataMapper; |
6
|
|
|
use Ajir\RabbitMqSqlBundle\Factory\EntityFactoryInterface; |
7
|
|
|
use Ajir\RabbitMqSqlBundle\Factory\RelationFactoryInterface; |
8
|
|
|
use Ajir\RabbitMqSqlBundle\Model\EntityInterface; |
9
|
|
|
use Ajir\RabbitMqSqlBundle\Provider\ProviderInterface; |
10
|
|
|
|
11
|
|
|
/** |
12
|
|
|
* Class Persister |
13
|
|
|
* |
14
|
|
|
* @author Florian Ajir <[email protected]> |
15
|
|
|
*/ |
16
|
|
|
class Persister implements PersisterInterface |
17
|
|
|
{ |
18
|
|
|
/** |
19
|
|
|
* @var ProviderInterface |
20
|
|
|
*/ |
21
|
|
|
protected $provider; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* @var EntityFactoryInterface |
25
|
|
|
*/ |
26
|
|
|
protected $entityFactory; |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* @var RelationFactoryInterface |
30
|
|
|
*/ |
31
|
|
|
protected $relationFactory; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* @param ProviderInterface $provider |
35
|
|
|
* @param EntityFactoryInterface $entityFactory |
36
|
|
|
* @param RelationFactoryInterface $relationFactory |
37
|
|
|
*/ |
38
|
1 |
|
public function __construct( |
39
|
|
|
ProviderInterface $provider, |
40
|
|
|
EntityFactoryInterface $entityFactory, |
41
|
|
|
RelationFactoryInterface $relationFactory |
42
|
|
|
) { |
43
|
1 |
|
$this->provider = $provider; |
44
|
1 |
|
$this->entityFactory = $entityFactory; |
45
|
1 |
|
$this->relationFactory = $relationFactory; |
46
|
1 |
|
} |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* Persist data |
50
|
|
|
* |
51
|
|
|
* @param array $data An associative array containing column-value pairs. |
52
|
|
|
* |
53
|
|
|
* @throws Exception |
54
|
|
|
*/ |
55
|
1 |
|
public function persist(array $data) |
56
|
|
|
{ |
57
|
1 |
|
foreach ($data as $infos) { |
58
|
1 |
|
$entity = $this->entityFactory->create($infos); |
59
|
1 |
|
$this->persistRecursive($entity); |
60
|
|
|
} |
61
|
1 |
|
} |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* Persist data recursively |
65
|
|
|
* |
66
|
|
|
* @param EntityInterface $entity |
67
|
|
|
* |
68
|
|
|
* @return array |
69
|
|
|
* |
70
|
|
|
* @throws Exception |
71
|
|
|
*/ |
72
|
1 |
|
protected function persistRecursive(EntityInterface $entity) |
73
|
|
|
{ |
74
|
1 |
|
$entity->addDataSet($this->persistOneToOneRelations($entity)); |
75
|
1 |
|
$entity->addDataSet($this->persistManyToOneRelations($entity)); |
76
|
1 |
|
$id = $this->insertOrUpdateIfExists($entity); |
77
|
1 |
|
if ($entity->getIdentifier() === null) { |
78
|
1 |
|
$entity->setIdentifier(array('id' => $id)); |
79
|
|
|
} |
80
|
1 |
|
$this->persistOneToManyRelations($entity); |
81
|
1 |
|
$this->persistManyToManyRelations($entity); |
82
|
|
|
|
83
|
1 |
|
return $entity->getIdentifier(); |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* Persist oneToOne relations |
88
|
|
|
* |
89
|
|
|
* @param EntityInterface $entity |
90
|
|
|
* |
91
|
|
|
* @return array associative array( 'foreign_key' => 'value' ) |
92
|
|
|
* |
93
|
|
|
* @throws Exception |
94
|
|
|
*/ |
95
|
1 |
View Code Duplication |
protected function persistOneToOneRelations(EntityInterface $entity) |
|
|
|
|
96
|
|
|
{ |
97
|
1 |
|
$joinData = array(); |
98
|
1 |
|
$relations = $entity->getOneToOneRelations(); |
99
|
1 |
|
foreach ($relations as $relation) { |
100
|
1 |
|
$oneToOne = $this->relationFactory->create(DataMapper::RELATION_ONE_TO_ONE, $relation); |
101
|
1 |
|
$entity = $this->entityFactory->create($oneToOne->getEntity()); |
|
|
|
|
102
|
1 |
|
$id = $this->persistRecursive($entity); |
103
|
1 |
|
$joinVal = $entity->getProperty($oneToOne->getJoinColumnReferencedColumnName()); |
104
|
1 |
|
$joinData[$oneToOne->getJoinColumnName()] = !is_null($joinVal) |
105
|
|
|
? $joinVal |
106
|
1 |
|
: $this->provider->getColumnValueWhere( |
107
|
1 |
|
$oneToOne->getTable(), |
108
|
1 |
|
$oneToOne->getJoinColumnReferencedColumnName(), |
109
|
|
|
key($id), |
110
|
|
|
current($id) |
111
|
|
|
); |
112
|
|
|
} |
113
|
|
|
|
114
|
1 |
|
return $joinData; |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* Persist manyToOne relations |
119
|
|
|
* |
120
|
|
|
* @param EntityInterface $entity |
121
|
|
|
* |
122
|
|
|
* @return array associative array( 'foreign_key' => 'value' ) |
123
|
|
|
* |
124
|
|
|
* @throws Exception |
125
|
|
|
*/ |
126
|
1 |
View Code Duplication |
protected function persistManyToOneRelations(EntityInterface $entity) |
|
|
|
|
127
|
|
|
{ |
128
|
1 |
|
$joinData = array(); |
129
|
1 |
|
$relations = $entity->getManyToOneRelations(); |
130
|
1 |
|
foreach ($relations as $relation) { |
131
|
1 |
|
$manyToOne = $this->relationFactory->create(DataMapper::RELATION_MANY_TO_ONE, $relation); |
132
|
1 |
|
$entity = $this->entityFactory->create($manyToOne->getEntity()); |
|
|
|
|
133
|
1 |
|
$id = $this->persistRecursive($entity); |
134
|
1 |
|
$joinVal = $entity->getProperty($manyToOne->getJoinColumnReferencedColumnName()); |
135
|
1 |
|
$joinData[$manyToOne->getJoinColumnName()] = !is_null($joinVal) |
136
|
|
|
? $joinVal |
137
|
1 |
|
: $this->provider->getColumnValueWhere( |
138
|
1 |
|
$manyToOne->getTable(), |
139
|
1 |
|
$manyToOne->getJoinColumnReferencedColumnName(), |
140
|
|
|
key($id), |
141
|
|
|
current($id) |
142
|
|
|
); |
143
|
|
|
} |
144
|
|
|
|
145
|
1 |
|
return $joinData; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
/** |
149
|
|
|
* @param EntityInterface $entity |
150
|
|
|
* |
151
|
|
|
* @return int |
152
|
|
|
*/ |
153
|
1 |
|
protected function insertOrUpdateIfExists(EntityInterface $entity) |
154
|
|
|
{ |
155
|
1 |
|
return $this->provider->insertOrUpdateIfExists( |
156
|
1 |
|
$entity->getTable(), |
157
|
1 |
|
$entity->getData(), |
|
|
|
|
158
|
1 |
|
$entity->getIdentifier() |
159
|
|
|
); |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
/** |
163
|
|
|
* @param EntityInterface $entity |
164
|
|
|
* |
165
|
|
|
* @throws Exception |
166
|
|
|
*/ |
167
|
1 |
|
protected function persistOneToManyRelations(EntityInterface $entity) |
168
|
|
|
{ |
169
|
1 |
|
$relations = $entity->getOneToManyRelations(); |
170
|
1 |
|
foreach ($relations as $relation) { |
171
|
1 |
|
$oneToMany = $this->relationFactory->create(DataMapper::RELATION_ONE_TO_MANY, $relation); |
172
|
1 |
|
$foreignValue = $entity->getProperty($oneToMany->getJoinColumnReferencedColumnName()); |
173
|
1 |
|
$parentIdent = $entity->getIdentifier(); |
174
|
1 |
View Code Duplication |
if (is_null($foreignValue) && !empty($parentIdent)) { |
|
|
|
|
175
|
|
|
$foreignValue = $this->provider->getColumnValueWhere( |
176
|
|
|
$entity->getTable(), |
177
|
|
|
$oneToMany->getJoinColumnReferencedColumnName(), |
178
|
|
|
key($parentIdent), |
179
|
|
|
current($parentIdent) |
180
|
|
|
); |
181
|
|
|
} |
182
|
1 |
|
if (is_null($foreignValue)) { |
183
|
|
|
throw new Exception("Unable to get an identifier. (Table: {$entity->getTable()})"); |
184
|
|
|
} |
185
|
|
|
|
186
|
1 |
|
foreach ($oneToMany->getEntities() as $childData) { |
187
|
1 |
|
$child = $this->entityFactory->create($childData[$oneToMany->getEntityName()]); |
188
|
1 |
|
$joinData = array($oneToMany->getJoinColumnName() => $foreignValue); |
189
|
1 |
|
foreach ($oneToMany->getReferences() as $field => $reference) { |
190
|
|
|
$referenceValue = $this->provider->getColumnValueWhere( |
191
|
|
|
$reference[DataMapper::MAPPING_KEY_TABLE], |
192
|
|
|
$reference[DataMapper::RELATION_KEY_JOIN_COLUMN_REFERENCED_COLUMN_NAME], |
193
|
|
|
key($reference[DataMapper::WHERE_KEY]), |
194
|
|
|
current($reference[DataMapper::WHERE_KEY]) |
195
|
|
|
); |
196
|
|
|
$joinData[$field] = $referenceValue; |
197
|
|
|
} |
198
|
1 |
|
$child->addDataSet($joinData); |
199
|
1 |
|
if ($oneToMany->isRemoveReferenced()) { |
200
|
|
|
$this->provider->delete($oneToMany->getTable(), $joinData); |
201
|
|
|
} |
202
|
1 |
|
$this->persistRecursive($child); |
203
|
|
|
} |
204
|
|
|
} |
205
|
1 |
|
} |
206
|
|
|
|
207
|
|
|
/** |
208
|
|
|
* @param EntityInterface $entity |
209
|
|
|
* |
210
|
|
|
* @throws Exception |
211
|
|
|
*/ |
212
|
1 |
|
protected function persistManyToManyRelations(EntityInterface $entity) |
213
|
|
|
{ |
214
|
1 |
|
$relations = $entity->getManyToManyRelations(); |
215
|
1 |
|
foreach ($relations as $relation) { |
216
|
1 |
|
$manyToMany = $this->relationFactory->create(DataMapper::RELATION_MANY_TO_MANY, $relation); |
217
|
1 |
|
$foreignValue = $entity->getProperty($manyToMany->getJoinColumnReferencedColumnName()); |
218
|
1 |
|
$parentIdent = $entity->getIdentifier(); |
219
|
1 |
View Code Duplication |
if (is_null($foreignValue) && !empty($parentIdent)) { |
|
|
|
|
220
|
|
|
$foreignValue = $this->provider->getColumnValueWhere( |
221
|
|
|
$entity->getTable(), |
222
|
|
|
$manyToMany->getJoinColumnReferencedColumnName(), |
223
|
|
|
key($parentIdent), |
224
|
|
|
current($parentIdent) |
225
|
|
|
); |
226
|
|
|
} |
227
|
1 |
|
if (is_null($foreignValue)) { |
228
|
|
|
throw new Exception("Unable to get an identifier. (Table: {$entity->getTable()})"); |
229
|
|
|
} |
230
|
|
|
$joinData = array( |
231
|
1 |
|
$manyToMany->getJoinColumnName() => $foreignValue |
232
|
|
|
); |
233
|
|
|
//delete joins before loop |
234
|
1 |
|
$this->provider->delete($manyToMany->getJoinTableName(), $joinData); |
235
|
1 |
|
foreach ($manyToMany->getEntities() as $childData) { |
236
|
1 |
|
$child = $this->entityFactory->create($childData[$manyToMany->getEntityName()]); |
237
|
1 |
|
$this->persistRecursive($child); |
238
|
1 |
|
$newJoinDataValue = $child->getProperty($manyToMany->getInverseJoinColumnReferencedColumnName()); |
|
|
|
|
239
|
1 |
|
$joinIdent = $child->getIdentifier(); |
240
|
1 |
|
$joinData[$manyToMany->getInverseJoinColumnName()] = !is_null($newJoinDataValue) |
241
|
|
|
? $newJoinDataValue |
242
|
1 |
|
: $this->provider->getColumnValueWhere( |
243
|
1 |
|
$child->getTable(), |
244
|
1 |
|
$manyToMany->getInverseJoinColumnReferencedColumnName(), |
|
|
|
|
245
|
|
|
key($joinIdent), |
246
|
|
|
current($joinIdent) |
247
|
|
|
); |
248
|
|
|
//insert in join table |
249
|
1 |
|
$this->provider->insert($manyToMany->getJoinTableName(), $joinData); |
250
|
|
|
} |
251
|
|
|
} |
252
|
1 |
|
} |
253
|
|
|
} |
254
|
|
|
|
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.