1
|
|
|
<?php |
2
|
|
|
namespace Ajir\RabbitMqSqlBundle\DataTransformer; |
3
|
|
|
|
4
|
|
|
use InvalidArgumentException; |
5
|
|
|
use Ajir\RabbitMqSqlBundle\DataMapper\DataMapperInterface; |
6
|
|
|
use Ajir\RabbitMqSqlBundle\DataValidator\DataValidatorInterface; |
7
|
|
|
|
8
|
|
|
/** |
9
|
|
|
* Class DataTransformer |
10
|
|
|
* |
11
|
|
|
* @author Florian Ajir <[email protected]> |
12
|
|
|
*/ |
13
|
|
|
class DataTransformer implements DataTransformerInterface |
14
|
|
|
{ |
15
|
|
|
const RELATED_KEY = '_related'; |
16
|
|
|
const RELATED_RELATION_KEY = '_relation'; |
17
|
|
|
const RELATED_DATA_KEY = '_data'; |
18
|
|
|
const IDENTIFIER_KEY = '_identifier'; |
19
|
|
|
const DISCRIMINATOR_KEY = '_discriminator'; |
20
|
|
|
const TABLE_KEY = '_table'; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* @var DataMapperInterface |
24
|
|
|
*/ |
25
|
|
|
protected $mapper; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* @var DataValidatorInterface |
29
|
|
|
*/ |
30
|
|
|
protected $validator; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* @param DataMapperInterface $mapper |
34
|
|
|
* @param DataValidatorInterface $validator |
35
|
|
|
*/ |
36
|
10 |
|
public function __construct(DataMapperInterface $mapper, DataValidatorInterface $validator = null) |
37
|
|
|
{ |
38
|
10 |
|
$this->mapper = $mapper; |
39
|
10 |
|
$this->validator = $validator; |
40
|
10 |
|
} |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* Prepare data from mapping rules (recursive) |
44
|
|
|
* |
45
|
|
|
* @param string $type |
46
|
|
|
* @param array $data |
47
|
|
|
* |
48
|
|
|
* @return array |
49
|
|
|
* |
50
|
|
|
* @throws InvalidArgumentException |
51
|
|
|
*/ |
52
|
10 |
|
public function prepare($type, array $data) |
53
|
|
|
{ |
54
|
10 |
|
$prepared = array(); |
55
|
10 |
|
$data = $this->prepareData($type, $data); |
56
|
7 |
|
$prepared[$type] = $this->checkFieldsMapping($type, $data); |
57
|
|
|
|
58
|
6 |
|
return $prepared; |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* @param string $type |
63
|
|
|
* @param array $data |
64
|
|
|
* |
65
|
|
|
* @return array |
66
|
|
|
*/ |
67
|
10 |
|
protected function prepareData($type, array $data) |
68
|
|
|
{ |
69
|
10 |
|
$prepared = array(); |
70
|
10 |
|
if ($identifier = $this->mapper->getIdentifier($type)) { |
71
|
7 |
|
$prepared[self::IDENTIFIER_KEY] = $identifier; |
72
|
|
|
} |
73
|
10 |
|
if ($tableName = $this->mapper->getTableName($type)) { |
74
|
8 |
|
$prepared[self::TABLE_KEY] = $tableName; |
75
|
|
|
} |
76
|
10 |
|
if ($discr = $this->mapper->getDiscriminator($type)) { |
77
|
1 |
|
if (array_key_exists($discr, $data)) { |
78
|
1 |
|
$prepared[self::TABLE_KEY] = $data[$discr]; |
79
|
|
|
} |
80
|
|
|
} |
81
|
10 |
|
foreach ($data as $field => $value) { |
82
|
10 |
|
$fieldMapping = $this->mapper->getFieldMapping($type, $field); |
83
|
10 |
|
if (!empty($fieldMapping)) { |
84
|
10 |
|
$this->prepareField($prepared, $type, $field, $value); |
85
|
3 |
|
} elseif ($relation = $this->mapper->getRelation($type, $field)) { |
86
|
8 |
|
$this->prepareRelated($prepared, $type, $field, $value, $relation); |
87
|
|
|
} |
88
|
|
|
} |
89
|
|
|
|
90
|
7 |
|
return $prepared; |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* @param array &$prepared |
95
|
|
|
* @param string $type |
96
|
|
|
* @param string $field |
97
|
|
|
* @param string $value |
98
|
|
|
* |
99
|
|
|
* @return array |
100
|
|
|
*/ |
101
|
10 |
|
protected function prepareField(array &$prepared, $type, $field, $value) |
102
|
|
|
{ |
103
|
10 |
|
if ($this->validator) { |
104
|
5 |
|
$this->validate($type, $field, $value); |
105
|
|
|
} |
106
|
8 |
|
$fieldColumn = $this->mapper->getFieldColumn($type, $field); |
107
|
8 |
|
$prepared[$fieldColumn] = $value; |
108
|
|
|
|
109
|
8 |
|
return $prepared; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* @param string $type |
114
|
|
|
* @param string $field |
115
|
|
|
* @param string $value |
116
|
|
|
* |
117
|
|
|
* @throws InvalidArgumentException |
118
|
|
|
*/ |
119
|
5 |
|
protected function validate($type, $field, $value) |
120
|
|
|
{ |
121
|
|
|
// validate length if defined |
122
|
5 |
View Code Duplication |
if ($maxLength = $this->mapper->getFieldMaxLength($type, $field)) { |
|
|
|
|
123
|
4 |
|
if (!$this->validator->validateLength($value, $maxLength)) { |
124
|
2 |
|
throw new InvalidArgumentException($type . '.' . $field . ' value length exceed database max length.'); |
125
|
|
|
} |
126
|
|
|
} |
127
|
|
|
// validate field type |
128
|
3 |
View Code Duplication |
if ($fieldType = $this->mapper->getFieldType($type, $field)) { |
|
|
|
|
129
|
3 |
|
if (!$this->validator->validateType($value, $fieldType)) { |
130
|
1 |
|
throw new InvalidArgumentException($type . '.' . $field . ' type not valid.'); |
131
|
|
|
} |
132
|
|
|
} |
133
|
3 |
|
} |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* @param array &$prepared |
137
|
|
|
* @param string $type |
138
|
|
|
* @param string $field |
139
|
|
|
* @param array $data |
140
|
|
|
* @param string $relation |
141
|
|
|
* |
142
|
|
|
* @return array |
143
|
|
|
*/ |
144
|
2 |
|
protected function prepareRelated(array &$prepared, $type, $field, array $data, $relation) |
145
|
|
|
{ |
146
|
2 |
|
$relationInfos = $this->mapper->getRelationInfos($type, $field, $relation); |
147
|
2 |
|
if ($relationInfos) { |
|
|
|
|
148
|
2 |
|
$collection = $this->mapper->isCollection($relation); |
149
|
2 |
|
$targetEntity = $this->mapper->getTargetEntity($type, $field, $relation); |
150
|
2 |
|
$prepared[self::RELATED_KEY][$relation][$targetEntity][self::RELATED_RELATION_KEY] = $relationInfos; |
151
|
2 |
|
$relatedData = array(); |
152
|
2 |
|
if ($collection) { |
153
|
1 |
|
foreach ($data as $element) { |
154
|
1 |
|
$relatedData[] = $this->prepare($targetEntity, $element); |
155
|
|
|
} |
156
|
|
|
} else { |
157
|
1 |
|
$relatedData = $this->prepare($targetEntity, $data); |
158
|
|
|
} |
159
|
2 |
|
$prepared[self::RELATED_KEY][$relation][$targetEntity][self::RELATED_DATA_KEY] = $relatedData; |
160
|
|
|
} |
161
|
|
|
|
162
|
2 |
|
return $prepared; |
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
/** |
166
|
|
|
* Last step of prepare which loop over entity mapping fields |
167
|
|
|
* |
168
|
|
|
* @param string $type entity name |
169
|
|
|
* @param array $data entity data |
170
|
|
|
* |
171
|
|
|
* @return array |
172
|
|
|
*/ |
173
|
7 |
|
protected function checkFieldsMapping($type, array $data) |
174
|
|
|
{ |
175
|
7 |
|
foreach ($this->mapper->getFieldsName($type) as $field) { |
176
|
7 |
|
if ($this->validator) { |
177
|
2 |
|
$this->checkNullable($type, $field, $data); |
178
|
|
|
} |
179
|
6 |
|
if ($fixedValue = $this->mapper->getFixedFieldMapping($type, $field)) { |
180
|
6 |
|
$data = array_merge($data, $fixedValue); |
181
|
|
|
} |
182
|
|
|
} |
183
|
|
|
|
184
|
6 |
|
return $data; |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
/** |
188
|
|
|
* @param string $type |
189
|
|
|
* @param string $field |
190
|
|
|
* @param array $data |
191
|
|
|
* |
192
|
|
|
* @throws InvalidArgumentException |
193
|
|
|
*/ |
194
|
2 |
|
protected function checkNullable($type, $field, array $data) |
195
|
|
|
{ |
196
|
2 |
|
if (!$this->mapper->isFieldNullable($type, $field) |
197
|
2 |
|
&& !isset($data[$this->mapper->getFieldColumn($type, $field)]) |
198
|
|
|
) { |
199
|
1 |
|
throw new InvalidArgumentException($type . '.' . $field . ' is not nullable.'); |
200
|
|
|
} |
201
|
1 |
|
} |
202
|
|
|
} |
203
|
|
|
|
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.