diff --git a/core/config/schema/core.data_types.schema.yml b/core/config/schema/core.data_types.schema.yml index 3615197..354cf2e 100644 --- a/core/config/schema/core.data_types.schema.yml +++ b/core/config/schema/core.data_types.schema.yml @@ -161,6 +161,12 @@ theme_settings: node_user_picture: type: boolean label: 'User pictures in posts' + main_menu: + type: boolean + label: 'Main menu' + secondary_menu: + type: boolean + label: 'Secondary menu' slogan: type: boolean label: 'Site slogan' diff --git a/core/core.services.yml b/core/core.services.yml index 7abab67..91a2c2b 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -489,9 +489,6 @@ services: arguments: ['@router.route_provider', '@path_processor_manager', '@route_processor_manager', '@config.factory', '@settings', '@logger.channel.default', '@request_stack'] calls: - [setContext, ['@?router.request_context']] - unrouted_url_assembler: - class: Drupal\Core\Utility\UnroutedUrlAssembler - arguments: ['@request_stack', '@config.factory' ] link_generator: class: Drupal\Core\Utility\LinkGenerator arguments: ['@url_generator', '@module_handler'] diff --git a/core/includes/common.inc b/core/includes/common.inc index e57821e..1379b4e 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -2451,6 +2451,20 @@ function drupal_prepare_page($page) { \Drupal::moduleHandler()->alter('page', $page); \Drupal::theme()->alter('page', $page); + // The "main" and "secondary" menus are never part of the page-level render + // array and therefore their cache tags will never bubble up into the page + // cache, even though they should be. This happens because they're rendered + // directly by the theme system. + // @todo Remove this once https://drupal.org/node/1869476 lands. + if (theme_get_setting('features.main_menu') && count(menu_main_menu())) { + $main_links_source = _menu_get_links_source('main_links', 'main'); + $page['page_top']['#cache']['tags'][] = 'menu:' . $main_links_source; + } + if (theme_get_setting('features.secondary_menu') && count(menu_secondary_menu())) { + $secondary_links_source = _menu_get_links_source('secondary_links', 'account'); + $page['page_top']['#cache']['tags'][] = 'menu:' . $secondary_links_source; + } + // If no module has taken care of the main content, add it to the page now. // This allows the site to still be usable even if no modules that // control page regions (for example, the Block module) are enabled. diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 5a6859d..5425dc2 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -1228,10 +1228,7 @@ function install_download_translation(&$install_state) { } // The download was successful, reload the page in the new language. - $install_state['translations'][$install_state['parameters']['langcode']] = TRUE; - if ($install_state['interactive']) { - install_goto(install_redirect_url($install_state)); - } + install_goto(install_redirect_url($install_state)); } /** @@ -1562,7 +1559,6 @@ function install_download_additional_translations_operations(&$install_state) { // remove English. if ($langcode != 'en') { \Drupal::config('system.site')->set('langcode', $langcode)->save(); - \Drupal::service('language.default')->set($language); entity_delete_multiple('configurable_language', array('en')); } diff --git a/core/includes/menu.inc b/core/includes/menu.inc index be5171e..0780a1d 100644 --- a/core/includes/menu.inc +++ b/core/includes/menu.inc @@ -414,6 +414,72 @@ function menu_list_system_menus() { } /** + * Returns an array of links to be rendered as the Main menu. + */ +function menu_main_menu() { + $main_links_source = _menu_get_links_source('main_links', 'main'); + return menu_navigation_links($main_links_source); +} + +/** + * Returns an array of links to be rendered as the Secondary links. + */ +function menu_secondary_menu() { + $main_links_source = _menu_get_links_source('main_links', 'main'); + $secondary_links_source = _menu_get_links_source('secondary_links', 'account'); + + // If the secondary menu source is set as the primary menu, we display the + // second level of the primary menu. + if ($secondary_links_source == $main_links_source) { + return menu_navigation_links($main_links_source, 1); + } + else { + return menu_navigation_links($secondary_links_source, 0); + } +} + +/** + * Returns the source of links of a menu. + * + * @param string $name + * A string configuration key of menu link source. + * @param string $default + * Default menu name. + * + * @return string + * Returns menu name, if exist + */ +function _menu_get_links_source($name, $default) { + $config = \Drupal::config('menu_ui.settings'); + return \Drupal::moduleHandler()->moduleExists('menu_ui') ? $config->get($name) : $default; +} + +/** + * Builds a renderable array for a navigation menu. + * + * @param string $menu_name + * The name of the menu. + * @param int $level + * Optional, the depth of the menu to be returned. + * + * @return array + * A renderable array. + */ +function menu_navigation_links($menu_name, $level = 0) { + $menu_tree = \Drupal::menuTree(); + $parameters = $menu_tree->getCurrentRouteMenuTreeParameters($menu_name); + $parameters->setMaxDepth($level + 1); + $tree = $menu_tree->load($menu_name, $parameters); + $manipulators = array( + array('callable' => 'menu.default_tree_manipulators:checkAccess'), + array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'), + array('callable' => 'menu.default_tree_manipulators:extractSubtreeOfActiveTrail', 'args' => array($level)), + ); + $tree = $menu_tree->transform($tree, $manipulators); + return $menu_tree->build($tree); +} + +/** * Collects the local tasks (tabs), action links, and the root path. * * @param int $level diff --git a/core/includes/theme.inc b/core/includes/theme.inc index f136ca1..c726d07 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -1805,6 +1805,8 @@ function template_preprocess_page(&$variables) { $variables['site_slogan'] = (theme_get_setting('features.slogan') ? Xss::filterAdmin($site_config->get('slogan')) : ''); if (!defined('MAINTENANCE_MODE')) { + $variables['main_menu'] = theme_get_setting('features.main_menu') ? menu_main_menu() : array(); + $variables['secondary_menu'] = theme_get_setting('features.secondary_menu') ? menu_secondary_menu() : array(); $variables['action_links'] = menu_get_local_actions(); $variables['tabs'] = menu_local_tabs(); @@ -1822,11 +1824,21 @@ function template_preprocess_page(&$variables) { } } else { + $variables['main_menu'] = array(); + $variables['secondary_menu'] = array(); $variables['action_links'] = array(); $variables['tabs'] = array(); $variables['feed_icons'] = ''; } + // Pass the main menu and secondary menu to the template as render arrays. + if (!empty($variables['main_menu'])) { + $variables['main_menu']['#prefix'] = ''; + } + if (!empty($variables['secondary_menu'])) { + $variables['secondary_menu']['#prefix'] = ''; + } + if ($node = \Drupal::routeMatch()->getParameter('node')) { $variables['node'] = $node; } diff --git a/core/includes/update.inc b/core/includes/update.inc index d31f994..9a4606e 100644 --- a/core/includes/update.inc +++ b/core/includes/update.inc @@ -751,9 +751,9 @@ function update_language_list($flags = LanguageInterface::STATE_CONFIGURABLE) { } foreach ($languages as $langcode => $language) { - if (($language->isLocked() && !($flags & LanguageInterface::STATE_LOCKED)) || (!$language->isLocked() && !($flags & LanguageInterface::STATE_CONFIGURABLE))) { + if (($language->locked && !($flags & LanguageInterface::STATE_LOCKED)) || (!$language->locked && !($flags & LanguageInterface::STATE_CONFIGURABLE))) { continue; - } + } $filtered_languages[$langcode] = $language; } diff --git a/core/lib/Drupal/Core/Access/AccessResult.php b/core/lib/Drupal/Core/Access/AccessResult.php index 7dc8688..528d39b 100644 --- a/core/lib/Drupal/Core/Access/AccessResult.php +++ b/core/lib/Drupal/Core/Access/AccessResult.php @@ -139,7 +139,7 @@ public static function forbiddenIf($condition) { * The permission to check for. * * @return \Drupal\Core\Access\AccessResult - * If the account has the permission, isAllowed() will be TRUE, otherwise + * If the account has the permission, isAlowed() will be TRUE, otherwise * isNeutral() will be TRUE. */ public static function allowedIfHasPermission(AccountInterface $account, $permission) { @@ -147,47 +147,6 @@ public static function allowedIfHasPermission(AccountInterface $account, $permis } /** - * Creates an allowed access result if the permissions are present, neutral otherwise. - * - * Convenience method, checks the permissions and calls ::cachePerRole(). - * - * @param \Drupal\Core\Session\AccountInterface $account - * The account for which to check permissions. - * @param array $permissions - * The permissions to check. - * @param string $conjunction - * (optional) 'AND' if all permissions are required, 'OR' in case just one. - * Defaults to 'AND' - * - * @return \Drupal\Core\Access\AccessResult - * If the account has the permissions, isAllowed() will be TRUE, otherwise - * isNeutral() will be TRUE. - */ - public static function allowedIfHasPermissions(AccountInterface $account, array $permissions, $conjunction = 'AND') { - $access = FALSE; - - if ($conjunction == 'AND' && !empty($permissions)) { - $access = TRUE; - foreach ($permissions as $permission) { - if (!$permission_access = $account->hasPermission($permission)) { - $access = FALSE; - break; - } - } - } - else { - foreach ($permissions as $permission) { - if ($permission_access = $account->hasPermission($permission)) { - $access = TRUE; - break; - } - } - } - - return static::allowedIf($access)->cachePerRole(); - } - - /** * {@inheritdoc} * * @see \Drupal\Core\Access\AccessResultAllowed diff --git a/core/lib/Drupal/Core/Config/ConfigFactory.php b/core/lib/Drupal/Core/Config/ConfigFactory.php index 970a500..7d9f23b 100644 --- a/core/lib/Drupal/Core/Config/ConfigFactory.php +++ b/core/lib/Drupal/Core/Config/ConfigFactory.php @@ -23,8 +23,6 @@ * is used for reading and writing the configuration data. * * @see \Drupal\Core\Config\StorageInterface - * - * @ingroup config_api */ class ConfigFactory implements ConfigFactoryInterface, EventSubscriberInterface { diff --git a/core/lib/Drupal/Core/Config/ConfigFactoryInterface.php b/core/lib/Drupal/Core/Config/ConfigFactoryInterface.php index d51e023..4166ff7 100644 --- a/core/lib/Drupal/Core/Config/ConfigFactoryInterface.php +++ b/core/lib/Drupal/Core/Config/ConfigFactoryInterface.php @@ -9,8 +9,6 @@ /** * Defines the interface for a configuration object factory. - * - * @ingroup config_api */ interface ConfigFactoryInterface { diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php index d226243..dc6b46a 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php @@ -360,13 +360,6 @@ public function url($rel = 'edit-form', $options = array()) { /** * {@inheritdoc} */ - public function link($text = NULL, $rel = 'edit-form', array $options = []) { - return parent::link($text, $rel, $options); - } - - /** - * {@inheritdoc} - */ protected function addDependency($type, $name) { // A config entity is always dependent on its provider. There is no need to // explicitly declare the dependency. An explicit dependency on Core, which diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBundleBase.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBundleBase.php index eb1cb81..c6618a6 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBundleBase.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBundleBase.php @@ -68,11 +68,11 @@ public function postSave(EntityStorageInterface $storage, $update = TRUE) { parent::postSave($storage, $update); if (!$update) { - $this->entityManager()->onBundleCreate($this->id(), $this->getEntityType()->getBundleOf()); + $this->entityManager()->onBundleCreate($this->getEntityType()->getBundleOf(), $this->id()); } elseif ($this->getOriginalId() != $this->id()) { $this->renameDisplays(); - $this->entityManager()->onBundleRename($this->getOriginalId(), $this->id(), $this->getEntityType()->getBundleOf()); + $this->entityManager()->onBundleRename($this->getEntityType()->getBundleOf(), $this->getOriginalId(), $this->id()); } } @@ -84,7 +84,7 @@ public static function postDelete(EntityStorageInterface $storage, array $entiti foreach ($entities as $entity) { $entity->deleteDisplays(); - \Drupal::entityManager()->onBundleDelete($entity->id(), $entity->getEntityType()->getBundleOf()); + \Drupal::entityManager()->onBundleDelete($entity->getEntityType()->getBundleOf(), $entity->id()); } } diff --git a/core/lib/Drupal/Core/Database/Install/Tasks.php b/core/lib/Drupal/Core/Database/Install/Tasks.php index bc05bdd..070d24c 100644 --- a/core/lib/Drupal/Core/Database/Install/Tasks.php +++ b/core/lib/Drupal/Core/Database/Install/Tasks.php @@ -7,8 +7,6 @@ namespace Drupal\Core\Database\Install; -use Drupal\Component\Utility\SafeMarkup; -use Drupal\Component\Utility\String; use Drupal\Core\Database\Database; /** @@ -152,11 +150,11 @@ public function runTasks() { $message = ''; foreach ($this->results as $result => $success) { if (!$success) { - $message = SafeMarkup::isSafe($result) ? $result : String::checkPlain($result); + $message .= '

' . $result . '

'; } } if (!empty($message)) { - $message = SafeMarkup::set('Resolve all issues below to continue the installation. For help configuring your database server, see the installation handbook, or contact your hosting provider.' . $message); + $message = 'Resolve all issues below to continue the installation. For help configuring your database server, see the installation handbook, or contact your hosting provider.' . $message; throw new TaskException($message); } } diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php index 636c00b..2ad6d69 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php @@ -9,6 +9,7 @@ use Drupal\Component\Utility\String; use Drupal\Core\Entity\Plugin\DataType\EntityReference; +use Drupal\Core\Entity\TypedData\EntityDataDefinition; use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Session\AccountInterface; use Drupal\Core\TypedData\TypedDataInterface; @@ -130,6 +131,13 @@ protected $entityKeys = array(); /** + * The instantiated entity data definition. + * + * @var \Drupal\Core\Entity\TypedData\EntityDataDefinition + */ + protected $dataDefinition; + + /** * Overrides Entity::__construct(). */ public function __construct(array $values, $entity_type, $bundle = FALSE, $translations = array()) { @@ -241,7 +249,7 @@ public function isTranslatable() { // Check that the bundle is translatable, the entity has a language defined // and if we have more than one language on the site. $bundles = $this->entityManager()->getBundleInfo($this->entityTypeId); - return !empty($bundles[$this->bundle()]['translatable']) && !$this->getUntranslated()->language()->isLocked() && $this->languageManager()->isMultilingual(); + return !empty($bundles[$this->bundle()]['translatable']) && empty($this->getUntranslated()->language()->locked) && $this->languageManager()->isMultilingual(); } /** @@ -253,8 +261,98 @@ public function preSaveRevision(EntityStorageInterface $storage, \stdClass $reco /** * {@inheritdoc} */ + public function getDataDefinition() { + if (!$this->dataDefinition) { + $this->dataDefinition = EntityDataDefinition::create($this->getEntityTypeId()); + $this->dataDefinition->setBundles(array($this->bundle())); + } + return $this->dataDefinition; + } + + /** + * {@inheritdoc} + */ + public function getValue() { + // @todo: This does not make much sense, so remove once TypedDataInterface + // is removed. See https://drupal.org/node/2002138. + return $this->toArray(); + } + + /** + * {@inheritdoc} + */ + public function setValue($value, $notify = TRUE) { + // @todo: This does not make much sense, so remove once TypedDataInterface + // is removed. See https://drupal.org/node/2002138. + foreach ($value as $field_name => $field_value) { + $this->set($field_name, $field_value, $notify); + } + } + + /** + * {@inheritdoc} + */ + public function getString() { + return (string) $this->label(); + } + + /** + * {@inheritdoc} + */ public function validate() { - return $this->getTypedData()->validate(); + return $this->typedDataManager()->getValidator()->validate($this); + } + + /** + * {@inheritdoc} + */ + public function applyDefaultValue($notify = TRUE) { + foreach ($this->getProperties() as $property) { + $property->applyDefaultValue(FALSE); + } + } + + /** + * {@inheritdoc} + */ + public function getConstraints() { + return array(); + } + + /** + * {@inheritdoc} + */ + public function getName() { + return NULL; + } + + /** + * {@inheritdoc} + */ + public function getRoot() { + return $this; + } + + /** + * {@inheritdoc} + */ + public function getPropertyPath() { + return ''; + } + + /** + * {@inheritdoc} + */ + public function getParent() { + return NULL; + } + + /** + * {@inheritdoc} + */ + public function setContext($name = NULL, TypedDataInterface $parent = NULL) { + // As entities are always the root of the tree of typed data, we do not need + // to set any parent or name. } /** @@ -278,6 +376,7 @@ public function __sleep() { } $this->fields = array(); $this->fieldDefinitions = NULL; + $this->dataDefinition = NULL; $this->clearTranslationCache(); return parent::__sleep(); @@ -314,11 +413,11 @@ public function hasField($field_name) { /** * {@inheritdoc} */ - public function get($field_name) { - if (!isset($this->fields[$field_name][$this->activeLangcode])) { - return $this->getTranslatedField($field_name, $this->activeLangcode); + public function get($property_name) { + if (!isset($this->fields[$property_name][$this->activeLangcode])) { + return $this->getTranslatedField($property_name, $this->activeLangcode); } - return $this->fields[$field_name][$this->activeLangcode]; + return $this->fields[$property_name][$this->activeLangcode]; } /** @@ -353,8 +452,7 @@ protected function getTranslatedField($name, $langcode) { if (isset($this->values[$name][$langcode])) { $value = $this->values[$name][$langcode]; } - $entity_adapter = $this->getTypedData(); - $field = \Drupal::typedDataManager()->getPropertyInstance($entity_adapter, $name, $value); + $field = \Drupal::typedDataManager()->getPropertyInstance($this, $name, $value); if ($default) { // $this->defaultLangcode might not be set if we are initializing the // default language code cache, in which case there is no valid @@ -383,21 +481,21 @@ public function set($name, $value, $notify = TRUE) { /** * {@inheritdoc} */ - public function getFields($include_computed = TRUE) { - $fields = array(); + public function getProperties($include_computed = FALSE) { + $properties = array(); foreach ($this->getFieldDefinitions() as $name => $definition) { if ($include_computed || !$definition->isComputed()) { - $fields[$name] = $this->get($name); + $properties[$name] = $this->get($name); } } - return $fields; + return $properties; } /** * {@inheritdoc} */ public function getIterator() { - return new \ArrayIterator($this->getFields()); + return new \ArrayIterator($this->getProperties()); } /** @@ -427,7 +525,7 @@ public function getFieldDefinitions() { */ public function toArray() { $values = array(); - foreach ($this->getFields() as $name => $property) { + foreach ($this->getProperties() as $name => $property) { $values[$name] = $property->getValue(); } return $values; @@ -436,6 +534,21 @@ public function toArray() { /** * {@inheritdoc} */ + public function isEmpty() { + if (!$this->isNew()) { + return FALSE; + } + foreach ($this->getProperties() as $property) { + if ($property->getValue() !== NULL) { + return FALSE; + } + } + return TRUE; + } + + /** + * {@inheritdoc} + */ public function access($operation, AccountInterface $account = NULL, $return_as_object = FALSE) { if ($operation == 'create') { return $this->entityManager() @@ -531,6 +644,8 @@ public function onChange($name) { /** * {@inheritdoc} + * + * @return \Drupal\Core\Entity\ContentEntityInterface */ public function getTranslation($langcode) { // Ensure we always use the default language code when dealing with the @@ -562,7 +677,7 @@ public function getTranslation($langcode) { // If the entity or the requested language is not a configured // language, we fall back to the entity itself, since in this case it // cannot have translations. - $translation = !$this->languages[$this->defaultLangcode]->isLocked() && !$this->languages[$langcode]->isLocked() ? $this->addTranslation($langcode) : $this; + $translation = empty($this->languages[$this->defaultLangcode]->locked) && empty($this->languages[$langcode]->locked) ? $this->addTranslation($langcode) : $this; } } } @@ -711,6 +826,15 @@ public function getTranslationLanguages($include_default = TRUE) { } /** + * Overrides Entity::translations(). + * + * @todo: Remove once Entity::translations() gets removed. + */ + public function translations() { + return $this->getTranslationLanguages(FALSE); + } + + /** * Updates the original values with the interim changes. */ public function updateOriginalValues() { @@ -833,6 +957,8 @@ public function createDuplicate() { $duplicate->{$entity_type->getKey('revision')}->value = NULL; } + $duplicate->entityKeys = array(); + return $duplicate; } @@ -843,8 +969,6 @@ public function __clone() { // Avoid deep-cloning when we are initializing a translation object, since // it will represent the same entity, only with a different active language. if (!$this->translationInitialize) { - // The translation is a different object, and needs its own TypedData object. - $this->typedData = NULL; $definitions = $this->getFieldDefinitions(); foreach ($this->fields as $name => $values) { $this->fields[$name] = array(); @@ -857,7 +981,7 @@ public function __clone() { } foreach ($values as $langcode => $items) { $this->fields[$name][$langcode] = clone $items; - $this->fields[$name][$langcode]->setContext($name, $this->getTypedData()); + $this->fields[$name][$langcode]->setContext($name, $this); } } @@ -891,11 +1015,11 @@ public function referencedEntities() { $referenced_entities = array(); // Gather a list of referenced entities. - foreach ($this->getFields() as $field_items) { + foreach ($this->getProperties() as $field_items) { foreach ($field_items as $field_item) { // Loop over all properties of a field item. foreach ($field_item->getProperties(TRUE) as $property) { - if ($property instanceof EntityReference && $entity = $property->getValue()) { + if ($property instanceof EntityReference && $entity = $property->getTarget()) { $referenced_entities[] = $entity; } } diff --git a/core/lib/Drupal/Core/Entity/ContentEntityInterface.php b/core/lib/Drupal/Core/Entity/ContentEntityInterface.php index 4d3afa3..249c302 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityInterface.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityInterface.php @@ -7,6 +7,7 @@ namespace Drupal\Core\Entity; +use Drupal\Core\TypedData\ComplexDataInterface; use Drupal\Core\TypedData\TranslatableInterface; /** @@ -27,7 +28,7 @@ * * @ingroup entity_api */ -interface ContentEntityInterface extends \Traversable, EntityInterface, RevisionableInterface, TranslatableInterface { +interface ContentEntityInterface extends EntityInterface, RevisionableInterface, TranslatableInterface, ComplexDataInterface { /** * Marks the translation identified by the given language code as existing. @@ -105,9 +106,6 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type); * * @see \Drupal\Core\Entity\EntityManagerInterface::getFieldDefinitions() * @see \Drupal\Core\Entity\ContentEntityInterface::baseFieldDefinitions() - * - * @todo WARNING: This method will be changed in - * https://www.drupal.org/node/2346347. */ public static function bundleFieldDefinitions(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions); @@ -154,67 +152,4 @@ public function getFieldDefinitions(); */ public function toArray(); - /** - * Gets a field item list. - * - * @param string $field_name - * The name of the field to get; e.g., 'title' or 'name'. - * - * @throws \InvalidArgumentException - * If an invalid field name is given. - * - * @return \Drupal\Core\Field\FieldItemListInterface - * The field item list, containing the field items. - */ - public function get($field_name); - - /** - * Sets a field value. - * - * @param string $field_name - * The name of the field to set; e.g., 'title' or 'name'. - * @param mixed $value - * The value to set, or NULL to unset the field. - * @param bool $notify - * (optional) Whether to notify the entity of the change. Defaults to - * TRUE. If the update stems from the entity, set it to FALSE to avoid - * being notified again. - * - * @throws \InvalidArgumentException - * If the specified field does not exist. - * - * @return $this - */ - public function set($field_name, $value, $notify = TRUE); - - /** - * Gets an array of field item lists. - * - * @param bool $include_computed - * If set to TRUE, computed fields are included. Defaults to FALSE. - * - * @return \Drupal\Core\Field\FieldItemListInterface[] - * An array of field item lists implementing, keyed by field name. - */ - public function getFields($include_computed = TRUE); - - /** - * Reacts to changes to a field. - * - * Note that this is invoked after any changes have been applied. - * - * @param string $field_name - * The name of the field which is changed. - */ - public function onChange($field_name); - - /** - * Validates the currently set values. - * - * @return \Symfony\Component\Validator\ConstraintViolationListInterface - * A list of constraint violations. If the list is empty, validation - * succeeded. - */ - public function validate(); - } diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php index 6415285..6d75946 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php @@ -12,7 +12,7 @@ use Drupal\Core\Field\FieldStorageDefinitionInterface; use Symfony\Component\DependencyInjection\ContainerInterface; -abstract class ContentEntityStorageBase extends EntityStorageBase implements DynamicallyFieldableEntityStorageInterface { +abstract class ContentEntityStorageBase extends EntityStorageBase implements FieldableEntityStorageInterface { /** * The entity bundle key. @@ -106,6 +106,21 @@ public function onFieldDefinitionDelete(FieldDefinitionInterface $field_definiti /** * {@inheritdoc} */ + public function onBundleCreate($bundle) { } + + /** + * {@inheritdoc} + */ + public function onBundleRename($bundle, $bundle_new) { } + + /** + * {@inheritdoc} + */ + public function onBundleDelete($bundle) { } + + /** + * {@inheritdoc} + */ public function purgeFieldData(FieldDefinitionInterface $field_definition, $batch_size) { $items_by_entity = $this->readFieldItemsToPurge($field_definition, $batch_size); @@ -180,7 +195,7 @@ protected function invokeTranslationHooks(ContentEntityInterface $entity) { protected function invokeFieldMethod($method, ContentEntityInterface $entity) { foreach (array_keys($entity->getTranslationLanguages()) as $langcode) { $translation = $entity->getTranslation($langcode); - foreach ($translation->getFields() as $field) { + foreach ($translation->getProperties(TRUE) as $field) { $field->$method(); } } diff --git a/core/lib/Drupal/Core/Entity/DynamicallyFieldableEntityStorageInterface.php b/core/lib/Drupal/Core/Entity/DynamicallyFieldableEntityStorageInterface.php deleted file mode 100644 index 6d12c98..0000000 --- a/core/lib/Drupal/Core/Entity/DynamicallyFieldableEntityStorageInterface.php +++ /dev/null @@ -1,95 +0,0 @@ -label(); - } - $url = $this->urlInfo($rel); - $options += $url->getOptions(); - $url->setOptions($options); - return (new Link($text, $url))->toString(); - } - - /** - * {@inheritdoc} - */ public function url($rel = 'canonical', $options = array()) { // While self::urlInfo() will throw an exception if the entity is new, // the expected result for a URL is always a string. @@ -569,23 +547,4 @@ public function toArray() { return array(); } - /** - * {@inheritdoc} - */ - public function getTypedData() { - if (!isset($this->typedData)) { - $class = \Drupal::typedDataManager()->getDefinition('entity')['class']; - $this->typedData = $class::createFromEntity($this); - } - return $this->typedData; - } - - /** - * {@inheritdoc} - */ - public function __sleep() { - $this->typedData = NULL; - return $this->traitSleep(); - } - } diff --git a/core/lib/Drupal/Core/Entity/EntityBundleListenerInterface.php b/core/lib/Drupal/Core/Entity/EntityBundleListenerInterface.php deleted file mode 100644 index cbe96b3..0000000 --- a/core/lib/Drupal/Core/Entity/EntityBundleListenerInterface.php +++ /dev/null @@ -1,53 +0,0 @@ -entityManager->getStorage($entity_type_id) instanceof DynamicallyFieldableEntityStorageInterface) { + if ($entity_type->isFieldable()) { $field_changes = array(); $storage_definitions = $this->entityManager->getFieldStorageDefinitions($entity_type_id); $original_storage_definitions = $this->entityManager->getLastInstalledFieldStorageDefinitions($entity_type_id); @@ -238,7 +238,7 @@ protected function requiresEntityStorageSchemaChanges(EntityTypeInterface $entit */ protected function requiresFieldStorageSchemaChanges(FieldStorageDefinitionInterface $storage_definition, FieldStorageDefinitionInterface $original) { $storage = $this->entityManager->getStorage($storage_definition->getTargetEntityTypeId()); - return ($storage instanceof DynamicallyFieldableEntityStorageSchemaInterface) && $storage->requiresFieldStorageSchemaChanges($storage_definition, $original); + return ($storage instanceof FieldableEntityStorageSchemaInterface) && $storage->requiresFieldStorageSchemaChanges($storage_definition, $original); } } diff --git a/core/lib/Drupal/Core/Entity/EntityInterface.php b/core/lib/Drupal/Core/Entity/EntityInterface.php index 9280d79..f60b635 100644 --- a/core/lib/Drupal/Core/Entity/EntityInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityInterface.php @@ -142,23 +142,6 @@ public function urlInfo($rel = 'canonical', array $options = array()); public function url($rel = 'canonical', $options = array()); /** - * Generates the HTML for a link to this entity. - * - * @param string|null $text - * (optional) The link text for the anchor tag as a translated string. - * If NULL, it will use the entity's label. Defaults to NULL. - * @param string $rel - * (optional) The link relationship type. Defaults to 'canonical'. - * @param array $options - * See \Drupal\Core\Routing\UrlGeneratorInterface::generateFromRoute() for - * the available options. - * - * @return string - * An HTML string containing a link to the entity. - */ - public function link($text = NULL, $rel = 'canonical', array $options = []); - - /** * Returns the internal path for this entity. * * self::url() will return the full path including any prefixes, fragments, or @@ -379,19 +362,6 @@ public function setOriginalId($id); public function toArray(); /** - * Returns a typed data object for this entity object. - * - * The returned typed data object wraps this entity and allows dealing with - * entities based on the generic typed data API. - * - * @return \Drupal\Core\TypedData\ComplexDataInterface - * The typed data object for this entity. - * - * @see \Drupal\Core\TypedData\TypedDataInterface - */ - public function getTypedData(); - - /** * The unique cache tag associated with this entity. * * @return array diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php index 9ed6671..94fe169 100644 --- a/core/lib/Drupal/Core/Entity/EntityManager.php +++ b/core/lib/Drupal/Core/Entity/EntityManager.php @@ -405,7 +405,7 @@ protected function buildBaseFieldDefinitions($entity_type_id) { if ($base_field_definition instanceof BaseFieldDefinition) { $base_field_definition->setName($field_name); $base_field_definition->setTargetEntityTypeId($entity_type_id); - $base_field_definition->setTargetBundle(NULL); + $base_field_definition->setBundle(NULL); } } @@ -518,7 +518,7 @@ protected function buildBundleFieldDefinitions($entity_type_id, $bundle, array $ if ($field_definition instanceof BaseFieldDefinition) { $field_definition->setName($field_name); $field_definition->setTargetEntityTypeId($entity_type_id); - $field_definition->setTargetBundle($bundle); + $field_definition->setBundle($bundle); } } @@ -987,7 +987,7 @@ public function onEntityTypeCreate(EntityTypeInterface $entity_type) { } $this->setLastInstalledDefinition($entity_type); - if ($entity_type->isSubclassOf('\Drupal\Core\Entity\ContentEntityInterface')) { + if ($entity_type->isFieldable()) { $this->setLastInstalledFieldStorageDefinitions($entity_type_id, $this->getFieldStorageDefinitions($entity_type_id)); } } @@ -1078,12 +1078,12 @@ public function onFieldStorageDefinitionDelete(FieldStorageDefinitionInterface $ /** * {@inheritdoc} */ - public function onBundleCreate($bundle, $entity_type_id) { + public function onBundleCreate($entity_type_id, $bundle) { $this->clearCachedBundles(); // Notify the entity storage. $storage = $this->getStorage($entity_type_id); - if ($storage instanceof EntityBundleListenerInterface) { - $storage->onBundleCreate($bundle, $entity_type_id); + if ($storage instanceof FieldableEntityStorageInterface) { + $storage->onBundleCreate($bundle); } // Invoke hook_entity_bundle_create() hook. $this->moduleHandler->invokeAll('entity_bundle_create', array($entity_type_id, $bundle)); @@ -1092,12 +1092,12 @@ public function onBundleCreate($bundle, $entity_type_id) { /** * {@inheritdoc} */ - public function onBundleRename($bundle_old, $bundle_new, $entity_type_id) { + public function onBundleRename($entity_type_id, $bundle_old, $bundle_new) { $this->clearCachedBundles(); // Notify the entity storage. $storage = $this->getStorage($entity_type_id); - if ($storage instanceof EntityBundleListenerInterface) { - $storage->onBundleRename($bundle_old, $bundle_new, $entity_type_id); + if ($storage instanceof FieldableEntityStorageInterface) { + $storage->onBundleRename($bundle_old, $bundle_new); } // Rename existing base field bundle overrides. @@ -1117,12 +1117,12 @@ public function onBundleRename($bundle_old, $bundle_new, $entity_type_id) { /** * {@inheritdoc} */ - public function onBundleDelete($bundle, $entity_type_id) { + public function onBundleDelete($entity_type_id, $bundle) { $this->clearCachedBundles(); // Notify the entity storage. $storage = $this->getStorage($entity_type_id); - if ($storage instanceof EntityBundleListenerInterface) { - $storage->onBundleDelete($bundle, $entity_type_id); + if ($storage instanceof FieldableEntityStorageInterface) { + $storage->onBundleDelete($bundle); } // Invoke hook_entity_bundle_delete() hook. $this->moduleHandler->invokeAll('entity_bundle_delete', array($entity_type_id, $bundle)); diff --git a/core/lib/Drupal/Core/Entity/EntityManagerInterface.php b/core/lib/Drupal/Core/Entity/EntityManagerInterface.php index daea71f..7a13fff 100644 --- a/core/lib/Drupal/Core/Entity/EntityManagerInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityManagerInterface.php @@ -13,7 +13,7 @@ /** * Provides an interface for entity type managers. */ -interface EntityManagerInterface extends PluginManagerInterface, EntityTypeListenerInterface, EntityBundleListenerInterface, FieldStorageDefinitionListenerInterface { +interface EntityManagerInterface extends PluginManagerInterface, EntityTypeListenerInterface, FieldStorageDefinitionListenerInterface { /** * Builds a list of entity type labels suitable for a Form API options list. @@ -465,4 +465,42 @@ public function loadEntityByUuid($entity_type_id, $uuid); */ public function getEntityTypeFromClass($class_name); + /** + * Reacts to the creation of a entity bundle. + * + * @param string $entity_type_id + * The entity type to which the bundle is bound; e.g. 'node' or 'user'. + * @param string $bundle + * The name of the bundle. + * + * @see entity_crud + */ + public function onBundleCreate($entity_type_id, $bundle); + + /** + * Reacts to the rename of a entity bundle. + * + * @param string $entity_type_id + * The entity type to which the bundle is bound; e.g. 'node' or 'user'. + * @param string $bundle_old + * The previous name of the bundle. + * @param string $bundle_new + * The new name of the bundle. + * + * @see entity_crud + */ + public function onBundleRename($entity_type_id, $bundle_old, $bundle_new); + + /** + * Reacts to the deletion of a entity bundle. + * + * @param string $entity_type_id + * The entity type to which the bundle is bound; e.g. 'node' or 'user'. + * @param string $bundle + * The bundle that was just deleted. + * + * @see entity_crud + */ + public function onBundleDelete($entity_type_id, $bundle); + } diff --git a/core/lib/Drupal/Core/Entity/EntityType.php b/core/lib/Drupal/Core/Entity/EntityType.php index 8cc1cbe..79c092e 100644 --- a/core/lib/Drupal/Core/Entity/EntityType.php +++ b/core/lib/Drupal/Core/Entity/EntityType.php @@ -101,6 +101,14 @@ class EntityType implements EntityTypeInterface { * @var string */ protected $permission_granularity = 'entity_type'; + + /** + * Indicates whether fields can be attached to entities of this type. + * + * @var bool + */ + protected $fieldable = FALSE; + /** * Link templates using the URI template syntax. * @@ -495,6 +503,13 @@ public function getPermissionGranularity() { /** * {@inheritdoc} */ + public function isFieldable() { + return $this->fieldable; + } + + /** + * {@inheritdoc} + */ public function getLinkTemplates() { return $this->links; } diff --git a/core/lib/Drupal/Core/Entity/EntityTypeInterface.php b/core/lib/Drupal/Core/Entity/EntityTypeInterface.php index 40f5d5d..7e8662b 100644 --- a/core/lib/Drupal/Core/Entity/EntityTypeInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityTypeInterface.php @@ -396,6 +396,14 @@ public function getAdminPermission(); public function getPermissionGranularity(); /** + * Indicates whether fields can be attached to entities of this type. + * + * @return bool + * Returns TRUE if the entity type can has fields, otherwise FALSE. + */ + public function isFieldable(); + + /** * Returns link templates using the URI template syntax. * * Links are an array of standard link relations to the URI template that diff --git a/core/lib/Drupal/Core/Entity/FieldableEntityStorageInterface.php b/core/lib/Drupal/Core/Entity/FieldableEntityStorageInterface.php new file mode 100644 index 0000000..aaab687 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/FieldableEntityStorageInterface.php @@ -0,0 +1,117 @@ +entityManager->getDefinitions() as $entity_type_id => $entity_type) { $this->derivatives[$entity_type_id] = array( 'label' => $entity_type->getLabel(), + 'class' => $entity_type->getClass(), 'constraints' => array('EntityType' => $entity_type_id), ) + $base_plugin_definition; @@ -91,6 +92,7 @@ public function getDerivativeDefinitions($base_plugin_definition) { if ($bundle !== $entity_type_id) { $this->derivatives[$entity_type_id . ':' . $bundle] = array( 'label' => $bundle_info['label'], + 'class' => $entity_type->getClass(), 'constraints' => array( 'EntityType' => $entity_type_id, 'Bundle' => $bundle, diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php new file mode 100644 index 0000000..5755c51 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/Entity.php @@ -0,0 +1,26 @@ +setEntityTypeId($entity->getEntityTypeId()) - ->setBundles([ $entity->bundle() ]); - $instance = new static($definition); - $instance->setValue($entity); - return $instance; - } - - /** - * {@inheritdoc} - */ - public function getValue() { - return $this->entity; - } - - /** - * {@inheritdoc} - */ - public function setValue($entity, $notify = TRUE) { - $this->entity = $entity; - // Notify the parent of any changes. - if ($notify && isset($this->parent)) { - $this->parent->onChange($this->name); - } - } - - /** - * {@inheritdoc} - */ - public function get($property_name) { - if (!isset($this->entity)) { - throw new MissingDataException(String::format('Unable to get property @name as no entity has been provided.', array('@name' => $property_name))); - } - if (!$this->entity instanceof ContentEntityInterface) { - // @todo: Add support for config entities in - // https://www.drupal.org/node/1818574. - throw new \InvalidArgumentException(String::format('Unable to get unknown property @name.', array('@name' => $property_name))); - } - // This will throw an exception for unknown fields. - return $this->entity->get($property_name); - } - - /** - * {@inheritdoc} - */ - public function set($property_name, $value, $notify = TRUE) { - if (!isset($this->entity)) { - throw new MissingDataException(String::format('Unable to set property @name as no entity has been provided.', array('@name' => $property_name))); - } - if (!$this->entity instanceof ContentEntityInterface) { - // @todo: Add support for config entities in - // https://www.drupal.org/node/1818574. - throw new \InvalidArgumentException(String::format('Unable to set unknown property @name.', array('@name' => $property_name))); - } - // This will throw an exception for unknown fields. - return $this->entity->set($property_name, $value, $notify); - } - - /** - * {@inheritdoc} - */ - public function getProperties($include_computed = FALSE) { - if (!isset($this->entity)) { - throw new MissingDataException(String::format('Unable to get properties as no entity has been provided.')); - } - if (!$this->entity instanceof ContentEntityInterface) { - // @todo: Add support for config entities in - // https://www.drupal.org/node/1818574. - return array(); - } - return $this->entity->getFields($include_computed); - } - - /** - * {@inheritdoc} - */ - public function toArray() { - if (!isset($this->entity)) { - throw new MissingDataException(String::format('Unable to get property values as no entity has been provided.')); - } - return $this->entity->toArray(); - } - - /** - * {@inheritdoc} - */ - public function isEmpty() { - return !isset($this->entity); - } - - /** - * {@inheritdoc} - */ - public function onChange($property_name) { - if (isset($this->entity) && $this->entity instanceof ContentEntityInterface) { - // Let the entity know of any changes. - $this->entity->onChange($property_name); - } - } - - /** - * {@inheritdoc} - */ - public function getDataDefinition() { - return $this->definition; - } - - /** - * {@inheritdoc} - */ - public function getString() { - return isset($this->entity) ? $this->entity->label() : ''; - } - - /** - * {@inheritdoc} - */ - public function applyDefaultValue($notify = TRUE) { - // Apply the default value of all properties. - foreach ($this->getProperties() as $property) { - $property->applyDefaultValue(FALSE); - } - return $this; - } - - /** - * {@inheritdoc} - */ - public function getIterator() { - return isset($this->entity) ? $this->entity->getIterator() : new \ArrayIterator([]); - } - -} diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php index 3ecce46..a4e8940 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php +++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php @@ -60,9 +60,9 @@ public function getTargetDefinition() { */ public function getTarget() { if (!isset($this->target) && isset($this->id)) { - // If we have a valid reference, return the entity's TypedData adapter. - $entity = entity_load($this->getTargetDefinition()->getEntityTypeId(), $this->id); - $this->target = isset($entity) ? $entity->getTypedData() : NULL; + // If we have a valid reference, return the entity object which is typed + // data itself. + $this->target = entity_load($this->getTargetDefinition()->getEntityTypeId(), $this->id); } return $this->target; } @@ -82,17 +82,22 @@ public function getTargetIdentifier() { /** * {@inheritdoc} */ + public function getValue() { + // Entities are already typed data, so just return that. + return $this->getTarget(); + } + + /** + * {@inheritdoc} + */ public function setValue($value, $notify = TRUE) { unset($this->target); unset($this->id); // Both the entity ID and the entity object may be passed as value. The // reference may also be unset by passing NULL as value. - if (!isset($value)) { - $this->target = NULL; - } - elseif ($value instanceof EntityInterface) { - $this->target = $value->getTypedData(); + if (!isset($value) || $value instanceof EntityInterface) { + $this->target = $value; } elseif (!is_scalar($value) || $this->getTargetDefinition()->getEntityTypeId() === NULL) { throw new \InvalidArgumentException('Value is not a valid entity.'); diff --git a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/BundleConstraintValidator.php b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/BundleConstraintValidator.php index c6743c8..196dab9 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/BundleConstraintValidator.php +++ b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/BundleConstraintValidator.php @@ -7,7 +7,6 @@ namespace Drupal\Core\Entity\Plugin\Validation\Constraint; -use Drupal\Core\TypedData\TypedDataInterface; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; @@ -17,27 +16,11 @@ class BundleConstraintValidator extends ConstraintValidator { /** - * {@inheritdoc} + * Implements \Symfony\Component\Validator\ConstraintValidatorInterface::validate(). */ - public function validate($entity_adapter, Constraint $constraint) { - if (!isset($entity_adapter)) { - return; - } - - // @todo The $entity_adapter parameter passed to this function should always - // be a typed data object, but due to a bug, the unwrapped entity is - // passed for the computed entity property of entity reference fields. - // Remove this after fixing that in https://www.drupal.org/node/2346373. - if (!$entity_adapter instanceof TypedDataInterface) { - $entity = $entity_adapter; - } - else { - $entity = $entity_adapter->getValue(); - } - - if (!in_array($entity->bundle(), $constraint->getBundleOption())) { + public function validate($entity, Constraint $constraint) { + if (!empty($entity) && !in_array($entity->bundle(), $constraint->getBundleOption())) { $this->context->addViolation($constraint->message, array('%bundle' => implode(', ', $constraint->getBundleOption()))); } } - } diff --git a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php index 5138856..5e316ca 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php +++ b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php @@ -7,7 +7,7 @@ namespace Drupal\Core\Entity\Plugin\Validation\Constraint; -use Drupal\Core\TypedData\TypedDataInterface; +use Drupal\Core\Entity\EntityInterface; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; @@ -19,26 +19,11 @@ class EntityTypeConstraintValidator extends ConstraintValidator { /** * Implements \Symfony\Component\Validator\ConstraintValidatorInterface::validate(). */ - public function validate($entity_adapter, Constraint $constraint) { - if (!isset($entity_adapter)) { - return; - } - - // @todo The $entity_adapter parameter passed to this function should always - // be a typed data object, but due to a bug, the unwrapped entity is - // passed for the computed entity property of entity reference fields. - // Remove this after fixing that in https://www.drupal.org/node/2346373. - if (!$entity_adapter instanceof TypedDataInterface) { - $entity = $entity_adapter; - } - else { - $entity = $entity_adapter->getValue(); - } + public function validate($entity, Constraint $constraint) { /** @var $entity \Drupal\Core\Entity\EntityInterface */ - if ($entity->getEntityTypeId() != $constraint->type) { + if (!empty($entity) && $entity->getEntityTypeId() != $constraint->type) { $this->context->addViolation($constraint->message, array('%type' => $constraint->type)); } } - } diff --git a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ValidReferenceConstraintValidator.php b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ValidReferenceConstraintValidator.php index 75cc152..bc269c5 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ValidReferenceConstraintValidator.php +++ b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ValidReferenceConstraintValidator.php @@ -27,7 +27,7 @@ public function validate($value, Constraint $constraint) { if (empty($id)) { return; } - $referenced_entity = $value->get('entity')->getValue(); + $referenced_entity = $value->get('entity')->getTarget(); if (!$referenced_entity) { $type = $value->getFieldDefinition()->getSetting('target_type'); $this->context->addViolation($constraint->message, array('%type' => $type, '%id' => $id)); diff --git a/core/lib/Drupal/Core/Entity/Schema/DynamicallyFieldableEntityStorageSchemaInterface.php b/core/lib/Drupal/Core/Entity/Schema/DynamicallyFieldableEntityStorageSchemaInterface.php deleted file mode 100644 index 59272f8..0000000 --- a/core/lib/Drupal/Core/Entity/Schema/DynamicallyFieldableEntityStorageSchemaInterface.php +++ /dev/null @@ -1,84 +0,0 @@ -attachPropertyData($entities); // Attach field values. - $this->loadFieldItems($entities); + if ($this->entityType->isFieldable()) { + $this->loadFieldItems($entities); + } return $entities; } @@ -1179,7 +1180,7 @@ public function getQueryServiceName() { * An array of entities keyed by entity ID. */ protected function loadFieldItems(array $entities) { - if (empty($entities)) { + if (empty($entities) || !$this->entityType->isFieldable()) { return; } @@ -1531,12 +1532,12 @@ public function onFieldDefinitionDelete(FieldDefinitionInterface $field_definiti $revision_name = $table_mapping->getDedicatedRevisionTableName($storage_definition); $this->database->update($table_name) ->fields(array('deleted' => 1)) - ->condition('bundle', $field_definition->getTargetBundle()) + ->condition('bundle', $field_definition->getBundle()) ->execute(); if ($this->entityType->isRevisionable()) { $this->database->update($revision_name) ->fields(array('deleted' => 1)) - ->condition('bundle', $field_definition->getTargetBundle()) + ->condition('bundle', $field_definition->getBundle()) ->execute(); } } @@ -1545,17 +1546,7 @@ public function onFieldDefinitionDelete(FieldDefinitionInterface $field_definiti /** * {@inheritdoc} */ - public function onBundleCreate($bundle, $entity_type_id) { } - - /** - * {@inheritdoc} - */ - public function onBundleDelete($bundle, $entity_type_id) { } - - /** - * {@inheritdoc} - */ - public function onBundleRename($bundle, $bundle_new, $entity_type_id) { + public function onBundleRename($bundle, $bundle_new) { // The method runs before the field definitions are updated, so we use the // old bundle name. $field_definitions = $this->entityManager->getFieldDefinitions($this->entityTypeId, $bundle); @@ -1606,7 +1597,7 @@ protected function readFieldItemsToPurge(FieldDefinitionInterface $field_definit $entity_query ->distinct(TRUE) ->fields('t', array('entity_id')) - ->condition('bundle', $field_definition->getTargetBundle()) + ->condition('bundle', $field_definition->getBundle()) ->range(0, $batch_size); // Create a map of field data table column names to field column names. @@ -1641,8 +1632,7 @@ protected function readFieldItemsToPurge(FieldDefinitionInterface $field_definit // Create field item objects and return. foreach ($items_by_entity as $revision_id => $values) { - $entity_adapter = $entities[$revision_id]->getTypedData(); - $items_by_entity[$revision_id] = \Drupal::typedDataManager()->create($field_definition, $values, $field_definition->getName(), $entity_adapter); + $items_by_entity[$revision_id] = \Drupal::typedDataManager()->create($field_definition, $values, $field_definition->getName(), $entities[$revision_id]); } return $items_by_entity; } diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php index dac6584..de6910f 100644 --- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php @@ -14,7 +14,7 @@ use Drupal\Core\Entity\EntityStorageException; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Entity\Exception\FieldStorageDefinitionUpdateForbiddenException; -use Drupal\Core\Entity\Schema\DynamicallyFieldableEntityStorageSchemaInterface; +use Drupal\Core\Entity\Schema\FieldableEntityStorageSchemaInterface; use Drupal\Core\Field\FieldException; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\field\FieldStorageConfigInterface; @@ -27,7 +27,7 @@ * optimizations and getSharedTableFieldSchema() for optimizations applying to * a single field. */ -class SqlContentEntityStorageSchema implements DynamicallyFieldableEntityStorageSchemaInterface { +class SqlContentEntityStorageSchema implements FieldableEntityStorageSchemaInterface { /** * The entity manager. diff --git a/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinition.php b/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinition.php index 30a63a2..c2268c8 100644 --- a/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinition.php +++ b/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinition.php @@ -57,9 +57,9 @@ public static function createFromDataType($data_type) { public function getPropertyDefinitions() { if (!isset($this->propertyDefinitions)) { if ($entity_type_id = $this->getEntityTypeId()) { - // Return an empty array for entities that are not content entities. + // Return an empty array for entity types that don't support typed data. $entity_type_class = \Drupal::entityManager()->getDefinition($entity_type_id)->getClass(); - if (!in_array('Drupal\Core\Entity\ContentEntityInterface', class_implements($entity_type_class))) { + if (!in_array('Drupal\Core\TypedData\TypedDataInterface', class_implements($entity_type_class))) { $this->propertyDefinitions = array(); } else { @@ -89,13 +89,9 @@ public function getDataType() { $type = 'entity'; if ($entity_type = $this->getEntityTypeId()) { $type .= ':' . $entity_type; - // Append the bundle only if we know it for sure and it is not the default - // bundle. + // Append the bundle only if we know it for sure. if (($bundles = $this->getBundles()) && count($bundles) == 1) { - $bundle = reset($bundles); - if ($bundle != $entity_type) { - $type .= ':' . $bundle; - } + $type .= ':' . reset($bundles); } } return $type; diff --git a/core/lib/Drupal/Core/Extension/ModuleHandler.php b/core/lib/Drupal/Core/Extension/ModuleHandler.php index ae2f890..f0b06dd 100644 --- a/core/lib/Drupal/Core/Extension/ModuleHandler.php +++ b/core/lib/Drupal/Core/Extension/ModuleHandler.php @@ -944,7 +944,7 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) { foreach ($entity_manager->getDefinitions() as $entity_type_id => $entity_type) { if ($entity_type->getProvider() == $module) { foreach (array_keys($entity_manager->getBundleInfo($entity_type_id)) as $bundle) { - $entity_manager->onBundleDelete($bundle, $entity_type_id); + $entity_manager->onBundleDelete($entity_type_id, $bundle); } } } diff --git a/core/lib/Drupal/Core/Extension/ThemeHandler.php b/core/lib/Drupal/Core/Extension/ThemeHandler.php index 694185f..387da80 100644 --- a/core/lib/Drupal/Core/Extension/ThemeHandler.php +++ b/core/lib/Drupal/Core/Extension/ThemeHandler.php @@ -35,6 +35,8 @@ class ThemeHandler implements ThemeHandlerInterface { 'node_user_picture', 'comment_user_picture', 'comment_user_verification', + 'main_menu', + 'secondary_menu', ); /** @@ -449,8 +451,6 @@ public function rebuildThemeData() { 'sidebar_second' => 'Right sidebar', 'content' => 'Content', 'header' => 'Header', - 'primary_menu' => 'Primary menu', - 'secondary_menu' => 'Secondary menu', 'footer' => 'Footer', 'highlighted' => 'Highlighted', 'help' => 'Help', diff --git a/core/lib/Drupal/Core/Field/BaseFieldDefinition.php b/core/lib/Drupal/Core/Field/BaseFieldDefinition.php index 7eb0d8a..fb9f0a6 100644 --- a/core/lib/Drupal/Core/Field/BaseFieldDefinition.php +++ b/core/lib/Drupal/Core/Field/BaseFieldDefinition.php @@ -11,7 +11,6 @@ use Drupal\Core\Field\Entity\BaseFieldOverride; use Drupal\Core\Field\TypedData\FieldItemDataDefinition; use Drupal\Core\TypedData\ListDataDefinition; -use Drupal\Core\TypedData\OptionsProviderInterface; /** * A class for defining entity fields. @@ -435,19 +434,6 @@ public function setDefaultValue($value) { /** * {@inheritdoc} */ - public function getOptionsProvider($property_name, ContentEntityInterface $entity) { - // If the field item class implements the interface, proxy it through. - $item = $entity->get($this->getName())->first(); - if ($item instanceof OptionsProviderInterface) { - return $item; - } - // @todo: Allow setting custom options provider, see - // https://www.drupal.org/node/2002138. - } - - /** - * {@inheritdoc} - */ public function getPropertyDefinition($name) { if (!isset($this->propertyDefinitions)) { $this->getPropertyDefinitions(); @@ -533,7 +519,7 @@ public function setTargetEntityTypeId($entity_type_id) { /** * {@inheritdoc} */ - public function getTargetBundle() { + public function getBundle() { return isset($this->definition['bundle']) ? $this->definition['bundle'] : NULL; } @@ -545,7 +531,7 @@ public function getTargetBundle() { * * @return $this */ - public function setTargetBundle($bundle) { + public function setBundle($bundle) { $this->definition['bundle'] = $bundle; return $this; } diff --git a/core/lib/Drupal/Core/Field/FieldConfigBase.php b/core/lib/Drupal/Core/Field/FieldConfigBase.php index 69473f4..2c230c3 100644 --- a/core/lib/Drupal/Core/Field/FieldConfigBase.php +++ b/core/lib/Drupal/Core/Field/FieldConfigBase.php @@ -219,7 +219,7 @@ public function getTargetEntityTypeId() { /** * {@inheritdoc} */ - public function getTargetBundle() { + public function targetBundle() { return $this->bundle; } @@ -428,6 +428,13 @@ public function getItemDefinition() { /** * {@inheritdoc} */ + public function getBundle() { + return $this->bundle; + } + + /** + * {@inheritdoc} + */ public function setDefaultValue($value) { if (!is_array($value)) { $key = $this->getFieldStorageDefinition()->getPropertyNames()[0]; diff --git a/core/lib/Drupal/Core/Field/FieldConfigInterface.php b/core/lib/Drupal/Core/Field/FieldConfigInterface.php index 650c5d4..7d3c384 100644 --- a/core/lib/Drupal/Core/Field/FieldConfigInterface.php +++ b/core/lib/Drupal/Core/Field/FieldConfigInterface.php @@ -52,6 +52,14 @@ public function setTranslatable($translatable); public function allowBundleRename(); /** + * Returns the name of the bundle this field is attached to. + * + * @return string + * The name of the bundle this field is attached to. + */ + public function targetBundle(); + + /** * Sets a default value. * * Note that if a default value callback is set, it will take precedence over diff --git a/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php b/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php index 02843e6..9d1e446 100644 --- a/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php +++ b/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php @@ -76,29 +76,13 @@ public function getName(); public function getType(); /** - * Returns the ID of the entity type the field is attached to. - * - * This method should not be confused with EntityInterface::entityType() - * (configurable fields are config entities, and thus implement both - * interfaces): - * - FieldDefinitionInterface::getTargetEntityTypeId() answers "as a field, - * which entity type are you attached to?". - * - EntityInterface::getEntityTypeId() answers "as a (config) entity, what - * is your own entity type?". - * - * @return string - * The entity type ID. - */ - public function getTargetEntityTypeId(); - - /** * Gets the bundle the field is defined for. * * @return string|null * The bundle the field is defined for, or NULL if it is a base field; i.e., * it is not bundle-specific. */ - public function getTargetBundle(); + public function getBundle(); /** * Returns whether the display for the field can be configured. diff --git a/core/lib/Drupal/Core/Field/FieldItemInterface.php b/core/lib/Drupal/Core/Field/FieldItemInterface.php index 26e885e..03fab78 100644 --- a/core/lib/Drupal/Core/Field/FieldItemInterface.php +++ b/core/lib/Drupal/Core/Field/FieldItemInterface.php @@ -90,7 +90,7 @@ public static function schema(FieldStorageDefinitionInterface $field_definition) /** * Gets the entity that field belongs to. * - * @return \Drupal\Core\Entity\ContentEntityInterface + * @return \Drupal\Core\Entity\EntityInterface * The entity object. */ public function getEntity(); diff --git a/core/lib/Drupal/Core/Field/FieldItemList.php b/core/lib/Drupal/Core/Field/FieldItemList.php index f6ae7d5..69daf67 100644 --- a/core/lib/Drupal/Core/Field/FieldItemList.php +++ b/core/lib/Drupal/Core/Field/FieldItemList.php @@ -57,9 +57,7 @@ public function __construct(DataDefinitionInterface $definition, $name = NULL, T * {@inheritdoc} */ public function getEntity() { - // The "parent" is the TypedData object for the entity, we need to unwrap - // the actual entity. - return $this->getParent()->getValue(); + return $this->getParent(); } /** diff --git a/core/lib/Drupal/Core/Field/FieldStorageDefinitionInterface.php b/core/lib/Drupal/Core/Field/FieldStorageDefinitionInterface.php index 7df3c83..6ace3fa 100644 --- a/core/lib/Drupal/Core/Field/FieldStorageDefinitionInterface.php +++ b/core/lib/Drupal/Core/Field/FieldStorageDefinitionInterface.php @@ -7,8 +7,6 @@ namespace Drupal\Core\Field; -use Drupal\Core\Entity\ContentEntityInterface; - /** * Defines an interface for entity field storage definitions. * @@ -133,19 +131,6 @@ public function getLabel(); public function getDescription(); /** - * Gets an options provider for the given field item property. - * - * @param string $property_name - * The name of the property to get options for; e.g., 'value'. - * @param \Drupal\Core\Entity\ContentEntityInterface $entity - * The entity for which the options should be provided. - * - * @return \Drupal\Core\TypedData\OptionsProviderInterface|null - * An options provider, or NULL if no options are defined. - */ - public function getOptionsProvider($property_name, ContentEntityInterface $entity); - - /** * Returns whether the field can contain multiple items. * * @return bool @@ -213,18 +198,18 @@ public function getPropertyNames(); public function getMainPropertyName(); /** - * Returns the ID of the entity type the field is attached to. + * Returns the ID of the type of the entity this field is attached to. * * This method should not be confused with EntityInterface::entityType() * (configurable fields are config entities, and thus implement both * interfaces): * - FieldStorageDefinitionInterface::getTargetEntityTypeId() answers "as a - * field storage, which entity type are you attached to?". + * field, which entity type are you attached to?". * - EntityInterface::getEntityTypeId() answers "as a (config) entity, what - * is your own entity type?". + * is your own entity type". * * @return string - * The entity type ID. + * The name of the entity type. */ public function getTargetEntityTypeId(); diff --git a/core/lib/Drupal/Core/Language/Language.php b/core/lib/Drupal/Core/Language/Language.php index b04f60f..9e04077 100644 --- a/core/lib/Drupal/Core/Language/Language.php +++ b/core/lib/Drupal/Core/Language/Language.php @@ -68,7 +68,7 @@ class Language implements LanguageInterface { * * @var bool */ - protected $locked = FALSE; + public $locked = FALSE; /** * Constructs a new class instance. @@ -132,13 +132,6 @@ public function isDefault() { } /** - * {@inheritdoc} - */ - public function isLocked() { - return (bool) $this->locked; - } - - /** * Sort language objects. * * @param \Drupal\Core\Language\LanguageInterface[] $languages diff --git a/core/lib/Drupal/Core/Language/LanguageInterface.php b/core/lib/Drupal/Core/Language/LanguageInterface.php index 5f5ff24..f2e58f3 100644 --- a/core/lib/Drupal/Core/Language/LanguageInterface.php +++ b/core/lib/Drupal/Core/Language/LanguageInterface.php @@ -137,12 +137,4 @@ public function getWeight(); */ public function isDefault(); - /** - * Returns whether this language is locked. - * - * @return bool - * Whether the language is locked or not. - */ - public function isLocked(); - } diff --git a/core/lib/Drupal/Core/Language/LanguageManager.php b/core/lib/Drupal/Core/Language/LanguageManager.php index 605a5ab..e86c6ce 100644 --- a/core/lib/Drupal/Core/Language/LanguageManager.php +++ b/core/lib/Drupal/Core/Language/LanguageManager.php @@ -154,7 +154,7 @@ public function getLanguages($flags = LanguageInterface::STATE_CONFIGURABLE) { } foreach ($this->languages as $id => $language) { - if (($language->isLocked() && ($flags & LanguageInterface::STATE_LOCKED)) || (!$language->isLocked() && ($flags & LanguageInterface::STATE_CONFIGURABLE))) { + if (($language->locked && ($flags & LanguageInterface::STATE_LOCKED)) || (!$language->locked && ($flags & LanguageInterface::STATE_CONFIGURABLE))) { $filtered_languages[$id] = $language; } } @@ -226,7 +226,7 @@ public function getDefaultLockedLanguages($weight = 0) { */ public function isLanguageLocked($langcode) { $language = $this->getLanguage($langcode); - return ($language ? $language->isLocked() : FALSE); + return ($language ? $language->locked : FALSE); } /** diff --git a/core/lib/Drupal/Core/Link.php b/core/lib/Drupal/Core/Link.php index 35dddee..936b541 100644 --- a/core/lib/Drupal/Core/Link.php +++ b/core/lib/Drupal/Core/Link.php @@ -7,15 +7,11 @@ namespace Drupal\Core; -use Drupal\Core\Routing\LinkGeneratorTrait; - /** * Defines an object that holds information about a link. */ class Link { - use LinkGeneratorTrait; - /** * The text of the link. * @@ -120,11 +116,4 @@ public function setUrl(Url $url) { return $this; } - /** - * Generates the HTML for this Link object. - */ - public function toString() { - return $this->getLinkGenerator()->generateFromLink($this); - } - } diff --git a/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php b/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php index 29fa9bc..0d6c995 100644 --- a/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php +++ b/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php @@ -234,4 +234,31 @@ public function flatten(array $tree) { return $tree; } + /** + * Extracts a subtree of the active trail. + * + * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree + * The menu link tree to manipulate. + * @param int $level + * The level in the active trail to extract. + * + * @return \Drupal\Core\Menu\MenuLinkTreeElement[] + * The manipulated menu link tree. + */ + public function extractSubtreeOfActiveTrail(array $tree, $level) { + // Go down the active trail until the right level is reached. + while ($level-- > 0 && $tree) { + // Loop through the current level's elements until we find one that is in + // the active trail. + while ($element = array_shift($tree)) { + if ($element->inActiveTrail) { + // If the element is in the active trail, we continue in the subtree. + $tree = $element->subtree; + break; + } + } + } + return $tree; + } + } diff --git a/core/lib/Drupal/Core/Plugin/Context/Context.php b/core/lib/Drupal/Core/Plugin/Context/Context.php index a0ad01f..0366b71 100644 --- a/core/lib/Drupal/Core/Plugin/Context/Context.php +++ b/core/lib/Drupal/Core/Plugin/Context/Context.php @@ -10,6 +10,7 @@ use Drupal\Component\Plugin\Context\Context as ComponentContext; use Drupal\Component\Plugin\Exception\ContextException; use Drupal\Component\Utility\String; +use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\TypedData\TypedDataInterface; use Drupal\Core\TypedData\TypedDataTrait; @@ -46,6 +47,11 @@ public function getContextValue() { } return NULL; } + // Special case entities. + // @todo: Remove once entities do not implemented TypedDataInterface. + if ($this->contextData instanceof ContentEntityInterface) { + return $this->contextData; + } return $this->contextData->getValue(); } diff --git a/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php b/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php index 1397485..923090e 100644 --- a/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php +++ b/core/lib/Drupal/Core/TypedData/ComplexDataInterface.php @@ -31,13 +31,11 @@ * @param $property_name * The name of the property to get; e.g., 'title' or 'name'. * - * @return \Drupal\Core\TypedData\TypedDataInterface - * The property object. - * * @throws \InvalidArgumentException * If an invalid property name is given. - * @throws \Drupal\Core\TypedData\Exception\MissingDataException - * If the complex data structure is unset and no property can be created. + * + * @return \Drupal\Core\TypedData\TypedDataInterface + * The property object. */ public function get($property_name); @@ -53,13 +51,11 @@ public function get($property_name); * TRUE. If the update stems from a parent object, set it to FALSE to avoid * being notified again. * - * @return \Drupal\Core\TypedData\TypedDataInterface - * The property object. - * * @throws \InvalidArgumentException * If the specified property does not exist. - * @throws \Drupal\Core\TypedData\Exception\MissingDataException - * If the complex data structure is unset and no property can be set. + * + * @return \Drupal\Core\TypedData\TypedDataInterface + * The property object. */ public function set($property_name, $value, $notify = TRUE); @@ -72,9 +68,6 @@ public function set($property_name, $value, $notify = TRUE); * @return \Drupal\Core\TypedData\TypedDataInterface[] * An array of property objects implementing the TypedDataInterface, keyed * by property name. - * - * @throws \Drupal\Core\TypedData\Exception\MissingDataException - * If the complex data structure is unset and no property can be created. */ public function getProperties($include_computed = FALSE); @@ -86,9 +79,6 @@ public function getProperties($include_computed = FALSE); * * @return array * An array of property values, keyed by property name. - * - * @throws \Drupal\Core\TypedData\Exception\MissingDataException - * If the complex data structure is unset and no property can be created. */ public function toArray(); diff --git a/core/lib/Drupal/Core/TypedData/DataDefinitionException.php b/core/lib/Drupal/Core/TypedData/DataDefinitionException.php new file mode 100644 index 0000000..2a23315 --- /dev/null +++ b/core/lib/Drupal/Core/TypedData/DataDefinitionException.php @@ -0,0 +1,15 @@ +get('system.filter')->get('protocols') ?: ['http', 'https']; - UrlHelper::setAllowedProtocols($allowed_protocols); - $this->requestStack = $request_stack; - } - - /** - * {@inheritdoc} - * - * This is a helper function that calls buildExternalUrl() or buildLocalUrl() - * based on a check of whether the path is a valid external URL. - */ - public function assemble($uri, array $options = []) { - // Note that UrlHelper::isExternal will return FALSE if the $uri has a - // disallowed protocol. This is later made safe since we always add at - // least a leading slash. - if (strpos($uri, 'base://') === 0) { - return $this->buildLocalUrl($uri, $options); - } - elseif (UrlHelper::isExternal($uri)) { - // UrlHelper::isExternal() only returns true for safe protocols. - return $this->buildExternalUrl($uri, $options); - } - throw new \InvalidArgumentException('You must use a valid URI scheme. Use base:// for a path e.g. to a Drupal file that needs the base path.'); - } - - /** - * {@inheritdoc} - */ - protected function buildExternalUrl($uri, array $options = []) { - $this->addOptionDefaults($options); - // Split off the fragment. - if (strpos($uri, '#') !== FALSE) { - list($uri, $old_fragment) = explode('#', $uri, 2); - // If $options contains no fragment, take it over from the path. - if (isset($old_fragment) && !$options['fragment']) { - $options['fragment'] = '#' . $old_fragment; - } - } - - if (isset($options['https'])) { - if ($options['https'] === TRUE) { - $uri = str_replace('http://', 'https://', $uri); - } - elseif ($options['https'] === FALSE) { - $uri = str_replace('https://', 'http://', $uri); - } - } - // Append the query. - if ($options['query']) { - $uri .= (strpos($uri, '?') !== FALSE ? '&' : '?') . UrlHelper::buildQuery($options['query']); - } - // Reassemble. - return $uri . $options['fragment']; - } - - /** - * {@inheritdoc} - */ - protected function buildLocalUrl($uri, array $options = []) { - $this->addOptionDefaults($options); - $request = $this->requestStack->getCurrentRequest(); - - // Remove the base:// scheme. - $uri = substr($uri, 7); - // Add any subdirectory where Drupal is installed. - $current_base_path = $request->getBasePath() . '/'; - - if ($options['absolute']) { - $current_base_url = $request->getSchemeAndHttpHost() . $current_base_path; - if (isset($options['https'])) { - if (!empty($options['https'])) { - $base = str_replace('http://', 'https://', $current_base_url); - $options['absolute'] = TRUE; - } - else { - $base = str_replace('https://', 'http://', $current_base_url); - $options['absolute'] = TRUE; - } - } - else { - $base = $current_base_url; - } - } - else { - $base = $current_base_path; - } - - $prefix = empty($uri) ? rtrim($options['prefix'], '/') : $options['prefix']; - - $uri = str_replace('%2F', '/', rawurlencode($prefix . $uri)); - $query = $options['query'] ? ('?' . UrlHelper::buildQuery($options['query'])) : ''; - return $base . $options['script'] . $uri . $query . $options['fragment']; - } - - /** - * Merges in default defaults - * - * @param array $options - * The options to merge in the defaults. - */ - protected function addOptionDefaults(array &$options) { - // Merge in defaults. - $options += [ - 'fragment' => '', - 'query' => [], - 'absolute' => FALSE, - 'prefix' => '', - 'script' => '', - ]; - - if (isset($options['fragment']) && $options['fragment'] !== '') { - $options['fragment'] = '#' . $options['fragment']; - } - } - -} diff --git a/core/lib/Drupal/Core/Utility/UnroutedUrlAssemblerInterface.php b/core/lib/Drupal/Core/Utility/UnroutedUrlAssemblerInterface.php deleted file mode 100644 index cba87fe..0000000 --- a/core/lib/Drupal/Core/Utility/UnroutedUrlAssemblerInterface.php +++ /dev/null @@ -1,54 +0,0 @@ -_entity; $item = new \stdClass(); - foreach ($entity as $name => $field) { + foreach ($entity->getProperties() as $name => $value) { // views_view_row_rss takes care about the escaping. - $item->{$name} = $field->value; + $item->{$name} = $value->value; } $item->elements = array( diff --git a/core/modules/block/src/Entity/Block.php b/core/modules/block/src/Entity/Block.php index 0036eb8..0c71ed1 100644 --- a/core/modules/block/src/Entity/Block.php +++ b/core/modules/block/src/Entity/Block.php @@ -31,6 +31,7 @@ * } * }, * admin_permission = "administer blocks", + * fieldable = FALSE, * entity_keys = { * "id" = "id" * }, diff --git a/core/modules/block/src/Tests/BlockHtmlTest.php b/core/modules/block/src/Tests/BlockHtmlTest.php index c3a4eff..add65e2 100644 --- a/core/modules/block/src/Tests/BlockHtmlTest.php +++ b/core/modules/block/src/Tests/BlockHtmlTest.php @@ -48,7 +48,7 @@ function testHtml() { $this->assertFieldByXPath('//div[@id="block-test-html-block" and @data-custom-attribute="foo"]', NULL, 'HTML ID and attributes for test block are valid and on the same DOM element.'); // Ensure expected markup for a menu block. - $elements = $this->xpath('//nav[contains(@class, :nav-class)]/ul[contains(@class, :ul-class)]/li', array(':nav-class' => 'block-menu', ':ul-class' => 'menu')); + $elements = $this->xpath('//div[contains(@class, :div-class)]/ul[contains(@class, :ul-class)]/li', array(':div-class' => 'block-system', ':ul-class' => 'menu')); $this->assertTrue(!empty($elements), 'The proper block markup was found.'); } diff --git a/core/modules/block/src/Tests/BlockUiTest.php b/core/modules/block/src/Tests/BlockUiTest.php index 7b6f945..ebe5712 100644 --- a/core/modules/block/src/Tests/BlockUiTest.php +++ b/core/modules/block/src/Tests/BlockUiTest.php @@ -64,7 +64,7 @@ protected function setUp() { ), array( 'label' => 'Powered by Drupal', - 'tr' => '16', + 'tr' => '12', 'plugin_id' => 'system_powered_by_block', 'settings' => array('region' => 'footer', 'id' => 'powered'), 'test_weight' => '0', diff --git a/core/modules/block_content/src/BlockContentTypeForm.php b/core/modules/block_content/src/BlockContentTypeForm.php index 8927162..e34bbc3 100644 --- a/core/modules/block_content/src/BlockContentTypeForm.php +++ b/core/modules/block_content/src/BlockContentTypeForm.php @@ -92,7 +92,7 @@ public function save(array $form, FormStateInterface $form_state) { $block_type = $this->entity; $status = $block_type->save(); - $edit_link = $this->entity->link($this->t('Edit')); + $edit_link = \Drupal::linkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo()); $logger = $this->logger('block_content'); if ($status == SAVED_UPDATED) { drupal_set_message(t('Custom block type %label has been updated.', array('%label' => $block_type->label()))); diff --git a/core/modules/block_content/src/BlockContentTypeListBuilder.php b/core/modules/block_content/src/BlockContentTypeListBuilder.php index 7af28b1..6cfda1d 100644 --- a/core/modules/block_content/src/BlockContentTypeListBuilder.php +++ b/core/modules/block_content/src/BlockContentTypeListBuilder.php @@ -44,7 +44,7 @@ public function buildHeader() { * {@inheritdoc} */ public function buildRow(EntityInterface $entity) { - $row['type'] = $entity->link(); + $row['type'] = \Drupal::linkGenerator()->generateFromUrl($entity->label(), $entity->urlInfo()); $row['description'] = Xss::filterAdmin($entity->description); return $row + parent::buildRow($entity); } diff --git a/core/modules/block_content/src/Entity/BlockContent.php b/core/modules/block_content/src/Entity/BlockContent.php index e2320bd..2d035ec 100644 --- a/core/modules/block_content/src/Entity/BlockContent.php +++ b/core/modules/block_content/src/Entity/BlockContent.php @@ -43,6 +43,7 @@ * "delete-form" = "entity.block_content.delete_form", * "edit-form" = "entity.block_content.canonical", * }, + * fieldable = TRUE, * translatable = TRUE, * entity_keys = { * "id" = "id", diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index 4231ee5..d838125 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -412,7 +412,7 @@ function comment_entity_predelete(EntityInterface $entity) { // mismatched types. So, we need to verify that the ID is numeric (even for an // entity type that has an integer ID, $entity->id() might be a string // containing a number), and then cast it to an integer when querying. - if ($entity instanceof ContentEntityInterface && is_numeric($entity->id())) { + if ($entity->getEntityType()->isFieldable() && is_numeric($entity->id())) { $entity_query = \Drupal::entityQuery('comment'); $entity_query->condition('entity_id', (int) $entity->id()); $entity_query->condition('entity_type', $entity->getEntityTypeId()); diff --git a/core/modules/comment/comment.views.inc b/core/modules/comment/comment.views.inc index cdd7ec0..a3d873b 100644 --- a/core/modules/comment/comment.views.inc +++ b/core/modules/comment/comment.views.inc @@ -22,7 +22,7 @@ function comment_views_data_alter(&$data) { // Provide a integration for each entity type except comment. foreach (\Drupal::entityManager()->getDefinitions() as $entity_type_id => $entity_type) { - if ($entity_type_id == 'comment' || !$entity_type->isSubclassOf('\Drupal\Core\Entity\ContentEntityInterface') || !$entity_type->getBaseTable()) { + if ($entity_type_id == 'comment' || !$entity_type->isFieldable() || !$entity_type->getBaseTable()) { continue; } $fields = \Drupal::service('comment.manager')->getFields($entity_type_id); diff --git a/core/modules/comment/src/CommentTypeForm.php b/core/modules/comment/src/CommentTypeForm.php index 8e73652..0d93b1c 100644 --- a/core/modules/comment/src/CommentTypeForm.php +++ b/core/modules/comment/src/CommentTypeForm.php @@ -7,7 +7,6 @@ namespace Drupal\comment; -use Drupal\Core\Entity\ContentEntityTypeInterface; use Drupal\Core\Entity\EntityForm; use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Entity\EntityTypeInterface; @@ -92,9 +91,7 @@ public function form(array $form, FormStateInterface $form_state) { if ($comment_type->isNew()) { $options = array(); foreach ($this->entityManager->getDefinitions() as $entity_type) { - // Only expose entities that have field UI enabled, only those can - // get comment fields added in the UI. - if ($entity_type->get('field_ui_base_route')) { + if ($entity_type->isFieldable()) { $options[$entity_type->id()] = $entity_type->getLabel(); } } @@ -150,7 +147,7 @@ public function save(array $form, FormStateInterface $form_state) { $comment_type = $this->entity; $status = $comment_type->save(); - $edit_link = $this->entity->link($this->t('Edit')); + $edit_link = \Drupal::linkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo()); if ($status == SAVED_UPDATED) { drupal_set_message(t('Comment type %label has been updated.', array('%label' => $comment_type->label()))); $this->logger->notice('Comment type %label has been updated.', array('%label' => $comment_type->label(), 'link' => $edit_link)); diff --git a/core/modules/comment/src/CommentViewsData.php b/core/modules/comment/src/CommentViewsData.php index ee4f1ce..866bc99 100644 --- a/core/modules/comment/src/CommentViewsData.php +++ b/core/modules/comment/src/CommentViewsData.php @@ -386,7 +386,7 @@ public function getViewsData() { // Provide a relationship for each entity type except comment. foreach ($entities_types as $type => $entity_type) { - if ($type == 'comment' || !$entity_type->isSubclassOf('\Drupal\Core\Entity\ContentEntityInterface') || !$entity_type->getBaseTable()) { + if ($type == 'comment' || !$entity_type->isFieldable() || !$entity_type->getBaseTable()) { continue; } if ($fields = \Drupal::service('comment.manager')->getFields($type)) { @@ -465,7 +465,7 @@ public function getViewsData() { // Provide a relationship for each entity type except comment. foreach ($entities_types as $type => $entity_type) { - if ($type == 'comment' || !$entity_type->isSubclassOf('\Drupal\Core\Entity\ContentEntityInterface') || !$entity_type->getBaseTable()) { + if ($type == 'comment' || !$entity_type->isFieldable() || !$entity_type->getBaseTable()) { continue; } // This relationship does not use the 'field id' column, if the entity has diff --git a/core/modules/comment/src/Entity/Comment.php b/core/modules/comment/src/Entity/Comment.php index 57c7287..b49d993 100644 --- a/core/modules/comment/src/Entity/Comment.php +++ b/core/modules/comment/src/Entity/Comment.php @@ -38,6 +38,7 @@ * base_table = "comment", * data_table = "comment_field_data", * uri_callback = "comment_uri", + * fieldable = TRUE, * translatable = TRUE, * entity_keys = { * "id" = "cid", diff --git a/core/modules/config_translation/config_translation.api.php b/core/modules/config_translation/config_translation.api.php index e44c168..9f7abfc 100644 --- a/core/modules/config_translation/config_translation.api.php +++ b/core/modules/config_translation/config_translation.api.php @@ -48,8 +48,8 @@ function hook_config_translation_info(&$info) { // Ignore non-existent routes. } - // Make sure entity type has field UI enabled and has a base route. - if ($entity_type->get('field_ui_base_route') && !empty($base_route)) { + // Make sure entity type is fieldable and has a base route. + if ($entity_type->isFieldable() && !empty($base_route)) { $info[$entity_type_id . '_fields'] = array( 'base_route_name' => 'field_ui.field_edit_' . $entity_type_id, 'entity_type' => 'field_config', diff --git a/core/modules/config_translation/config_translation.module b/core/modules/config_translation/config_translation.module index 956861a..fa5b183 100644 --- a/core/modules/config_translation/config_translation.module +++ b/core/modules/config_translation/config_translation.module @@ -120,8 +120,8 @@ function config_translation_config_translation_info(&$info) { // Ignore non-existent routes. } - // Make sure entity type has field UI enabled and has a base route. - if ($entity_type->get('field_ui_base_route') && !empty($base_route)) { + // Make sure entity type is fieldable and has a base route. + if ($entity_type->isFieldable() && !empty($base_route)) { $info[$entity_type_id . '_fields'] = array( 'base_route_name' => 'field_ui.field_edit_' . $entity_type_id, 'entity_type' => 'field_config', diff --git a/core/modules/config_translation/src/Access/ConfigTranslationFormAccess.php b/core/modules/config_translation/src/Access/ConfigTranslationFormAccess.php index 09f7fdc..9ea54ef 100644 --- a/core/modules/config_translation/src/Access/ConfigTranslationFormAccess.php +++ b/core/modules/config_translation/src/Access/ConfigTranslationFormAccess.php @@ -32,7 +32,7 @@ public function access(Route $route, AccountInterface $account, $langcode = NULL // that is logically not a good idea. $access = !empty($target_language) && - !$target_language->isLocked() && + !$target_language->locked && (empty($this->sourceLanguage) || ($target_language->id != $this->sourceLanguage->id)); return $base_access->andIf(AccessResult::allowedIf($access)); diff --git a/core/modules/config_translation/src/Access/ConfigTranslationOverviewAccess.php b/core/modules/config_translation/src/Access/ConfigTranslationOverviewAccess.php index 2669778..fe0266b 100644 --- a/core/modules/config_translation/src/Access/ConfigTranslationOverviewAccess.php +++ b/core/modules/config_translation/src/Access/ConfigTranslationOverviewAccess.php @@ -70,12 +70,11 @@ public function access(Route $route, AccountInterface $account) { // Allow access to the translation overview if the proper permission is // granted, the configuration has translatable pieces, and the source // language is not locked if it is present. - $source_language_access = is_null($this->sourceLanguage) || !$this->sourceLanguage->isLocked(); $access = $account->hasPermission('translate configuration') && $mapper->hasSchema() && $mapper->hasTranslatable() && - $source_language_access; + empty($this->sourceLanguage->locked); return AccessResult::allowedIf($access)->cachePerRole(); } diff --git a/core/modules/config_translation/src/ConfigFieldMapper.php b/core/modules/config_translation/src/ConfigFieldMapper.php index 242e084..61e4878 100644 --- a/core/modules/config_translation/src/ConfigFieldMapper.php +++ b/core/modules/config_translation/src/ConfigFieldMapper.php @@ -30,7 +30,7 @@ class ConfigFieldMapper extends ConfigEntityMapper { public function getBaseRouteParameters() { $parameters = parent::getBaseRouteParameters(); $base_entity_info = $this->entityManager->getDefinition($this->pluginDefinition['base_entity_type']); - $parameters[$base_entity_info->getBundleEntityType()] = $this->entity->getTargetBundle(); + $parameters[$base_entity_info->getBundleEntityType()] = $this->entity->targetBundle(); return $parameters; } diff --git a/core/modules/contact/src/ContactFormEditForm.php b/core/modules/contact/src/ContactFormEditForm.php index 123ba38..c07dbf2 100644 --- a/core/modules/contact/src/ContactFormEditForm.php +++ b/core/modules/contact/src/ContactFormEditForm.php @@ -96,7 +96,8 @@ public function save(array $form, FormStateInterface $form_state) { $status = $contact_form->save(); $contact_settings = $this->config('contact.settings'); - $edit_link = $this->entity->link($this->t('Edit')); + $edit_link = \Drupal::linkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo()); + if ($status == SAVED_UPDATED) { drupal_set_message($this->t('Contact form %label has been updated.', array('%label' => $contact_form->label()))); $this->logger('contact')->notice('Contact form %label has been updated.', array('%label' => $contact_form->label(), 'link' => $edit_link)); diff --git a/core/modules/contact/src/Entity/Message.php b/core/modules/contact/src/Entity/Message.php index 20be2e8..bbccd17 100644 --- a/core/modules/contact/src/Entity/Message.php +++ b/core/modules/contact/src/Entity/Message.php @@ -31,6 +31,7 @@ * }, * bundle_entity_type = "contact_form", * field_ui_base_route = "entity.contact_form.edit_form", + * fieldable = TRUE, * ) */ class Message extends ContentEntityBase implements MessageInterface { diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module index 49e4b67..b8d9363 100644 --- a/core/modules/content_translation/content_translation.module +++ b/core/modules/content_translation/content_translation.module @@ -224,7 +224,7 @@ function _content_translation_menu_strip_loaders($path) { */ function content_translation_translate_access(EntityInterface $entity) { $account = \Drupal::currentUser(); - $condition = $entity instanceof ContentEntityInterface && !$entity->getUntranslated()->language()->isLocked() && \Drupal::languageManager()->isMultilingual() && $entity->isTranslatable() && + $condition = $entity instanceof ContentEntityInterface && empty($entity->getUntranslated()->language()->locked) && \Drupal::languageManager()->isMultilingual() && $entity->isTranslatable() && ($account->hasPermission('create content translations') || $account->hasPermission('update content translations') || $account->hasPermission('delete content translations')); return AccessResult::allowedIf($condition)->cachePerRole()->cacheUntilEntityChanges($entity); } diff --git a/core/modules/content_translation/src/Tests/ContentTranslationTestBase.php b/core/modules/content_translation/src/Tests/ContentTranslationTestBase.php index 3e14a6a..8bed5da 100644 --- a/core/modules/content_translation/src/Tests/ContentTranslationTestBase.php +++ b/core/modules/content_translation/src/Tests/ContentTranslationTestBase.php @@ -173,28 +173,31 @@ protected function enableTranslation() { * Creates the test fields. */ protected function setupTestFields() { - if (empty($this->fieldName)) { - $this->fieldName = 'field_test_et_ui_test'; + $entity_type = \Drupal::entityManager()->getDefinition($this->entityTypeId); + if ($entity_type->isFieldable()) { + if (empty($this->fieldName)) { + $this->fieldName = 'field_test_et_ui_test'; + } + entity_create('field_storage_config', array( + 'field_name' => $this->fieldName, + 'type' => 'string', + 'entity_type' => $this->entityTypeId, + 'cardinality' => 1, + 'translatable' => TRUE, + ))->save(); + entity_create('field_config', array( + 'entity_type' => $this->entityTypeId, + 'field_name' => $this->fieldName, + 'bundle' => $this->bundle, + 'label' => 'Test translatable text-field', + ))->save(); + entity_get_form_display($this->entityTypeId, $this->bundle, 'default') + ->setComponent($this->fieldName, array( + 'type' => 'string_textfield', + 'weight' => 0, + )) + ->save(); } - entity_create('field_storage_config', array( - 'field_name' => $this->fieldName, - 'type' => 'string', - 'entity_type' => $this->entityTypeId, - 'cardinality' => 1, - 'translatable' => TRUE, - ))->save(); - entity_create('field_config', array( - 'entity_type' => $this->entityTypeId, - 'field_name' => $this->fieldName, - 'bundle' => $this->bundle, - 'label' => 'Test translatable text-field', - ))->save(); - entity_get_form_display($this->entityTypeId, $this->bundle, 'default') - ->setComponent($this->fieldName, array( - 'type' => 'string_textfield', - 'weight' => 0, - )) - ->save(); } /** diff --git a/core/modules/field/field.module b/core/modules/field/field.module index 3988f25..980ec21 100644 --- a/core/modules/field/field.module +++ b/core/modules/field/field.module @@ -6,7 +6,6 @@ use Drupal\Core\Config\ConfigImporter; use Drupal\Core\Entity\EntityTypeInterface; -use Drupal\Core\Entity\DynamicallyFieldableEntityStorageInterface; use Drupal\Core\Extension\Extension; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Routing\RouteMatchInterface; @@ -153,19 +152,20 @@ function field_system_info_alter(&$info, Extension $file, $type) { * Implements hook_entity_field_storage_info(). */ function field_entity_field_storage_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type) { - if (\Drupal::entityManager()->getStorage($entity_type->id()) instanceof DynamicallyFieldableEntityStorageInterface) { + // Expose storage definitions for all exposed bundle fields. + if ($entity_type->isFieldable()) { // Query by filtering on the ID as this is more efficient than filtering // on the entity_type property directly. $ids = \Drupal::entityQuery('field_storage_config') ->condition('id', $entity_type->id() . '.', 'STARTS_WITH') ->execute(); + // Fetch all fields and key them by field name. $field_storages = entity_load_multiple('field_storage_config', $ids); $result = array(); foreach ($field_storages as $field_storage) { $result[$field_storage->getName()] = $field_storage; } - return $result; } } @@ -174,19 +174,19 @@ function field_entity_field_storage_info(\Drupal\Core\Entity\EntityTypeInterface * Implements hook_entity_bundle_field_info(). */ function field_entity_bundle_field_info(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) { - if (\Drupal::entityManager()->getStorage($entity_type->id()) instanceof DynamicallyFieldableEntityStorageInterface) { + if ($entity_type->isFieldable()) { // Query by filtering on the ID as this is more efficient than filtering // on the entity_type property directly. $ids = \Drupal::entityQuery('field_config') ->condition('id', $entity_type->id() . '.' . $bundle . '.', 'STARTS_WITH') ->execute(); + // Fetch all fields and key them by field name. $field_configs = entity_load_multiple('field_config', $ids); $result = array(); - foreach ($field_configs as $field_instance) { - $result[$field_instance->getName()] = $field_instance; + foreach ($field_configs as $field) { + $result[$field->getName()] = $field; } - return $result; } } diff --git a/core/modules/field/src/Entity/FieldStorageConfig.php b/core/modules/field/src/Entity/FieldStorageConfig.php index c6e9bd1..7f9d5d9 100644 --- a/core/modules/field/src/Entity/FieldStorageConfig.php +++ b/core/modules/field/src/Entity/FieldStorageConfig.php @@ -10,11 +10,9 @@ use Drupal\Component\Utility\String; use Drupal\Component\Utility\Unicode; use Drupal\Core\Config\Entity\ConfigEntityBase; -use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Field\FieldException; use Drupal\Core\Field\FieldStorageDefinitionInterface; -use Drupal\Core\TypedData\OptionsProviderInterface; use Drupal\field\FieldStorageConfigInterface; /** @@ -585,19 +583,6 @@ public function isRequired() { /** * {@inheritdoc} */ - public function getOptionsProvider($property_name, ContentEntityInterface $entity) { - // If the field item class implements the interface, proxy it through. - $item = $entity->get($this->getName())->first(); - if ($item instanceof OptionsProviderInterface) { - return $item; - } - // @todo: Allow setting custom options provider, see - // https://www.drupal.org/node/2002138. - } - - /** - * {@inheritdoc} - */ public function isMultiple() { $cardinality = $this->getCardinality(); return ($cardinality == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) || ($cardinality > 1); diff --git a/core/modules/field/src/Tests/FieldDataCountTest.php b/core/modules/field/src/Tests/FieldDataCountTest.php index cc1d792..967e60f 100644 --- a/core/modules/field/src/Tests/FieldDataCountTest.php +++ b/core/modules/field/src/Tests/FieldDataCountTest.php @@ -20,7 +20,7 @@ class FieldDataCountTest extends FieldUnitTestBase { /** - * @var \Drupal\Core\Entity\DynamicallyFieldableEntityStorageInterface + * @var \Drupal\Core\Entity\FieldableEntityStorageInterface */ protected $storage; diff --git a/core/modules/field_ui/src/Controller/EntityDisplayModeController.php b/core/modules/field_ui/src/Controller/EntityDisplayModeController.php index 88ffd4e..a2e11c9 100644 --- a/core/modules/field_ui/src/Controller/EntityDisplayModeController.php +++ b/core/modules/field_ui/src/Controller/EntityDisplayModeController.php @@ -24,7 +24,7 @@ class EntityDisplayModeController extends ControllerBase { public function viewModeTypeSelection() { $entity_types = array(); foreach ($this->entityManager()->getDefinitions() as $entity_type_id => $entity_type) { - if ($entity_type->get('field_ui_base_route') && $entity_type->hasViewBuilderClass()) { + if ($entity_type->isFieldable() && $entity_type->hasViewBuilderClass()) { $entity_types[$entity_type_id] = array( 'title' => $entity_type->getLabel(), 'url' => new Url('field_ui.entity_view_mode_add_type', array('entity_type_id' => $entity_type_id)), @@ -47,7 +47,7 @@ public function viewModeTypeSelection() { public function formModeTypeSelection() { $entity_types = array(); foreach ($this->entityManager()->getDefinitions() as $entity_type_id => $entity_type) { - if ($entity_type->get('field_ui_base_route') && $entity_type->hasFormClasses()) { + if ($entity_type->isFieldable() && $entity_type->hasFormClasses()) { $entity_types[$entity_type_id] = array( 'title' => $entity_type->getLabel(), 'url' => new Url('field_ui.entity_form_mode_add_type', array('entity_type_id' => $entity_type_id)), diff --git a/core/modules/field_ui/src/EntityDisplayModeListBuilder.php b/core/modules/field_ui/src/EntityDisplayModeListBuilder.php index 2a73834..f52d721 100644 --- a/core/modules/field_ui/src/EntityDisplayModeListBuilder.php +++ b/core/modules/field_ui/src/EntityDisplayModeListBuilder.php @@ -92,8 +92,8 @@ public function render() { continue; } - // Filter entities. - if (!$this->isValidEntity($entity_type)) { + // Filter entities + if ($this->entityTypes[$entity_type]->isFieldable() && !$this->isValidEntity($entity_type)) { continue; } @@ -142,7 +142,7 @@ public function render() { * doesn't has the correct controller. */ protected function isValidEntity($entity_type) { - return $this->entityTypes[$entity_type]->get('field_ui_base_route') && $this->entityTypes[$entity_type]->hasViewBuilderClass(); + return $this->entityTypes[$entity_type]->hasViewBuilderClass(); } } diff --git a/core/modules/field_ui/src/FieldUiPermissions.php b/core/modules/field_ui/src/FieldUiPermissions.php index 48c8a64..c71e938 100644 --- a/core/modules/field_ui/src/FieldUiPermissions.php +++ b/core/modules/field_ui/src/FieldUiPermissions.php @@ -52,7 +52,7 @@ public function fieldPermissions() { $permissions = []; foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) { - if ($entity_type->get('field_ui_base_route')) { + if ($entity_type->isFieldable()) { // Create a permission for each fieldable entity to manage // the fields and the display. $permissions['administer ' . $entity_type_id . ' fields'] = [ diff --git a/core/modules/field_ui/src/Form/EntityDisplayModeAddForm.php b/core/modules/field_ui/src/Form/EntityDisplayModeAddForm.php index cd207de..f8075c9 100644 --- a/core/modules/field_ui/src/Form/EntityDisplayModeAddForm.php +++ b/core/modules/field_ui/src/Form/EntityDisplayModeAddForm.php @@ -49,7 +49,7 @@ public function validate(array $form, FormStateInterface $form_state) { */ protected function prepareEntity() { $definition = $this->entityManager->getDefinition($this->targetEntityTypeId); - if (!$definition->get('field_ui_base_route') || !$definition->hasViewBuilderClass()) { + if (!$definition->isFieldable() || !$definition->hasViewBuilderClass()) { throw new NotFoundHttpException(); } diff --git a/core/modules/field_ui/src/Form/EntityFormModeAddForm.php b/core/modules/field_ui/src/Form/EntityFormModeAddForm.php index d7864ca..b00fb37 100644 --- a/core/modules/field_ui/src/Form/EntityFormModeAddForm.php +++ b/core/modules/field_ui/src/Form/EntityFormModeAddForm.php @@ -19,7 +19,7 @@ class EntityFormModeAddForm extends EntityDisplayModeAddForm { */ protected function prepareEntity() { $definition = $this->entityManager->getDefinition($this->targetEntityTypeId); - if (!$definition->get('field_ui_base_route') || !$definition->hasFormClasses()) { + if (!$definition->isFieldable() || !$definition->hasFormClasses()) { throw new NotFoundHttpException(); } diff --git a/core/modules/field_ui/src/Plugin/Derivative/FieldUiLocalTask.php b/core/modules/field_ui/src/Plugin/Derivative/FieldUiLocalTask.php index ad1f7da..788392c 100644 --- a/core/modules/field_ui/src/Plugin/Derivative/FieldUiLocalTask.php +++ b/core/modules/field_ui/src/Plugin/Derivative/FieldUiLocalTask.php @@ -69,7 +69,7 @@ public function getDerivativeDefinitions($base_plugin_definition) { $this->derivatives = array(); foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) { - if ($entity_type->get('field_ui_base_route')) { + if ($entity_type->isFieldable() && $entity_type->get('field_ui_base_route')) { $this->derivatives["overview_$entity_type_id"] = array( 'route_name' => "field_ui.overview_$entity_type_id", 'weight' => 1, @@ -172,7 +172,7 @@ public function getDerivativeDefinitions($base_plugin_definition) { */ public function alterLocalTasks(&$local_tasks) { foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) { - if ($route_name = $entity_type->get('field_ui_base_route')) { + if ($entity_type->isFieldable() && $route_name = $entity_type->get('field_ui_base_route')) { $local_tasks["field_ui.fields:overview_$entity_type_id"]['base_route'] = $route_name; $local_tasks["field_ui.fields:form_display_overview_$entity_type_id"]['base_route'] = $route_name; $local_tasks["field_ui.fields:display_overview_$entity_type_id"]['base_route'] = $route_name; diff --git a/core/modules/field_ui/src/Routing/RouteSubscriber.php b/core/modules/field_ui/src/Routing/RouteSubscriber.php index 3abb6cf..5fe9f36 100644 --- a/core/modules/field_ui/src/Routing/RouteSubscriber.php +++ b/core/modules/field_ui/src/Routing/RouteSubscriber.php @@ -41,7 +41,7 @@ public function __construct(EntityManagerInterface $manager) { protected function alterRoutes(RouteCollection $collection) { foreach ($this->manager->getDefinitions() as $entity_type_id => $entity_type) { $defaults = array(); - if ($route_name = $entity_type->get('field_ui_base_route')) { + if ($entity_type->isFieldable() && $route_name = $entity_type->get('field_ui_base_route')) { // Try to get the route from the current collection. if (!$entity_route = $collection->get($route_name)) { continue; diff --git a/core/modules/field_ui/tests/modules/field_ui_test/src/Entity/FieldUITestNoBundle.php b/core/modules/field_ui/tests/modules/field_ui_test/src/Entity/FieldUITestNoBundle.php index ec75368..e7b2113 100644 --- a/core/modules/field_ui/tests/modules/field_ui_test/src/Entity/FieldUITestNoBundle.php +++ b/core/modules/field_ui/tests/modules/field_ui_test/src/Entity/FieldUITestNoBundle.php @@ -18,7 +18,8 @@ * entity_keys = { * "id" = "id", * "uuid" = "uuid", - * } + * }, + * fieldable = TRUE * ) */ class FieldUITestNoBundle extends EntityTest { diff --git a/core/modules/hal/src/Normalizer/ContentEntityNormalizer.php b/core/modules/hal/src/Normalizer/ContentEntityNormalizer.php index 6a24454..cec6b4a 100644 --- a/core/modules/hal/src/Normalizer/ContentEntityNormalizer.php +++ b/core/modules/hal/src/Normalizer/ContentEntityNormalizer.php @@ -85,7 +85,7 @@ public function normalize($entity, $format = NULL, array $context = array()) { } } else { - $fields = $entity->getFields(); + $fields = $entity->getProperties(); } // Ignore the entity ID and revision ID. $exclude = array($entity->getEntityType()->getKey('id'), $entity->getEntityType()->getKey('revision')); diff --git a/core/modules/language/language.module b/core/modules/language/language.module index 40b9bfa..381fbd4 100644 --- a/core/modules/language/language.module +++ b/core/modules/language/language.module @@ -148,7 +148,7 @@ function language_process_language_select($element) { if (!isset($element['#options'])) { $element['#options'] = array(); foreach (\Drupal::languageManager()->getLanguages($element['#languages']) as $langcode => $language) { - $element['#options'][$langcode] = $language->isLocked() ? t('- @name -', array('@name' => $language->name)) : $language->name; + $element['#options'][$langcode] = $language->locked ? t('- @name -', array('@name' => $language->name)) : $language->name; } } // Add "Built-in English" language to the select when the default value is @@ -434,7 +434,7 @@ function language_modules_uninstalled($modules) { * Implements hook_ENTITY_TYPE_insert() for 'configurable_language'. */ function language_configurable_language_insert(ConfigurableLanguage $language) { - if ($language->isLocked()) { + if (!empty($language->locked)) { return; } diff --git a/core/modules/language/src/ConfigurableLanguageManager.php b/core/modules/language/src/ConfigurableLanguageManager.php index 6699ab0..1726236 100644 --- a/core/modules/language/src/ConfigurableLanguageManager.php +++ b/core/modules/language/src/ConfigurableLanguageManager.php @@ -337,7 +337,7 @@ public function updateLockedLanguageWeights() { // Get maximum weight to update the system languages to keep them on bottom. foreach ($this->getLanguages(LanguageInterface::STATE_CONFIGURABLE) as $language) { - if (!$language->isLocked() && $language->weight > $max_weight) { + if (!$language->locked && $language->weight > $max_weight) { $max_weight = $language->weight; } } diff --git a/core/modules/language/src/Element/LanguageConfiguration.php b/core/modules/language/src/Element/LanguageConfiguration.php index e24f8bd..273d733 100644 --- a/core/modules/language/src/Element/LanguageConfiguration.php +++ b/core/modules/language/src/Element/LanguageConfiguration.php @@ -100,7 +100,7 @@ protected static function getDefaultOptions() { $languages = static::languageManager()->getLanguages(LanguageInterface::STATE_ALL); foreach ($languages as $langcode => $language) { - $language_options[$langcode] = $language->isLocked() ? t('- @name -', array('@name' => $language->name)) : $language->name; + $language_options[$langcode] = $language->locked ? t('- @name -', array('@name' => $language->name)) : $language->name; } return $language_options; diff --git a/core/modules/language/src/Entity/ConfigurableLanguage.php b/core/modules/language/src/Entity/ConfigurableLanguage.php index 1235b8a..bcdf7e2 100644 --- a/core/modules/language/src/Entity/ConfigurableLanguage.php +++ b/core/modules/language/src/Entity/ConfigurableLanguage.php @@ -78,7 +78,7 @@ class ConfigurableLanguage extends ConfigEntityBase implements ConfigurableLangu * * @var bool */ - protected $locked = FALSE; + public $locked = FALSE; /** * Used during saving to detect when the site becomes multilingual. @@ -103,13 +103,6 @@ public function isDefault() { /** * {@inheritdoc} */ - public function isLocked() { - return (bool) $this->locked; - } - - /** - * {@inheritdoc} - */ public function preSave(EntityStorageInterface $storage) { parent::preSave($storage); // Store whether or not the site is already multilingual so that we can diff --git a/core/modules/language/src/LanguageAccessControlHandler.php b/core/modules/language/src/LanguageAccessControlHandler.php index 0490e91..4322c17 100644 --- a/core/modules/language/src/LanguageAccessControlHandler.php +++ b/core/modules/language/src/LanguageAccessControlHandler.php @@ -26,8 +26,7 @@ public function checkAccess(EntityInterface $entity, $operation, $langcode, Acco switch ($operation) { case 'update': case 'delete': - /* @var \Drupal\Core\Language\LanguageInterface $entity */ - return AccessResult::allowedIf(!$entity->isLocked())->cacheUntilEntityChanges($entity) + return AccessResult::allowedIf(!$entity->locked)->cacheUntilEntityChanges($entity) ->andIf(parent::checkAccess($entity, $operation, $langcode, $account)); default: diff --git a/core/modules/language/src/Tests/LanguageConfigurationTest.php b/core/modules/language/src/Tests/LanguageConfigurationTest.php index d7cc61f..c7e66d6 100644 --- a/core/modules/language/src/Tests/LanguageConfigurationTest.php +++ b/core/modules/language/src/Tests/LanguageConfigurationTest.php @@ -172,7 +172,7 @@ protected function getHighestConfigurableLanguageWeight(){ $languages = entity_load_multiple('configurable_language', NULL, TRUE); foreach ($languages as $language) { - if (!$language->isLocked() && $language->weight > $max_weight) { + if (!$language->locked && $language->weight > $max_weight) { $max_weight = $language->weight; } } diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module index a6b785e..d2db127 100644 --- a/core/modules/locale/locale.module +++ b/core/modules/locale/locale.module @@ -592,7 +592,7 @@ function locale_form_language_admin_overview_form_alter(&$form, FormStateInterfa 'translated' => 0, 'ratio' => 0, ); - if (!$language->isLocked() && ($langcode != 'en' || locale_translate_english())) { + if (!$language->locked && ($langcode != 'en' || locale_translate_english())) { $form['languages'][$langcode]['locale_statistics'] = array( '#markup' => \Drupal::l( t('@translated/@total (@ratio%)', array( diff --git a/core/modules/locale/src/Tests/LocaleConfigTranslationImportTest.php b/core/modules/locale/src/Tests/LocaleConfigTranslationImportTest.php new file mode 100644 index 0000000..daa5cb8 --- /dev/null +++ b/core/modules/locale/src/Tests/LocaleConfigTranslationImportTest.php @@ -0,0 +1,86 @@ +drupalCreateUser(array('administer modules', 'administer site configuration', 'administer languages', 'access administration pages', 'administer permissions')); + $this->drupalLogin($admin_user); + + // Update module should not go out to d.o to check for updates. We override + // the url to the default update_test xml path. But without providing + // a mock xml file, no update data will be found. + \Drupal::config('update.settings')->set('fetch.url', url('update-test', array('absolute' => TRUE)))->save(); + + } + + /** + * Tests configuration translation import when locale module is enabled after + * a language was added. + */ + public function testConfigTranslationImport() { + + // Add a language. The Afrikaans translation file of locale_test_translate + // (test.af.po) has been prepared with a configuration translation. + \Drupal\language\Entity\ConfigurableLanguage::createFromLangcode('af')->save(); + + // Enable locale module. + $this->container->get('module_handler')->install(array('locale')); + $this->resetAll(); + + // Enable import of translations. By default this is disabled for automated + // tests. + \Drupal::config('locale.settings') + ->set('translation.import_enabled', TRUE) + ->save(); + + // Add translation permissions now the locale module has been enabled. + $edit = array( + 'authenticated[translate interface]' => 'translate interface', + ); + $this->drupalPostForm('admin/people/permissions', $edit, t('Save permissions')); + + // Check and update the translation status. This will import the Afrikaans + // translations of locale_test_translate module. + $this->drupalGet('admin/reports/translations/check'); + + // Override the Drupal core translation status to be up to date. + // Drupal core should not be a subject in this test. + $status = locale_translation_get_status(); + $status['drupal']['af']->type = 'current'; + \Drupal::state()->set('locale.translation_status', $status); + + $this->drupalPostForm('admin/reports/translations', array(), t('Update translations')); + + // Check if configuration translations have been imported. + $override = \Drupal::languageManager()->getLanguageConfigOverride('af', 'system.maintenance'); + $this->assertEqual($override->get('message'), 'Ons is tans besig met onderhoud op @site. Wees asseblief geduldig, ons sal binnekort weer terug wees.'); + } + +} diff --git a/core/modules/locale/tests/test.af.po b/core/modules/locale/tests/test.af.po new file mode 100644 index 0000000..2391464 --- /dev/null +++ b/core/modules/locale/tests/test.af.po @@ -0,0 +1,10 @@ +msgid "" +msgstr "" +"Project-Id-Version: Drupal 8\\n" +"MIME-Version: 1.0\\n" +"Content-Type: text/plain; charset=UTF-8\\n" +"Content-Transfer-Encoding: 8bit\\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\\n" + +msgid "@site is currently under maintenance. We should be back shortly. Thank you for your patience." +msgstr "Ons is tans besig met onderhoud op @site. Wees asseblief geduldig, ons sal binnekort weer terug wees." diff --git a/core/modules/menu_link_content/src/Entity/MenuLinkContent.php b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php index 55f3489..c39d156 100644 --- a/core/modules/menu_link_content/src/Entity/MenuLinkContent.php +++ b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php @@ -31,6 +31,7 @@ * admin_permission = "administer menu", * base_table = "menu_link_content", * data_table = "menu_link_content_data", + * fieldable = TRUE, * translatable = TRUE, * entity_keys = { * "id" = "id", diff --git a/core/modules/menu_ui/config/install/menu_ui.settings.yml b/core/modules/menu_ui/config/install/menu_ui.settings.yml index c3ee6fb..a79ac97 100644 --- a/core/modules/menu_ui/config/install/menu_ui.settings.yml +++ b/core/modules/menu_ui/config/install/menu_ui.settings.yml @@ -1 +1,3 @@ +main_links: main +secondary_links: account override_parent_selector: false diff --git a/core/modules/menu_ui/config/schema/menu_ui.schema.yml b/core/modules/menu_ui/config/schema/menu_ui.schema.yml index ed1fef8..7855ba3 100644 --- a/core/modules/menu_ui/config/schema/menu_ui.schema.yml +++ b/core/modules/menu_ui/config/schema/menu_ui.schema.yml @@ -4,6 +4,12 @@ menu_ui.settings: type: mapping label: 'Menu settings' mapping: + main_links: + type: string + label: 'Main links' + secondary_links: + type: string + label: 'Source for secondary links' override_parent_selector: type: boolean label: 'Override parent selector' diff --git a/core/modules/menu_ui/menu_ui.links.task.yml b/core/modules/menu_ui/menu_ui.links.task.yml index 10dd8d0..d9f1937 100644 --- a/core/modules/menu_ui/menu_ui.links.task.yml +++ b/core/modules/menu_ui/menu_ui.links.task.yml @@ -7,3 +7,9 @@ menu_ui.overview_page: title: 'List' route_name: menu_ui.overview_page base_route: menu_ui.overview_page + +menu_ui.settings: + title: 'Settings' + route_name: menu_ui.settings + base_route: menu_ui.overview_page + weight: 100 diff --git a/core/modules/menu_ui/menu_ui.routing.yml b/core/modules/menu_ui/menu_ui.routing.yml index 97fd744..1b431e9 100644 --- a/core/modules/menu_ui/menu_ui.routing.yml +++ b/core/modules/menu_ui/menu_ui.routing.yml @@ -1,3 +1,11 @@ +menu_ui.settings: + path: '/admin/structure/menu/settings' + defaults: + _form: 'Drupal\menu_ui\MenuSettingsForm' + _title: 'Menus' + requirements: + _permission: 'administer menu' + menu_ui.overview_page: path: '/admin/structure/menu' defaults: diff --git a/core/modules/menu_ui/src/MenuForm.php b/core/modules/menu_ui/src/MenuForm.php index 46faf55..1115070 100644 --- a/core/modules/menu_ui/src/MenuForm.php +++ b/core/modules/menu_ui/src/MenuForm.php @@ -182,7 +182,7 @@ public function save(array $form, FormStateInterface $form_state) { $status = $menu->save(); - $edit_link = $this->entity->link($this->t('Edit')); + $edit_link = $this->linkGenerator->generateFromUrl($this->t('Edit'), $this->entity->urlInfo()); if ($status == SAVED_UPDATED) { drupal_set_message($this->t('Menu %label has been updated.', array('%label' => $menu->label()))); $this->logger('menu')->notice('Menu %label has been updated.', array('%label' => $menu->label(), 'link' => $edit_link)); diff --git a/core/modules/menu_ui/src/MenuSettingsForm.php b/core/modules/menu_ui/src/MenuSettingsForm.php new file mode 100644 index 0000000..7644790 --- /dev/null +++ b/core/modules/menu_ui/src/MenuSettingsForm.php @@ -0,0 +1,73 @@ +config('menu_ui.settings'); + $form['intro'] = array( + '#type' => 'item', + '#markup' => t('The Menu UI module allows on-the-fly creation of menu links in the content authoring forms. To configure these settings for a particular content type, visit the Content types page, click the edit link for the content type, and go to the Menu settings section.', array('@content-types' => $this->url('node.overview_types'))), + ); + + $menu_options = menu_ui_get_menus(); + + $main = $config->get('main_links'); + $form['menu_main_links_source'] = array( + '#type' => 'select', + '#title' => t('Source for the Main links'), + '#default_value' => $main, + '#empty_option' => t('No Main links'), + '#options' => $menu_options, + '#tree' => FALSE, + '#description' => t('Select what should be displayed as the Main links (typically at the top of the page).'), + ); + + $form['menu_secondary_links_source'] = array( + '#type' => 'select', + '#title' => t('Source for the Secondary links'), + '#default_value' => $config->get('secondary_links'), + '#empty_option' => t('No Secondary links'), + '#options' => $menu_options, + '#tree' => FALSE, + '#description' => t('Select the source for the Secondary links. An advanced option allows you to use the same source for both Main links (currently %main) and Secondary links: if your source menu has two levels of hierarchy, the top level menu links will appear in the Main links, and the children of the active link will appear in the Secondary links.', array('%main' => $main ? $menu_options[$main] : t('none'))), + ); + + return parent::buildForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + $this->config('menu_ui.settings') + ->set('main_links', $form_state->getValue('menu_main_links_source')) + ->set('secondary_links', $form_state->getValue('menu_secondary_links_source')) + ->save(); + + parent::submitForm($form, $form_state); + } + +} diff --git a/core/modules/menu_ui/src/Tests/MenuNodeTest.php b/core/modules/menu_ui/src/Tests/MenuNodeTest.php index fdd0e71..11a1aca 100644 --- a/core/modules/menu_ui/src/Tests/MenuNodeTest.php +++ b/core/modules/menu_ui/src/Tests/MenuNodeTest.php @@ -22,13 +22,10 @@ class MenuNodeTest extends WebTestBase { * * @var array */ - public static $modules = array('menu_ui', 'test_page_test', 'node', 'block'); + public static $modules = array('menu_ui', 'test_page_test', 'node'); protected function setUp() { parent::setUp(); - - $this->drupalPlaceBlock('system_menu_block:main'); - $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page')); $this->admin_user = $this->drupalCreateUser(array( diff --git a/core/modules/menu_ui/src/Tests/MenuTest.php b/core/modules/menu_ui/src/Tests/MenuTest.php index c35d0d1..09bc6f4 100644 --- a/core/modules/menu_ui/src/Tests/MenuTest.php +++ b/core/modules/menu_ui/src/Tests/MenuTest.php @@ -839,6 +839,13 @@ private function verifyAccess($response = 200) { $this->assertText(t('Edit menu item'), 'Menu edit page was displayed'); } + // View menu settings page. + $this->drupalGet('admin/structure/menu/settings'); + $this->assertResponse($response); + if ($response == 200) { + $this->assertText(t('Menus'), 'Menu settings page was displayed'); + } + // View add menu page. $this->drupalGet('admin/structure/menu/add'); $this->assertResponse($response); diff --git a/core/modules/migrate_drupal/src/Tests/Dump/Drupal6MenuSettings.php b/core/modules/migrate_drupal/src/Tests/Dump/Drupal6MenuSettings.php index a5ac43f..752614a 100644 --- a/core/modules/migrate_drupal/src/Tests/Dump/Drupal6MenuSettings.php +++ b/core/modules/migrate_drupal/src/Tests/Dump/Drupal6MenuSettings.php @@ -23,6 +23,14 @@ public function load() { 'value', )) ->values(array( + 'name' => 'menu_primary_links_source', + 'value' => 's:13:"primary-links";', + )) + ->values(array( + 'name' => 'menu_secondary_links_source', + 'value' => 's:15:"secondary-links";', + )) + ->values(array( 'name' => 'menu_override_parent_selector', 'value' => 'b:0;', )) diff --git a/core/modules/migrate_drupal/src/Tests/d6/MigrateMenuConfigsTest.php b/core/modules/migrate_drupal/src/Tests/d6/MigrateMenuConfigsTest.php index cc8a89d..aa4fd0c 100644 --- a/core/modules/migrate_drupal/src/Tests/d6/MigrateMenuConfigsTest.php +++ b/core/modules/migrate_drupal/src/Tests/d6/MigrateMenuConfigsTest.php @@ -46,6 +46,8 @@ protected function setUp() { */ public function testMenuSettings() { $config = \Drupal::config('menu_ui.settings'); + $this->assertIdentical($config->get('main_links'), 'primary-links'); + $this->assertIdentical($config->get('secondary_links'), 'secondary-links'); $this->assertIdentical($config->get('override_parent_selector'), FALSE); $this->assertConfigSchema(\Drupal::service('config.typed'), 'menu_ui.settings', $config->get()); } diff --git a/core/modules/node/config/install/views.view.glossary.yml b/core/modules/node/config/install/views.view.glossary.yml index f7ccaef..64541c6 100644 --- a/core/modules/node/config/install/views.view.glossary.yml +++ b/core/modules/node/config/install/views.view.glossary.yml @@ -369,8 +369,6 @@ display: type: normal title: Glossary weight: 0 - menu_name: main - parent: '' field_langcode: '***LANGUAGE_language_content***' field_langcode_add_to_query: null attachment_1: diff --git a/core/modules/node/src/Entity/Node.php b/core/modules/node/src/Entity/Node.php index b01ae1e..ef8c23b 100644 --- a/core/modules/node/src/Entity/Node.php +++ b/core/modules/node/src/Entity/Node.php @@ -41,6 +41,7 @@ * data_table = "node_field_data", * revision_table = "node_revision", * revision_data_table = "node_field_revision", + * fieldable = TRUE, * translatable = TRUE, * entity_keys = { * "id" = "nid", diff --git a/core/modules/node/src/Plugin/Search/NodeSearch.php b/core/modules/node/src/Plugin/Search/NodeSearch.php index 5d13e7d..bd51e98 100644 --- a/core/modules/node/src/Plugin/Search/NodeSearch.php +++ b/core/modules/node/src/Plugin/Search/NodeSearch.php @@ -446,7 +446,7 @@ public function searchFormAlter(array &$form, FormStateInterface $form_state) { $language_list = \Drupal::languageManager()->getLanguages(LanguageInterface::STATE_ALL); foreach ($language_list as $langcode => $language) { // Make locked languages appear special in the list. - $language_options[$langcode] = $language->isLocked() ? t('- @name -', array('@name' => $language->name)) : $language->name; + $language_options[$langcode] = $language->locked ? t('- @name -', array('@name' => $language->name)) : $language->name; } if (count($language_options) > 1) { $form['advanced']['lang-fieldset'] = array( diff --git a/core/modules/options/src/Plugin/Field/FieldWidget/ButtonsWidget.php b/core/modules/options/src/Plugin/Field/FieldWidget/ButtonsWidget.php index 906b8fd..d84854c 100644 --- a/core/modules/options/src/Plugin/Field/FieldWidget/ButtonsWidget.php +++ b/core/modules/options/src/Plugin/Field/FieldWidget/ButtonsWidget.php @@ -33,7 +33,7 @@ class ButtonsWidget extends OptionsWidgetBase { public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) { $element = parent::formElement($items, $delta, $element, $form, $form_state); - $options = $this->getOptions($items->getEntity()); + $options = $this->getOptions($items[$delta]); $selected = $this->getSelectedOptions($items); // If required and there is one single option, preselect it. diff --git a/core/modules/options/src/Plugin/Field/FieldWidget/OptionsWidgetBase.php b/core/modules/options/src/Plugin/Field/FieldWidget/OptionsWidgetBase.php index 6ed388e..ab93250 100644 --- a/core/modules/options/src/Plugin/Field/FieldWidget/OptionsWidgetBase.php +++ b/core/modules/options/src/Plugin/Field/FieldWidget/OptionsWidgetBase.php @@ -7,9 +7,9 @@ namespace Drupal\options\Plugin\Field\FieldWidget; -use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldItemListInterface; +use Drupal\Core\Field\FieldItemInterface; use Drupal\Core\Field\WidgetBase; use Drupal\Core\Form\FormStateInterface; @@ -114,19 +114,16 @@ public static function validateElement(array $element, FormStateInterface $form_ /** * Returns the array of options for the widget. * - * @param \Drupal\Core\Entity\ContentEntityInterface $entity - * The entity for which to return options. + * @param \Drupal\Core\Field\FieldItemInterface $item + * The field item. * * @return array * The array of options for the widget. */ - protected function getOptions(ContentEntityInterface $entity) { + protected function getOptions(FieldItemInterface $item) { if (!isset($this->options)) { // Limit the settable options for the current user account. - $options = $this->fieldDefinition - ->getFieldStorageDefinition() - ->getOptionsProvider($this->column, $entity) - ->getSettableOptions(\Drupal::currentUser()); + $options = $item->getSettableOptions(\Drupal::currentUser()); // Add an empty option if the widget needs one. if ($empty_option = $this->getEmptyOption()) { @@ -146,7 +143,7 @@ protected function getOptions(ContentEntityInterface $entity) { $module_handler = \Drupal::moduleHandler(); $context = array( 'fieldDefinition' => $this->fieldDefinition, - 'entity' => $entity, + 'entity' => $item->getEntity(), ); $module_handler->alter('options_list', $options, $context); @@ -176,7 +173,7 @@ protected function getOptions(ContentEntityInterface $entity) { */ protected function getSelectedOptions(FieldItemListInterface $items, $delta = 0) { // We need to check against a flat list of options. - $flat_options = $this->flattenOptions($this->getOptions($items->getEntity())); + $flat_options = $this->flattenOptions($this->getOptions($items[$delta])); $selected_options = array(); foreach ($items as $item) { diff --git a/core/modules/options/src/Plugin/Field/FieldWidget/SelectWidget.php b/core/modules/options/src/Plugin/Field/FieldWidget/SelectWidget.php index 09e9d37..2c27c3a 100644 --- a/core/modules/options/src/Plugin/Field/FieldWidget/SelectWidget.php +++ b/core/modules/options/src/Plugin/Field/FieldWidget/SelectWidget.php @@ -35,7 +35,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen $element += array( '#type' => 'select', - '#options' => $this->getOptions($items->getEntity()), + '#options' => $this->getOptions($items[$delta]), '#default_value' => $this->getSelectedOptions($items, $delta), // Do not display a 'multiple' select box if there is only one option. '#multiple' => $this->multiple && count($this->options) > 1, diff --git a/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php b/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php index 77f42e7..20c3810 100644 --- a/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php +++ b/core/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php @@ -23,7 +23,7 @@ public function defaultAccess($operation = 'view', AccountInterface $account = N if ($operation == 'view') { return AccessResult::allowed(); } - return AccessResult::allowedIfHasPermissions($account, ['create url aliases', 'administer url aliases'], 'OR')->cachePerRole(); + return AccessResult::allowedIf($account->hasPermission('create url aliases') || $account->hasPermission('administer url aliases'))->cachePerRole(); } } diff --git a/core/modules/rest/src/LinkManager/RelationLinkManager.php b/core/modules/rest/src/LinkManager/RelationLinkManager.php index 04ed8ee..8a56fa8 100644 --- a/core/modules/rest/src/LinkManager/RelationLinkManager.php +++ b/core/modules/rest/src/LinkManager/RelationLinkManager.php @@ -9,7 +9,6 @@ use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\CacheBackendInterface; -use Drupal\Core\Entity\ContentEntityTypeInterface; use Drupal\Core\Entity\EntityManagerInterface; class RelationLinkManager implements RelationLinkManagerInterface{ @@ -88,7 +87,7 @@ protected function writeCache() { $data = array(); foreach ($this->entityManager->getDefinitions() as $entity_type) { - if ($entity_type instanceof ContentEntityTypeInterface) { + if ($entity_type->isFieldable()) { foreach ($this->entityManager->getBundleInfo($entity_type->id()) as $bundle => $bundle_info) { foreach ($this->entityManager->getFieldDefinitions($entity_type->id(), $bundle) as $field_definition) { $relation_uri = $this->getRelationUri($entity_type->id(), $bundle, $field_definition->getName()); diff --git a/core/modules/rest/src/Plugin/views/style/Serializer.php b/core/modules/rest/src/Plugin/views/style/Serializer.php index 09e94e6..51366bd 100644 --- a/core/modules/rest/src/Plugin/views/style/Serializer.php +++ b/core/modules/rest/src/Plugin/views/style/Serializer.php @@ -125,12 +125,7 @@ public function render() { $rows[] = $this->view->rowPlugin->render($row); } - $content_type = $this->displayHandler->getContentType(); - if (!empty($this->view->live_preview)) { - $content_type = $this->options['formats'] ? reset($this->options['formats']) : 'json'; - } - - return $this->serializer->serialize($rows, $content_type); + return $this->serializer->serialize($rows, $this->displayHandler->getContentType()); } /** diff --git a/core/modules/rest/src/Tests/Views/StyleSerializerTest.php b/core/modules/rest/src/Tests/Views/StyleSerializerTest.php index 0822eab..ea19d5e 100644 --- a/core/modules/rest/src/Tests/Views/StyleSerializerTest.php +++ b/core/modules/rest/src/Tests/Views/StyleSerializerTest.php @@ -11,7 +11,6 @@ use Drupal\views\Views; use Drupal\views\Tests\Plugin\PluginTestBase; use Drupal\views\Tests\ViewTestData; -use Symfony\Component\HttpFoundation\Request; /** * Tests the serializer style plugin. @@ -260,17 +259,9 @@ public function testFieldRawOutput() { } /** - * Tests the live preview output for json output. + * Tests the preview output for json output. */ - public function testLivePreview() { - // We set up a request so it looks like an request in the live preview. - $request = new Request(); - $request->setFormat('drupal_ajax', 'application/vnd.drupal-ajax'); - $request->headers->set('Accept', 'application/vnd.drupal-ajax'); - /** @var \Symfony\Component\HttpFoundation\RequestStack $request_stack */ - $request_stack = \Drupal::service('request_stack'); - $request_stack->push($request); - + public function testPreview() { $view = Views::getView('test_serializer_display_entity'); $view->setDisplay('rest_export_1'); $this->executeView($view); @@ -285,6 +276,7 @@ public function testLivePreview() { $expected = String::checkPlain($serializer->serialize($entities, 'json')); + $view->display_handler->setContentType('json'); $view->live_preview = TRUE; $build = $view->preview(); diff --git a/core/modules/serialization/tests/src/Unit/Normalizer/EntityNormalizerTest.php b/core/modules/serialization/tests/src/Unit/Normalizer/EntityNormalizerTest.php index 652c650..c9eaa9a 100644 --- a/core/modules/serialization/tests/src/Unit/Normalizer/EntityNormalizerTest.php +++ b/core/modules/serialization/tests/src/Unit/Normalizer/EntityNormalizerTest.php @@ -61,10 +61,10 @@ public function testNormalize() { $content_entity = $this->getMockBuilder('Drupal\Core\Entity\ContentEntityBase') ->disableOriginalConstructor() - ->setMethods(array('getFields')) + ->setMethods(array('getProperties')) ->getMockForAbstractClass(); $content_entity->expects($this->once()) - ->method('getFields') + ->method('getProperties') ->will($this->returnValue($definitions)); $serializer = $this->getMockBuilder('Symfony\Component\Serializer\Serializer') diff --git a/core/modules/shortcut/src/Entity/Shortcut.php b/core/modules/shortcut/src/Entity/Shortcut.php index df96d6f..a3e15e7 100644 --- a/core/modules/shortcut/src/Entity/Shortcut.php +++ b/core/modules/shortcut/src/Entity/Shortcut.php @@ -45,7 +45,8 @@ * "delete-form" = "entity.shortcut.delete_form", * "edit-form" = "entity.shortcut.canonical", * }, - * bundle_entity_type = "shortcut_set" + * bundle_entity_type = "shortcut_set", + * field_ui_base_route = "entity.shortcut.canonical", * ) */ class Shortcut extends ContentEntityBase implements ShortcutInterface { diff --git a/core/modules/shortcut/src/ShortcutSetAccessControlHandler.php b/core/modules/shortcut/src/ShortcutSetAccessControlHandler.php index 384a22d..37da46f 100644 --- a/core/modules/shortcut/src/ShortcutSetAccessControlHandler.php +++ b/core/modules/shortcut/src/ShortcutSetAccessControlHandler.php @@ -46,7 +46,8 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, A * {@inheritdoc} */ protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) { - return AccessResult::allowedIfHasPermission($account, 'administer shortcuts')->orIf(AccessResult::allowedIfHasPermissions($account, ['access shortcuts', 'customize shortcut links'], 'AND')); + $condition = $account->hasPermission('administer shortcuts') || ($account->hasPermission('access shortcuts') && $account->hasPermission('customize shortcut links')); + return AccessResult::allowedIf($condition)->cachePerRole(); } } diff --git a/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php b/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php index 453e465..1627b60 100644 --- a/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php +++ b/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php @@ -35,6 +35,7 @@ class ShortcutTranslationUITest extends ContentTranslationUITest { protected function setUp() { $this->entityTypeId = 'shortcut'; $this->bundle = 'default'; + $this->fieldName = 'title'; parent::setUp(); } @@ -53,13 +54,6 @@ protected function createEntity($values, $langcode, $bundle_name = NULL) { return parent::createEntity($values, $langcode, $bundle_name); } - /** - * {@inheritdoc} - */ - protected function getNewEntityValues($langcode) { - return array('title' => array(array('value' => $this->randomMachineName()))) + parent::getNewEntityValues($langcode); - } - protected function doTestBasicTranslation() { parent::doTestBasicTranslation(); diff --git a/core/modules/system/config/install/system.theme.global.yml b/core/modules/system/config/install/system.theme.global.yml index 5ee6cc7..13036bf 100644 --- a/core/modules/system/config/install/system.theme.global.yml +++ b/core/modules/system/config/install/system.theme.global.yml @@ -10,6 +10,8 @@ features: logo: true name: true node_user_picture: true + main_menu: true + secondary_menu: true slogan: true logo: path: '' diff --git a/core/modules/system/entity.api.php b/core/modules/system/entity.api.php index 8979ce8..18d9828 100644 --- a/core/modules/system/entity.api.php +++ b/core/modules/system/entity.api.php @@ -8,7 +8,6 @@ use Drupal\Component\Utility\String; use Drupal\Core\Access\AccessResult; use Drupal\Core\Entity\ContentEntityInterface; -use Drupal\Core\Entity\DynamicallyFieldableEntityStorageInterface; use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Render\Element; @@ -1659,9 +1658,6 @@ function hook_entity_base_field_info(\Drupal\Core\Entity\EntityTypeInterface $en * @see hook_entity_base_field_info() * @see hook_entity_bundle_field_info() * @see hook_entity_bundle_field_info_alter() - * - * @todo WARNING: This hook will be changed in - * https://www.drupal.org/node/2346329. */ function hook_entity_base_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type) { // Alter the mymodule_text field to use a custom class. @@ -1694,9 +1690,6 @@ function hook_entity_base_field_info_alter(&$fields, \Drupal\Core\Entity\EntityT * @see hook_entity_bundle_field_info_alter() * @see \Drupal\Core\Field\FieldDefinitionInterface * @see \Drupal\Core\Entity\EntityManagerInterface::getFieldDefinitions() - * - * @todo WARNING: This hook will be changed in - * https://www.drupal.org/node/2346347. */ function hook_entity_bundle_field_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) { // Add a property only to nodes of the 'article' bundle. @@ -1723,9 +1716,6 @@ function hook_entity_bundle_field_info(\Drupal\Core\Entity\EntityTypeInterface $ * @see hook_entity_base_field_info() * @see hook_entity_base_field_info_alter() * @see hook_entity_bundle_field_info() - * - * @todo WARNING: This hook will be changed in - * https://www.drupal.org/node/2346347. */ function hook_entity_bundle_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle) { if ($entity_type->id() == 'node' && $bundle == 'article' && !empty($fields['mymodule_text'])) { @@ -1748,19 +1738,20 @@ function hook_entity_bundle_field_info_alter(&$fields, \Drupal\Core\Entity\Entit * @see \Drupal\Core\Entity\EntityManagerInterface::getFieldStorageDefinitions() */ function hook_entity_field_storage_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type) { - if (\Drupal::entityManager()->getStorage($entity_type->id()) instanceof DynamicallyFieldableEntityStorageInterface) { + // Expose storage definitions for all exposed bundle fields. + if ($entity_type->isFieldable()) { // Query by filtering on the ID as this is more efficient than filtering // on the entity_type property directly. $ids = \Drupal::entityQuery('field_storage_config') ->condition('id', $entity_type->id() . '.', 'STARTS_WITH') ->execute(); + // Fetch all fields and key them by field name. $field_storages = entity_load_multiple('field_storage_config', $ids); $result = array(); foreach ($field_storages as $field_storage) { $result[$field_storage->getName()] = $field_storage; } - return $result; } } diff --git a/core/modules/system/src/Form/ThemeSettingsForm.php b/core/modules/system/src/Form/ThemeSettingsForm.php index 25568b0..83ca32f 100644 --- a/core/modules/system/src/Form/ThemeSettingsForm.php +++ b/core/modules/system/src/Form/ThemeSettingsForm.php @@ -106,6 +106,8 @@ public function buildForm(array $form, FormStateInterface $form_state, $theme = 'comment_user_picture' => t('User pictures in comments'), 'comment_user_verification' => t('User verification status in comments'), 'favicon' => t('Shortcut icon'), + 'main_menu' => t('Main menu'), + 'secondary_menu' => t('Secondary menu'), ); // Some features are not always available diff --git a/core/modules/system/src/Tests/Cache/PageCacheTagsIntegrationTest.php b/core/modules/system/src/Tests/Cache/PageCacheTagsIntegrationTest.php index 4b4e222..be9027f 100644 --- a/core/modules/system/src/Tests/Cache/PageCacheTagsIntegrationTest.php +++ b/core/modules/system/src/Tests/Cache/PageCacheTagsIntegrationTest.php @@ -77,11 +77,7 @@ function testPageCacheTags() { 'block:bartik_login', 'block:bartik_footer', 'block:bartik_powered', - 'block:bartik_main_menu', - 'block:bartik_account_menu', 'block_plugin:system_main_block', - 'block_plugin:system_menu_block__account', - 'block_plugin:system_menu_block__main', 'block_plugin:system_menu_block__tools', 'block_plugin:user_login_block', 'block_plugin:system_menu_block__footer', @@ -90,7 +86,6 @@ function testPageCacheTags() { 'node:' . $node_1->id(), 'user:' . $author_1->id(), 'filter_format:basic_html', - 'menu:account', 'menu:tools', 'menu:footer', 'menu:main', @@ -108,11 +103,7 @@ function testPageCacheTags() { 'block:' . $block->id(), 'block:bartik_footer', 'block:bartik_powered', - 'block:bartik_main_menu', - 'block:bartik_account_menu', 'block_plugin:system_main_block', - 'block_plugin:system_menu_block__account', - 'block_plugin:system_menu_block__main', 'block_plugin:system_menu_block__tools', 'block_plugin:user_login_block', 'block_plugin:views_block__comments_recent-block_1', @@ -122,7 +113,6 @@ function testPageCacheTags() { 'node:' . $node_2->id(), 'user:' . $author_2->id(), 'filter_format:full_html', - 'menu:account', 'menu:tools', 'menu:footer', 'menu:main', diff --git a/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php b/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php index b4e3fce..b7299a5 100644 --- a/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php +++ b/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php @@ -60,11 +60,11 @@ protected function setUp() { // Create an entity. $this->entity = $this->createEntity(); - // If this is an entity with field UI enabled, then add a configurable - // field. We will use this configurable field in later tests to ensure that + // If this is a fieldable entity, then add a configurable field. We will use + // this configurable field in later tests to ensure that modifications to // field configuration invalidate render cache entries. - if ($this->entity->getEntityType()->get('field_ui_base_route')) { - // Add field, so we can modify the field storage and field entities to + if ($this->entity->getEntityType()->isFieldable()) { + // Add field, so we can modify the Field and Field entities to // verify that changes to those indeed clear cache tags. entity_create('field_storage_config', array( 'field_name' => 'configurable_field', @@ -394,7 +394,7 @@ public function testReferencedEntity() { } - if ($this->entity->getEntityType()->get('field_ui_base_route')) { + if ($this->entity->getEntityType()->isFieldable()) { // Verify that after modifying a configurable field on the entity, there // is a cache miss. $this->pass("Test modification of referenced entity's configurable field.", 'Debug'); diff --git a/core/modules/system/src/Tests/Entity/EntityFieldTest.php b/core/modules/system/src/Tests/Entity/EntityFieldTest.php index 83ec6b5..e9d50ad 100644 --- a/core/modules/system/src/Tests/Entity/EntityFieldTest.php +++ b/core/modules/system/src/Tests/Entity/EntityFieldTest.php @@ -416,28 +416,27 @@ protected function checkIntrospection($entity_type) { $this->assertEqual($textfield_properties['processed']->getDataType(), 'string', $entity_type .': String processed property of the test-text field found.'); // Make sure provided contextual information is right. - $entity_adapter = $entity->getTypedData(); - $this->assertIdentical($entity_adapter->getRoot(), $entity_adapter, 'Entity is root object.'); - $this->assertEqual($entity_adapter->getPropertyPath(), ''); - $this->assertEqual($entity_adapter->getName(), ''); - $this->assertEqual($entity_adapter->getParent(), NULL); + $this->assertIdentical($entity->getRoot(), $entity, 'Entity is root object.'); + $this->assertEqual($entity->getPropertyPath(), ''); + $this->assertEqual($entity->getName(), ''); + $this->assertEqual($entity->getParent(), NULL); $field = $entity->user_id; - $this->assertIdentical($field->getRoot()->getValue(), $entity, 'Entity is root object.'); + $this->assertIdentical($field->getRoot(), $entity, 'Entity is root object.'); $this->assertIdentical($field->getEntity(), $entity, 'getEntity() returns the entity.'); $this->assertEqual($field->getPropertyPath(), 'user_id'); $this->assertEqual($field->getName(), 'user_id'); - $this->assertIdentical($field->getParent()->getValue(), $entity, 'Parent object matches.'); + $this->assertIdentical($field->getParent(), $entity, 'Parent object matches.'); $field_item = $field[0]; - $this->assertIdentical($field_item->getRoot()->getValue(), $entity, 'Entity is root object.'); + $this->assertIdentical($field_item->getRoot(), $entity, 'Entity is root object.'); $this->assertIdentical($field_item->getEntity(), $entity, 'getEntity() returns the entity.'); $this->assertEqual($field_item->getPropertyPath(), 'user_id.0'); $this->assertEqual($field_item->getName(), '0'); $this->assertIdentical($field_item->getParent(), $field, 'Parent object matches.'); $item_value = $field_item->get('entity'); - $this->assertIdentical($item_value->getRoot()->getValue(), $entity, 'Entity is root object.'); + $this->assertIdentical($item_value->getRoot(), $entity, 'Entity is root object.'); $this->assertEqual($item_value->getPropertyPath(), 'user_id.0.entity'); $this->assertEqual($item_value->getName(), 'entity'); $this->assertIdentical($item_value->getParent(), $field_item, 'Parent object matches.'); @@ -477,9 +476,9 @@ protected function assertIterator($entity_type) { } } - $fields = $entity->getFields(); - $this->assertEqual(array_keys($fields), array_keys($entity->getTypedData()->getDataDefinition()->getPropertyDefinitions()), format_string('%entity_type: All fields returned.', array('%entity_type' => $entity_type))); - $this->assertEqual($fields, iterator_to_array($entity->getIterator()), format_string('%entity_type: Entity iterator iterates over all fields.', array('%entity_type' => $entity_type))); + $properties = $entity->getProperties(); + $this->assertEqual(array_keys($properties), array_keys($entity->getDataDefinition()->getPropertyDefinitions()), format_string('%entity_type: All properties returned.', array('%entity_type' => $entity_type))); + $this->assertEqual($properties, iterator_to_array($entity->getIterator()), format_string('%entity_type: Entity iterator iterates over all properties.', array('%entity_type' => $entity_type))); } /** @@ -505,7 +504,7 @@ protected function assertDataStructureInterfaces($entity_type) { // contained properties and getting all contained strings, limited by a // certain depth. $strings = array(); - $this->getContainedStrings($entity->getTypedData(), 0, $strings); + $this->getContainedStrings($entity, 0, $strings); // @todo: Once the user entity has defined properties this should contain // the user name and other user entity strings as well. @@ -594,11 +593,11 @@ public function testFieldOverrideBundleField() { entity_test_create_bundle('some_test_bundle', 'Some test bundle', 'entity_test_field_override'); $field_definitions = $this->entityManager->getFieldDefinitions('entity_test_field_override', 'entity_test_field_override'); $this->assertEqual($field_definitions['name']->getDescription(), 'The default description.'); - $this->assertNull($field_definitions['name']->getTargetBundle()); + $this->assertNull($field_definitions['name']->getBundle()); $field_definitions = $this->entityManager->getFieldDefinitions('entity_test_field_override', 'some_test_bundle'); $this->assertEqual($field_definitions['name']->getDescription(), 'Custom description.'); - $this->assertEqual($field_definitions['name']->getTargetBundle(), 'some_test_bundle'); + $this->assertEqual($field_definitions['name']->getBundle(), 'some_test_bundle'); // Now create a config override of the bundle field. $field_config = $field_definitions['name']->getConfig('some_test_bundle'); @@ -609,7 +608,7 @@ public function testFieldOverrideBundleField() { $this->entityManager->clearCachedFieldDefinitions(); $field_definitions = $this->entityManager->getFieldDefinitions('entity_test_field_override', 'some_test_bundle'); $this->assertEqual($field_definitions['name']->getDescription(), 'Custom description.'); - $this->assertEqual($field_definitions['name']->getTargetBundle(), 'some_test_bundle'); + $this->assertEqual($field_definitions['name']->getBundle(), 'some_test_bundle'); $this->assertFalse($field_definitions['name']->isTranslatable()); } diff --git a/core/modules/system/src/Tests/Entity/EntityUUIDTest.php b/core/modules/system/src/Tests/Entity/EntityUUIDTest.php index 5f3b6e1..39bfa70 100644 --- a/core/modules/system/src/Tests/Entity/EntityUUIDTest.php +++ b/core/modules/system/src/Tests/Entity/EntityUUIDTest.php @@ -73,7 +73,7 @@ protected function assertCRUD($entity_type) { // Creating a duplicate needs to result in a new UUID. $entity_duplicate = $entity->createDuplicate(); - foreach ($entity->getFields() as $property => $value) { + foreach ($entity->getProperties() as $property => $value) { switch($property) { case 'uuid': $this->assertNotNull($entity_duplicate->uuid()); diff --git a/core/modules/system/src/Tests/Entity/EntityValidationTest.php b/core/modules/system/src/Tests/Entity/EntityValidationTest.php index 8fdcf82..73f0fd9 100644 --- a/core/modules/system/src/Tests/Entity/EntityValidationTest.php +++ b/core/modules/system/src/Tests/Entity/EntityValidationTest.php @@ -133,7 +133,7 @@ protected function checkValidation($entity_type) { // Make sure the information provided by a violation is correct. $violation = $violations[0]; - $this->assertEqual($violation->getRoot()->getValue(), $test_entity, 'Violation root is entity.'); + $this->assertEqual($violation->getRoot(), $test_entity, 'Violation root is entity.'); $this->assertEqual($violation->getPropertyPath(), 'name.0.value', 'Violation property path is correct.'); $this->assertEqual($violation->getInvalidValue(), $test_entity->name->value, 'Violation contains invalid value.'); @@ -151,7 +151,7 @@ protected function checkValidation($entity_type) { // Make sure the information provided by a violation is correct. $violation = $violations[0]; - $this->assertEqual($violation->getRoot()->getValue(), $test_entity, 'Violation root is entity.'); + $this->assertEqual($violation->getRoot(), $test_entity, 'Violation root is entity.'); $this->assertEqual($violation->getPropertyPath(), 'field_test_text.0.format', 'Violation property path is correct.'); $this->assertEqual($violation->getInvalidValue(), $test_entity->field_test_text->format, 'Violation contains invalid value.'); } diff --git a/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php b/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php index d2ef4dd..4ce93b8 100644 --- a/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php +++ b/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php @@ -82,7 +82,7 @@ public function testEntityUri() { } - if ($this->entity->getEntityType()->get('field_ui_base_route')) { + if ($this->entity->getEntityType()->isFieldable()) { // Verify that after modifying a configurable field on the entity, there // is a cache miss. $this->pass("Test modification of entity's configurable field.", 'Debug'); diff --git a/core/modules/system/src/Tests/Form/LanguageSelectElementTest.php b/core/modules/system/src/Tests/Form/LanguageSelectElementTest.php index 3ec7fe8..2f4408a 100644 --- a/core/modules/system/src/Tests/Form/LanguageSelectElementTest.php +++ b/core/modules/system/src/Tests/Form/LanguageSelectElementTest.php @@ -56,7 +56,7 @@ function testLanguageSelectElementOptions() { $this->assertField($id, format_string('The @id field was found on the page.', array('@id' => $id))); $options = array(); foreach ($this->container->get('language_manager')->getLanguages($flags) as $langcode => $language) { - $options[$langcode] = $language->isLocked() ? t('- @name -', array('@name' => $language->name)) : $language->name; + $options[$langcode] = $language->locked ? t('- @name -', array('@name' => $language->name)) : $language->name; } $this->_testLanguageSelectElementOptions($id, $options); } diff --git a/core/modules/system/src/Tests/Menu/BreadcrumbTest.php b/core/modules/system/src/Tests/Menu/BreadcrumbTest.php index cf5ab1a..ea55662 100644 --- a/core/modules/system/src/Tests/Menu/BreadcrumbTest.php +++ b/core/modules/system/src/Tests/Menu/BreadcrumbTest.php @@ -278,7 +278,7 @@ function testBreadCrumbs() { // untranslated menu links automatically generated from menu router items // ('taxonomy/term/%') should never be translated and appear in any menu // other than the breadcrumb trail. - $elements = $this->xpath('//nav[@id=:menu]/descendant::a[@href=:href]', array( + $elements = $this->xpath('//div[@id=:menu]/descendant::a[@href=:href]', array( ':menu' => 'block-bartik-tools', ':href' => url($link_path), )); diff --git a/core/modules/system/src/Tests/Plugin/ContextPluginTest.php b/core/modules/system/src/Tests/Plugin/ContextPluginTest.php index c7dab96..d67d055 100644 --- a/core/modules/system/src/Tests/Plugin/ContextPluginTest.php +++ b/core/modules/system/src/Tests/Plugin/ContextPluginTest.php @@ -68,7 +68,7 @@ function testContext() { $user = entity_create('user', array('name' => $name)); $plugin->setContextValue('user', $user); - $this->assertEqual($plugin->getContextValue('user')->getUsername(), $user->getUsername()); + $this->assertEqual($plugin->getContextValue('user')->getName(), $user->getName()); $this->assertEqual($user->label(), $plugin->getTitle()); // Test Optional context handling. diff --git a/core/modules/system/src/Tests/System/PageTitleTest.php b/core/modules/system/src/Tests/System/PageTitleTest.php index 4516a57..6b2d249 100644 --- a/core/modules/system/src/Tests/System/PageTitleTest.php +++ b/core/modules/system/src/Tests/System/PageTitleTest.php @@ -75,6 +75,8 @@ function testTitleXSS() { $edit = array( 'toggle_name' => TRUE, 'toggle_slogan' => TRUE, + 'toggle_main_menu' => TRUE, + 'toggle_secondary_menu' => TRUE, ); $this->drupalPostForm('admin/appearance/settings', $edit, t('Save configuration')); diff --git a/core/modules/system/system.module b/core/modules/system/system.module index b478fb4..3f19f14 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -156,18 +156,13 @@ function system_help($route_name, RouteMatchInterface $route_match) { function system_theme() { return array_merge(drupal_common_theme(), array( // Normally theme suggestion templates are only picked up when they are in - // themes. We explicitly define theme suggestions here so that the block - // templates in core/modules/system/templates are picked up. + // themes. We explicitly define the block__system_branding_block theme + // suggestion here so that the template in core/modules/system/templates + // is picked up. 'block__system_branding_block' => array( - 'render element' => 'elements', 'base hook' => 'block', 'template' => 'block--system-branding-block', ), - 'block__system_menu_block' => array( - 'render element' => 'elements', - 'base hook' => 'block', - 'template' => 'block--system-menu-block', - ), 'system_themes_page' => array( 'variables' => array( 'theme_groups' => array(), @@ -678,6 +673,14 @@ function system_preprocess_block(&$variables) { case 'system_help_block': $variables['attributes']['role'] = 'complementary'; break; + + case 'system_menu_block': + $menus = menu_list_system_menus(); + if (isset($menus[$variables['derivative_plugin_id']])) { + $variables['attributes']['role'] = 'navigation'; + $variables['attributes']['class'][] = 'block-menu'; + } + break; } } @@ -925,6 +928,8 @@ function _system_default_theme_features() { 'node_user_picture', 'comment_user_picture', 'comment_user_verification', + 'main_menu', + 'secondary_menu', ); } diff --git a/core/modules/system/templates/block--system-menu-block.html.twig b/core/modules/system/templates/block--system-menu-block.html.twig deleted file mode 100644 index dff7e39..0000000 --- a/core/modules/system/templates/block--system-menu-block.html.twig +++ /dev/null @@ -1,65 +0,0 @@ -{# -/** - * @file - * Default theme implementation for a menu block. - * - * Available variables: - * - plugin_id: The ID of the block implementation. - * - label: The configured label of the block if visible. - * - configuration: A list of the block's configuration values. - * - label: The configured label for the block. - * - label_display: The display settings for the label. - * - module: The module that provided this block plugin. - * - cache: The cache settings. - * - Block plugin specific settings will also be stored here. - * - block - The full block entity. - * - label_hidden: The hidden block title value if the block was - * configured to hide the title ('label' is empty in this case). - * - module: The module that generated the block. - * - delta: An ID for the block, unique within each module. - * - region: The block region embedding the current block. - * - content: The content of this block. - * - attributes: HTML attributes for the containing element. - * - id: A valid HTML ID and guaranteed unique. - * - title_attributes: HTML attributes for the title element. - * - content_attributes: HTML attributes for the content element. - * - title_prefix: Additional output populated by modules, intended to be - * displayed in front of the main title tag that appears in the template. - * - title_suffix: Additional output populated by modules, intended to be - * displayed after the main title tag that appears in the template. - * - * Headings should be used on navigation menus that consistently appear on - * multiple pages. When this menu block's label is configured to not be - * displayed, it is automatically made invisible using the 'visually-hidden' CSS - * class, which still keeps it visible for screen-readers and assistive - * technology. Headings allow screen-reader and keyboard only users to navigate - * to or skip the links. - * See http://juicystudio.com/article/screen-readers-display-none.php and - * http://www.w3.org/TR/WCAG-TECHS/H42.html for more information. - * - * @ingroup themeable - */ -#} -{% - set classes = [ - 'block', - 'block-menu', - 'navigation', - 'menu--' ~ derivative_plugin_id|clean_class, - ] -%} -{% set heading_id = attributes.id ~ '-menu'|clean_id %} - - {# Label. If not displayed, we still provide it for screen readers. #} - {% if not configuration.label_display %} - {% set title_attributes = title_attributes.addClass('visually-hidden') %} - {% endif %} - {{ title_prefix }} -

{{ configuration.label }}

- {{ title_suffix }} - - {# Menu. #} - {% block content %} - {{ content }} - {% endblock %} - diff --git a/core/modules/system/templates/page.html.twig b/core/modules/system/templates/page.html.twig index 41d8270..ba013a2 100644 --- a/core/modules/system/templates/page.html.twig +++ b/core/modules/system/templates/page.html.twig @@ -26,6 +26,9 @@ * slogan has been disabled in theme settings. * * Navigation: + * - main_menu: The Main menu links for the site, if they have been configured. + * - secondary_menu: The Secondary menu links for the site, if they have been + * configured. * - breadcrumb: The breadcrumb trail for the current page. * * Page content (in order of occurrence in the default page.html.twig): @@ -47,8 +50,6 @@ * * Regions: * - page.header: Items for the header region. - * - page.primary_menu: Items for the primary menu region. - * - page.secondary_menu: Items for the secondary menu region. * - page.highlighted: Items for the highlighted content region. * - page.help: Dynamic help text, mostly for admin pages. * - page.content: The main content of the current page. @@ -89,13 +90,17 @@
{{ site_slogan }}
{% endif %} {# ./name-and-slogan #} - {% endif %} + {% endif %} {{ page.header }} - {{ page.primary_menu }} - {{ page.secondary_menu }} + {% if main_menu or secondary_menu %} + + {% endif %} {{ breadcrumb }} diff --git a/core/modules/system/tests/modules/entity_schema_test/entity_schema_test.module b/core/modules/system/tests/modules/entity_schema_test/entity_schema_test.module index ab1d71b..206ffa2 100644 --- a/core/modules/system/tests/modules/entity_schema_test/entity_schema_test.module +++ b/core/modules/system/tests/modules/entity_schema_test/entity_schema_test.module @@ -71,7 +71,7 @@ function entity_schema_test_entity_bundle_delete($entity_type_id, $bundle) { $field_definitions = entity_schema_test_entity_bundle_field_info($entity_type, $bundle); $field_definitions['custom_bundle_field'] ->setTargetEntityTypeId($entity_type_id) - ->setTargetBundle($bundle); + ->setBundle($bundle); // Notify the entity storage that our field is gone. \Drupal::entityManager()->getStorage($entity_type_id) ->onFieldDefinitionDelete($field_definitions['custom_bundle_field']); diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module index 06ec1dc..bf0cded 100644 --- a/core/modules/system/tests/modules/entity_test/entity_test.module +++ b/core/modules/system/tests/modules/entity_test/entity_test.module @@ -117,7 +117,7 @@ function entity_test_create_bundle($bundle, $text = NULL, $entity_type = 'entity $bundles += array($bundle => array('label' => $text ? $text : $bundle)); \Drupal::state()->set($entity_type . '.bundles', $bundles); - \Drupal::entityManager()->onBundleCreate($bundle, $entity_type); + \Drupal::entityManager()->onBundleCreate($entity_type, $bundle); } /** @@ -137,7 +137,7 @@ function entity_test_rename_bundle($bundle_old, $bundle_new, $entity_type = 'ent unset($bundles[$bundle_old]); \Drupal::state()->set($entity_type . '.bundles', $bundles); - \Drupal::entityManager()->onBundleRename($bundle_old, $bundle_new, $entity_type); + \Drupal::entityManager()->onBundleRename($entity_type, $bundle_old, $bundle_new); } /** @@ -154,7 +154,7 @@ function entity_test_delete_bundle($bundle, $entity_type = 'entity_test') { unset($bundles[$bundle]); \Drupal::state()->set($entity_type . '.bundles', $bundles); - \Drupal::entityManager()->onBundleDelete($bundle, $entity_type); + \Drupal::entityManager()->onBundleDelete($entity_type, $bundle); } /** diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php index b4cb26e..dca9c0d 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php @@ -33,6 +33,7 @@ * "views_data" = "Drupal\views\EntityViewsData" * }, * base_table = "entity_test", + * fieldable = TRUE, * persistent_cache = FALSE, * entity_keys = { * "id" = "id", diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBaseFieldDisplay.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBaseFieldDisplay.php index ed213e3..84cc5f1 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBaseFieldDisplay.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBaseFieldDisplay.php @@ -24,6 +24,7 @@ * "translation" = "Drupal\content_translation\ContentTranslationHandler" * }, * base_table = "entity_test", + * fieldable = TRUE, * entity_keys = { * "id" = "id", * "uuid" = "uuid", diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCache.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCache.php index 96dd6d2..584a457 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCache.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCache.php @@ -21,6 +21,7 @@ * "translation" = "Drupal\content_translation\ContentTranslationHandler" * }, * base_table = "entity_test", + * fieldable = TRUE, * entity_keys = { * "id" = "id", * "uuid" = "uuid", diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraintViolation.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraintViolation.php index 48b27ab..e34bfd7 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraintViolation.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraintViolation.php @@ -21,6 +21,7 @@ * } * }, * base_table = "entity_test", + * fieldable = TRUE, * persistent_cache = FALSE, * entity_keys = { * "id" = "id", diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestDefaultValue.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestDefaultValue.php index 13189c2..3779567 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestDefaultValue.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestDefaultValue.php @@ -17,6 +17,7 @@ * id = "entity_test_default_value", * label = @Translation("Test entity for default values"), * base_table = "entity_test_default_value", + * fieldable = TRUE, * entity_keys = { * "id" = "id", * "uuid" = "uuid", diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestFieldOverride.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestFieldOverride.php index 7632125..f469275 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestFieldOverride.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestFieldOverride.php @@ -16,6 +16,7 @@ * id = "entity_test_field_override", * label = @Translation("Test entity field overrides"), * base_table = "entity_test_field_override", + * fieldable = TRUE, * entity_keys = { * "id" = "id", * "uuid" = "uuid", diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestLabelCallback.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestLabelCallback.php index 1088114..e15d389 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestLabelCallback.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestLabelCallback.php @@ -16,6 +16,7 @@ * persistent_cache = FALSE, * base_table = "entity_test", * label_callback = "entity_test_label_callback", + * fieldable = TRUE, * entity_keys = { * "id" = "id", * "bundle" = "type" diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMul.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMul.php index 402936f..4e03fd1 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMul.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMul.php @@ -29,6 +29,7 @@ * }, * base_table = "entity_test_mul", * data_table = "entity_test_mul_property_data", + * fieldable = TRUE, * translatable = TRUE, * entity_keys = { * "id" = "id", diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php index b5fc86f..13aca32 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php @@ -30,6 +30,7 @@ * data_table = "entity_test_mulrev_property_data", * revision_table = "entity_test_mulrev_revision", * revision_data_table = "entity_test_mulrev_property_revision", + * fieldable = TRUE, * translatable = TRUE, * entity_keys = { * "id" = "id", diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoId.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoId.php index a29c1e2..a0daadc 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoId.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoId.php @@ -16,6 +16,7 @@ * handlers = { * "storage" = "Drupal\Core\Entity\ContentEntityNullStorage", * }, + * fieldable = TRUE, * entity_keys = { * "bundle" = "type", * }, diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php index 3b40ed9..f97d2fd 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php @@ -28,6 +28,7 @@ * }, * base_table = "entity_test_rev", * revision_table = "entity_test_rev_revision", + * fieldable = TRUE, * entity_keys = { * "id" = "id", * "uuid" = "uuid", diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php index 9d74938..98b19b0 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php @@ -23,6 +23,8 @@ * "translation" = "Drupal\content_translation\ContentTranslationHandler" * }, * base_table = "entity_test_string", + * fieldable = TRUE, + * field_cache = TRUE, * entity_keys = { * "id" = "id", * "uuid" = "uuid", diff --git a/core/modules/taxonomy/src/Entity/Term.php b/core/modules/taxonomy/src/Entity/Term.php index caebc53..fda4f52 100644 --- a/core/modules/taxonomy/src/Entity/Term.php +++ b/core/modules/taxonomy/src/Entity/Term.php @@ -35,6 +35,7 @@ * base_table = "taxonomy_term_data", * data_table = "taxonomy_term_field_data", * uri_callback = "taxonomy_term_uri", + * fieldable = TRUE, * translatable = TRUE, * entity_keys = { * "id" = "tid", diff --git a/core/modules/taxonomy/src/Plugin/Field/FieldFormatter/TaxonomyFormatterBase.php b/core/modules/taxonomy/src/Plugin/Field/FieldFormatter/TaxonomyFormatterBase.php index 3c140cc..8343d3d 100644 --- a/core/modules/taxonomy/src/Plugin/Field/FieldFormatter/TaxonomyFormatterBase.php +++ b/core/modules/taxonomy/src/Plugin/Field/FieldFormatter/TaxonomyFormatterBase.php @@ -27,7 +27,7 @@ public function prepareView(array $entities_items) { /* @var \Drupal\Core\Field\EntityReferenceFieldItemList $items */ foreach ($entities_items as $items) { /* @var \Drupal\Core\Entity\ContentEntityBase $parent */ - $parent = $items->getEntity(); + $parent = $items->getParent(); $active_langcode = $parent->language()->getId(); /* @var \Drupal\taxonomy\Entity\Term $term */ foreach ($items->referencedEntities() as $term) { diff --git a/core/modules/taxonomy/src/TermAccessControlHandler.php b/core/modules/taxonomy/src/TermAccessControlHandler.php index b4ccb53..a478373 100644 --- a/core/modules/taxonomy/src/TermAccessControlHandler.php +++ b/core/modules/taxonomy/src/TermAccessControlHandler.php @@ -29,11 +29,11 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, A break; case 'update': - return AccessResult::allowedIfHasPermissions($account, ["edit terms in {$entity->bundle()}", 'administer taxonomy'], 'OR'); + return AccessResult::allowedIf($account->hasPermission("edit terms in {$entity->bundle()}") || $account->hasPermission('administer taxonomy'))->cachePerRole(); break; case 'delete': - return AccessResult::allowedIfHasPermissions($account, ["delete terms in {$entity->bundle()}", 'administer taxonomy'], 'OR'); + return AccessResult::allowedIf($account->hasPermission("delete terms in {$entity->bundle()}") || $account->hasPermission('administer taxonomy'))->cachePerRole(); break; default: diff --git a/core/modules/taxonomy/src/VocabularyForm.php b/core/modules/taxonomy/src/VocabularyForm.php index 34dc3ed..ef61676 100644 --- a/core/modules/taxonomy/src/VocabularyForm.php +++ b/core/modules/taxonomy/src/VocabularyForm.php @@ -138,7 +138,7 @@ public function save(array $form, FormStateInterface $form_state) { $vocabulary->name = trim($vocabulary->name); $status = $vocabulary->save(); - $edit_link = $this->entity->link($this->t('Edit')); + $edit_link = \Drupal::linkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo()); switch ($status) { case SAVED_NEW: drupal_set_message($this->t('Created new vocabulary %name.', array('%name' => $vocabulary->name))); diff --git a/core/modules/update/src/Tests/UpdateContribTest.php b/core/modules/update/src/Tests/UpdateContribTest.php index b389c24..622d448 100644 --- a/core/modules/update/src/Tests/UpdateContribTest.php +++ b/core/modules/update/src/Tests/UpdateContribTest.php @@ -56,9 +56,6 @@ function testNoReleasesAvailable() { $this->assertNoText(t('Update available')); $this->assertText(t('No available releases found')); $this->assertNoRaw(l(t('AAA Update test'), 'http://example.com/project/aaa_update_test')); - - $available = update_get_available(); - $this->assertFalse(isset($available['aaa_update_test']['fetch_status']), 'Results are cached even if no releases are available.'); } /** diff --git a/core/modules/update/update.module b/core/modules/update/update.module index 64a4255..65e1364 100644 --- a/core/modules/update/update.module +++ b/core/modules/update/update.module @@ -347,7 +347,7 @@ function update_get_available($refresh = FALSE) { // If we have project data but no release data, we need to fetch. This // can be triggered when we fail to contact a release history server. - if (empty($available[$key]['releases']) && !$available[$key]['last_fetch']) { + if (empty($available[$key]['releases'])) { $available[$key]['fetch_status'] = UPDATE_FETCH_PENDING; } diff --git a/core/modules/user/src/Access/PermissionAccessCheck.php b/core/modules/user/src/Access/PermissionAccessCheck.php index a261481..70c99db 100644 --- a/core/modules/user/src/Access/PermissionAccessCheck.php +++ b/core/modules/user/src/Access/PermissionAccessCheck.php @@ -31,15 +31,6 @@ class PermissionAccessCheck implements AccessInterface { */ public function access(Route $route, AccountInterface $account) { $permission = $route->getRequirement('_permission'); - // Allow to conjunct the permissions with OR ('+') or AND (','). - $split = explode(',', $permission); - if (count($split) > 1) { - return AccessResult::allowedIfHasPermissions($account, $split, 'AND'); - } - else { - $split = explode('+', $permission); - return AccessResult::allowedIfHasPermissions($account, $split, 'OR'); - } + return AccessResult::allowedIfHasPermission($account, $permission); } - } diff --git a/core/modules/user/src/Entity/User.php b/core/modules/user/src/Entity/User.php index 6bb533c..ee75930 100644 --- a/core/modules/user/src/Entity/User.php +++ b/core/modules/user/src/Entity/User.php @@ -41,6 +41,7 @@ * base_table = "users", * data_table = "users_field_data", * label_callback = "user_format_name", + * fieldable = TRUE, * translatable = TRUE, * entity_keys = { * "id" = "uid", diff --git a/core/modules/user/src/RoleForm.php b/core/modules/user/src/RoleForm.php index d9ef7cd..55e0ccd 100644 --- a/core/modules/user/src/RoleForm.php +++ b/core/modules/user/src/RoleForm.php @@ -59,7 +59,7 @@ public function save(array $form, FormStateInterface $form_state) { $entity->set('label', trim($entity->label())); $status = $entity->save(); - $edit_link = $this->entity->link($this->t('Edit')); + $edit_link = \Drupal::linkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo()); if ($status == SAVED_UPDATED) { drupal_set_message($this->t('Role %label has been updated.', array('%label' => $entity->label()))); $this->logger('user')->notice('Role %label has been updated.', array('%label' => $entity->label(), 'link' => $edit_link)); diff --git a/core/modules/user/src/Tests/UserAccountLinksTests.php b/core/modules/user/src/Tests/UserAccountLinksTests.php index 97fa8a3..4ad246b 100644 --- a/core/modules/user/src/Tests/UserAccountLinksTests.php +++ b/core/modules/user/src/Tests/UserAccountLinksTests.php @@ -24,12 +24,8 @@ class UserAccountLinksTests extends WebTestBase { */ public static $modules = array('menu_ui', 'block', 'test_page_test'); - /** - * {@inheritdoc} - */ protected function setUp() { parent::setUp(); - $this->drupalPlaceBlock('system_menu_block:account'); // Make test-page default. \Drupal::config('system.site')->set('page.front', 'test-page')->save(); } diff --git a/core/modules/user/src/Tests/UserPasswordResetTest.php b/core/modules/user/src/Tests/UserPasswordResetTest.php index 1d27865..651a4ea 100644 --- a/core/modules/user/src/Tests/UserPasswordResetTest.php +++ b/core/modules/user/src/Tests/UserPasswordResetTest.php @@ -22,21 +22,9 @@ class UserPasswordResetTest extends WebTestBase { */ protected $account; - /** - * Modules to enable. - * - * @var array - */ - public static $modules = ['block']; - - /** - * {@inheritdoc} - */ protected function setUp() { parent::setUp(); - $this->drupalPlaceBlock('system_menu_block:account'); - // Create a user. $account = $this->drupalCreateUser(); diff --git a/core/modules/user/src/Tests/Views/HandlerFilterPermissionTest.php b/core/modules/user/src/Tests/Views/HandlerFilterPermissionTest.php index 27a7715..49af462 100644 --- a/core/modules/user/src/Tests/Views/HandlerFilterPermissionTest.php +++ b/core/modules/user/src/Tests/Views/HandlerFilterPermissionTest.php @@ -80,15 +80,15 @@ public function testFilterPermission() { // Test the value options. $value_options = $view->filter['permission']->getValueOptions(); - $permission_by_module = []; + $permisssion_by_module = []; $permissions = \Drupal::service('user.permissions')->getPermissions(); foreach ($permissions as $name => $permission) { - $permission_by_module[$permission['provider']][$name] = $permission; + $permisssion_by_module[$permission['provider']][$name] = $permission; } foreach (array('system' => 'System', 'user' => 'User') as $module => $title) { $expected = array_map(function ($permission) { return String::checkPlain(strip_tags($permission['title'])); - }, $permission_by_module[$module]); + }, $permisssion_by_module[$module]); $this->assertEqual($expected, $value_options[$title], 'Ensure the all permissions are available'); } diff --git a/core/modules/user/tests/src/Unit/PermissionAccessCheckTest.php b/core/modules/user/tests/src/Unit/PermissionAccessCheckTest.php deleted file mode 100644 index a6e57e1..0000000 --- a/core/modules/user/tests/src/Unit/PermissionAccessCheckTest.php +++ /dev/null @@ -1,77 +0,0 @@ -accessCheck = new PermissionAccessCheck(); - } - - /** - * Provides data for the testAccess method. - * - * @return array - */ - public function providerTestAccess() { - $allowed = AccessResult::allowedIf(TRUE)->cachePerRole(); - $neutral = AccessResult::allowedIf(FALSE)->cachePerRole(); - return [ - [[], $neutral], - [['_permission' => 'allowed'], $allowed], - [['_permission' => 'denied'], $neutral], - [['_permission' => 'allowed+denied'], $allowed], - [['_permission' => 'allowed+denied+other'], $allowed], - [['_permission' => 'allowed-denied'], $neutral], - ]; - } - - /** - * Tests the access check method. - * - * @dataProvider providerTestAccess - * @covers ::access - */ - public function testAccess($requirements, $access) { - $user = $this->getMock('Drupal\Core\Session\AccountInterface'); - $user->expects($this->any()) - ->method('hasPermission') - ->will($this->returnValueMap([ - ['allowed', TRUE], - ['denied', FALSE], - ['other', FALSE] - ] - )); - $route = new Route('', [], $requirements); - - $this->assertEquals($access, $this->accessCheck->access($route, $user)); - } - -} diff --git a/core/modules/views/config/schema/views.display.schema.yml b/core/modules/views/config/schema/views.display.schema.yml index 6531990..212941b 100644 --- a/core/modules/views/config/schema/views.display.schema.yml +++ b/core/modules/views/config/schema/views.display.schema.yml @@ -37,9 +37,6 @@ views.display.page: menu_name: type: string label: 'Menu name' - parent: - type: string - label: 'Parent' context: type: string label: 'Context' diff --git a/core/modules/views/src/Entity/View.php b/core/modules/views/src/Entity/View.php index ea3664e..1ad685a 100644 --- a/core/modules/views/src/Entity/View.php +++ b/core/modules/views/src/Entity/View.php @@ -348,23 +348,6 @@ public function postCreate(EntityStorageInterface $storage) { /** * {@inheritdoc} */ - public static function preDelete(EntityStorageInterface $storage, array $entities) { - parent::preDelete($storage, $entities); - - // Call the remove() hook on the individual displays. - /** @var \Drupal\views\ViewStorageInterface $entity */ - foreach ($entities as $entity) { - $executable = Views::executableFactory()->get($entity); - foreach ($entity->get('display') as $display_id => $display) { - $executable->setDisplay($display_id); - $executable->getDisplay()->remove(); - } - } - } - - /** - * {@inheritdoc} - */ public static function postDelete(EntityStorageInterface $storage, array $entities) { parent::postDelete($storage, $entities); diff --git a/core/modules/views/src/Plugin/Menu/ViewsMenuLink.php b/core/modules/views/src/Plugin/Menu/ViewsMenuLink.php index 85c2350..a07862f 100644 --- a/core/modules/views/src/Plugin/Menu/ViewsMenuLink.php +++ b/core/modules/views/src/Plugin/Menu/ViewsMenuLink.php @@ -154,17 +154,4 @@ public function updateLink(array $new_definition_values, $persist) { return $this->pluginDefinition; } - /** - * {@inheritdoc} - */ - public function isDeletable() { - return TRUE; - } - - /** - * {@inheritdoc} - */ - public function deleteLink() { - } - } diff --git a/core/modules/views/src/Plugin/views/PluginBase.php b/core/modules/views/src/Plugin/views/PluginBase.php index 17f39e1..1b66bdc 100644 --- a/core/modules/views/src/Plugin/views/PluginBase.php +++ b/core/modules/views/src/Plugin/views/PluginBase.php @@ -92,14 +92,7 @@ /** - * Constructs a PluginBase object. - * - * @param array $configuration - * A configuration array containing information about the plugin instance. - * @param string $plugin_id - * The plugin_id for the plugin instance. - * @param mixed $plugin_definition - * The plugin implementation definition. + * Constructs a Plugin object. */ public function __construct(array $configuration, $plugin_id, $plugin_definition) { parent::__construct($configuration, $plugin_id, $plugin_definition); diff --git a/core/modules/views/src/Plugin/views/display/Block.php b/core/modules/views/src/Plugin/views/display/Block.php index 5986381..ffb40b6 100644 --- a/core/modules/views/src/Plugin/views/display/Block.php +++ b/core/modules/views/src/Plugin/views/display/Block.php @@ -8,10 +8,8 @@ namespace Drupal\views\Plugin\views\display; use Drupal\Component\Utility\String; -use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\views\Plugin\Block\ViewsBlock; -use Symfony\Component\DependencyInjection\ContainerInterface; /** * The plugin that handles a block. @@ -41,46 +39,6 @@ class Block extends DisplayPluginBase { */ protected $usesAttachments = TRUE; - /** - * The entity manager. - * - * @var \Drupal\Core\Entity\EntityManagerInterface - */ - protected $entityManager; - - /** - * Constructs a new Block instance. - * - * @param array $configuration - * A configuration array containing information about the plugin instance. - * @param string $plugin_id - * The plugin_id for the plugin instance. - * @param mixed $plugin_definition - * The plugin implementation definition. - * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager - * The entity manager. - */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager) { - parent::__construct($configuration, $plugin_id, $plugin_definition); - - $this->entityManager = $entity_manager; - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { - return new static( - $configuration, - $plugin_id, - $plugin_definition, - $container->get('entity.manager') - ); - } - - /** - * {@inheritdoc} - */ protected function defineOptions() { $options = parent::defineOptions(); @@ -358,16 +316,14 @@ public function usesExposed() { } /** - * {@inheritdoc} + * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::remove(). */ public function remove() { parent::remove(); - if ($this->entityManager->hasDefinition('block')) { - $plugin_id = 'views_block:' . $this->view->storage->id() . '-' . $this->display['id']; - foreach ($this->entityManager->getStorage('block')->loadByProperties(['plugin' => $plugin_id]) as $block) { - $block->delete(); - } + $plugin_id = 'views_block:' . $this->view->storage->id() . '-' . $this->display['id']; + foreach (entity_load_multiple_by_properties('block', array('plugin' => $plugin_id)) as $block) { + $block->delete(); } } diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php index 0dd89bb..5348df1 100644 --- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php +++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php @@ -134,13 +134,6 @@ * * @todo Replace DisplayPluginBase::$display with * DisplayPluginBase::$configuration to standardize with other plugins. - * - * @param array $configuration - * A configuration array containing information about the plugin instance. - * @param string $plugin_id - * The plugin_id for the plugin instance. - * @param mixed $plugin_definition - * The plugin implementation definition. */ public function __construct(array $configuration, $plugin_id, $plugin_definition) { parent::__construct(array(), $plugin_id, $plugin_definition); @@ -2396,12 +2389,6 @@ public function newDisplay() { * Reacts on deleting a display. */ public function remove() { - $menu_links = $this->getMenuLinks(); - /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */ - $menu_link_manager = \Drupal::service('plugin.manager.menu.link'); - foreach ($menu_links as $menu_link_id => $menu_link) { - $menu_link_manager->removeDefinition("views_view:$menu_link_id"); - } } /** diff --git a/core/modules/views/src/Plugin/views/display/Page.php b/core/modules/views/src/Plugin/views/display/Page.php index 5234f2c..08da0a2 100644 --- a/core/modules/views/src/Plugin/views/display/Page.php +++ b/core/modules/views/src/Plugin/views/display/Page.php @@ -50,7 +50,7 @@ protected function defineOptions() { 'title' => array('default' => '', 'translatable' => FALSE), 'description' => array('default' => '', 'translatable' => FALSE), 'weight' => array('default' => 0), - 'menu_name' => array('default' => 'main'), + 'menu_name' => array('default' => 'navigation'), 'parent' => array('default' => ''), 'context' => array('default' => ''), ), @@ -62,7 +62,7 @@ protected function defineOptions() { 'title' => array('default' => '', 'translatable' => FALSE), 'description' => array('default' => '', 'translatable' => FALSE), 'weight' => array('default' => 0), - 'menu_name' => array('default' => 'main'), + 'menu_name' => array('default' => 'navigation'), ), ); @@ -338,11 +338,11 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { ); // Only display the menu selector if Menu UI module is enabled. if (\Drupal::moduleHandler()->moduleExists('menu_ui')) { - $form['tab_options']['menu_name'] = array( + $form['tab_options']['name'] = array( '#title' => $this->t('Menu'), '#type' => 'select', '#options' => menu_ui_get_menus(), - '#default_value' => $tab_options['menu_name'], + '#default_value' => $tab_options['name'], '#description' => $this->t('Insert item into an available menu.'), '#states' => array( 'visible' => array( diff --git a/core/modules/views/src/Tests/Plugin/DisplayPageWebTest.php b/core/modules/views/src/Tests/Plugin/DisplayPageWebTest.php index d975a80..3750601 100644 --- a/core/modules/views/src/Tests/Plugin/DisplayPageWebTest.php +++ b/core/modules/views/src/Tests/Plugin/DisplayPageWebTest.php @@ -108,7 +108,7 @@ public function testPageDisplayMenu() { $this->drupalPlaceBlock('system_menu_block:tools'); $this->drupalGet(''); - $menu_link = $this->cssSelect('nav.block-menu ul.menu a'); + $menu_link = $this->cssSelect('div.block-menu ul.menu a'); $this->assertEqual((string) $menu_link[0], 'Test menu link'); // Update the menu link. @@ -117,7 +117,7 @@ public function testPageDisplayMenu() { ], t('Save')); $this->drupalGet(''); - $menu_link = $this->cssSelect('nav.block-menu ul.menu a'); + $menu_link = $this->cssSelect('div.block-menu ul.menu a'); $this->assertEqual((string) $menu_link[0], 'New title'); } diff --git a/core/modules/views/src/Tests/ViewTestBase.php b/core/modules/views/src/Tests/ViewTestBase.php index 6aa899d..82e42e2 100644 --- a/core/modules/views/src/Tests/ViewTestBase.php +++ b/core/modules/views/src/Tests/ViewTestBase.php @@ -33,6 +33,12 @@ protected function setUp() { parent::setUp(); + // Views' Page displays put menu links in the 'navigation' menu by default. + entity_create('menu', array( + 'id' => 'navigation', + 'label' => 'Navigation', + ))->save(); + // Ensure that the plugin definitions are cleared. foreach (ViewExecutable::getPluginTypes() as $plugin_type) { $this->container->get("plugin.manager.views.$plugin_type")->clearCachedDefinitions(); diff --git a/core/modules/views/src/Tests/Wizard/MenuTest.php b/core/modules/views/src/Tests/Wizard/MenuTest.php index ba3aa42..505b4ce 100644 --- a/core/modules/views/src/Tests/Wizard/MenuTest.php +++ b/core/modules/views/src/Tests/Wizard/MenuTest.php @@ -20,8 +20,6 @@ class MenuTest extends WizardTestBase { * Tests the menu functionality. */ function testMenus() { - $this->drupalPlaceBlock('system_menu_block:main'); - // Create a view with a page display and a menu link in the Main Menu. $view = array(); $view['label'] = $this->randomMachineName(16); diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_page_display_menu.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_page_display_menu.yml index 7b6efae..cd812f2 100644 --- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_page_display_menu.yml +++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_page_display_menu.yml @@ -97,24 +97,6 @@ display: display_title: Page id: page_4 position: 0 - page_5: - display_options: - path: test-path - title: 'Tests a menu with a non-existing parent' - menu: - type: normal - title: 'Test child' - parent: 'system.admin' - description: '' - name: not-existing-menu-name - weight: '0' - context: '0' - defaults: - title: '0' - display_plugin: page - display_title: Page - id: page_4 - position: 0 label: 'Test page menu' id: test_page_display_menu tag: '' diff --git a/core/modules/views_ui/src/Tests/DisplayPathTest.php b/core/modules/views_ui/src/Tests/DisplayPathTest.php index 7e553e3..38f662e 100644 --- a/core/modules/views_ui/src/Tests/DisplayPathTest.php +++ b/core/modules/views_ui/src/Tests/DisplayPathTest.php @@ -16,20 +16,12 @@ class DisplayPathTest extends UITestBase { /** - * {@inheritdoc} - */ - public static $modules = array('menu_ui'); - - /** * Views used by this test. * * @var array */ - public static $testViews = array('test_view', 'test_page_display_menu'); + public static $testViews = array('test_view'); - /** - * Runs the tests. - */ public function testPathUI() { $this->doBasicPathUITest(); $this->doAdvancedPathsValidationTest(); @@ -104,25 +96,6 @@ public function testMenuOptions() { $this->assertLink(t('Tab: @title', array('@title' => 'Test tab title'))); // If it's a default tab, it should also have an additional settings link. $this->assertLinkByHref('admin/structure/views/nojs/display/test_view/page_1/tab_options'); - - // Ensure that you can select a parent in case the parent does not exist. - $this->drupalGet('admin/structure/views/nojs/display/test_page_display_menu/page_5/menu'); - $this->assertResponse(200); - $menu_parent = $this->xpath('//select[@id="edit-menu-parent"]'); - $menu_options = (array) $menu_parent[0]->option; - unset($menu_options['@attributes']); - - $this->assertEqual([ - '', - '-- My account', - '-- Log out', - '', - '