Issue #2069373 by swentel, yched: Race conditions on import if CUD on ConfigEntity A triggers changes in ConfigEntity B.
parent
e0d8e66bf4
commit
9e72283378
|
@ -34,6 +34,14 @@ abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface
|
|||
*/
|
||||
public $status = TRUE;
|
||||
|
||||
/**
|
||||
* Whether the config is being created, updated or deleted through the
|
||||
* import process.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $isSyncing = FALSE;
|
||||
|
||||
/**
|
||||
* Overrides Entity::__construct().
|
||||
*/
|
||||
|
@ -90,21 +98,21 @@ abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\Config\Entity\ConfigEntityInterface::enable().
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function enable() {
|
||||
return $this->setStatus(TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\Config\Entity\ConfigEntityInterface::disable().
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function disable() {
|
||||
return $this->setStatus(FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\Config\Entity\ConfigEntityInterface::setStatus().
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setStatus($status) {
|
||||
$this->status = (bool) $status;
|
||||
|
@ -112,14 +120,28 @@ abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\Config\Entity\ConfigEntityInterface::status().
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function status() {
|
||||
return !empty($this->status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides Entity::createDuplicate().
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setSyncing($syncing) {
|
||||
$this->isSyncing = $syncing;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isSyncing() {
|
||||
return $this->isSyncing;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createDuplicate() {
|
||||
$duplicate = parent::createDuplicate();
|
||||
|
|
|
@ -59,6 +59,14 @@ interface ConfigEntityInterface extends EntityInterface {
|
|||
*/
|
||||
public function setStatus($status);
|
||||
|
||||
/**
|
||||
* Sets the status of the isSyncing flag.
|
||||
*
|
||||
* @param bool $status
|
||||
* The status of the sync flag.
|
||||
*/
|
||||
public function setSyncing($status);
|
||||
|
||||
/**
|
||||
* Returns whether the configuration entity is enabled.
|
||||
*
|
||||
|
@ -75,6 +83,14 @@ interface ConfigEntityInterface extends EntityInterface {
|
|||
*/
|
||||
public function status();
|
||||
|
||||
/**
|
||||
* Returns whether the configuration entity is created, updated or deleted
|
||||
* through the import process.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isSyncing();
|
||||
|
||||
/**
|
||||
* Returns the value of a property.
|
||||
*
|
||||
|
|
|
@ -484,6 +484,7 @@ class ConfigStorageController extends EntityStorageControllerBase {
|
|||
*/
|
||||
public function importCreate($name, Config $new_config, Config $old_config) {
|
||||
$entity = $this->create($new_config->get());
|
||||
$entity->setSyncing(TRUE);
|
||||
$entity->save();
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -504,6 +505,7 @@ class ConfigStorageController extends EntityStorageControllerBase {
|
|||
public function importUpdate($name, Config $new_config, Config $old_config) {
|
||||
$id = static::getIDFromConfigName($name, $this->entityInfo['config_prefix']);
|
||||
$entity = $this->load($id);
|
||||
$entity->setSyncing(TRUE);
|
||||
$entity->original = clone $entity;
|
||||
|
||||
foreach ($old_config->get() as $property => $value) {
|
||||
|
@ -534,6 +536,7 @@ class ConfigStorageController extends EntityStorageControllerBase {
|
|||
public function importDelete($name, Config $new_config, Config $old_config) {
|
||||
$id = static::getIDFromConfigName($name, $this->entityInfo['config_prefix']);
|
||||
$entity = $this->load($id);
|
||||
$entity->setSyncing(TRUE);
|
||||
$entity->delete();
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -170,8 +170,9 @@ class NodeType extends ConfigEntityBase implements NodeTypeInterface {
|
|||
|
||||
entity_invoke_bundle_hook('create', 'node', $this->id());
|
||||
|
||||
// Unless disabled, automatically create a Body field for new node types.
|
||||
if ($this->get('create_body')) {
|
||||
// Create a body if the create_body property is true and we're not in
|
||||
// the syncing process.
|
||||
if ($this->get('create_body') && !$this->isSyncing()) {
|
||||
$label = $this->get('create_body_label');
|
||||
node_add_body_field($this, $label);
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ class NodeImportCreateTest extends DrupalUnitTestBase {
|
|||
// Check that the content type was created.
|
||||
$node_type = entity_load('node_type', $node_type_id);
|
||||
$this->assertTrue($node_type, 'Import node type from staging was created.');
|
||||
$this->assertFalse(field_info_instance('node', 'body', $node_type_id));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -138,6 +138,14 @@ class ViewUI implements ViewStorageInterface {
|
|||
'reorder-displays' => '\Drupal\views_ui\Form\Ajax\ReorderDisplays',
|
||||
);
|
||||
|
||||
/**
|
||||
* Whether the config is being created, updated or deleted through the
|
||||
* import process.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $isSyncing = FALSE;
|
||||
|
||||
/**
|
||||
* Constructs a View UI object.
|
||||
*
|
||||
|
@ -187,6 +195,20 @@ class ViewUI implements ViewStorageInterface {
|
|||
return '<div class="message">' . t("Click on an item to edit that item's details.") . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setSyncing($syncing) {
|
||||
$this->isSyncing = $syncing;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isSyncing() {
|
||||
return $this->isSyncing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic submit handler applicable to all 'standard' forms.
|
||||
*
|
||||
|
|
|
@ -45,7 +45,8 @@ class ViewUIObjectTest extends UnitTestCase {
|
|||
|
||||
// EntityInterface::isNew() is missing from the list of methods, because it
|
||||
// calls id(), which breaks the ->expect($this->once()) call. Call it later.
|
||||
if ($reflection_method->getName() != 'isNew') {
|
||||
// EntityInterface::isSyncing() is only called during syncing process.
|
||||
if ($reflection_method->getName() != 'isNew' && $reflection_method->getName() != 'isSyncing') {
|
||||
if (count($reflection_method->getParameters()) == 0) {
|
||||
$method_args[$reflection_method->getName()] = array();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue