diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php index e020a2e..309f201 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php @@ -10,6 +10,7 @@ use Drupal\Component\Plugin\ConfigurablePluginInterface; use Drupal\Component\Utility\String; use Drupal\Core\Cache\Cache; +use Drupal\Core\Config\Schema\SchemaIncompleteException; use Drupal\Core\Entity\Entity; use Drupal\Core\Config\ConfigDuplicateUUIDException; use Drupal\Core\Entity\EntityStorageInterface; @@ -240,20 +241,52 @@ public static function sort(ConfigEntityInterface $a, ConfigEntityInterface $b) * {@inheritdoc} */ public function toArray() { - // 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); + try { + foreach ($this->getPropertiesFromSchema() as $name) { + $properties[$name] = $this->get($name); + } + } + catch (SchemaIncompleteException $e) { + // Some 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); + } } - // Add protected dependencies property. - $properties['dependencies'] = $this->dependencies; return $properties; } /** + * Gets the root properties of the configuration entity from its schema. + * + * @return array + * An array of property names. + * + * @throws \Exception + */ + protected function getPropertiesFromSchema() { + $config_name = $this->getEntityType()->getConfigPrefix() . '.' . $this->id(); + $definition = $this->getTypedConfig()->getDefinition($config_name); + if (!isset($definition['mapping'])) { + throw new SchemaIncompleteException(String::format('Missing root mapping definition in config schema for !name', array('!name' => $config_name))); + } + return array_keys($definition['mapping']); + } + + /** + * Gets the typed config manager. + * + * @return \Drupal\Core\Config\TypedConfigManagerInterface + */ + protected function getTypedConfig() { + return \Drupal::service('config.typed'); + } + + /** * {@inheritdoc} */ public function preSave(EntityStorageInterface $storage) { diff --git a/core/modules/block/lib/Drupal/block/Entity/Block.php b/core/modules/block/lib/Drupal/block/Entity/Block.php index decd0b1..954eeb2 100644 --- a/core/modules/block/lib/Drupal/block/Entity/Block.php +++ b/core/modules/block/lib/Drupal/block/Entity/Block.php @@ -130,25 +130,6 @@ public function label() { } /** - * {@inheritdoc} - */ - public function toArray() { - $properties = parent::toArray(); - $names = array( - 'theme', - 'region', - 'weight', - 'plugin', - 'settings', - 'visibility', - ); - foreach ($names as $name) { - $properties[$name] = $this->get($name); - } - return $properties; - } - - /** * Sorts active blocks by weight; sorts inactive blocks by name. */ public static function sort(ConfigEntityInterface $a, ConfigEntityInterface $b) { diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockStorageUnitTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockStorageUnitTest.php index 65d67f6..e0dc29c 100644 --- a/core/modules/block/lib/Drupal/block/Tests/BlockStorageUnitTest.php +++ b/core/modules/block/lib/Drupal/block/Tests/BlockStorageUnitTest.php @@ -91,12 +91,12 @@ protected function createTests() { // Ensure that default values are filled in. $expected_properties = array( 'id' => 'test_block', - 'weight' => NULL, - 'status' => TRUE, - 'langcode' => \Drupal::languageManager()->getDefaultLanguage()->id, - 'dependencies' => array('module' => array('block_test'), 'theme' => array('stark')), 'theme' => 'stark', 'region' => '-1', + 'weight' => NULL, + 'provider' => NULL, + 'status' => TRUE, + 'visibility' => NULL, 'plugin' => 'test_html', 'settings' => array( 'id' => 'test_html', @@ -108,7 +108,8 @@ protected function createTests() { 'contexts' => array(), ), ), - 'visibility' => NULL, + 'langcode' => \Drupal::languageManager()->getDefaultLanguage()->id, + 'dependencies' => array('module' => array('block_test'), 'theme' => array('stark')), ); $this->assertIdentical($actual_properties, $expected_properties); diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigEntityTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityTest.php index f3ca94f..776c6ee 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigEntityTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityTest.php @@ -47,7 +47,6 @@ function testCRUD() { $default_langcode = \Drupal::languageManager()->getDefaultLanguage()->id; // Verify default properties on a newly created empty entity. $empty = entity_create('config_test'); - $this->assertIdentical($empty->id, NULL); $this->assertTrue($empty->uuid); $this->assertIdentical($empty->label, NULL); $this->assertIdentical($empty->style, NULL); @@ -106,7 +105,6 @@ function testCRUD() { 'label' => $this->randomString(), 'style' => $this->randomName(), )); - $this->assertIdentical($config_test->id, $expected['id']); $this->assertTrue($config_test->uuid); $this->assertNotEqual($config_test->uuid, $empty->uuid); $this->assertIdentical($config_test->label, $expected['label']); @@ -160,7 +158,7 @@ function testCRUD() { try { $id_length_config_test->save(); $this->pass(String::format("config_test entity with ID length @length was saved.", array( - '@length' => strlen($id_length_config_test->id)) + '@length' => strlen($id_length_config_test->id())) )); } catch (ConfigEntityIdLengthException $e) { @@ -174,7 +172,7 @@ function testCRUD() { try { $id_length_config_test->save(); $this->pass(String::format("config_test entity with ID length @length was saved.", array( - '@length' => strlen($id_length_config_test->id), + '@length' => strlen($id_length_config_test->id()), ))); } catch (ConfigEntityIdLengthException $e) { @@ -188,13 +186,13 @@ function testCRUD() { try { $status = $id_length_config_test->save(); $this->fail(String::format("config_test entity with ID length @length exceeding the maximum allowed length of @max saved successfully", array( - '@length' => strlen($id_length_config_test->id), + '@length' => strlen($id_length_config_test->id()), '@max' => static::MAX_ID_LENGTH, ))); } catch (ConfigEntityIdLengthException $e) { $this->pass(String::format("config_test entity with ID length @length exceeding the maximum allowed length of @max failed to save", array( - '@length' => strlen($id_length_config_test->id), + '@length' => strlen($id_length_config_test->id()), '@max' => static::MAX_ID_LENGTH, ))); } @@ -222,7 +220,7 @@ function testCRUD() { $this->assertIdentical($config_test->getOriginalId(), $old_id); // Rename. - $config_test->id = $new_id; + $config_test->set('id', $new_id); $this->assertIdentical($config_test->id(), $new_id); $status = $config_test->save(); $this->assertIdentical($status, SAVED_UPDATED); diff --git a/core/modules/config/tests/config_test/config/schema/config_test.schema.yml b/core/modules/config/tests/config_test/config/schema/config_test.schema.yml index 984026f..33662e6 100644 --- a/core/modules/config/tests/config_test/config/schema/config_test.schema.yml +++ b/core/modules/config/tests/config_test/config/schema/config_test.schema.yml @@ -1,12 +1,11 @@ # Schema for the configuration files of the Configuration Test module. -config_test.dynamic.*: +config_test_dynamic: type: mapping - label: 'Config test entity' mapping: id: type: string - label: 'Machine name' + label: 'ID' label: type: label label: 'Label' @@ -15,12 +14,35 @@ config_test.dynamic.*: label: 'Weight' style: type: string - label: 'Image style' + label: 'style' + test_dependencies: + type: config_dependencies + label: 'Configuration dependencies' + status: + type: boolean + label: 'Status' + uuid: + type: string + label: 'UUID' + langcode: + type: string + label: 'Default language' + dependencies: + type: config_dependencies + label: 'Configuration dependencies' protected_property: type: string label: 'Protected property' -config_test_dynamic: +config_test.dynamic.*: + type: config_test_dynamic + label: 'Config test dynamic settings' + +config_test.dynamic.*.*: + type: config_test_dynamic + label: 'Config test dynamic settings' + +config_test.query.*: type: mapping mapping: id: @@ -32,29 +54,23 @@ config_test_dynamic: label: type: label label: 'Label' - weight: + array: + type: sequence + label: 'Array' + sequence: + - type: string + number: type: integer - label: 'Weight' - style: - type: string - label: 'style' + label: 'number' status: type: boolean label: 'Status' langcode: type: string label: 'Default language' - protected_property: - type: string - label: 'Protected property' - -config_test.dynamic.*: - type: config_test_dynamic - label: 'Config test dynamic settings' - -config_test.dynamic.*.*: - type: config_test_dynamic - label: 'Config test dynamic settings' + dependencies: + type: config_dependencies + label: 'Configuration dependencies' config_test.types: type: mapping diff --git a/core/modules/config/tests/config_test/lib/Drupal/config_test/Entity/ConfigTest.php b/core/modules/config/tests/config_test/lib/Drupal/config_test/Entity/ConfigTest.php index 07ec50a..b5f2dea 100644 --- a/core/modules/config/tests/config_test/lib/Drupal/config_test/Entity/ConfigTest.php +++ b/core/modules/config/tests/config_test/lib/Drupal/config_test/Entity/ConfigTest.php @@ -48,7 +48,7 @@ class ConfigTest extends ConfigEntityBase implements ConfigTestInterface { * * @var string */ - public $id; + protected $id; /** * The human-readable name of the configuration entity. @@ -86,20 +86,6 @@ class ConfigTest extends ConfigEntityBase implements ConfigTestInterface { protected $protected_property; /** - * {@inheritdoc} - */ - public function toArray() { - $properties = parent::toArray(); - $protected_names = array( - 'protected_property', - ); - foreach ($protected_names as $name) { - $properties[$name] = $this->get($name); - } - return $properties; - } - - /** * Overrides \Drupal\Core\Config\Entity\ConfigEntityBase::sort(). */ public static function sort(ConfigEntityInterface $a, ConfigEntityInterface $b) { diff --git a/core/modules/filter/lib/Drupal/filter/Entity/FilterFormat.php b/core/modules/filter/lib/Drupal/filter/Entity/FilterFormat.php index ff6954f..21bfc98 100644 --- a/core/modules/filter/lib/Drupal/filter/Entity/FilterFormat.php +++ b/core/modules/filter/lib/Drupal/filter/Entity/FilterFormat.php @@ -175,13 +175,9 @@ public function setFilterConfig($instance_id, array $configuration) { */ public function toArray() { $properties = parent::toArray(); - // @todo Make self::$weight and self::$cache protected and add them here. - $names = array( - 'filters', - ); - foreach ($names as $name) { - $properties[$name] = $this->get($name); - } + // The 'roles' property is only used during install and should never + // actually be saved. + unset($properties['roles']); return $properties; } diff --git a/core/modules/system/lib/Drupal/system/Entity/DateFormat.php b/core/modules/system/lib/Drupal/system/Entity/DateFormat.php index a3d6ece..cfbc471 100644 --- a/core/modules/system/lib/Drupal/system/Entity/DateFormat.php +++ b/core/modules/system/lib/Drupal/system/Entity/DateFormat.php @@ -70,21 +70,6 @@ class DateFormat extends ConfigEntityBase implements DateFormatInterface { /** * {@inheritdoc} */ - public function toArray() { - $properties = parent::toArray(); - $names = array( - 'locked', - 'pattern', - ); - foreach ($names as $name) { - $properties[$name] = $this->get($name); - } - return $properties; - } - - /** - * {@inheritdoc} - */ public function getPattern($type = DrupalDateTime::PHP) { return isset($this->pattern[$type]) ? $this->pattern[$type] : ''; } diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php index 3c52f73..0b1485f 100644 --- a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php +++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php @@ -86,6 +86,13 @@ class ConfigEntityBaseUnitTest extends UnitTestCase { protected $cacheBackend; /** + * The mocked typed config manager. + * + * @var \Drupal\Core\Config\TypedConfigManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $typedConfigManager; + + /** * {@inheritdoc} */ public static function getInfo() { @@ -129,11 +136,14 @@ public function setUp() { $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); + $this->typedConfigManager = $this->getMock('Drupal\Core\Config\TypedConfigManagerInterface'); + $container = new ContainerBuilder(); $container->set('entity.manager', $this->entityManager); $container->set('uuid', $this->uuid); $container->set('language_manager', $this->languageManager); $container->set('cache.test', $this->cacheBackend); + $container->set('config.typed', $this->typedConfigManager); $container->setParameter('cache_bins', array('cache.test' => 'test')); \Drupal::setContainer($container); @@ -431,6 +441,18 @@ public function testSort() { * @covers ::toArray */ public function testToArray() { + $this->typedConfigManager->expects($this->once()) + ->method('getDefinition') + ->will($this->returnValue(array('mapping' => array('id' => '', 'dependencies' => '')))); + $properties = $this->entity->toArray(); + $this->assertInternalType('array', $properties); + $this->assertEquals(array('id' => $this->entity->id(), 'dependencies' => array()), $properties); + } + + /** + * @covers ::toArray + */ + public function testToArrayFallback() { $properties = $this->entity->toArray(); $this->assertInternalType('array', $properties); $class_info = new \ReflectionClass($this->entity); @@ -439,6 +461,7 @@ public function testToArray() { $this->assertArrayHasKey($name, $properties); $this->assertSame($this->entity->get($name), $properties[$name]); } + $this->assertArrayNotHasKey('dependencies', $properties); } } diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php index 37019f5..6eee404 100644 --- a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php +++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php @@ -98,6 +98,13 @@ class ConfigEntityStorageTest extends UnitTestCase { protected $cacheBackend; /** + * The mocked typed config manager. + * + * @var \Drupal\Core\Config\TypedConfigManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $typedConfigManager; + + /** * {@inheritdoc} */ public static function getInfo() { @@ -167,8 +174,11 @@ protected function setUp() { $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); + $this->typedConfigManager = $this->getMock('Drupal\Core\Config\TypedConfigManagerInterface'); + $container = new ContainerBuilder(); $container->set('entity.manager', $this->entityManager); + $container->set('config.typed', $this->typedConfigManager); $container->set('cache.test', $this->cacheBackend); $container->setParameter('cache_bins', array('cache.test' => 'test')); \Drupal::setContainer($container); @@ -242,7 +252,7 @@ public function testSaveInsert(EntityInterface $entity) { $config_object->expects($this->atLeastOnce()) ->method('isNew') ->will($this->returnValue(TRUE)); - $config_object->expects($this->exactly(4)) + $config_object->expects($this->exactly(3)) ->method('set'); $config_object->expects($this->once()) ->method('save'); @@ -301,7 +311,7 @@ public function testSaveUpdate(EntityInterface $entity) { $config_object->expects($this->atLeastOnce()) ->method('isNew') ->will($this->returnValue(FALSE)); - $config_object->expects($this->exactly(4)) + $config_object->expects($this->exactly(3)) ->method('set'); $config_object->expects($this->once()) ->method('save'); @@ -361,7 +371,7 @@ public function testSaveRename(ConfigEntityInterface $entity) { $config_object->expects($this->atLeastOnce()) ->method('isNew') ->will($this->returnValue(FALSE)); - $config_object->expects($this->exactly(4)) + $config_object->expects($this->exactly(3)) ->method('set'); $config_object->expects($this->once()) ->method('save');