Issue #2226027 by tim.plunkett: ConfigEntityBase::preSave() tries to load the original entity but instead loads itself.

8.0.x
catch 2014-03-30 15:02:28 +02:00
parent 669b898b86
commit 979bb625ce
12 changed files with 793 additions and 26 deletions

View File

@ -278,8 +278,9 @@ abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface
throw new ConfigDuplicateUUIDException(String::format('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 entity is not new, load the original entity for comparison.
if (!$this->isNew()) {
$original = $storage->loadUnchanged($this->id());
$original = $storage->loadUnchanged($this->getOriginalId());
// Ensure that the UUID cannot be changed for an existing entity.
if ($original && ($original->uuid() != $this->uuid())) {
throw new ConfigDuplicateUUIDException(String::format('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())));

View File

@ -18,6 +18,7 @@ use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityStorageException;
use Drupal\Core\Entity\Query\QueryFactory;
use Drupal\Component\Uuid\UuidInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@ -65,6 +66,13 @@ class ConfigEntityStorage extends EntityStorageBase implements ConfigEntityStora
*/
protected $configStorage;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* Constructs a ConfigEntityStorage object.
*
@ -76,8 +84,10 @@ class ConfigEntityStorage extends EntityStorageBase implements ConfigEntityStora
* The config storage service.
* @param \Drupal\Component\Uuid\UuidInterface $uuid_service
* The UUID service.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
*/
public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, StorageInterface $config_storage, UuidInterface $uuid_service) {
public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, StorageInterface $config_storage, UuidInterface $uuid_service, LanguageManagerInterface $language_manager) {
parent::__construct($entity_type);
$this->idKey = $this->entityType->getKey('id');
@ -86,6 +96,7 @@ class ConfigEntityStorage extends EntityStorageBase implements ConfigEntityStora
$this->configFactory = $config_factory;
$this->configStorage = $config_storage;
$this->uuidService = $uuid_service;
$this->languageManager = $language_manager;
}
/**
@ -96,7 +107,8 @@ class ConfigEntityStorage extends EntityStorageBase implements ConfigEntityStora
$entity_type,
$container->get('config.factory'),
$container->get('config.storage'),
$container->get('uuid')
$container->get('uuid'),
$container->get('language_manager')
);
}
@ -228,7 +240,7 @@ class ConfigEntityStorage extends EntityStorageBase implements ConfigEntityStora
$class::preCreate($this, $values);
// Set default language to site default if not provided.
$values += array('langcode' => language_default()->id);
$values += array('langcode' => $this->languageManager->getDefaultLanguage()->id);
$entity = new $class($values, $this->entityTypeId);
// Mark this entity as new, so isNew() returns TRUE. This does not check
@ -331,9 +343,6 @@ class ConfigEntityStorage extends EntityStorageBase implements ConfigEntityStora
$config->save();
$entity->postSave($this, TRUE);
$this->invokeHook('update', $entity);
// Immediately update the original ID.
$entity->setOriginalId($entity->id());
}
else {
$return = SAVED_NEW;
@ -343,6 +352,11 @@ class ConfigEntityStorage extends EntityStorageBase implements ConfigEntityStora
$this->invokeHook('insert', $entity);
}
// After saving, this is now the "original entity", and subsequent saves
// will be updates instead of inserts, and updates must always be able to
// correctly identify the original entity.
$entity->setOriginalId($entity->id());
unset($entity->original);
return $return;

View File

@ -314,7 +314,9 @@ abstract class Entity extends DependencySerialization implements EntityInterface
public function createDuplicate() {
$duplicate = clone $this;
$entity_type = $this->getEntityType();
// Reset the entity ID and indicate that this is a new entity.
$duplicate->{$entity_type->getKey('id')} = NULL;
$duplicate->enforceIsNew();
// Check if the entity type supports UUIDs and generate a new one if so.
if ($entity_type->hasKey('uuid')) {

View File

@ -105,6 +105,18 @@ class Breakpoint extends ConfigEntityBase implements BreakpointInterface {
*/
public $multipliers = array();
/**
* {@inheritdoc}
*/
public function id() {
// If no ID is specified, build one from the properties that uniquely define
// this breakpoint.
if (!isset($this->id)) {
$this->id = $this->sourceType . '.' . $this->source . '.' . $this->name;
}
return $this->id;
}
/**
* Overrides Drupal\config\ConfigEntityBase::save().
*/
@ -114,13 +126,6 @@ class Breakpoint extends ConfigEntityBase implements BreakpointInterface {
throw new InvalidBreakpointException('Invalid data detected.');
}
// Build an id if none is set.
// Since a particular name can be used by multiple theme/modules we need
// to make a unique id.
if (empty($this->id)) {
$this->id = $this->sourceType . '.' . $this->source . '.' . $this->name;
}
// Set the label if none is set.
if (empty($this->label)) {
$this->label = $this->name;

View File

@ -104,10 +104,19 @@ class BreakpointGroup extends ConfigEntityBase implements BreakpointGroupInterfa
if (!$this->isValid()) {
throw new InvalidBreakpointException('Invalid data detected.');
}
if (empty($this->id)) {
parent::save();
}
/**
* {@inheritdoc}
*/
public function id() {
// If no ID is specified, build one from the properties that uniquely define
// this breakpoint group.
if (!isset($this->id)) {
$this->id = $this->sourceType . '.' . $this->source . '.' . $this->name;
}
parent::save();
return $this->id;
}
/**

View File

@ -46,7 +46,7 @@ class BreakpointAPITest extends BreakpointTestBase {
$this->assertTrue($exception, 'breakpoint_config_name: An exception is thrown when an invalid sourceType is entered.');
// Try an invalid source.
$breakpoint->id = '';
$breakpoint = $breakpoint->createDuplicate();
$breakpoint->sourceType = Breakpoint::SOURCE_TYPE_USER_DEFINED;
$breakpoint->source = 'custom*_module source';
@ -60,7 +60,7 @@ class BreakpointAPITest extends BreakpointTestBase {
$this->assertTrue($exception, 'breakpoint_config_name: An exception is thrown when an invalid source is entered.');
// Try an invalid name (make sure there is at least once capital letter).
$breakpoint->id = '';
$breakpoint = $breakpoint->createDuplicate();
$breakpoint->source = 'custom_module';
$breakpoint->name = drupal_ucfirst($this->randomName());
@ -74,7 +74,7 @@ class BreakpointAPITest extends BreakpointTestBase {
$this->assertTrue($exception, 'breakpoint_config_name: An exception is thrown when an invalid name is entered.');
// Try a valid breakpoint.
$breakpoint->id = '';
$breakpoint = $breakpoint->createDuplicate();
$breakpoint->name = drupal_strtolower($this->randomName());
$breakpoint->mediaQuery = 'all';

View File

@ -49,6 +49,7 @@ class BreakpointGroupAPITest extends BreakpointGroupTestBase {
$this->assertTrue($exception, 'An exception is thrown when an invalid sourceType is entered.');
// Try an invalid source.
$breakpoint_group = $breakpoint_group->createDuplicate();
$breakpoint_group->name = '';
$breakpoint_group->sourceType = Breakpoint::SOURCE_TYPE_USER_DEFINED;
$breakpoint_group->source = 'custom*_module source';
@ -63,6 +64,7 @@ class BreakpointGroupAPITest extends BreakpointGroupTestBase {
$this->assertTrue($exception, 'An exception is thrown when an invalid source is entered.');
// Try a valid breakpoint_group.
$breakpoint_group = $breakpoint_group->createDuplicate();
$breakpoint_group->name = 'test';
$breakpoint_group->source = 'custom_module_source';

View File

@ -13,6 +13,7 @@ use Drupal\Core\Config\Entity\ConfigEntityStorage;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\Query\QueryFactory;
use Drupal\Core\Language\LanguageManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\StorageInterface;
@ -56,6 +57,8 @@ class FieldConfigStorage extends ConfigEntityStorage {
* The config storage service.
* @param \Drupal\Component\Uuid\UuidInterface $uuid_service
* The UUID service.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
* @param \Drupal\Core\Extension\ModuleHandler $module_handler
@ -63,8 +66,8 @@ class FieldConfigStorage extends ConfigEntityStorage {
* @param \Drupal\Core\KeyValueStore\StateInterface $state
* The state key value store.
*/
public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, StorageInterface $config_storage, UuidInterface $uuid_service, EntityManagerInterface $entity_manager, ModuleHandler $module_handler, StateInterface $state) {
parent::__construct($entity_type, $config_factory, $config_storage, $uuid_service);
public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, StorageInterface $config_storage, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, EntityManagerInterface $entity_manager, ModuleHandler $module_handler, StateInterface $state) {
parent::__construct($entity_type, $config_factory, $config_storage, $uuid_service, $language_manager);
$this->entityManager = $entity_manager;
$this->moduleHandler = $module_handler;
$this->state = $state;
@ -79,6 +82,7 @@ class FieldConfigStorage extends ConfigEntityStorage {
$container->get('config.factory'),
$container->get('config.storage'),
$container->get('uuid'),
$container->get('language_manager'),
$container->get('entity.manager'),
$container->get('module_handler'),
$container->get('state')

View File

@ -12,6 +12,7 @@ use Drupal\Core\Config\Entity\ConfigEntityStorage;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\Query\QueryFactory;
use Drupal\Core\Language\LanguageManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Component\Uuid\UuidInterface;
@ -54,13 +55,15 @@ class FieldInstanceConfigStorage extends ConfigEntityStorage {
* The config storage service.
* @param \Drupal\Component\Uuid\UuidInterface $uuid_service
* The UUID service.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
* @param \Drupal\Core\KeyValueStore\StateInterface $state
* The state key value store.
*/
public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, StorageInterface $config_storage, UuidInterface $uuid_service, EntityManagerInterface $entity_manager, StateInterface $state) {
parent::__construct($entity_type, $config_factory, $config_storage, $uuid_service);
public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, StorageInterface $config_storage, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, EntityManagerInterface $entity_manager, StateInterface $state) {
parent::__construct($entity_type, $config_factory, $config_storage, $uuid_service, $language_manager);
$this->entityManager = $entity_manager;
$this->state = $state;
}
@ -74,6 +77,7 @@ class FieldInstanceConfigStorage extends ConfigEntityStorage {
$container->get('config.factory'),
$container->get('config.storage'),
$container->get('uuid'),
$container->get('language_manager'),
$container->get('entity.manager'),
$container->get('state')
);

View File

@ -41,9 +41,10 @@ class FilterCrudTest extends DrupalUnitTestBase {
$this->verifyTextFormat($format);
// Add another text format specifying all possible properties.
$format = entity_create('filter_format');
$format->format = 'custom_format';
$format->name = 'Custom format';
$format = entity_create('filter_format', array(
'format' => 'custom_format',
'name' => 'Custom format',
));
$format->setFilterConfig('filter_url', array(
'status' => 1,
'settings' => array(

View File

@ -369,6 +369,8 @@ class ConfigEntityBaseUnitTest extends UnitTestCase {
$duplicate = $this->entity->createDuplicate();
$this->assertInstanceOf('\Drupal\Core\Entity\Entity', $duplicate);
$this->assertNotSame($this->entity, $duplicate);
$this->assertFalse($this->entity->isNew());
$this->assertTrue($duplicate->isNew());
$this->assertNull($duplicate->id());
$this->assertNull($duplicate->getOriginalId());
$this->assertNotEquals($this->entity->uuid(), $duplicate->uuid());

View File

@ -0,0 +1,723 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Config\Entity\ConfigEntityStorageTest.
*/
namespace Drupal\Tests\Core\Config\Entity {
use Drupal\Core\Config\Entity\ConfigEntityInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Language\Language;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\Core\Config\Entity\ConfigEntityStorage
*
* @group Drupal
*/
class ConfigEntityStorageTest extends UnitTestCase {
/**
* The entity type.
*
* @var \Drupal\Core\Entity\EntityTypeInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $entityType;
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $moduleHandler;
/**
* The UUID service.
*
* @var \Drupal\Component\Uuid\UuidInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $uuidService;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $languageManager;
/**
* The config storage controller.
*
* @var \Drupal\Core\Config\Entity\ConfigEntityStorage
*/
protected $entityStorage;
/**
* The config factory service.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $configFactory;
/**
* The config storage service.
*
* @var \Drupal\Core\Config\StorageInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $configStorage;
/**
* The entity query.
*
* @var \Drupal\Core\Entity\Query\QueryInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $entityQuery;
/**
* {@inheritdoc}
*/
public static function getInfo() {
return array(
'name' => 'ConfigEntityStorage unit test',
'description' => 'Tests \Drupal\Core\Config\Entity\ConfigEntityStorage',
'group' => 'Configuration',
);
}
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->entityType = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
$this->entityType->expects($this->any())
->method('getKey')
->will($this->returnValueMap(array(
array('id', 'id'),
array('uuid', 'uuid'),
)));
$this->entityType->expects($this->any())
->method('id')
->will($this->returnValue('test_entity_type'));
$this->entityType->expects($this->any())
->method('getConfigPrefix')
->will($this->returnValue('the_config_prefix'));
$this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
$this->uuidService = $this->getMock('Drupal\Component\Uuid\UuidInterface');
$this->languageManager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
$this->languageManager->expects($this->any())
->method('getDefaultLanguage')
->will($this->returnValue(new Language(array('langcode' => 'en'))));
$this->configStorage = $this->getConfigStorageStub(array());
$this->configFactory = $this->getMock('Drupal\Core\Config\ConfigFactoryInterface');
$this->entityQuery = $this->getMock('Drupal\Core\Entity\Query\QueryInterface');
$this->entityStorage = $this->getMockBuilder('Drupal\Core\Config\Entity\ConfigEntityStorage')
->setConstructorArgs(array($this->entityType, $this->configFactory, $this->configStorage, $this->uuidService, $this->languageManager))
->setMethods(array('getQuery'))
->getMock();
$this->entityStorage->expects($this->any())
->method('getQuery')
->will($this->returnValue($this->entityQuery));
$this->entityStorage->setModuleHandler($this->moduleHandler);
}
/**
* @covers ::create()
*/
public function testCreateWithPredefinedUuid() {
$this->entityType->expects($this->atLeastOnce())
->method('getClass')
->will($this->returnValue(get_class($this->getMockEntity())));
$this->moduleHandler->expects($this->at(0))
->method('invokeAll')
->with('test_entity_type_create');
$this->moduleHandler->expects($this->at(1))
->method('invokeAll')
->with('entity_create');
$this->uuidService->expects($this->never())
->method('generate');
$entity = $this->entityStorage->create(array('id' => 'foo', 'uuid' => 'baz'));
$this->assertInstanceOf('Drupal\Core\Entity\EntityInterface', $entity);
$this->assertSame('foo', $entity->id());
$this->assertSame('baz', $entity->uuid());
}
/**
* @covers ::create()
*
* @return \Drupal\Core\Entity\EntityInterface
*/
public function testCreate() {
$this->entityType->expects($this->atLeastOnce())
->method('getClass')
->will($this->returnValue(get_class($this->getMockEntity())));
$this->moduleHandler->expects($this->at(0))
->method('invokeAll')
->with('test_entity_type_create');
$this->moduleHandler->expects($this->at(1))
->method('invokeAll')
->with('entity_create');
$this->uuidService->expects($this->once())
->method('generate')
->will($this->returnValue('bar'));
$entity = $this->entityStorage->create(array('id' => 'foo'));
$this->assertInstanceOf('Drupal\Core\Entity\EntityInterface', $entity);
$this->assertSame('foo', $entity->id());
$this->assertSame('bar', $entity->uuid());
return $entity;
}
/**
* @covers ::save()
*
* @param \Drupal\Core\Entity\EntityInterface $entity
*
* @return \Drupal\Core\Entity\EntityInterface
*
* @depends testCreate
*/
public function testSaveInsert(EntityInterface $entity) {
$config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
->disableOriginalConstructor()
->getMock();
$config_object->expects($this->atLeastOnce())
->method('isNew')
->will($this->returnValue(TRUE));
$config_object->expects($this->exactly(4))
->method('set');
$config_object->expects($this->once())
->method('save');
$this->configFactory->expects($this->once())
->method('get')
->with('the_config_prefix.foo')
->will($this->returnValue($config_object));
$this->moduleHandler->expects($this->at(0))
->method('invokeAll')
->with('test_entity_type_presave');
$this->moduleHandler->expects($this->at(1))
->method('invokeAll')
->with('entity_presave');
$this->moduleHandler->expects($this->at(2))
->method('invokeAll')
->with('test_entity_type_insert');
$this->moduleHandler->expects($this->at(3))
->method('invokeAll')
->with('entity_insert');
$this->entityQuery->expects($this->once())
->method('condition')
->with('uuid', 'bar')
->will($this->returnSelf());
$this->entityQuery->expects($this->once())
->method('execute')
->will($this->returnValue(array()));
$return = $this->entityStorage->save($entity);
$this->assertSame(SAVED_NEW, $return);
return $entity;
}
/**
* @covers ::save()
*
* @param \Drupal\Core\Entity\EntityInterface $entity
*
* @return \Drupal\Core\Entity\EntityInterface
*
* @depends testSaveInsert
*/
public function testSaveUpdate(EntityInterface $entity) {
$config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
->disableOriginalConstructor()
->getMock();
$config_object->expects($this->atLeastOnce())
->method('isNew')
->will($this->returnValue(FALSE));
$config_object->expects($this->exactly(4))
->method('set');
$config_object->expects($this->once())
->method('save');
$this->configFactory->expects($this->exactly(2))
->method('loadMultiple')
->with(array('the_config_prefix.foo'))
->will($this->returnValue(array()));
$this->configFactory->expects($this->once())
->method('get')
->with('the_config_prefix.foo')
->will($this->returnValue($config_object));
$this->moduleHandler->expects($this->at(0))
->method('invokeAll')
->with('test_entity_type_presave');
$this->moduleHandler->expects($this->at(1))
->method('invokeAll')
->with('entity_presave');
$this->moduleHandler->expects($this->at(2))
->method('invokeAll')
->with('test_entity_type_update');
$this->moduleHandler->expects($this->at(3))
->method('invokeAll')
->with('entity_update');
$this->entityQuery->expects($this->once())
->method('condition')
->with('uuid', 'bar')
->will($this->returnSelf());
$this->entityQuery->expects($this->once())
->method('execute')
->will($this->returnValue(array($entity->id())));
$return = $this->entityStorage->save($entity);
$this->assertSame(SAVED_UPDATED, $return);
return $entity;
}
/**
* @covers ::save()
*
* @depends testSaveInsert
*/
public function testSaveRename(ConfigEntityInterface $entity) {
$config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
->disableOriginalConstructor()
->getMock();
$config_object->expects($this->atLeastOnce())
->method('isNew')
->will($this->returnValue(FALSE));
$config_object->expects($this->exactly(4))
->method('set');
$config_object->expects($this->once())
->method('save');
$this->configFactory->expects($this->once())
->method('rename')
->will($this->returnValue($config_object));
$this->configFactory->expects($this->exactly(2))
->method('loadMultiple')
->with(array('the_config_prefix.foo'))
->will($this->returnValue(array()));
$this->configFactory->expects($this->once())
->method('get')
->with('the_config_prefix.foo')
->will($this->returnValue($config_object));
// Performing a rename does not change the original ID until saving.
$this->assertSame('foo', $entity->getOriginalId());
$entity->set('id', 'bar');
$this->assertSame('foo', $entity->getOriginalId());
$this->entityQuery->expects($this->once())
->method('condition')
->with('uuid', 'bar')
->will($this->returnSelf());
$this->entityQuery->expects($this->once())
->method('execute')
->will($this->returnValue(array($entity->id())));
$return = $this->entityStorage->save($entity);
$this->assertSame(SAVED_UPDATED, $return);
$this->assertSame('bar', $entity->getOriginalId());
}
/**
* @covers ::save()
*
* @expectedException \Drupal\Core\Entity\EntityMalformedException
* @expectedExceptionMessage The entity does not have an ID.
*/
public function testSaveInvalid() {
$entity = $this->getMockEntity();
$this->entityStorage->save($entity);
}
/**
* @covers ::save()
*
* @expectedException \Drupal\Core\Entity\EntityStorageException
*/
public function testSaveDuplicate() {
$config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
->disableOriginalConstructor()
->getMock();
$config_object->expects($this->atLeastOnce())
->method('isNew')
->will($this->returnValue(FALSE));
$config_object->expects($this->never())
->method('set');
$config_object->expects($this->never())
->method('save');
$this->configFactory->expects($this->once())
->method('get')
->with('the_config_prefix.foo')
->will($this->returnValue($config_object));
$entity = $this->getMockEntity(array('id' => 'foo'));
$entity->enforceIsNew();
$this->entityStorage->save($entity);
}
/**
* @covers ::save()
*
* @expectedException \Drupal\Core\Config\ConfigDuplicateUUIDException
* @expectedExceptionMessage when this UUID is already used for
*/
public function testSaveMismatch() {
$config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
->disableOriginalConstructor()
->getMock();
$config_object->expects($this->atLeastOnce())
->method('isNew')
->will($this->returnValue(TRUE));
$config_object->expects($this->never())
->method('save');
$this->configFactory->expects($this->once())
->method('get')
->with('the_config_prefix.foo')
->will($this->returnValue($config_object));
$this->entityQuery->expects($this->once())
->method('condition')
->will($this->returnSelf());
$this->entityQuery->expects($this->once())
->method('execute')
->will($this->returnValue(array('baz')));
$entity = $this->getMockEntity(array('id' => 'foo'));
$this->entityStorage->save($entity);
}
/**
* @covers ::save()
*/
public function testSaveNoMismatch() {
$config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
->disableOriginalConstructor()
->getMock();
$config_object->expects($this->atLeastOnce())
->method('isNew')
->will($this->returnValue(TRUE));
$config_object->expects($this->once())
->method('save');
$this->configFactory->expects($this->once())
->method('get')
->with('the_config_prefix.baz')
->will($this->returnValue($config_object));
$this->configFactory->expects($this->once())
->method('rename')
->will($this->returnValue($config_object));
$this->entityQuery->expects($this->once())
->method('condition')
->will($this->returnSelf());
$this->entityQuery->expects($this->once())
->method('execute')
->will($this->returnValue(array('baz')));
$entity = $this->getMockEntity(array('id' => 'foo'));
$entity->enforceIsNew();
$entity->setOriginalId('baz');
$this->entityStorage->save($entity);
}
/**
* @covers ::save()
*
* @expectedException \Drupal\Core\Config\ConfigDuplicateUUIDException
* @expectedExceptionMessage when this entity already exists with UUID
*/
public function testSaveChangedUuid() {
$config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
->disableOriginalConstructor()
->getMock();
$config_object->expects($this->atLeastOnce())
->method('isNew')
->will($this->returnValue(FALSE));
$config_object->expects($this->never())
->method('save');
$config_object->expects($this->exactly(2))
->method('get')
->will($this->returnValueMap(array(
array('', array('id' => 'foo')),
array('id', 'foo'),
)));
$this->configFactory->expects($this->at(1))
->method('loadMultiple')
->with(array('the_config_prefix.foo'))
->will($this->returnValue(array()));
$this->configFactory->expects($this->at(2))
->method('loadMultiple')
->with(array('the_config_prefix.foo'))
->will($this->returnValue(array($config_object)));
$this->configFactory->expects($this->once())
->method('get')
->with('the_config_prefix.foo')
->will($this->returnValue($config_object));
$this->configFactory->expects($this->never())
->method('rename')
->will($this->returnValue($config_object));
$this->moduleHandler->expects($this->exactly(2))
->method('getImplementations')
->will($this->returnValue(array()));
$this->entityQuery->expects($this->once())
->method('condition')
->will($this->returnSelf());
$this->entityQuery->expects($this->once())
->method('execute')
->will($this->returnValue(array('foo')));
$entity = $this->getMockEntity(array('id' => 'foo'));
$this->entityType->expects($this->atLeastOnce())
->method('getClass')
->will($this->returnValue(get_class($entity)));
$entity->set('uuid', 'baz');
$this->entityStorage->save($entity);
}
/**
* @covers ::load()
* @covers ::postLoad()
* @covers ::buildQuery()
*/
public function testLoad() {
$config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
->disableOriginalConstructor()
->getMock();
$config_object->expects($this->exactly(2))
->method('get')
->will($this->returnValueMap(array(
array('', array('id' => 'foo')),
array('id', 'foo'),
)));
$this->configFactory->expects($this->once())
->method('loadMultiple')
->with(array('the_config_prefix.foo'))
->will($this->returnValue(array($config_object)));
$this->moduleHandler->expects($this->exactly(2))
->method('getImplementations')
->will($this->returnValue(array()));
$this->entityType->expects($this->atLeastOnce())
->method('getClass')
->will($this->returnValue(get_class($this->getMockEntity())));
$entity = $this->entityStorage->load('foo');
$this->assertInstanceOf('Drupal\Core\Entity\EntityInterface', $entity);
$this->assertSame('foo', $entity->id());
}
/**
* @covers ::loadMultiple()
* @covers ::postLoad()
* @covers ::buildQuery()
*/
public function testLoadMultipleAll() {
$foo_config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
->disableOriginalConstructor()
->getMock();
$foo_config_object->expects($this->exactly(2))
->method('get')
->will($this->returnValueMap(array(
array('', array('id' => 'foo')),
array('id', 'foo'),
)));
$bar_config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
->disableOriginalConstructor()
->getMock();
$bar_config_object->expects($this->exactly(2))
->method('get')
->will($this->returnValueMap(array(
array('', array('id' => 'bar')),
array('id', 'bar'),
)));
$this->configFactory->expects($this->once())
->method('loadMultiple')
->with(array())
->will($this->returnValue(array($foo_config_object, $bar_config_object)));
$this->moduleHandler->expects($this->exactly(2))
->method('getImplementations')
->will($this->returnValue(array()));
$this->entityType->expects($this->atLeastOnce())
->method('getClass')
->will($this->returnValue(get_class($this->getMockEntity())));
$entities = $this->entityStorage->loadMultiple();
$expected['foo'] = 'foo';
$expected['bar'] = 'bar';
foreach ($entities as $id => $entity) {
$this->assertInstanceOf('Drupal\Core\Entity\EntityInterface', $entity);
$this->assertSame($id, $entity->id());
$this->assertSame($expected[$id], $entity->id());
}
}
/**
* @covers ::loadMultiple()
* @covers ::postLoad()
* @covers ::buildQuery()
*/
public function testLoadMultipleIds() {
$config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
->disableOriginalConstructor()
->getMock();
$config_object->expects($this->exactly(2))
->method('get')
->will($this->returnValueMap(array(
array('', array('id' => 'foo')),
array('id', 'foo'),
)));
$this->configFactory->expects($this->once())
->method('loadMultiple')
->with(array('the_config_prefix.foo'))
->will($this->returnValue(array($config_object)));
$this->moduleHandler->expects($this->exactly(2))
->method('getImplementations')
->will($this->returnValue(array()));
$this->entityType->expects($this->atLeastOnce())
->method('getClass')
->will($this->returnValue(get_class($this->getMockEntity())));
$entities = $this->entityStorage->loadMultiple(array('foo'));
foreach ($entities as $id => $entity) {
$this->assertInstanceOf('Drupal\Core\Entity\EntityInterface', $entity);
$this->assertSame($id, $entity->id());
}
}
/**
* @covers ::loadRevision()
*/
public function testLoadRevision() {
$this->assertSame(FALSE, $this->entityStorage->loadRevision(1));
}
/**
* @covers ::deleteRevision()
*/
public function testDeleteRevision() {
$this->assertSame(NULL, $this->entityStorage->deleteRevision(1));
}
/**
* @covers ::delete()
*/
public function testDelete() {
$this->entityType->expects($this->atLeastOnce())
->method('getClass')
->will($this->returnValue(get_class($this->getMockEntity())));
$entities = array();
$configs = array();
$config_map = array();
foreach (array('foo', 'bar') as $id) {
$entity = $this->getMockEntity(array('id' => $id));
$entities[] = $entity;
$config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
->disableOriginalConstructor()
->getMock();
$config_object->expects($this->once())
->method('delete');
$configs[] = $config_object;
$config_map[] = array("the_config_prefix.$id", $config_object);
}
$this->configFactory->expects($this->exactly(2))
->method('get')
->will($this->returnValueMap($config_map));
$this->moduleHandler->expects($this->at(0))
->method('invokeAll')
->with('test_entity_type_predelete');
$this->moduleHandler->expects($this->at(1))
->method('invokeAll')
->with('entity_predelete');
$this->moduleHandler->expects($this->at(2))
->method('invokeAll')
->with('test_entity_type_predelete');
$this->moduleHandler->expects($this->at(3))
->method('invokeAll')
->with('entity_predelete');
$this->moduleHandler->expects($this->at(4))
->method('invokeAll')
->with('test_entity_type_delete');
$this->moduleHandler->expects($this->at(5))
->method('invokeAll')
->with('entity_delete');
$this->moduleHandler->expects($this->at(6))
->method('invokeAll')
->with('test_entity_type_delete');
$this->moduleHandler->expects($this->at(7))
->method('invokeAll')
->with('entity_delete');
$this->entityStorage->delete($entities);
}
/**
* @covers ::delete()
*/
public function testDeleteNothing() {
$this->moduleHandler->expects($this->never())
->method($this->anything());
$this->configFactory->expects($this->never())
->method('get');
$this->entityStorage->delete(array());
}
/**
* Creates an entity with specific methods mocked.
*
* @param array $values
* (optional) Values to pass to the constructor.
* @param array $methods
* (optional) The methods to mock.
*
* @return \Drupal\Core\Entity\EntityInterface|\PHPUnit_Framework_MockObject_MockObject
*/
public function getMockEntity(array $values = array(), $methods = array()) {
$methods[] = 'onSaveOrDelete';
$methods[] = 'onUpdateBundleEntity';
return $this->getMockForAbstractClass('Drupal\Core\Config\Entity\ConfigEntityBase', array($values, 'test_entity_type'), '', TRUE, TRUE, TRUE, $methods);
}
}
}
namespace {
if (!defined('SAVED_NEW')) {
define('SAVED_NEW', 1);
}
if (!defined('SAVED_UPDATED')) {
define('SAVED_UPDATED', 2);
}
}