Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace Drupal\migrate;
|
Chris@0
|
4
|
Chris@0
|
5 use Drupal\Component\Utility\NestedArray;
|
Chris@0
|
6 use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
Chris@0
|
7
|
Chris@0
|
8 /**
|
Chris@0
|
9 * Stores a row.
|
Chris@0
|
10 */
|
Chris@0
|
11 class Row {
|
Chris@0
|
12
|
Chris@0
|
13 /**
|
Chris@0
|
14 * The actual values of the source row.
|
Chris@0
|
15 *
|
Chris@0
|
16 * @var array
|
Chris@0
|
17 */
|
Chris@0
|
18 protected $source = [];
|
Chris@0
|
19
|
Chris@0
|
20 /**
|
Chris@0
|
21 * The source identifiers.
|
Chris@0
|
22 *
|
Chris@0
|
23 * @var array
|
Chris@0
|
24 */
|
Chris@0
|
25 protected $sourceIds = [];
|
Chris@0
|
26
|
Chris@0
|
27 /**
|
Chris@0
|
28 * The destination values.
|
Chris@0
|
29 *
|
Chris@0
|
30 * @var array
|
Chris@0
|
31 */
|
Chris@0
|
32 protected $destination = [];
|
Chris@0
|
33
|
Chris@0
|
34 /**
|
Chris@0
|
35 * Level separator of destination and source properties.
|
Chris@0
|
36 */
|
Chris@0
|
37 const PROPERTY_SEPARATOR = '/';
|
Chris@0
|
38
|
Chris@0
|
39 /**
|
Chris@0
|
40 * The mapping between source and destination identifiers.
|
Chris@0
|
41 *
|
Chris@0
|
42 * @var array
|
Chris@0
|
43 */
|
Chris@0
|
44 protected $idMap = [
|
Chris@0
|
45 'original_hash' => '',
|
Chris@0
|
46 'hash' => '',
|
Chris@0
|
47 'source_row_status' => MigrateIdMapInterface::STATUS_NEEDS_UPDATE,
|
Chris@0
|
48 ];
|
Chris@0
|
49
|
Chris@0
|
50 /**
|
Chris@0
|
51 * Whether the source has been frozen already.
|
Chris@0
|
52 *
|
Chris@0
|
53 * Once frozen the source can not be changed any more.
|
Chris@0
|
54 *
|
Chris@0
|
55 * @var bool
|
Chris@0
|
56 */
|
Chris@0
|
57 protected $frozen = FALSE;
|
Chris@0
|
58
|
Chris@0
|
59 /**
|
Chris@0
|
60 * The raw destination properties.
|
Chris@0
|
61 *
|
Chris@0
|
62 * Unlike $destination which is set by using
|
Chris@0
|
63 * \Drupal\Component\Utility\NestedArray::setValue() this array contains
|
Chris@0
|
64 * the destination as setDestinationProperty was called.
|
Chris@0
|
65 *
|
Chris@0
|
66 * @var array
|
Chris@0
|
67 * The raw destination.
|
Chris@0
|
68 *
|
Chris@0
|
69 * @see getRawDestination()
|
Chris@0
|
70 */
|
Chris@0
|
71 protected $rawDestination = [];
|
Chris@0
|
72
|
Chris@0
|
73 /**
|
Chris@0
|
74 * TRUE when this row is a stub.
|
Chris@0
|
75 *
|
Chris@0
|
76 * @var bool
|
Chris@0
|
77 */
|
Chris@0
|
78 protected $isStub = FALSE;
|
Chris@0
|
79
|
Chris@0
|
80 /**
|
Chris@0
|
81 * The empty destination properties.
|
Chris@0
|
82 *
|
Chris@0
|
83 * @var array
|
Chris@0
|
84 */
|
Chris@0
|
85 protected $emptyDestinationProperties = [];
|
Chris@0
|
86
|
Chris@0
|
87 /**
|
Chris@0
|
88 * Constructs a \Drupal\Migrate\Row object.
|
Chris@0
|
89 *
|
Chris@0
|
90 * @param array $values
|
Chris@0
|
91 * An array of values to add as properties on the object.
|
Chris@0
|
92 * @param array $source_ids
|
Chris@0
|
93 * An array containing the IDs of the source using the keys as the field
|
Chris@0
|
94 * names.
|
Chris@0
|
95 * @param bool $is_stub
|
Chris@0
|
96 * TRUE if the row being created is a stub.
|
Chris@0
|
97 *
|
Chris@0
|
98 * @throws \InvalidArgumentException
|
Chris@0
|
99 * Thrown when a source ID property does not exist.
|
Chris@0
|
100 */
|
Chris@0
|
101 public function __construct(array $values = [], array $source_ids = [], $is_stub = FALSE) {
|
Chris@0
|
102 $this->source = $values;
|
Chris@0
|
103 $this->sourceIds = $source_ids;
|
Chris@0
|
104 $this->isStub = $is_stub;
|
Chris@0
|
105 foreach (array_keys($source_ids) as $id) {
|
Chris@0
|
106 if (!$this->hasSourceProperty($id)) {
|
Chris@0
|
107 throw new \InvalidArgumentException("$id is defined as a source ID but has no value.");
|
Chris@0
|
108 }
|
Chris@0
|
109 }
|
Chris@0
|
110 }
|
Chris@0
|
111
|
Chris@0
|
112 /**
|
Chris@0
|
113 * Retrieves the values of the source identifiers.
|
Chris@0
|
114 *
|
Chris@0
|
115 * @return array
|
Chris@0
|
116 * An array containing the values of the source identifiers. Returns values
|
Chris@0
|
117 * in the same order as defined in $this->sourceIds.
|
Chris@0
|
118 */
|
Chris@0
|
119 public function getSourceIdValues() {
|
Chris@0
|
120 return array_merge($this->sourceIds, array_intersect_key($this->source, $this->sourceIds));
|
Chris@0
|
121 }
|
Chris@0
|
122
|
Chris@0
|
123 /**
|
Chris@0
|
124 * Determines whether a source has a property.
|
Chris@0
|
125 *
|
Chris@0
|
126 * @param string $property
|
Chris@0
|
127 * A property on the source.
|
Chris@0
|
128 *
|
Chris@0
|
129 * @return bool
|
Chris@0
|
130 * TRUE if the source has property; FALSE otherwise.
|
Chris@0
|
131 */
|
Chris@0
|
132 public function hasSourceProperty($property) {
|
Chris@0
|
133 return NestedArray::keyExists($this->source, explode(static::PROPERTY_SEPARATOR, $property));
|
Chris@0
|
134 }
|
Chris@0
|
135
|
Chris@0
|
136 /**
|
Chris@0
|
137 * Retrieves a source property.
|
Chris@0
|
138 *
|
Chris@0
|
139 * @param string $property
|
Chris@0
|
140 * A property on the source.
|
Chris@0
|
141 *
|
Chris@0
|
142 * @return mixed|null
|
Chris@0
|
143 * The found returned property or NULL if not found.
|
Chris@0
|
144 */
|
Chris@0
|
145 public function getSourceProperty($property) {
|
Chris@0
|
146 $return = NestedArray::getValue($this->source, explode(static::PROPERTY_SEPARATOR, $property), $key_exists);
|
Chris@0
|
147 if ($key_exists) {
|
Chris@0
|
148 return $return;
|
Chris@0
|
149 }
|
Chris@0
|
150 }
|
Chris@0
|
151
|
Chris@0
|
152 /**
|
Chris@0
|
153 * Returns the whole source array.
|
Chris@0
|
154 *
|
Chris@0
|
155 * @return array
|
Chris@0
|
156 * An array of source plugins.
|
Chris@0
|
157 */
|
Chris@0
|
158 public function getSource() {
|
Chris@0
|
159 return $this->source;
|
Chris@0
|
160 }
|
Chris@0
|
161
|
Chris@0
|
162 /**
|
Chris@0
|
163 * Sets a source property.
|
Chris@0
|
164 *
|
Chris@0
|
165 * This can only be called from the source plugin.
|
Chris@0
|
166 *
|
Chris@0
|
167 * @param string $property
|
Chris@0
|
168 * A property on the source.
|
Chris@0
|
169 * @param mixed $data
|
Chris@0
|
170 * The property value to set on the source.
|
Chris@0
|
171 *
|
Chris@0
|
172 * @throws \Exception
|
Chris@0
|
173 */
|
Chris@0
|
174 public function setSourceProperty($property, $data) {
|
Chris@0
|
175 if ($this->frozen) {
|
Chris@0
|
176 throw new \Exception("The source is frozen and can't be changed any more");
|
Chris@0
|
177 }
|
Chris@0
|
178 else {
|
Chris@0
|
179 NestedArray::setValue($this->source, explode(static::PROPERTY_SEPARATOR, $property), $data, TRUE);
|
Chris@0
|
180 }
|
Chris@0
|
181 }
|
Chris@0
|
182
|
Chris@0
|
183 /**
|
Chris@0
|
184 * Freezes the source.
|
Chris@0
|
185 *
|
Chris@0
|
186 * @return $this
|
Chris@0
|
187 */
|
Chris@0
|
188 public function freezeSource() {
|
Chris@0
|
189 $this->frozen = TRUE;
|
Chris@0
|
190 return $this;
|
Chris@0
|
191 }
|
Chris@0
|
192
|
Chris@0
|
193 /**
|
Chris@0
|
194 * Clones the row with an empty set of destination values.
|
Chris@0
|
195 *
|
Chris@0
|
196 * @return static
|
Chris@0
|
197 */
|
Chris@0
|
198 public function cloneWithoutDestination() {
|
Chris@0
|
199 return (new static($this->getSource(), $this->sourceIds, $this->isStub()))->freezeSource();
|
Chris@0
|
200 }
|
Chris@0
|
201
|
Chris@0
|
202 /**
|
Chris@0
|
203 * Tests if destination property exists.
|
Chris@0
|
204 *
|
Chris@0
|
205 * @param array|string $property
|
Chris@0
|
206 * An array of properties on the destination.
|
Chris@0
|
207 *
|
Chris@0
|
208 * @return bool
|
Chris@0
|
209 * TRUE if the destination property exists.
|
Chris@0
|
210 */
|
Chris@0
|
211 public function hasDestinationProperty($property) {
|
Chris@0
|
212 return NestedArray::keyExists($this->destination, explode(static::PROPERTY_SEPARATOR, $property));
|
Chris@0
|
213 }
|
Chris@0
|
214
|
Chris@0
|
215 /**
|
Chris@0
|
216 * Sets destination properties.
|
Chris@0
|
217 *
|
Chris@0
|
218 * @param string $property
|
Chris@0
|
219 * The name of the destination property.
|
Chris@0
|
220 * @param mixed $value
|
Chris@0
|
221 * The property value to set on the destination.
|
Chris@0
|
222 */
|
Chris@0
|
223 public function setDestinationProperty($property, $value) {
|
Chris@0
|
224 $this->rawDestination[$property] = $value;
|
Chris@0
|
225 NestedArray::setValue($this->destination, explode(static::PROPERTY_SEPARATOR, $property), $value, TRUE);
|
Chris@0
|
226 }
|
Chris@0
|
227
|
Chris@0
|
228 /**
|
Chris@0
|
229 * Removes destination property.
|
Chris@0
|
230 *
|
Chris@0
|
231 * @param string $property
|
Chris@0
|
232 * The name of the destination property.
|
Chris@0
|
233 */
|
Chris@0
|
234 public function removeDestinationProperty($property) {
|
Chris@0
|
235 unset($this->rawDestination[$property]);
|
Chris@0
|
236 NestedArray::unsetValue($this->destination, explode(static::PROPERTY_SEPARATOR, $property));
|
Chris@0
|
237 }
|
Chris@0
|
238
|
Chris@0
|
239 /**
|
Chris@0
|
240 * Sets a destination to be empty.
|
Chris@0
|
241 *
|
Chris@0
|
242 * @param string $property
|
Chris@0
|
243 * The destination property.
|
Chris@0
|
244 */
|
Chris@0
|
245 public function setEmptyDestinationProperty($property) {
|
Chris@0
|
246 $this->emptyDestinationProperties[] = $property;
|
Chris@0
|
247 }
|
Chris@0
|
248
|
Chris@0
|
249 /**
|
Chris@0
|
250 * Gets the empty destination properties.
|
Chris@0
|
251 *
|
Chris@0
|
252 * @return array
|
Chris@0
|
253 * An array of destination properties.
|
Chris@0
|
254 */
|
Chris@0
|
255 public function getEmptyDestinationProperties() {
|
Chris@0
|
256 return $this->emptyDestinationProperties;
|
Chris@0
|
257 }
|
Chris@0
|
258
|
Chris@0
|
259 /**
|
Chris@0
|
260 * Returns the whole destination array.
|
Chris@0
|
261 *
|
Chris@0
|
262 * @return array
|
Chris@0
|
263 * An array of destination values.
|
Chris@0
|
264 */
|
Chris@0
|
265 public function getDestination() {
|
Chris@0
|
266 return $this->destination;
|
Chris@0
|
267 }
|
Chris@0
|
268
|
Chris@0
|
269 /**
|
Chris@0
|
270 * Returns the raw destination. Rarely necessary.
|
Chris@0
|
271 *
|
Chris@0
|
272 * For example calling setDestination('foo/bar', 'baz') results in
|
Chris@0
|
273 * @code
|
Chris@0
|
274 * $this->destination['foo']['bar'] = 'baz';
|
Chris@0
|
275 * $this->rawDestination['foo/bar'] = 'baz';
|
Chris@0
|
276 * @endcode
|
Chris@0
|
277 *
|
Chris@0
|
278 * @return array
|
Chris@0
|
279 * The raw destination values.
|
Chris@0
|
280 */
|
Chris@0
|
281 public function getRawDestination() {
|
Chris@0
|
282 return $this->rawDestination;
|
Chris@0
|
283 }
|
Chris@0
|
284
|
Chris@0
|
285 /**
|
Chris@0
|
286 * Returns the value of a destination property.
|
Chris@0
|
287 *
|
Chris@0
|
288 * @param string $property
|
Chris@0
|
289 * The name of a property on the destination.
|
Chris@0
|
290 *
|
Chris@0
|
291 * @return mixed
|
Chris@0
|
292 * The destination value.
|
Chris@0
|
293 */
|
Chris@0
|
294 public function getDestinationProperty($property) {
|
Chris@0
|
295 return NestedArray::getValue($this->destination, explode(static::PROPERTY_SEPARATOR, $property));
|
Chris@0
|
296 }
|
Chris@0
|
297
|
Chris@0
|
298 /**
|
Chris@0
|
299 * Sets the Migrate ID mappings.
|
Chris@0
|
300 *
|
Chris@0
|
301 * @param array $id_map
|
Chris@0
|
302 * An array of mappings between source ID and destination ID.
|
Chris@0
|
303 */
|
Chris@0
|
304 public function setIdMap(array $id_map) {
|
Chris@0
|
305 $this->idMap = $id_map;
|
Chris@0
|
306 }
|
Chris@0
|
307
|
Chris@0
|
308 /**
|
Chris@0
|
309 * Retrieves the Migrate ID mappings.
|
Chris@0
|
310 *
|
Chris@0
|
311 * @return array
|
Chris@0
|
312 * An array of mapping between source and destination identifiers.
|
Chris@0
|
313 */
|
Chris@0
|
314 public function getIdMap() {
|
Chris@0
|
315 return $this->idMap;
|
Chris@0
|
316 }
|
Chris@0
|
317
|
Chris@0
|
318 /**
|
Chris@0
|
319 * Recalculates the hash for the row.
|
Chris@0
|
320 */
|
Chris@0
|
321 public function rehash() {
|
Chris@0
|
322 $this->idMap['original_hash'] = $this->idMap['hash'];
|
Chris@0
|
323 $this->idMap['hash'] = hash('sha256', serialize($this->source));
|
Chris@0
|
324 }
|
Chris@0
|
325
|
Chris@0
|
326 /**
|
Chris@0
|
327 * Checks whether the row has changed compared to the original ID map.
|
Chris@0
|
328 *
|
Chris@0
|
329 * @return bool
|
Chris@0
|
330 * TRUE if the row has changed, FALSE otherwise. If setIdMap() was not
|
Chris@0
|
331 * called, this always returns FALSE.
|
Chris@0
|
332 */
|
Chris@0
|
333 public function changed() {
|
Chris@0
|
334 return $this->idMap['original_hash'] != $this->idMap['hash'];
|
Chris@0
|
335 }
|
Chris@0
|
336
|
Chris@0
|
337 /**
|
Chris@0
|
338 * Returns if this row needs an update.
|
Chris@0
|
339 *
|
Chris@0
|
340 * @return bool
|
Chris@0
|
341 * TRUE if the row needs updating, FALSE otherwise.
|
Chris@0
|
342 */
|
Chris@0
|
343 public function needsUpdate() {
|
Chris@0
|
344 return $this->idMap['source_row_status'] == MigrateIdMapInterface::STATUS_NEEDS_UPDATE;
|
Chris@0
|
345 }
|
Chris@0
|
346
|
Chris@0
|
347 /**
|
Chris@0
|
348 * Returns the hash for the source values..
|
Chris@0
|
349 *
|
Chris@0
|
350 * @return mixed
|
Chris@0
|
351 * The hash of the source values.
|
Chris@0
|
352 */
|
Chris@0
|
353 public function getHash() {
|
Chris@0
|
354 return $this->idMap['hash'];
|
Chris@0
|
355 }
|
Chris@0
|
356
|
Chris@0
|
357 /**
|
Chris@0
|
358 * Reports whether this row is a stub.
|
Chris@0
|
359 *
|
Chris@0
|
360 * @return bool
|
Chris@0
|
361 * The current stub value.
|
Chris@0
|
362 */
|
Chris@0
|
363 public function isStub() {
|
Chris@0
|
364 return $this->isStub;
|
Chris@0
|
365 }
|
Chris@0
|
366
|
Chris@0
|
367 }
|