Version 1
[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    * Constructs a \Drupal\Migrate\Row object.
82    *
83    * @param array $values
84    *   An array of values to add as properties on the object.
85    * @param array $source_ids
86    *   An array containing the IDs of the source using the keys as the field
87    *   names.
88    * @param bool $is_stub
89    *   TRUE if the row being created is a stub.
90    *
91    * @throws \InvalidArgumentException
92    *   Thrown when a source ID property does not exist.
93    */
94   public function __construct(array $values = [], array $source_ids = [], $is_stub = FALSE) {
95     $this->source = $values;
96     $this->sourceIds = $source_ids;
97     $this->isStub = $is_stub;
98     foreach (array_keys($source_ids) as $id) {
99       if (!$this->hasSourceProperty($id)) {
100         throw new \InvalidArgumentException("$id has no value");
101       }
102     }
103   }
104
105   /**
106    * Retrieves the values of the source identifiers.
107    *
108    * @return array
109    *   An array containing the values of the source identifiers. Returns values
110    *   in the same order as defined in $this->sourceIds.
111    */
112   public function getSourceIdValues() {
113     return array_merge($this->sourceIds, array_intersect_key($this->source, $this->sourceIds));
114   }
115
116   /**
117    * Determines whether a source has a property.
118    *
119    * @param string $property
120    *   A property on the source.
121    *
122    * @return bool
123    *   TRUE if the source has property; FALSE otherwise.
124    */
125   public function hasSourceProperty($property) {
126     return NestedArray::keyExists($this->source, explode(static::PROPERTY_SEPARATOR, $property));
127   }
128
129   /**
130    * Retrieves a source property.
131    *
132    * @param string $property
133    *   A property on the source.
134    *
135    * @return mixed|null
136    *   The found returned property or NULL if not found.
137    */
138   public function getSourceProperty($property) {
139     $return = NestedArray::getValue($this->source, explode(static::PROPERTY_SEPARATOR, $property), $key_exists);
140     if ($key_exists) {
141       return $return;
142     }
143   }
144
145   /**
146    * Returns the whole source array.
147    *
148    * @return array
149    *   An array of source plugins.
150    */
151   public function getSource() {
152     return $this->source;
153   }
154
155   /**
156    * Sets a source property.
157    *
158    * This can only be called from the source plugin.
159    *
160    * @param string $property
161    *   A property on the source.
162    * @param mixed $data
163    *   The property value to set on the source.
164    *
165    * @throws \Exception
166    */
167   public function setSourceProperty($property, $data) {
168     if ($this->frozen) {
169       throw new \Exception("The source is frozen and can't be changed any more");
170     }
171     else {
172       NestedArray::setValue($this->source, explode(static::PROPERTY_SEPARATOR, $property), $data, TRUE);
173     }
174   }
175
176   /**
177    * Freezes the source.
178    *
179    * @return $this
180    */
181   public function freezeSource() {
182     $this->frozen = TRUE;
183     return $this;
184   }
185
186   /**
187    * Clones the row with an empty set of destination values.
188    *
189    * @return static
190    */
191   public function cloneWithoutDestination() {
192     return (new static($this->getSource(), $this->sourceIds, $this->isStub()))->freezeSource();
193   }
194
195   /**
196    * Tests if destination property exists.
197    *
198    * @param array|string $property
199    *   An array of properties on the destination.
200    *
201    * @return bool
202    *   TRUE if the destination property exists.
203    */
204   public function hasDestinationProperty($property) {
205     return NestedArray::keyExists($this->destination, explode(static::PROPERTY_SEPARATOR, $property));
206   }
207
208   /**
209    * Sets destination properties.
210    *
211    * @param string $property
212    *   The name of the destination property.
213    * @param mixed $value
214    *   The property value to set on the destination.
215    */
216   public function setDestinationProperty($property, $value) {
217     $this->rawDestination[$property] = $value;
218     NestedArray::setValue($this->destination, explode(static::PROPERTY_SEPARATOR, $property), $value, TRUE);
219   }
220
221   /**
222    * Removes destination property.
223    *
224    * @param string $property
225    *   The name of the destination property.
226    */
227   public function removeDestinationProperty($property) {
228     unset($this->rawDestination[$property]);
229     NestedArray::unsetValue($this->destination, explode(static::PROPERTY_SEPARATOR, $property));
230   }
231
232   /**
233    * Returns the whole destination array.
234    *
235    * @return array
236    *   An array of destination values.
237    */
238   public function getDestination() {
239     return $this->destination;
240   }
241
242   /**
243    * Returns the raw destination. Rarely necessary.
244    *
245    * For example calling setDestination('foo/bar', 'baz') results in
246    * @code
247    * $this->destination['foo']['bar'] = 'baz';
248    * $this->rawDestination['foo/bar'] = 'baz';
249    * @endcode
250    *
251    * @return array
252    *   The raw destination values.
253    */
254   public function getRawDestination() {
255     return $this->rawDestination;
256   }
257
258   /**
259    * Returns the value of a destination property.
260    *
261    * @param string $property
262    *   The name of a property on the destination.
263    *
264    * @return mixed
265    *   The destination value.
266    */
267   public function getDestinationProperty($property) {
268     return NestedArray::getValue($this->destination, explode(static::PROPERTY_SEPARATOR, $property));
269   }
270
271   /**
272    * Sets the Migrate ID mappings.
273    *
274    * @param array $id_map
275    *   An array of mappings between source ID and destination ID.
276    */
277   public function setIdMap(array $id_map) {
278     $this->idMap = $id_map;
279   }
280
281   /**
282    * Retrieves the Migrate ID mappings.
283    *
284    * @return array
285    *   An array of mapping between source and destination identifiers.
286    */
287   public function getIdMap() {
288     return $this->idMap;
289   }
290
291   /**
292    * Recalculates the hash for the row.
293    */
294   public function rehash() {
295     $this->idMap['original_hash'] = $this->idMap['hash'];
296     $this->idMap['hash'] = hash('sha256', serialize($this->source));
297   }
298
299   /**
300    * Checks whether the row has changed compared to the original ID map.
301    *
302    * @return bool
303    *   TRUE if the row has changed, FALSE otherwise. If setIdMap() was not
304    *   called, this always returns FALSE.
305    */
306   public function changed() {
307     return $this->idMap['original_hash'] != $this->idMap['hash'];
308   }
309
310   /**
311    * Returns if this row needs an update.
312    *
313    * @return bool
314    *   TRUE if the row needs updating, FALSE otherwise.
315    */
316   public function needsUpdate() {
317     return $this->idMap['source_row_status'] == MigrateIdMapInterface::STATUS_NEEDS_UPDATE;
318   }
319
320   /**
321    * Returns the hash for the source values..
322    *
323    * @return mixed
324    *   The hash of the source values.
325    */
326   public function getHash() {
327     return $this->idMap['hash'];
328   }
329
330   /**
331    * Reports whether this row is a stub.
332    *
333    * @return bool
334    *   The current stub value.
335    */
336   public function isStub() {
337     return $this->isStub;
338   }
339
340 }