ConfigEntityBase.php 6.98 KB
Newer Older
1 2 3 4
<?php

/**
 * @file
5
 * Definition of Drupal\Core\Config\Entity\ConfigEntityBase.
6 7
 */

8
namespace Drupal\Core\Config\Entity;
9

10
use Drupal\Core\Entity\Entity;
11 12
use Drupal\Core\Entity\EntityStorageControllerInterface;
use Drupal\Core\Config\ConfigDuplicateUUIDException;
13 14

/**
15
 * Defines a base configuration entity class.
16
 */
17
abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface {
18 19

  /**
20
   * The original ID of the configuration entity.
21
   *
22 23
   * The ID of a configuration entity is a unique string (machine name). When a
   * configuration entity is updated and its machine name is renamed, the
24 25 26 27
   * original ID needs to be known.
   *
   * @var string
   */
28
  protected $originalId;
29

30 31 32 33 34 35 36 37 38 39 40 41 42 43
  /**
   * The name of the property that is used to store plugin configuration.
   *
   * This is needed when the entity utilizes a PluginBag, to dictate where the
   * plugin configuration should be stored.
   *
   * @todo Move this to a trait along with
   *   \Drupal\Core\Config\Entity\EntityWithPluginBagInterface, and give it a
   *   default value of 'configuration'.
   *
   * @var string
   */
  protected $pluginConfigKey;

44 45 46 47 48
  /**
   * The enabled/disabled status of the configuration entity.
   *
   * @var bool
   */
49
  public $status = TRUE;
50

51 52 53 54 55 56 57
  /**
   * The UUID for this entity.
   *
   * @var string
   */
  public $uuid;

58 59 60 61 62 63 64 65
  /**
   * Whether the config is being created, updated or deleted through the
   * import process.
   *
   * @var bool
   */
  private $isSyncing = FALSE;

66 67 68
  /**
   * Overrides Entity::__construct().
   */
69
  public function __construct(array $values, $entity_type) {
70 71 72
    parent::__construct($values, $entity_type);

    // Backup the original ID, if any.
73 74 75
    // Configuration entity IDs are strings, and '0' is a valid ID.
    $original_id = $this->id();
    if ($original_id !== NULL && $original_id !== '') {
76
      $this->setOriginalId($original_id);
77 78 79 80
    }
  }

  /**
81
   * {@inheritdoc}
82
   */
83 84
  public function getOriginalId() {
    return $this->originalId;
85 86 87
  }

  /**
88
   * {@inheritdoc}
89
   */
90 91 92 93
  public function setOriginalId($id) {
    $this->originalId = $id;

    return $this;
94 95 96
  }

  /**
97
   * Overrides Entity::isNew().
98
   *
99 100 101
   * EntityInterface::enforceIsNew() is only supported for newly created
   * configuration entities but has no effect after saving, since each
   * configuration entity is unique.
102
   */
103
  public function isNew() {
104
    return !empty($this->enforceIsNew);
105 106 107
  }

  /**
108
   * {@inheritdoc}
109
   */
110
  public function get($property_name) {
111 112 113 114
    return isset($this->{$property_name}) ? $this->{$property_name} : NULL;
  }

  /**
115
   * {@inheritdoc}
116
   */
117
  public function set($property_name, $value) {
118 119 120 121 122 123 124 125 126
    // @todo When \Drupal\Core\Config\Entity\EntityWithPluginBagInterface moves
    //   to a trait, switch to class_uses() instead.
    if ($this instanceof EntityWithPluginBagInterface) {
      if ($property_name == $this->pluginConfigKey) {
        // If external code updates the settings, pass it along to the plugin.
        $this->getPluginBag()->setConfiguration($value);
      }
    }

127 128 129
    $this->{$property_name} = $value;
  }

130
  /**
131
   * {@inheritdoc}
132 133
   */
  public function enable() {
134
    return $this->setStatus(TRUE);
135 136 137
  }

  /**
138
   * {@inheritdoc}
139 140
   */
  public function disable() {
141 142 143 144
    return $this->setStatus(FALSE);
  }

  /**
145
   * {@inheritdoc}
146
   */
147 148
  public function setStatus($status) {
    $this->status = (bool) $status;
149 150 151 152
    return $this;
  }

  /**
153
   * {@inheritdoc}
154 155 156 157 158
   */
  public function status() {
    return !empty($this->status);
  }

159
  /**
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
   * {@inheritdoc}
   */
  public function setSyncing($syncing) {
    $this->isSyncing = $syncing;
  }

  /**
   * {@inheritdoc}
   */
  public function isSyncing() {
    return $this->isSyncing;
  }

  /**
   * {@inheritdoc}
175 176
   */
  public function createDuplicate() {
177 178 179 180 181 182
    $duplicate = clone $this;
    $duplicate->set($this->getEntityType()->getKey('id'), NULL);

    // @todo Inject the UUID service into the Entity class once possible.
    $duplicate->set('uuid', \Drupal::service('uuid')->generate());

183
    // Prevent the new duplicate from being misinterpreted as a rename.
184
    $duplicate->setOriginalId(NULL);
185 186 187
    return $duplicate;
  }

188
  /**
189
   * Helper callback for uasort() to sort configuration entities by weight and label.
190 191 192 193 194 195 196 197 198 199 200
   */
  public static function sort($a, $b) {
    $a_weight = isset($a->weight) ? $a->weight : 0;
    $b_weight = isset($b->weight) ? $b->weight : 0;
    if ($a_weight == $b_weight) {
      $a_label = $a->label();
      $b_label = $b->label();
      return strnatcasecmp($a_label, $b_label);
    }
    return ($a_weight < $b_weight) ? -1 : 1;
  }
201 202

  /**
203
   * {@inheritdoc}
204 205 206 207 208 209 210 211 212 213 214 215
   */
  public function getExportProperties() {
    // Configuration objects do not have a schema. Extract all key names from
    // class properties.
    $class_info = new \ReflectionClass($this);
    $properties = array();
    foreach ($class_info->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) {
      $name = $property->getName();
      $properties[$name] = $this->get($name);
    }
    return $properties;
  }
216 217 218 219 220 221 222

  /**
   * {@inheritdoc}
   */
  public function preSave(EntityStorageControllerInterface $storage_controller) {
    parent::preSave($storage_controller);

223 224 225 226 227 228 229 230
    // @todo When \Drupal\Core\Config\Entity\EntityWithPluginBagInterface moves
    //   to a trait, switch to class_uses() instead.
    if ($this instanceof EntityWithPluginBagInterface) {
      // Any changes to the plugin configuration must be saved to the entity's
      // copy as well.
      $this->set($this->pluginConfigKey, $this->getPluginBag()->getConfiguration());
    }

231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
    // Ensure this entity's UUID does not exist with a different ID, regardless
    // of whether it's new or updated.
    $matching_entities = $storage_controller->getQuery()
      ->condition('uuid', $this->uuid())
      ->execute();
    $matched_entity = reset($matching_entities);
    if (!empty($matched_entity) && ($matched_entity != $this->id())) {
      throw new ConfigDuplicateUUIDException(format_string('Attempt to save a configuration entity %id with UUID %uuid when this UUID is already used for %matched', array('%id' => $this->id(), '%uuid' => $this->uuid(), '%matched' => $matched_entity)));
    }

    if (!$this->isNew()) {
      $original = $storage_controller->loadUnchanged($this->id());
      // Ensure that the UUID cannot be changed for an existing entity.
      if ($original && ($original->uuid() != $this->uuid())) {
        throw new ConfigDuplicateUUIDException(format_string('Attempt to save a configuration entity %id with UUID %uuid when this entity already exists with UUID %original_uuid', array('%id' => $this->id(), '%uuid' => $this->uuid(), '%original_uuid' => $original->uuid())));
      }
    }
  }

250 251 252
  /**
   * {@inheritdoc}
   */
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
  public function urlInfo($rel = 'edit-form') {
    return parent::urlInfo($rel);
  }

  /**
   * {@inheritdoc}
   */
  public function getSystemPath($rel = 'edit-form') {
    return parent::getSystemPath($rel);
  }

  /**
   * {@inheritdoc}
   */
  public function url($rel = 'edit-form', $options = array()) {
    return parent::url($rel, $options);
269 270
  }

271
}