annotate core/modules/migrate/src/Row.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents af1871eacc83
children
rev   line source
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@18 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@14 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@18 139 * This function directly retrieves a source property. It does not unescape
Chris@18 140 * '@' symbols. This is most useful in source plugins when you don't want to
Chris@18 141 * worry about escaping '@' symbols. If using this in a process plugin to
Chris@18 142 * retrieve a source property based on a configuration value, consider if the
Chris@18 143 * ::get() function might be more appropriate, to allow the migration to
Chris@18 144 * potentially specify a destination key as well.
Chris@18 145 *
Chris@0 146 * @param string $property
Chris@0 147 * A property on the source.
Chris@0 148 *
Chris@0 149 * @return mixed|null
Chris@0 150 * The found returned property or NULL if not found.
Chris@0 151 */
Chris@0 152 public function getSourceProperty($property) {
Chris@0 153 $return = NestedArray::getValue($this->source, explode(static::PROPERTY_SEPARATOR, $property), $key_exists);
Chris@0 154 if ($key_exists) {
Chris@0 155 return $return;
Chris@0 156 }
Chris@0 157 }
Chris@0 158
Chris@0 159 /**
Chris@0 160 * Returns the whole source array.
Chris@0 161 *
Chris@0 162 * @return array
Chris@0 163 * An array of source plugins.
Chris@0 164 */
Chris@0 165 public function getSource() {
Chris@0 166 return $this->source;
Chris@0 167 }
Chris@0 168
Chris@0 169 /**
Chris@0 170 * Sets a source property.
Chris@0 171 *
Chris@0 172 * This can only be called from the source plugin.
Chris@0 173 *
Chris@0 174 * @param string $property
Chris@0 175 * A property on the source.
Chris@0 176 * @param mixed $data
Chris@0 177 * The property value to set on the source.
Chris@0 178 *
Chris@0 179 * @throws \Exception
Chris@0 180 */
Chris@0 181 public function setSourceProperty($property, $data) {
Chris@0 182 if ($this->frozen) {
Chris@0 183 throw new \Exception("The source is frozen and can't be changed any more");
Chris@0 184 }
Chris@0 185 else {
Chris@0 186 NestedArray::setValue($this->source, explode(static::PROPERTY_SEPARATOR, $property), $data, TRUE);
Chris@0 187 }
Chris@0 188 }
Chris@0 189
Chris@0 190 /**
Chris@0 191 * Freezes the source.
Chris@0 192 *
Chris@0 193 * @return $this
Chris@0 194 */
Chris@0 195 public function freezeSource() {
Chris@0 196 $this->frozen = TRUE;
Chris@0 197 return $this;
Chris@0 198 }
Chris@0 199
Chris@0 200 /**
Chris@0 201 * Clones the row with an empty set of destination values.
Chris@0 202 *
Chris@0 203 * @return static
Chris@0 204 */
Chris@0 205 public function cloneWithoutDestination() {
Chris@0 206 return (new static($this->getSource(), $this->sourceIds, $this->isStub()))->freezeSource();
Chris@0 207 }
Chris@0 208
Chris@0 209 /**
Chris@0 210 * Tests if destination property exists.
Chris@0 211 *
Chris@0 212 * @param array|string $property
Chris@0 213 * An array of properties on the destination.
Chris@0 214 *
Chris@0 215 * @return bool
Chris@0 216 * TRUE if the destination property exists.
Chris@0 217 */
Chris@0 218 public function hasDestinationProperty($property) {
Chris@0 219 return NestedArray::keyExists($this->destination, explode(static::PROPERTY_SEPARATOR, $property));
Chris@0 220 }
Chris@0 221
Chris@0 222 /**
Chris@0 223 * Sets destination properties.
Chris@0 224 *
Chris@0 225 * @param string $property
Chris@0 226 * The name of the destination property.
Chris@0 227 * @param mixed $value
Chris@0 228 * The property value to set on the destination.
Chris@0 229 */
Chris@0 230 public function setDestinationProperty($property, $value) {
Chris@0 231 $this->rawDestination[$property] = $value;
Chris@0 232 NestedArray::setValue($this->destination, explode(static::PROPERTY_SEPARATOR, $property), $value, TRUE);
Chris@0 233 }
Chris@0 234
Chris@0 235 /**
Chris@0 236 * Removes destination property.
Chris@0 237 *
Chris@0 238 * @param string $property
Chris@0 239 * The name of the destination property.
Chris@0 240 */
Chris@0 241 public function removeDestinationProperty($property) {
Chris@0 242 unset($this->rawDestination[$property]);
Chris@0 243 NestedArray::unsetValue($this->destination, explode(static::PROPERTY_SEPARATOR, $property));
Chris@0 244 }
Chris@0 245
Chris@0 246 /**
Chris@0 247 * Sets a destination to be empty.
Chris@0 248 *
Chris@0 249 * @param string $property
Chris@0 250 * The destination property.
Chris@0 251 */
Chris@0 252 public function setEmptyDestinationProperty($property) {
Chris@0 253 $this->emptyDestinationProperties[] = $property;
Chris@0 254 }
Chris@0 255
Chris@0 256 /**
Chris@0 257 * Gets the empty destination properties.
Chris@0 258 *
Chris@0 259 * @return array
Chris@0 260 * An array of destination properties.
Chris@0 261 */
Chris@0 262 public function getEmptyDestinationProperties() {
Chris@0 263 return $this->emptyDestinationProperties;
Chris@0 264 }
Chris@0 265
Chris@0 266 /**
Chris@0 267 * Returns the whole destination array.
Chris@0 268 *
Chris@0 269 * @return array
Chris@0 270 * An array of destination values.
Chris@0 271 */
Chris@0 272 public function getDestination() {
Chris@0 273 return $this->destination;
Chris@0 274 }
Chris@0 275
Chris@0 276 /**
Chris@0 277 * Returns the raw destination. Rarely necessary.
Chris@0 278 *
Chris@0 279 * For example calling setDestination('foo/bar', 'baz') results in
Chris@0 280 * @code
Chris@0 281 * $this->destination['foo']['bar'] = 'baz';
Chris@0 282 * $this->rawDestination['foo/bar'] = 'baz';
Chris@0 283 * @endcode
Chris@0 284 *
Chris@0 285 * @return array
Chris@0 286 * The raw destination values.
Chris@0 287 */
Chris@0 288 public function getRawDestination() {
Chris@0 289 return $this->rawDestination;
Chris@0 290 }
Chris@0 291
Chris@0 292 /**
Chris@0 293 * Returns the value of a destination property.
Chris@0 294 *
Chris@18 295 * This function directly returns a destination property. The property name
Chris@18 296 * should not begin with an @ symbol. This is most useful in a destination
Chris@18 297 * plugin.
Chris@18 298 *
Chris@0 299 * @param string $property
Chris@0 300 * The name of a property on the destination.
Chris@0 301 *
Chris@0 302 * @return mixed
Chris@0 303 * The destination value.
Chris@0 304 */
Chris@0 305 public function getDestinationProperty($property) {
Chris@0 306 return NestedArray::getValue($this->destination, explode(static::PROPERTY_SEPARATOR, $property));
Chris@0 307 }
Chris@0 308
Chris@0 309 /**
Chris@18 310 * Retrieve a source or destination property.
Chris@18 311 *
Chris@18 312 * If the property key begins with '@' return a destination property,
Chris@18 313 * otherwise return a source property. the '@' symbol itself can be escaped
Chris@18 314 * as '@@'. Returns NULL if property is not found. Useful in process plugins
Chris@18 315 * to retrieve a row property specified in a configuration key which may be
Chris@18 316 * either a source or destination property prefixed with an '@'.
Chris@18 317 *
Chris@18 318 * @param string $property
Chris@18 319 * The property to get.
Chris@18 320 *
Chris@18 321 * @return mixed|null
Chris@18 322 * The requested property.
Chris@18 323 */
Chris@18 324 public function get($property) {
Chris@18 325 $values = $this->getMultiple([$property]);
Chris@18 326 return reset($values);
Chris@18 327 }
Chris@18 328
Chris@18 329 /**
Chris@18 330 * Retrieve multiple source and destination properties at once.
Chris@18 331 *
Chris@18 332 * @param string[] $properties
Chris@18 333 * An array of values to retrieve, with destination values prefixed with @.
Chris@18 334 *
Chris@18 335 * @return array
Chris@18 336 * An array of property values, keyed by property name.
Chris@18 337 */
Chris@18 338 public function getMultiple(array $properties) {
Chris@18 339 $return = [];
Chris@18 340 foreach ($properties as $orig_property) {
Chris@18 341 $property = $orig_property;
Chris@18 342 $is_source = TRUE;
Chris@18 343 if ($property[0] == '@') {
Chris@18 344 $property = preg_replace_callback('/^(@?)((?:@@)*)([^@]|$)/', function ($matches) use (&$is_source) {
Chris@18 345 // If there are an odd number of @ in the beginning, it's a
Chris@18 346 // destination.
Chris@18 347 $is_source = empty($matches[1]);
Chris@18 348 // Remove the possible escaping and do not lose the terminating
Chris@18 349 // non-@ either.
Chris@18 350 return str_replace('@@', '@', $matches[2]) . $matches[3];
Chris@18 351 }, $property);
Chris@18 352 }
Chris@18 353 if ($is_source) {
Chris@18 354 $return[$orig_property] = $this->getSourceProperty($property);
Chris@18 355 }
Chris@18 356 else {
Chris@18 357 $return[$orig_property] = $this->getDestinationProperty($property);
Chris@18 358 }
Chris@18 359 }
Chris@18 360 return $return;
Chris@18 361 }
Chris@18 362
Chris@18 363 /**
Chris@0 364 * Sets the Migrate ID mappings.
Chris@0 365 *
Chris@0 366 * @param array $id_map
Chris@0 367 * An array of mappings between source ID and destination ID.
Chris@0 368 */
Chris@0 369 public function setIdMap(array $id_map) {
Chris@0 370 $this->idMap = $id_map;
Chris@0 371 }
Chris@0 372
Chris@0 373 /**
Chris@0 374 * Retrieves the Migrate ID mappings.
Chris@0 375 *
Chris@0 376 * @return array
Chris@0 377 * An array of mapping between source and destination identifiers.
Chris@0 378 */
Chris@0 379 public function getIdMap() {
Chris@0 380 return $this->idMap;
Chris@0 381 }
Chris@0 382
Chris@0 383 /**
Chris@0 384 * Recalculates the hash for the row.
Chris@0 385 */
Chris@0 386 public function rehash() {
Chris@0 387 $this->idMap['original_hash'] = $this->idMap['hash'];
Chris@0 388 $this->idMap['hash'] = hash('sha256', serialize($this->source));
Chris@0 389 }
Chris@0 390
Chris@0 391 /**
Chris@0 392 * Checks whether the row has changed compared to the original ID map.
Chris@0 393 *
Chris@0 394 * @return bool
Chris@0 395 * TRUE if the row has changed, FALSE otherwise. If setIdMap() was not
Chris@0 396 * called, this always returns FALSE.
Chris@0 397 */
Chris@0 398 public function changed() {
Chris@0 399 return $this->idMap['original_hash'] != $this->idMap['hash'];
Chris@0 400 }
Chris@0 401
Chris@0 402 /**
Chris@0 403 * Returns if this row needs an update.
Chris@0 404 *
Chris@0 405 * @return bool
Chris@0 406 * TRUE if the row needs updating, FALSE otherwise.
Chris@0 407 */
Chris@0 408 public function needsUpdate() {
Chris@0 409 return $this->idMap['source_row_status'] == MigrateIdMapInterface::STATUS_NEEDS_UPDATE;
Chris@0 410 }
Chris@0 411
Chris@0 412 /**
Chris@0 413 * Returns the hash for the source values..
Chris@0 414 *
Chris@0 415 * @return mixed
Chris@0 416 * The hash of the source values.
Chris@0 417 */
Chris@0 418 public function getHash() {
Chris@0 419 return $this->idMap['hash'];
Chris@0 420 }
Chris@0 421
Chris@0 422 /**
Chris@0 423 * Reports whether this row is a stub.
Chris@0 424 *
Chris@0 425 * @return bool
Chris@0 426 * The current stub value.
Chris@0 427 */
Chris@0 428 public function isStub() {
Chris@0 429 return $this->isStub;
Chris@0 430 }
Chris@0 431
Chris@0 432 }