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