diff --git a/core/includes/batch.inc b/core/includes/batch.inc index 7e6e12f..b9e49f7 100644 --- a/core/includes/batch.inc +++ b/core/includes/batch.inc @@ -452,11 +452,17 @@ function _batch_finished() { if ($_batch['form_state']->getRedirect() === NULL) { $redirect = $_batch['batch_redirect'] ?: $_batch['source_url']; $options = UrlHelper::parse($redirect); - if (!UrlHelper::isExternal($options['path'])) { - $options['path'] = $GLOBALS['base_url'] . '/' . $options['path']; + if (UrlHelper::isExternal($options['path']) || strpos($options['path'], 'base://') === 0) { + $redirect = Url::unrouted($options['path'], $options); + } + else { + $redirect = \Drupal::pathValidator()->getUrlIfValid($options['path']); + if (!$redirect) { + // Stay on the same page if the redirect was invalid. + $redirect = Url::routed(''); + } + $redirect->setOptions($options); } - $redirect = Url::createFromPath($options['path']); - $redirect->setOptions($options); $_batch['form_state']->setRedirectUrl($redirect); } diff --git a/core/includes/common.inc b/core/includes/common.inc index 1379b4e..f46c9a9 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -639,6 +639,9 @@ function _format_date_callback(array $matches = NULL, $new_langcode = NULL) { * alternative than url(). * * @see \Drupal\Core\Routing\UrlGeneratorInterface::generateFromPath(). + * + * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0. + * System paths should not be used - use route names and parameters. */ function url($path = NULL, array $options = array()) { return \Drupal::urlGenerator()->generateFromPath($path, $options); diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 5a6859d..d546a52 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -543,7 +543,7 @@ function install_run_task($task, &$install_state) { } // Process the batch. For progressive batches, this will redirect. // Otherwise, the batch will complete. - $response = batch_process(install_redirect_url($install_state), install_full_redirect_url($install_state)); + $response = batch_process('base://' . install_redirect_url($install_state), install_full_redirect_url($install_state)); if ($response instanceof Response) { // Save $_SESSION data from batch. \Drupal::service('session_manager')->save(); @@ -850,7 +850,7 @@ function install_get_form($form_id, array &$install_state) { * @see install_full_redirect_url() */ function install_redirect_url($install_state) { - return 'core/install.php?' . UrlHelper::buildQuery($install_state['parameters']); + return 'install.php?' . UrlHelper::buildQuery($install_state['parameters']); } /** 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/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 02c2906..54ba225 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php @@ -383,7 +383,7 @@ public function set($name, $value, $notify = TRUE) { /** * {@inheritdoc} */ - public function getFields($include_computed = TRUE) { + public function getFields($include_computed = FALSE) { $fields = array(); foreach ($this->getFieldDefinitions() as $name => $definition) { if ($include_computed || !$definition->isComputed()) { diff --git a/core/lib/Drupal/Core/Entity/ContentEntityInterface.php b/core/lib/Drupal/Core/Entity/ContentEntityInterface.php index 292c3fd..fac4591 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityInterface.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityInterface.php @@ -105,9 +105,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); @@ -196,7 +193,7 @@ public function set($field_name, $value, $notify = TRUE); * @return \Drupal\Core\Field\FieldItemListInterface[] * An array of field item lists implementing, keyed by field name. */ - public function getFields($include_computed = TRUE); + public function getFields($include_computed = FALSE); /** * Reacts to changes to a field. diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php index 6415285..07d2efa 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->getFields(TRUE) as $field) { $field->$method(); } } 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/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/DynamicallyFieldableEntityStorageInterface.php b/core/lib/Drupal/Core/Entity/FieldableEntityStorageInterface.php similarity index 76% rename from core/lib/Drupal/Core/Entity/DynamicallyFieldableEntityStorageInterface.php rename to core/lib/Drupal/Core/Entity/FieldableEntityStorageInterface.php index 6d12c98..aaab687 100644 --- a/core/lib/Drupal/Core/Entity/DynamicallyFieldableEntityStorageInterface.php +++ b/core/lib/Drupal/Core/Entity/FieldableEntityStorageInterface.php @@ -2,7 +2,7 @@ /** * @file - * Contains \Drupal\Core\Entity\DynamicallyFieldableEntityStorageInterface. + * Contains \Drupal\Core\Entity\FieldableEntityStorageInterface. */ namespace Drupal\Core\Entity; @@ -11,16 +11,8 @@ use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Field\FieldStorageDefinitionListenerInterface; -/** - * A storage that supports entity types with dynamic field definitions. - * - * A storage that implements this interface can react to the entity type's field - * definitions changing, due to modules being installed or uninstalled, or via - * field UI, or via code changes to the entity class. - * - * For example, configurable fields defined and exposed by field.module. - */ -interface DynamicallyFieldableEntityStorageInterface extends EntityStorageInterface, FieldStorageDefinitionListenerInterface { +interface FieldableEntityStorageInterface extends EntityStorageInterface, FieldStorageDefinitionListenerInterface { + /** * Reacts to the creation of a field. * @@ -53,6 +45,36 @@ public function onFieldDefinitionUpdate(FieldDefinitionInterface $field_definiti public function onFieldDefinitionDelete(FieldDefinitionInterface $field_definition); /** + * Reacts to a bundle being created. + * + * @param string $bundle + * The name of the bundle created. + */ + public function onBundleCreate($bundle); + + /** + * Reacts to a bundle being renamed. + * + * This method runs before fields are updated with the new bundle name. + * + * @param string $bundle + * The name of the bundle being renamed. + * @param string $bundle_new + * The new name of the bundle. + */ + public function onBundleRename($bundle, $bundle_new); + + /** + * Reacts to a bundle being deleted. + * + * This method runs before fields are deleted. + * + * @param string $bundle + * The name of the bundle being deleted. + */ + public function onBundleDelete($bundle); + + /** * Purges a batch of field data. * * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition diff --git a/core/lib/Drupal/Core/Entity/Schema/DynamicallyFieldableEntityStorageSchemaInterface.php b/core/lib/Drupal/Core/Entity/Schema/FieldableEntityStorageSchemaInterface.php similarity index 83% rename from core/lib/Drupal/Core/Entity/Schema/DynamicallyFieldableEntityStorageSchemaInterface.php rename to core/lib/Drupal/Core/Entity/Schema/FieldableEntityStorageSchemaInterface.php index 59272f8..c20d9d1 100644 --- a/core/lib/Drupal/Core/Entity/Schema/DynamicallyFieldableEntityStorageSchemaInterface.php +++ b/core/lib/Drupal/Core/Entity/Schema/FieldableEntityStorageSchemaInterface.php @@ -2,7 +2,7 @@ /** * @file - * Contains \Drupal\Core\Entity\Schema\DynamicallyFieldableEntityStorageSchemaInterface. + * Contains \Drupal\Core\Entity\Schema\FieldableEntityStorageSchemaInterface. */ namespace Drupal\Core\Entity\Schema; @@ -11,15 +11,9 @@ use Drupal\Core\Field\FieldStorageDefinitionListenerInterface; /** - * A storage schema that supports entity types with dynamic field definitions. - * - * A storage schema that implements this interface can react to the entity - * type's field definitions changing, due to modules being installed or - * uninstalled, or via field UI, or via code changes to the entity class. - * - * For example, configurable fields defined and exposed by field.module. + * Defines the interface for storage schema classes for fieldable entity types. */ -interface DynamicallyFieldableEntityStorageSchemaInterface extends EntityStorageSchemaInterface, FieldStorageDefinitionListenerInterface { +interface FieldableEntityStorageSchemaInterface extends EntityStorageSchemaInterface, FieldStorageDefinitionListenerInterface { /** * Checks if the changes to the storage definition requires schema changes. diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php index 454944c..5b21b6b 100644 --- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php @@ -13,13 +13,12 @@ use Drupal\Core\Database\Database; use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\ContentEntityStorageBase; -use Drupal\Core\Entity\EntityBundleListenerInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Entity\EntityStorageException; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Entity\Query\QueryInterface; -use Drupal\Core\Entity\Schema\DynamicallyFieldableEntityStorageSchemaInterface; +use Drupal\Core\Entity\Schema\FieldableEntityStorageSchemaInterface; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Language\LanguageInterface; @@ -39,7 +38,7 @@ * * @ingroup entity_api */ -class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEntityStorageInterface, DynamicallyFieldableEntityStorageSchemaInterface, EntityBundleListenerInterface { +class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEntityStorageInterface, FieldableEntityStorageSchemaInterface { /** * The mapping of field columns to SQL tables. @@ -606,7 +605,9 @@ protected function mapFromStorageRecords(array $records) { $this->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. 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/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/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/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/Menu/MenuLinkBase.php b/core/lib/Drupal/Core/Menu/MenuLinkBase.php index b09bfa9..6edbcc0 100644 --- a/core/lib/Drupal/Core/Menu/MenuLinkBase.php +++ b/core/lib/Drupal/Core/Menu/MenuLinkBase.php @@ -141,8 +141,7 @@ public function getUrlObject($title_attribute = TRUE) { return new Url($this->pluginDefinition['route_name'], $this->pluginDefinition['route_parameters'], $options); } else { - $url = Url::createFromPath($this->pluginDefinition['url']); - $url->setOptions($options); + $url = Url::unrouted($this->pluginDefinition['url'], $options); return $url; } } diff --git a/core/lib/Drupal/Core/Path/PathValidator.php b/core/lib/Drupal/Core/Path/PathValidator.php index 1b519c7..d7506c6 100644 --- a/core/lib/Drupal/Core/Path/PathValidator.php +++ b/core/lib/Drupal/Core/Path/PathValidator.php @@ -99,7 +99,7 @@ public function getUrlIfValid($path) { if (empty($parsed_url['path'])) { return FALSE; } - return Url::createFromPath($path); + return Url::unrouted($path); } $path = ltrim($path, '/'); diff --git a/core/lib/Drupal/Core/Url.php b/core/lib/Drupal/Core/Url.php index d97f017..0511193 100644 --- a/core/lib/Drupal/Core/Url.php +++ b/core/lib/Drupal/Core/Url.php @@ -7,10 +7,10 @@ namespace Drupal\Core; -use Drupal\Component\Utility\UrlHelper; use Drupal\Core\DependencyInjection\DependencySerializationTrait; use Drupal\Core\Routing\UrlGeneratorInterface; use Drupal\Core\Session\AccountInterface; +use Drupal\Core\Utility\UnroutedUrlAssemblerInterface; use Symfony\Cmf\Component\Routing\RouteObjectInterface; use Symfony\Component\HttpFoundation\Request; @@ -28,6 +28,13 @@ class Url { protected $urlGenerator; /** + * The URL builder. + * + * @var \Drupal\Core\Utility\UnroutedUrlAssemblerInterface + */ + protected $urlAssembler; + + /** * The access manager * * @var \Drupal\Core\Access\AccessManagerInterface @@ -56,20 +63,27 @@ class Url { protected $options = array(); /** - * Indicates whether this URL is external. + * Indicates whether this object contains an external URL. * * @var bool */ protected $external = FALSE; /** - * The external path. + * Indicates whether this URL is a URI instead of a route. + * + * @var bool + */ + protected $unrouted = FALSE; + + /** + * The non-route uri. * - * Only used if self::$external is TRUE. + * Only used if self::$unrouted is TRUE. * * @var string */ - protected $path; + protected $uri; /** * Constructs a new Url object. @@ -103,44 +117,81 @@ public function __construct($route_name, $route_parameters = array(), $options = } /** - * Returns the Url object matching a path. READ THE FOLLOWING SECURITY NOTE. + * Creates a new routed (internal to Drupal) URL object. * - * SECURITY NOTE: The path is not checked to be valid and accessible by the - * current user to allow storing and reusing Url objects by different users. - * The 'path.validator' service getUrlIfValid() method should be used instead - * of this one if validation and access check is desired. Otherwise, - * 'access_manager' service checkNamedRoute() method should be used on the - * router name and parameters stored in the Url object returned by this - * method. + * @param string $route_name + * The name of the route + * @param array $route_parameters + * (optional) An associative array of parameter names and values. + * @param array $options + * (optional) An associative array of additional options, with the following + * elements: + * - 'query': An array of query key/value-pairs (without any URL-encoding) + * to append to the URL. Merged with the parameters array. + * - 'fragment': A fragment identifier (named anchor) to append to the URL. + * Do not include the leading '#' character. + * - 'absolute': Defaults to FALSE. Whether to force the output to be an + * absolute link (beginning with http:). Useful for links that will be + * displayed outside the site, such as in an RSS feed. + * - 'language': An optional language object used to look up the alias + * for the URL. If $options['language'] is omitted, it defaults to the + * current language for the language type LanguageInterface::TYPE_URL. + * - 'https': Whether this URL should point to a secure location. If not + * defined, the current scheme is used, so the user stays on HTTP or HTTPS + * respectively. if mixed mode sessions are permitted, TRUE enforces HTTPS + * and FALSE enforces HTTP. * - * @param string $path - * A path (e.g. 'node/1', 'http://drupal.org'). + * @return \Drupal\Core\Url + * A new routed (internal to Drupal) URL object. + */ + public static function routed($route_name, $route_parameters = array(), $options = array()) { + return new static($route_name, $route_parameters, $options); + } + + /** + * Creates a new unrouted (external to Drupal) URL object. * - * @return static - * An Url object. Warning: the object is created even if the current user - * can not access the path. + * @param string $uri + * The URI of the external resource including the scheme. For Drupal paths + * that are not handled by the routing system, you may use base:// for the + * scheme. + * @param array $options + * (optional) An associative array of additional options, with the following + * elements: + * - 'query': An array of query key/value-pairs (without any URL-encoding) + * to append to the URL. Merged with the parameters array. + * - 'fragment': A fragment identifier (named anchor) to append to the URL. + * Do not include the leading '#' character. + * - 'absolute': Defaults to FALSE. Whether to force the output to be an + * absolute link (beginning with http:). Useful for links that will be + * displayed outside the site, such as in an RSS feed. + * - 'language': An optional language object used to look up the alias + * for the URL. If $options['language'] is omitted, it defaults to the + * current language for the language type LanguageInterface::TYPE_URL. + * - 'https': Whether this URL should point to a secure location. If not + * defined, the current scheme is used, so the user stays on HTTP or HTTPS + * respectively. if mixed mode sessions are permitted, TRUE enforces HTTPS + * and FALSE enforces HTTP. * - * @throws \Drupal\Core\Routing\MatchingRouteNotFoundException - * Thrown when the path cannot be matched. + * @return \Drupal\Core\Url + * A new unrouted (external to Drupal) URL object. */ - public static function createFromPath($path) { - if (UrlHelper::isExternal($path)) { - $url = new static($path); - $url->setExternal(); - return $url; - } - - // Special case the front page route. - if ($path == '') { - return new static($path); - } - else { - return static::createFromRequest(Request::create("/$path")); - } + public static function unrouted($uri, $options = array()) { + $url = new static($uri, array(), $options); + $url->setUnrouted(); + return $url; } /** - * Returns the Url object matching a request. READ THE SECURITY NOTE ON createFromPath(). + * Returns the Url object matching a request. + * + * SECURITY NOTE: The request path is not checked to be valid and accessible + * by the current user to allow storing and reusing Url objects by different + * users. The 'path.validator' service getUrlIfValid() method should be used + * instead of this one if validation and access check is desired. Otherwise, + * 'access_manager' service checkNamedRoute() method should be used on the + * router name and parameters stored in the Url object returned by this + * method. * * @param \Symfony\Component\HttpFoundation\Request $request * A request object. @@ -163,23 +214,20 @@ public static function createFromRequest(Request $request) { } /** - * Sets this Url to be external. + * Sets this Url to encapselate an unrouted URI. * * @return $this */ - protected function setExternal() { - $this->external = TRUE; - - // What was passed in as the route name is actually the path. - $this->path = $this->routeName; - + protected function setUnrouted() { + $this->unrouted = TRUE; + // What was passed in as the route name is actually the uri. + $this->uri = $this->routeName; // Set empty route name and parameters. $this->routeName = NULL; $this->routeParameters = array(); - // Flag the path as external so the UrlGenerator does not need to check. - $this->options['external'] = TRUE; - - return $this; + if ($this->external = strpos($this->uri, 'base://') !== 0) { + $this->options['external'] = TRUE; + } } /** @@ -197,10 +245,10 @@ public function isExternal() { * @return string * * @throws \UnexpectedValueException. - * If this is an external URL with no corresponding route. + * If this is an URI with no corresponding route. */ public function getRouteName() { - if ($this->isExternal()) { + if ($this->unrouted) { throw new \UnexpectedValueException('External URLs do not have an internal route name.'); } @@ -213,10 +261,10 @@ public function getRouteName() { * @return array * * @throws \UnexpectedValueException. - * If this is an external URL with no corresponding route. + * If this is an URI with no corresponding route. */ public function getRouteParameters() { - if ($this->isExternal()) { + if ($this->unrouted) { throw new \UnexpectedValueException('External URLs do not have internal route parameters.'); } @@ -230,10 +278,13 @@ public function getRouteParameters() { * The array of parameters. * * @return $this + * + * @throws \UnexpectedValueException. + * If this is an URI with no corresponding route. */ public function setRouteParameters($parameters) { - if ($this->isExternal()) { - throw new \Exception('External URLs do not have route parameters.'); + if ($this->unrouted) { + throw new \UnexpectedValueException('External URLs do not have route parameters.'); } $this->routeParameters = $parameters; return $this; @@ -248,10 +299,13 @@ public function setRouteParameters($parameters) { * The route parameter. * * @return $this + * + * @throws \UnexpectedValueException. + * If this is an URI with no corresponding route. */ public function setRouteParameter($key, $value) { - if ($this->isExternal()) { - throw new \Exception('External URLs do not have route parameters.'); + if ($this->unrouted) { + throw new \UnexpectedValueException('External URLs do not have route parameters.'); } $this->routeParameters[$key] = $value; return $this; @@ -312,22 +366,22 @@ public function setOption($name, $value) { } /** - * Returns the external path of the URL. + * Returns the URI of the URL. * - * Only to be used if self::$external is TRUE. + * Only to be used if self::$unrouted is TRUE. * * @return string - * The external path. + * A URI not connected to a route. May be an external URL. * * @throws \UnexpectedValueException - * Thrown when the path was requested for an internal URL. + * Thrown when the uri was requested for route. */ - public function getPath() { - if (!$this->isExternal()) { - throw new \UnexpectedValueException('Internal URLs do not have external paths.'); + public function getUri() { + if (!$this->unrouted) { + throw new \UnexpectedValueException('Internal routes do not have uris.'); } - return $this->path; + return $this->uri; } /** @@ -344,11 +398,11 @@ public function setAbsolute($absolute = TRUE) { } /** - * Generates the path for this Url object. + * Generates the uri for this Url object. */ public function toString() { - if ($this->isExternal()) { - return $this->urlGenerator()->generateFromPath($this->getPath(), $this->getOptions()); + if ($this->unrouted) { + return $this->unroutedUrlAssembler()->assemble($this->getUri(), $this->getOptions()); } return $this->urlGenerator()->generateFromRoute($this->getRouteName(), $this->getRouteParameters(), $this->getOptions()); @@ -363,7 +417,7 @@ public function toString() { public function toArray() { if ($this->isExternal()) { return array( - 'path' => $this->getPath(), + 'path' => $this->getUri(), 'options' => $this->getOptions(), ); } @@ -383,9 +437,9 @@ public function toArray() { * An associative array suitable for a render array. */ public function toRenderArray() { - if ($this->isExternal()) { + if ($this->unrouted) { return array( - '#href' => $this->getPath(), + '#href' => $this->getUri(), '#options' => $this->getOptions(), ); } @@ -408,13 +462,13 @@ public function toRenderArray() { * The internal path for this route. * * @throws \UnexpectedValueException. - * If this is an external URL with no corresponding system path. + * If this is an URI with no corresponding system path. * * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0. * System paths should not be used - use route names and parameters. */ public function getInternalPath() { - if ($this->isExternal()) { + if ($this->unrouted) { throw new \UnexpectedValueException('External URLs do not have internal representations.'); } return $this->urlGenerator()->getPathFromRoute($this->getRouteName(), $this->getRouteParameters()); @@ -473,6 +527,19 @@ protected function urlGenerator() { } /** + * Gets the URL builder for non-Drupal URLs. + * + * @return \Drupal\Core\Utility\UnroutedUrlAssemblerInterface + * The URL builder. + */ + protected function unroutedUrlAssembler() { + if (!$this->urlAssembler) { + $this->urlAssembler = \Drupal::service('unrouted_url_assembler'); + } + return $this->urlAssembler; + } + + /** * Sets the URL generator. * * @param \Drupal\Core\Routing\UrlGeneratorInterface @@ -485,4 +552,17 @@ public function setUrlGenerator(UrlGeneratorInterface $url_generator) { return $this; } + /** + * Sets the unrouted URL assembler. + * + * @param \Drupal\Core\Utility\UnroutedUrlAssemblerInterface + * The unrouted URL assembler. + * + * @return $this + */ + public function setUnroutedUrlAssembler(UnroutedUrlAssemblerInterface $url_assembler) { + $this->urlAssembler = $url_assembler; + return $this; + } + } diff --git a/core/modules/aggregator/aggregator.module b/core/modules/aggregator/aggregator.module index aecd844..5e85078 100644 --- a/core/modules/aggregator/aggregator.module +++ b/core/modules/aggregator/aggregator.module @@ -26,6 +26,7 @@ function aggregator_help($route_name, RouteMatchInterface $route_match) { $output .= '

' . t('The Aggregator module is an on-site syndicator and news reader that gathers and displays fresh content from RSS-, RDF-, and Atom-based feeds made available across the web. Thousands of sites (particularly news sites and blogs) publish their latest headlines in feeds, using a number of standardized XML-based formats. For more information, see the online documentation for the Aggregator module.', array('!aggregator-module' => 'https://drupal.org/documentation/modules/aggregator')) . '

'; $output .= '

' . t('Uses') . '

'; $output .= '
'; + // Check if the aggregator sources View is enabled. if ($url = $path_validator->getUrlIfValid('aggregator/sources')) { $output .= '
' . t('Viewing feeds') . '
'; $output .= '
' . t('Users view feed content in the main aggregator display, or by their source (usually via an RSS feed reader). The most recent content in a feed can be displayed as a block through the Blocks administration page.', array('!aggregator' => \Drupal::url('aggregator.page_last'), '!aggregator-sources' => $url->toString(), '!admin-block' => \Drupal::url('block.admin_display'))) . '
'; @@ -33,6 +34,7 @@ function aggregator_help($route_name, RouteMatchInterface $route_match) { $output .= '
' . t('Adding, editing, and deleting feeds') . '
'; $output .= '
' . t('Administrators can add, edit, and delete feeds, and choose how often to check each feed for newly updated items on the Feed aggregator administration page.', array('!feededit' => \Drupal::url('aggregator.admin_overview'))) . '
'; $output .= '
' . t('OPML integration') . '
'; + // Check if the aggregator opml View is enabled. if ($url = $path_validator->getUrlIfValid('aggregator/opml')) { $output .= '
' . t('A machine-readable OPML file of all feeds is available. OPML is an XML-based file format used to share outline-structured information such as a list of RSS feeds. Feeds can also be imported via an OPML file.', array('!aggregator-opml' => $url->toString(), '!import-opml' => \Drupal::url('aggregator.opml_add'))) . '
'; } diff --git a/core/modules/aggregator/src/Entity/Feed.php b/core/modules/aggregator/src/Entity/Feed.php index 6532f36..5bcd787 100644 --- a/core/modules/aggregator/src/Entity/Feed.php +++ b/core/modules/aggregator/src/Entity/Feed.php @@ -39,6 +39,7 @@ * }, * field_ui_base_route = "aggregator.admin_overview", * base_table = "aggregator_feed", + * fieldable = TRUE, * render_cache = FALSE, * entity_keys = { * "id" = "fid", diff --git a/core/modules/aggregator/src/Entity/Item.php b/core/modules/aggregator/src/Entity/Item.php index 493e4cb..cb7f0b9 100644 --- a/core/modules/aggregator/src/Entity/Item.php +++ b/core/modules/aggregator/src/Entity/Item.php @@ -30,6 +30,7 @@ * }, * uri_callback = "Drupal\aggregator\Entity\Item::buildUri", * base_table = "aggregator_item", + * fieldable = TRUE, * render_cache = FALSE, * entity_keys = { * "id" = "iid", @@ -244,7 +245,7 @@ public function getListCacheTags() { * Entity URI callback. */ public static function buildUri(ItemInterface $item) { - return Url::createFromPath($item->getLink()); + return Url::unrouted($item->getLink()); } } 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_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..cea9b48 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(); } } 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/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/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/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/FieldUI.php b/core/modules/field_ui/src/FieldUI.php index 77ec651..be74fff 100644 --- a/core/modules/field_ui/src/FieldUI.php +++ b/core/modules/field_ui/src/FieldUI.php @@ -51,15 +51,15 @@ public static function getNextDestination(array $destinations) { $next_destination += array( 'route_parameters' => array(), ); - $next_destination = new Url($next_destination['route_name'], $next_destination['route_parameters'], $next_destination['options']); + $next_destination = Url::routed($next_destination['route_name'], $next_destination['route_parameters'], $next_destination['options']); } else { $options = UrlHelper::parse($next_destination); if ($destinations) { $options['query']['destinations'] = $destinations; } - $next_destination = Url::createFromPath($options['path']); - $next_destination->setOptions($options); + // Redirect to any given path within the same domain. + $next_destination = Url::unrouted('base://' . $options['path']); } return $next_destination; } 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/link/link.module b/core/modules/link/link.module index d33181e..c9837a3 100644 --- a/core/modules/link/link.module +++ b/core/modules/link/link.module @@ -69,6 +69,6 @@ function template_preprocess_link_formatter_link_separate(&$variables) { $variables['link'] = \Drupal::linkGenerator()->generateFromUrl($variables['url_title'], $variables['url']); } else { - $variables['link'] = l($variables['url_title'], $variables['url']->getPath(), $variables['url']->getOptions()); + $variables['link'] = l($variables['url_title'], $variables['url']->getUri(), $variables['url']->getOptions()); } } diff --git a/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php b/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php index 05caf97..a23972f 100644 --- a/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php +++ b/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php @@ -13,6 +13,7 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Url; use Drupal\link\LinkItemInterface; +use Symfony\Component\HttpFoundation\Request; /** * Plugin implementation of the 'link' formatter. @@ -163,7 +164,7 @@ public function viewElements(FieldItemListInterface $items) { '#options' => $url->getOptions(), ); if ($url->isExternal()) { - $element[$delta]['#href'] = $url->getPath(); + $element[$delta]['#href'] = $url->getUri(); } else { $element[$delta]['#route_name'] = $url->getRouteName(); @@ -206,11 +207,21 @@ protected function buildUrl(LinkItemInterface $item) { } if ($item->isExternal()) { - $url = Url::createFromPath($item->url); - $url->setOptions($options); + // @todo LinkItemInterface shouldn't treat items with no scheme as + // external, including . + if (parse_url($item->url, PHP_URL_SCHEME)) { + $url = Url::unrouted($item->url, $options); + } + elseif ($item->url == '') { + $url = new Url(''); + } + else { + // No base path - assume internal. + $url = Url::createFromRequest(Request::create('/' . ltrim($item->url, '/'))); + } } else { - $url = new Url($item->route_name, (array) $item->route_parameters, (array) $options); + $url = Url::routed($item->route_name, (array) $item->route_parameters, (array) $options); } return $url; diff --git a/core/modules/menu_link_content/src/Entity/MenuLinkContent.php b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php index 55f3489..b44fffc 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", @@ -107,7 +108,7 @@ public function getUrlObject() { else { $path = $this->getUrl(); if (isset($path)) { - $url = Url::createFromPath($path); + $url = Url::unrouted($path); } else { $url = new Url(''); diff --git a/core/modules/menu_link_content/src/Form/MenuLinkContentForm.php b/core/modules/menu_link_content/src/Form/MenuLinkContentForm.php index 2d37566..4fb93b2 100644 --- a/core/modules/menu_link_content/src/Form/MenuLinkContentForm.php +++ b/core/modules/menu_link_content/src/Form/MenuLinkContentForm.php @@ -198,7 +198,7 @@ public function extractFormValues(array &$form, FormStateInterface $form_state) if ($extracted) { if ($extracted->isExternal()) { - $new_definition['url'] = $extracted->getPath(); + $new_definition['url'] = $extracted->getUri(); } else { $new_definition['route_name'] = $extracted->getRouteName(); 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/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/shortcut/src/Entity/Shortcut.php b/core/modules/shortcut/src/Entity/Shortcut.php index df96d6f..9804fa5 100644 --- a/core/modules/shortcut/src/Entity/Shortcut.php +++ b/core/modules/shortcut/src/Entity/Shortcut.php @@ -14,6 +14,7 @@ use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Url; use Drupal\shortcut\ShortcutInterface; +use Symfony\Component\HttpFoundation\Request; /** * Defines the shortcut entity class. @@ -45,7 +46,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 { @@ -134,7 +136,12 @@ public static function preCreate(EntityStorageInterface $storage, array &$values public function preSave(EntityStorageInterface $storage) { parent::preSave($storage); - $url = Url::createFromPath($this->path->value); + if ($this->path->value == '') { + $url = new Url($this->path->value); + } + else { + $url = Url::createFromRequest(Request::create("/{$this->path->value}")); + } $this->setRouteName($url->getRouteName()); $this->setRouteParams($url->getRouteParameters()); } 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/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/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..dd9b2ef 100644 --- a/core/modules/system/src/Tests/Entity/EntityFieldTest.php +++ b/core/modules/system/src/Tests/Entity/EntityFieldTest.php @@ -594,11 +594,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 +609,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/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/system.module b/core/modules/system/system.module index 3f19f14..bc88307 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -452,7 +452,7 @@ function system_authorized_get_url(array $options = array()) { // Force HTTPS if available, regardless of what the caller specifies. $options['https'] = TRUE; // Prefix with $base_url so url() treats it as an external link. - $url = Url::createFromPath($base_url . '/core/authorize.php'); + $url = Url::unrouted('base://core/authorize.php'); $url_options = $url->getOptions(); $url->setOptions($options + $url_options); return $url; 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/system/tests/modules/form_test/src/Form/FormTestRedirectForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestRedirectForm.php index 7fc352e..3eb9cc4 100644 --- a/core/modules/system/tests/modules/form_test/src/Form/FormTestRedirectForm.php +++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestRedirectForm.php @@ -54,7 +54,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { public function submitForm(array &$form, FormStateInterface $form_state) { if (!$form_state->isValueEmpty('redirection')) { if (!$form_state->isValueEmpty('destination')) { - $form_state->setRedirectUrl(Url::createFromPath($GLOBALS['base_url'] . '/' . $form_state->getValue('destination'))); + $form_state->setRedirectUrl(Url::unrouted('base://' . $form_state->getValue('destination'))); } } else { 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/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/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module index b9174bc..815d1cf 100644 --- a/core/modules/toolbar/toolbar.module +++ b/core/modules/toolbar/toolbar.module @@ -298,7 +298,7 @@ function toolbar_menu_navigation_links(array $tree) { $url = $link->getUrlObject(); if ($url->isExternal()) { // This is an unusual case, so just get a distinct, safe string. - $id = substr(Crypt::hashBase64($url->getPath()), 0, 16); + $id = substr(Crypt::hashBase64($url->getUri()), 0, 16); } else { $id = str_replace(array('.', '<', '>'), array('-', '', ''), $url->getRouteName()); diff --git a/core/modules/update/update.report.inc b/core/modules/update/update.report.inc index 9ee4dbf..e885ce5 100644 --- a/core/modules/update/update.report.inc +++ b/core/modules/update/update.report.inc @@ -135,7 +135,7 @@ function template_preprocess_update_project_status(&$variables) { // Set the project title and URL. $variables['title'] = (isset($project['title'])) ? $project['title'] : $project['name']; - $variables['url'] = (isset($project['link'])) ? url($project['link']) : NULL; + $variables['url'] = (isset($project['link'])) ? \Drupal::service('unrouted_url_assembler')->assemble($project['link']) : NULL; $variables['install_type'] = $project['install_type']; if ($project['install_type'] == 'dev' && !empty($project['datestamp'])) { 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/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/user/user.module b/core/modules/user/user.module index e33cd28..71ecd5e 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -576,6 +576,7 @@ function template_preprocess_username(&$variables) { $variables['name'] = String::checkPlain($name); $variables['profile_access'] = \Drupal::currentUser()->hasPermission('access user profiles'); + $external = FALSE; // Populate link path and attributes if appropriate. if ($variables['uid'] && $variables['profile_access']) { // We are linking to a local user. @@ -589,10 +590,19 @@ function template_preprocess_username(&$variables) { $variables['attributes']['rel'] = 'nofollow'; $variables['link_path'] = $account->homepage; $variables['homepage'] = $account->homepage; + $external = TRUE; } - // We have a link path, so we should generate a link using url(). + // We have a link path, so we should generate a URL. if (isset($variables['link_path'])) { - $variables['attributes']['href'] = url($variables['link_path'], $variables['link_options']); + if ($external) { + $variables['attributes']['href'] = \Drupal::service('unrouted_url_assembler') + ->assemble($variables['link_path'], $variables['link_options']); + } + else { + $variables['attributes']['href'] = Url::routed('entity.user.canonical', array( + 'user' => $variables['uid'], + ))->toString(); + } } } diff --git a/core/modules/views_ui/src/Tests/RedirectTest.php b/core/modules/views_ui/src/Tests/RedirectTest.php index 30d387c..519ec79 100644 --- a/core/modules/views_ui/src/Tests/RedirectTest.php +++ b/core/modules/views_ui/src/Tests/RedirectTest.php @@ -27,17 +27,17 @@ class RedirectTest extends UITestBase { public function testRedirect() { $view_name = 'test_view'; - $random_destination = $this->randomMachineName(); + $random_destination = 'node'; $edit_path = "admin/structure/views/view/$view_name/edit"; - $this->drupalPostForm($edit_path, array(), t('Save') , array('query' => array('destination' => $random_destination))); - $this->assertUrl($random_destination, array(), 'Make sure the user got redirected to the expected page defined in the destination.'); + $this->drupalPostForm($edit_path, array(), t('Save') , array('query' => array('destination' => 'node'))); + $this->assertUrl('node', array(), 'Make sure the user got redirected to the expected page defined in the destination.'); // Setup a view with a certain page display path. If you change the path // but have the old url in the destination the user should be redirected to // the new path. $view_name = 'test_redirect_view'; - $new_path = $this->randomMachineName(); + $new_path = 'user'; $edit_path = "admin/structure/views/view/$view_name/edit"; $path_edit_path = "admin/structure/views/nojs/display/$view_name/page_1/path"; diff --git a/core/modules/views_ui/src/ViewEditForm.php b/core/modules/views_ui/src/ViewEditForm.php index 12083cf..a0f7ca6 100644 --- a/core/modules/views_ui/src/ViewEditForm.php +++ b/core/modules/views_ui/src/ViewEditForm.php @@ -20,6 +20,7 @@ use Drupal\Core\Url; use Drupal\user\TempStoreFactory; use Drupal\views\Views; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -322,10 +323,7 @@ public function save(array $form, FormStateInterface $form_state) { $query->remove('destination'); } } - if (!UrlHelper::isExternal($destination)) { - $destination = $GLOBALS['base_url'] . '/' . $destination; - } - $form_state->setRedirectUrl(Url::createFromPath($destination)); + $form_state->setRedirectUrl(Url::createFromRequest(Request::create("/$destination"))); } $view->save(); diff --git a/core/tests/Drupal/Tests/Core/Access/AccessResultTest.php b/core/tests/Drupal/Tests/Core/Access/AccessResultTest.php index 6f9c6be..4b92acb 100644 --- a/core/tests/Drupal/Tests/Core/Access/AccessResultTest.php +++ b/core/tests/Drupal/Tests/Core/Access/AccessResultTest.php @@ -32,7 +32,7 @@ protected function assertDefaultCacheability(AccessResult $access) { * Tests the construction of an AccessResult object. * * @covers ::__construct - * @covers ::neutral + * @covers ::create * @covers ::getCacheBin */ public function testConstruction() { @@ -55,6 +55,7 @@ public function testConstruction() { } /** + * @covers ::allow * @covers ::allowed * @covers ::isAllowed * @covers ::isForbidden @@ -74,6 +75,7 @@ public function testAccessAllowed() { } /** + * @covers ::forbid * @covers ::forbidden * @covers ::isAllowed * @covers ::isForbidden @@ -93,6 +95,7 @@ public function testAccessForbidden() { } /** + * @covers ::allowIf * @covers ::allowedIf * @covers ::isAllowed * @covers ::isForbidden @@ -113,6 +116,7 @@ public function testAccessConditionallyAllowed() { } /** + * @covers ::forbidIf * @covers ::forbiddenIf * @covers ::isAllowed * @covers ::isForbidden @@ -321,6 +325,7 @@ public function testCacheMaxAge() { * @covers ::getCacheKeys * @covers ::cachePerRole * @covers ::cachePerUser + * @covers ::allowIfHasPermission * @covers ::allowedIfHasPermission */ public function testCacheContexts() { @@ -802,45 +807,6 @@ public function testAndOrCacheabilityPropagation(AccessResultInterface $first, $ } } - /** - * Tests allowedIfHasPermissions(). - * - * @covers ::allowedIfHasPermissions - * - * @dataProvider providerTestAllowedIfHasPermissions - */ - public function testAllowIfHasPermissions($permissions, $conjunction, $expected_access) { - $account = $this->getMock('\Drupal\Core\Session\AccountInterface'); - $account->expects($this->any()) - ->method('hasPermission') - ->willReturnMap([ - ['allowed', TRUE], - ['denied', FALSE], - ]); - - $access_result = AccessResult::allowedIfHasPermissions($account, $permissions, $conjunction); - $this->assertEquals($expected_access, $access_result); - } - - /** - * Provides data for the testAllowedIfHasPermissions() method. - * - * @return array - */ - public function providerTestAllowedIfHasPermissions() { - return [ - [[], 'AND', AccessResult::allowedIf(FALSE)->cachePerRole()], - [[], 'OR', AccessResult::allowedIf(FALSE)->cachePerRole()], - [['allowed'], 'OR', AccessResult::allowedIf(TRUE)->cachePerRole()], - [['allowed'], 'AND', AccessResult::allowedIf(TRUE)->cachePerRole()], - [['denied'], 'OR', AccessResult::allowedIf(FALSE)->cachePerRole()], - [['denied'], 'AND', AccessResult::allowedIf(FALSE)->cachePerRole()], - [['allowed', 'denied'], 'OR', AccessResult::allowedIf(TRUE)->cachePerRole()], - [['allowed', 'denied', 'other'], 'OR', AccessResult::allowedIf(TRUE)->cachePerRole()], - [['allowed', 'denied'], 'AND', AccessResult::allowedIf(FALSE)->cachePerRole()], - ]; - } - } class UncacheableTestAccessResult implements AccessResultInterface { diff --git a/core/tests/Drupal/Tests/Core/ExternalUrlTest.php b/core/tests/Drupal/Tests/Core/ExternalUrlTest.php index 57a51d4..5073689 100644 --- a/core/tests/Drupal/Tests/Core/ExternalUrlTest.php +++ b/core/tests/Drupal/Tests/Core/ExternalUrlTest.php @@ -20,11 +20,11 @@ class ExternalUrlTest extends UnitTestCase { /** - * The URL generator + * The URL assembler * * @var \Drupal\Core\Routing\UrlGeneratorInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $urlGenerator; + protected $urlAssembler; /** * The router. @@ -46,15 +46,15 @@ class ExternalUrlTest extends UnitTestCase { protected function setUp() { parent::setUp(); - $this->urlGenerator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface'); - $this->urlGenerator->expects($this->any()) - ->method('generateFromPath') + $this->urlAssembler = $this->getMock('Drupal\Core\Utility\UnroutedUrlAssemblerInterface'); + $this->urlAssembler->expects($this->any()) + ->method('assemble') ->will($this->returnArgument(0)); $this->router = $this->getMock('Drupal\Tests\Core\Routing\TestRouterInterface'); $container = new ContainerBuilder(); $container->set('router.no_access_checks', $this->router); - $container->set('url_generator', $this->urlGenerator); + $container->set('unrouted_url_assembler', $this->urlAssembler); \Drupal::setContainer($container); } @@ -65,7 +65,7 @@ protected function setUp() { * @covers ::setExternal() */ public function testCreateFromPath() { - $url = Url::createFromPath($this->path); + $url = Url::unrouted($this->path); $this->assertInstanceOf('Drupal\Core\Url', $url); $this->assertTrue($url->isExternal()); return $url; @@ -172,8 +172,8 @@ public function testGetInternalPath(Url $url) { * * @covers ::getPath() */ - public function testGetPath(Url $url) { - $this->assertNotNull($url->getPath()); + public function testGetUri(Url $url) { + $this->assertNotNull($url->getUri()); } /** diff --git a/core/tests/Drupal/Tests/Core/UrlTest.php b/core/tests/Drupal/Tests/Core/UrlTest.php index 133a73c..7cc514a 100644 --- a/core/tests/Drupal/Tests/Core/UrlTest.php +++ b/core/tests/Drupal/Tests/Core/UrlTest.php @@ -102,8 +102,8 @@ public function testCreateFromPath() { $urls = array(); foreach ($this->map as $index => $values) { - $path = trim(array_pop($values), '/'); - $url = Url::createFromPath($path); + $path = array_pop($values); + $url = Url::createFromRequest(Request::create("$path")); $this->assertSame($values, array_values($url->toArray())); $urls[$index] = $url; } @@ -131,7 +131,7 @@ protected function getRequestConstraint($path) { * @covers ::createFromPath() */ public function testCreateFromPathFront() { - $url = Url::createFromPath(''); + $url = Url::routed(''); $this->assertSame('', $url->getRouteName()); } @@ -148,7 +148,7 @@ public function testCreateFromPathInvalid() { ->with($this->getRequestConstraint('/non-existent')) ->will($this->throwException(new ResourceNotFoundException())); - $this->assertNull(Url::createFromPath('non-existent')); + $this->assertNull(Url::createFromRequest(Request::create('/non-existent'))); } /** @@ -209,6 +209,9 @@ public function testIsExternal($urls) { /** * Tests the getPath() method for internal URLs. * + * @param \Drupal\Core\Url[] $urls + * Array of URL objects. + * * @depends testCreateFromPath * * @expectedException \UnexpectedValueException @@ -217,7 +220,7 @@ public function testIsExternal($urls) { */ public function testGetPathForInternalUrl($urls) { foreach ($urls as $url) { - $url->getPath(); + $url->getUri(); } } @@ -227,8 +230,8 @@ public function testGetPathForInternalUrl($urls) { * @covers ::getPath */ public function testGetPathForExternalUrl() { - $url = Url::createFromPath('http://example.com/test'); - $this->assertEquals('http://example.com/test', $url->getPath()); + $url = Url::unrouted('http://example.com/test'); + $this->assertEquals('http://example.com/test', $url->getUri()); } /** @@ -292,7 +295,7 @@ public function testGetRouteName($urls) { * @expectedException \UnexpectedValueException */ public function testGetRouteNameWithExternalUrl() { - $url = Url::createFromPath('http://example.com'); + $url = Url::unrouted('http://example.com'); $url->getRouteName(); } @@ -319,7 +322,7 @@ public function testGetRouteParameters($urls) { * @expectedException \UnexpectedValueException */ public function testGetRouteParametersWithExternalUrl() { - $url = Url::createFromPath('http://example.com'); + $url = Url::unrouted('http://example.com'); $url->getRouteParameters(); } diff --git a/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php b/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php index 7926b2f..8c38e75 100644 --- a/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php +++ b/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php @@ -40,6 +40,13 @@ class LinkGeneratorTest extends UnitTestCase { protected $moduleHandler; /** + * The mocked URL Assembler service. + * + * @var \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\Utility\UnroutedUrlAssemblerInterface + */ + protected $urlAssembler; + + /** * Contains the LinkGenerator default options. */ protected $defaultOptions = array( @@ -60,6 +67,7 @@ protected function setUp() { $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface'); $this->linkGenerator = new LinkGenerator($this->urlGenerator, $this->moduleHandler); + $this->urlAssembler = $this->getMock('\Drupal\Core\Utility\UnroutedUrlAssemblerInterface'); } /** @@ -142,17 +150,18 @@ public function testGenerateFromUrl() { * @covers ::generateFromUrl() */ public function testGenerateFromUrlExternal() { - $this->urlGenerator->expects($this->once()) - ->method('generateFromPath') - ->with('http://drupal.org', array('set_active_class' => TRUE, 'external' => TRUE) + $this->defaultOptions) - ->will($this->returnArgument(0)); - $this->moduleHandler->expects($this->once()) ->method('alter') ->with('link', $this->isType('array')); - $url = Url::createFromPath('http://drupal.org'); + $this->urlAssembler->expects($this->once()) + ->method('assemble') + ->with('http://drupal.org', array('set_active_class' => TRUE, 'external' => TRUE) + $this->defaultOptions) + ->willReturnArgument(0); + + $url = Url::unrouted('http://drupal.org'); $url->setUrlGenerator($this->urlGenerator); + $url->setUnroutedUrlAssembler($this->urlAssembler); $url->setOption('set_active_class', TRUE); $result = $this->linkGenerator->generateFromUrl('Drupal', $url);