diff --git a/core/core.services.yml b/core/core.services.yml index 32881da..cf4ebab 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -4,24 +4,6 @@ services: arguments: ['@settings'] calls: - [setContainer, ['@service_container']] - cache_contexts: - class: Drupal\Core\Cache\CacheContexts - arguments: ['@service_container', '%cache_contexts%' ] - cache_context.url: - class: Drupal\Core\Cache\UrlCacheContext - arguments: ['@request'] - tags: - - { name: cache.context} - cache_context.language: - class: Drupal\Core\Cache\LanguageCacheContext - arguments: ['@language_manager'] - tags: - - { name: cache.context} - cache_context.theme: - class: Drupal\Core\Cache\ThemeCacheContext - arguments: ['@request', '@theme.negotiator'] - tags: - - { name: cache.context} cache.backend.database: class: Drupal\Core\Cache\DatabaseBackendFactory arguments: ['@database'] diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index e38cfda..9e5c50f 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -900,13 +900,6 @@ function drupal_serve_page_from_cache(stdClass $cache, Response $response, Reque // max-age > 0, allowing the page to be cached by external proxies, when a // session cookie is present unless the Vary header has been replaced. $max_age = !$request->cookies->has(session_name()) || isset($boot_headers['vary']) ? $config->get('cache.page.max_age') : 0; - // RFC 2616, section 14.21 says: 'To mark a response as "never expires," an - // origin server sends an Expires date approximately one year from the time - // the response is sent. HTTP/1.1 servers SHOULD NOT send Expires dates more - // than one year in the future.' - if ($max_age > 31536000 || $max_age === \Drupal\Core\Cache\Cache::PERMANENT) { - $max_age = 31536000; - } $response->headers->set('Cache-Control', 'public, max-age=' . $max_age); // Entity tag should change if the output changes. diff --git a/core/includes/common.inc b/core/includes/common.inc index 7bb6d06..b7dfde2 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -132,6 +132,78 @@ const JS_THEME = 100; /** + * @defgroup block_caching Block Caching + * @{ + * Constants that define each block's caching state. + * + * Modules specify how their blocks can be cached in their hook_block_info() + * implementations. Caching can be turned off (DRUPAL_NO_CACHE), managed by the + * module declaring the block (DRUPAL_CACHE_CUSTOM), or managed by the core + * Block module. If the Block module is managing the cache, you can specify that + * the block is the same for every page and user (DRUPAL_CACHE_GLOBAL), or that + * it can change depending on the page (DRUPAL_CACHE_PER_PAGE) or by user + * (DRUPAL_CACHE_PER_ROLE or DRUPAL_CACHE_PER_USER). Page and user settings can + * be combined with a bitwise-binary or operator; for example, + * DRUPAL_CACHE_PER_ROLE | DRUPAL_CACHE_PER_PAGE means that the block can change + * depending on the user role or page it is on. + * + * The block cache is cleared when the 'content' cache tag is invalidated, + * following the same pattern as the page cache (node, comment, user, taxonomy + * added or updated...). + * + * Note that user 1 is excluded from block caching. + */ + +/** + * The block should not get cached. + * + * This setting should be used: + * - For simple blocks (notably those that do not perform any db query), where + * querying the db cache would be more expensive than directly generating the + * content. + * - For blocks that change too frequently. + */ +const DRUPAL_NO_CACHE = -1; + +/** + * The block is handling its own caching in its hook_block_view(). + * + * This setting is useful when time based expiration is needed or a site uses a + * node access which invalidates standard block cache. + */ +const DRUPAL_CACHE_CUSTOM = -2; + +/** + * The block or element can change depending on the user's roles. + * + * This is the default setting for blocks, used when the block does not specify + * anything. + */ +const DRUPAL_CACHE_PER_ROLE = 0x0001; + +/** + * The block or element can change depending on the user. + * + * This setting can be resource-consuming for sites with large number of users, + * and thus should only be used when DRUPAL_CACHE_PER_ROLE is not sufficient. + */ +const DRUPAL_CACHE_PER_USER = 0x0002; + +/** + * The block or element can change depending on the page being viewed. + */ +const DRUPAL_CACHE_PER_PAGE = 0x0004; + +/** + * The block or element is the same for every user and page that it is visible. + */ +const DRUPAL_CACHE_GLOBAL = 0x0008; + +/** + * @} End of "defgroup block_caching". + */ + +/** * The delimiter used to split plural strings. * * This is the ETX (End of text) character and is used as a minimal means to @@ -3646,12 +3718,16 @@ function drupal_render_page($page) { * associative array with one or several of the following keys: * - 'keys': An array of one or more keys that identify the element. If * 'keys' is set, the cache ID is created automatically from these keys. - * Cache keys may either be static (just strings) or tokens (placeholders - * that are converted to static keys by the @cache_contexts service, - * depending on the request). See drupal_render_cid_create(). + * See drupal_render_cid_create(). + * - 'granularity' (optional): Define the cache granularity using binary + * combinations of the cache granularity constants, e.g. + * DRUPAL_CACHE_PER_USER to cache for each user separately or + * DRUPAL_CACHE_PER_PAGE | DRUPAL_CACHE_PER_ROLE to cache separately for + * each page and role. If not specified the element is cached globally for + * each theme and language. * - 'cid': Specify the cache ID directly. Either 'keys' or 'cid' is - * required. If 'cid' is set, 'keys' is ignored. Use only if you have - * special requirements. + * required. If 'cid' is set, 'keys' and 'granularity' are ignored. Use + * only if you have special requirements. * - 'expire': Set to one of the cache lifetime constants. * - 'bin': Specify a cache bin to cache the element in. Default is 'cache'. * - If this element has #type defined and the default attributes for this @@ -4435,10 +4511,100 @@ function drupal_cache_tags_page_get(Response $response) { } /** + * Prepares an element for caching based on a query. + * + * This smart caching strategy saves Drupal from querying and rendering to HTML + * when the underlying query is unchanged. + * + * Expensive queries should use the query builder to create the query and then + * call this function. Executing the query and formatting results should happen + * in a #pre_render callback. + * + * @param $query + * A select query object as returned by db_select(). + * @param $function + * The name of the function doing this caching. A _pre_render suffix will be + * added to this string and is also part of the cache key in + * drupal_render_cache_set() and drupal_render_cache_get(). + * @param $expire + * The cache expire time, passed eventually to \Drupal::cache()->set(). + * @param $granularity + * One or more granularity constants passed to drupal_render_cid_parts(). + * + * @return + * A renderable array with the following keys and values: + * - #query: The passed-in $query. + * - #pre_render: $function with a _pre_render suffix. + * - #cache: An associative array prepared for drupal_render_cache_set(). + */ +function drupal_render_cache_by_query($query, $function, $expire = Cache::PERMANENT, $granularity = NULL) { + $cache_keys = array_merge(array($function), drupal_render_cid_parts($granularity)); + $query->preExecute(); + $cache_keys[] = hash('sha256', serialize(array((string) $query, $query->getArguments()))); + return array( + '#query' => $query, + '#pre_render' => array($function . '_pre_render'), + '#cache' => array( + 'keys' => $cache_keys, + 'expire' => $expire, + ), + ); +} + +/** + * Returns cache ID parts for building a cache ID. + * + * @param $granularity + * One or more cache granularity constants. For example, to cache separately + * for each user, use DRUPAL_CACHE_PER_USER. To cache separately for each + * page and role, use the expression: + * @code + * DRUPAL_CACHE_PER_PAGE | DRUPAL_CACHE_PER_ROLE + * @endcode + * + * @return + * An array of cache ID parts, always containing the active theme. If the + * locale module is enabled it also contains the active language. If + * $granularity was passed in, more parts are added. + */ +function drupal_render_cid_parts($granularity = NULL) { + global $theme, $base_root; + + $cid_parts[] = $theme; + + // If we have only one language enabled we do not need it as cid part. + $language_manager = \Drupal::languageManager(); + if ($language_manager->isMultilingual()) { + foreach ($language_manager->getLanguageTypes() as $type) { + $cid_parts[] = $language_manager->getCurrentLanguage($type)->id; + } + } + + if (!empty($granularity)) { + // 'PER_ROLE' and 'PER_USER' are mutually exclusive. 'PER_USER' can be a + // resource drag for sites with many users, so when a module is being + // equivocal, we favor the less expensive 'PER_ROLE' pattern. + if ($granularity & DRUPAL_CACHE_PER_ROLE) { + $cid_parts[] = 'r.' . implode(',', \Drupal::currentUser()->getRoles()); + } + elseif ($granularity & DRUPAL_CACHE_PER_USER) { + $cid_parts[] = 'u.' . \Drupal::currentUser()->id(); + } + + if ($granularity & DRUPAL_CACHE_PER_PAGE) { + $cid_parts[] = $base_root . request_uri(); + } + } + + return $cid_parts; +} + +/** * Creates the cache ID for a renderable element. * * This creates the cache ID string, either by returning the #cache['cid'] - * property if present or by building the cache ID out of the #cache['keys']. + * property if present or by building the cache ID out of the #cache['keys'] + * and, optionally, the #cache['granularity'] properties. * * @param $elements * A renderable array. @@ -4451,12 +4617,10 @@ function drupal_render_cid_create($elements) { return $elements['#cache']['cid']; } elseif (isset($elements['#cache']['keys'])) { - // Cache keys may either be static (just strings) or tokens (placeholders - // that are converted to static keys by the @cache_contexts service, - // depending on the request). - $cache_contexts = \Drupal::service("cache_contexts"); - $keys = $cache_contexts->convertTokensToKeys($elements['#cache']['keys']); - return implode(':', $keys); + $granularity = isset($elements['#cache']['granularity']) ? $elements['#cache']['granularity'] : NULL; + // Merge in additional cache ID parts based provided by drupal_render_cid_parts(). + $cid_parts = array_merge($elements['#cache']['keys'], drupal_render_cid_parts($granularity)); + return implode(':', $cid_parts); } return FALSE; } diff --git a/core/includes/entity.inc b/core/includes/entity.inc index 2859b59..51b0f79 100644 --- a/core/includes/entity.inc +++ b/core/includes/entity.inc @@ -423,6 +423,25 @@ function entity_access_controller($entity_type) { } /** + * Returns an entity list controller for a given entity type. + * + * @param string $entity_type + * The type of the entity. + * + * @return \Drupal\Core\Entity\EntityListControllerInterface + * An entity list controller. + * + * @see \Drupal\Core\Entity\EntityManagerInterface::getListController(). + * + * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0. + * Use \Drupal::entityManager()->getListController(). + */ +function entity_list_controller($entity_type) { + return \Drupal::entityManager() + ->getListController($entity_type); +} + +/** * Returns the render array for an entity. * * @param \Drupal\Core\Entity\EntityInterface $entity diff --git a/core/lib/Drupal/Core/Cache/Cache.php b/core/lib/Drupal/Core/Cache/Cache.php index ad59409..f224d14 100644 --- a/core/lib/Drupal/Core/Cache/Cache.php +++ b/core/lib/Drupal/Core/Cache/Cache.php @@ -7,8 +7,6 @@ namespace Drupal\Core\Cache; -use Drupal\Core\Database\Query\SelectInterface; - /** * Helper methods for cache. * @@ -74,26 +72,4 @@ public static function getBins() { return $bins; } - /** - * Generates a hash from a query object, to be used as part of the cache key. - * - * This smart caching strategy saves Drupal from querying and rendering to - * HTML when the underlying query is unchanged. - * - * Expensive queries should use the query builder to create the query and then - * call this function. Executing the query and formatting results should - * happen in a #pre_render callback. - * - * @param \Drupal\Core\Database\Query\SelectInterface $query - * A select query object. - * - * @return string - * A hash of the query arguments. - */ - public static function keyFromQuery(SelectInterface $query) { - $query->preExecute(); - $keys = array((string) $query, $query->getArguments()); - return hash('sha256', serialize($keys)); - } - } diff --git a/core/lib/Drupal/Core/Cache/CacheBackendInterface.php b/core/lib/Drupal/Core/Cache/CacheBackendInterface.php index f0e9882..0208b77 100644 --- a/core/lib/Drupal/Core/Cache/CacheBackendInterface.php +++ b/core/lib/Drupal/Core/Cache/CacheBackendInterface.php @@ -21,7 +21,7 @@ /** * Indicates that the item should never be removed unless explicitly deleted. */ - const CACHE_PERMANENT = -1; + const CACHE_PERMANENT = 0; /** * Returns data from the persistent cache. diff --git a/core/lib/Drupal/Core/Cache/CacheContextInterface.php b/core/lib/Drupal/Core/Cache/CacheContextInterface.php deleted file mode 100644 index fd9783a..0000000 --- a/core/lib/Drupal/Core/Cache/CacheContextInterface.php +++ /dev/null @@ -1,34 +0,0 @@ -container = $container; - $this->contexts = $contexts; - } - - /** - * Provides an array of available cache contexts. - * - * @return array - * An array of available cache contexts. - */ - public function getAll() { - return $this->contexts; - } - - /** - * Provides an array of available cache context labels. - * - * To be used in cache configuration forms. - * - * @return array - * An array of available cache contexts and corresponding labels. - */ - public function getLabels() { - $with_labels = array(); - foreach ($this->contexts as $context) { - $with_labels[$context] = $this->getService($context)->getLabel(); - } - return $with_labels; - } - - /** - * Converts cache context tokens to string representations of the context. - * - * Cache keys may either be static (just strings) or tokens (placeholders - * that are converted to static keys by the @cache_contexts service, depending - * depending on the request). This is the default cache contexts service. - * - * @param array $keys - * An array of cache keys that may or may not contain cache context tokens. - * - * @return array - * A copy of the input, with cache context tokens converted. - */ - public function convertTokensToKeys(array $keys) { - $context_keys = array_intersect($keys, $this->getAll()); - $new_keys = $keys; - - // Iterate over the indices instead of the values so that the order of the - // cache keys are preserved. - foreach (array_keys($context_keys) as $index) { - $new_keys[$index] = $this->getContext($keys[$index]); - } - return $new_keys; - } - - /** - * Provides the string representaton of a cache context. - * - * @param string $context - * A cache context token of an available cache context service. - * - * @return string - * The string representaton of a cache context. - */ - protected function getContext($context) { - return $this->getService($context)->getContext(); - } - - /** - * Retrieves a service from the container. - * - * @param string $service - * The ID of the service to retrieve. - * - * @return mixed - * The specified service. - */ - protected function getService($service) { - return $this->container->get($service); - } - -} diff --git a/core/lib/Drupal/Core/Cache/CacheContextsPass.php b/core/lib/Drupal/Core/Cache/CacheContextsPass.php deleted file mode 100644 index 645df03..0000000 --- a/core/lib/Drupal/Core/Cache/CacheContextsPass.php +++ /dev/null @@ -1,28 +0,0 @@ -findTaggedServiceIds('cache.context')); - $container->setParameter('cache_contexts', $cache_contexts); - } - -} diff --git a/core/lib/Drupal/Core/Cache/LanguageCacheContext.php b/core/lib/Drupal/Core/Cache/LanguageCacheContext.php deleted file mode 100644 index b73652f..0000000 --- a/core/lib/Drupal/Core/Cache/LanguageCacheContext.php +++ /dev/null @@ -1,54 +0,0 @@ -languageManager = $language_manager; - } - - /** - * {@inheritdoc} - */ - public static function getLabel() { - return t('Language'); - } - - /** - * {@inheritdoc} - */ - public function getContext() { - $context_parts = array(); - if ($this->language_manager->isMultilingual()) { - foreach ($this->language_manager->getLanguageTypes() as $type) { - $context_parts[] = $this->language_manager->getCurrentLanguage($type)->id; - } - } - return implode(':', $context_parts); - } - -} diff --git a/core/lib/Drupal/Core/Cache/ThemeCacheContext.php b/core/lib/Drupal/Core/Cache/ThemeCacheContext.php deleted file mode 100644 index d777471..0000000 --- a/core/lib/Drupal/Core/Cache/ThemeCacheContext.php +++ /dev/null @@ -1,59 +0,0 @@ -request = $request; - $this->themeNegotiator = $theme_negotiator; - } - - /** - * {@inheritdoc} - */ - public static function getLabel() { - return t('Theme'); - } - - /** - * {@inheritdoc} - */ - public function getContext() { - return $this->themeNegotiator->determineActiveTheme($this->request) ?: 'stark'; - } - -} diff --git a/core/lib/Drupal/Core/Cache/UrlCacheContext.php b/core/lib/Drupal/Core/Cache/UrlCacheContext.php deleted file mode 100644 index 596e134..0000000 --- a/core/lib/Drupal/Core/Cache/UrlCacheContext.php +++ /dev/null @@ -1,48 +0,0 @@ -request = $request; - } - - /** - * {@inheritdoc} - */ - public static function getLabel() { - return t('URL'); - } - - /** - * {@inheritdoc} - */ - public function getContext() { - return $this->request->getUri(); - } - -} diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityListBuilder.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityListBuilder.php deleted file mode 100644 index 601de73..0000000 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityListBuilder.php +++ /dev/null @@ -1,54 +0,0 @@ -entityType->getClass(), 'sort')); - return $entities; - } - - /** - * {@inheritdoc} - */ - public function getOperations(EntityInterface $entity) { - $operations = parent::getOperations($entity); - - if ($this->entityType->hasKey('status')) { - if (!$entity->status() && $entity->hasLinkTemplate('enable')) { - $operations['enable'] = array( - 'title' => t('Enable'), - 'weight' => -10, - ) + $entity->urlInfo('enable'); - } - elseif ($entity->hasLinkTemplate('disable')) { - $operations['disable'] = array( - 'title' => t('Disable'), - 'weight' => 40, - ) + $entity->urlInfo('disable'); - } - } - - return $operations; - } - -} diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php new file mode 100644 index 0000000..54afad2 --- /dev/null +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php @@ -0,0 +1,54 @@ +entityType->getClass(), 'sort')); + return $entities; + } + + /** + * {@inheritdoc} + */ + public function getOperations(EntityInterface $entity) { + $operations = parent::getOperations($entity); + + if ($this->entityType->hasKey('status')) { + if (!$entity->status() && $entity->hasLinkTemplate('enable')) { + $operations['enable'] = array( + 'title' => t('Enable'), + 'weight' => -10, + ) + $entity->urlInfo('enable'); + } + elseif ($entity->hasLinkTemplate('disable')) { + $operations['disable'] = array( + 'title' => t('Disable'), + 'weight' => 40, + ) + $entity->urlInfo('disable'); + } + } + + return $operations; + } + +} diff --git a/core/lib/Drupal/Core/Config/Entity/DraggableListBuilder.php b/core/lib/Drupal/Core/Config/Entity/DraggableListBuilder.php deleted file mode 100644 index cb68a0e..0000000 --- a/core/lib/Drupal/Core/Config/Entity/DraggableListBuilder.php +++ /dev/null @@ -1,171 +0,0 @@ -entityType->hasKey('weight')) { - $this->weightKey = $this->entityType->getKey('weight'); - } - } - - /** - * {@inheritdoc} - */ - public function buildHeader() { - $header = array(); - if (!empty($this->weightKey)) { - $header['weight'] = t('Weight'); - } - return $header + parent::buildHeader(); - } - - /** - * {@inheritdoc} - */ - public function buildRow(EntityInterface $entity) { - $row = array(); - if (!empty($this->weightKey)) { - // Override default values to markup elements. - $row['#attributes']['class'][] = 'draggable'; - $row['#weight'] = $entity->get($this->weightKey); - // Add weight column. - $row['weight'] = array( - '#type' => 'weight', - '#title' => t('Weight for @title', array('@title' => $entity->label())), - '#title_display' => 'invisible', - '#default_value' => $entity->get($this->weightKey), - '#attributes' => array('class' => array('weight')), - ); - } - return $row + parent::buildRow($entity); - } - - /** - * {@inheritdoc} - */ - public function render() { - if (!empty($this->weightKey)) { - return $this->formBuilder()->getForm($this); - } - return parent::render(); - } - - /** - * {@inheritdoc} - */ - public function buildForm(array $form, array &$form_state) { - $form[$this->entitiesKey] = array( - '#type' => 'table', - '#header' => $this->buildHeader(), - '#empty' => t('There is no @label yet.', array('@label' => $this->entityType->getLabel())), - '#tabledrag' => array( - array( - 'action' => 'order', - 'relationship' => 'sibling', - 'group' => 'weight', - ), - ), - ); - - $this->entities = $this->load(); - foreach ($this->entities as $entity) { - $row = $this->buildRow($entity); - if (isset($row['label'])) { - $row['label'] = array('#markup' => $row['label']); - } - $form[$this->entitiesKey][$entity->id()] = $row; - } - - $form['actions']['#type'] = 'actions'; - $form['actions']['submit'] = array( - '#type' => 'submit', - '#value' => t('Save order'), - '#button_type' => 'primary', - ); - - return $form; - } - - /** - * {@inheritdoc} - */ - public function validateForm(array &$form, array &$form_state) { - // No validation. - } - - /** - * {@inheritdoc} - */ - public function submitForm(array &$form, array &$form_state) { - foreach ($form_state['values'][$this->entitiesKey] as $id => $value) { - if (isset($this->entities[$id]) && $this->entities[$id]->get($this->weightKey) != $value['weight']) { - // Save entity only when its weight was changed. - $this->entities[$id]->set($this->weightKey, $value['weight']); - $this->entities[$id]->save(); - } - } - } - - /** - * Returns the form builder. - * - * @return \Drupal\Core\Form\FormBuilderInterface - * The form builder. - */ - protected function formBuilder() { - if (!$this->formBuilder) { - $this->formBuilder = \Drupal::formBuilder(); - } - return $this->formBuilder; - } - -} diff --git a/core/lib/Drupal/Core/Config/Entity/DraggableListController.php b/core/lib/Drupal/Core/Config/Entity/DraggableListController.php new file mode 100644 index 0000000..f2c3ff8 --- /dev/null +++ b/core/lib/Drupal/Core/Config/Entity/DraggableListController.php @@ -0,0 +1,171 @@ +entityType->hasKey('weight')) { + $this->weightKey = $this->entityType->getKey('weight'); + } + } + + /** + * {@inheritdoc} + */ + public function buildHeader() { + $header = array(); + if (!empty($this->weightKey)) { + $header['weight'] = t('Weight'); + } + return $header + parent::buildHeader(); + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + $row = array(); + if (!empty($this->weightKey)) { + // Override default values to markup elements. + $row['#attributes']['class'][] = 'draggable'; + $row['#weight'] = $entity->get($this->weightKey); + // Add weight column. + $row['weight'] = array( + '#type' => 'weight', + '#title' => t('Weight for @title', array('@title' => $entity->label())), + '#title_display' => 'invisible', + '#default_value' => $entity->get($this->weightKey), + '#attributes' => array('class' => array('weight')), + ); + } + return $row + parent::buildRow($entity); + } + + /** + * {@inheritdoc} + */ + public function render() { + if (!empty($this->weightKey)) { + return $this->formBuilder()->getForm($this); + } + return parent::render(); + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, array &$form_state) { + $form[$this->entitiesKey] = array( + '#type' => 'table', + '#header' => $this->buildHeader(), + '#empty' => t('There is no @label yet.', array('@label' => $this->entityType->getLabel())), + '#tabledrag' => array( + array( + 'action' => 'order', + 'relationship' => 'sibling', + 'group' => 'weight', + ), + ), + ); + + $this->entities = $this->load(); + foreach ($this->entities as $entity) { + $row = $this->buildRow($entity); + if (isset($row['label'])) { + $row['label'] = array('#markup' => $row['label']); + } + $form[$this->entitiesKey][$entity->id()] = $row; + } + + $form['actions']['#type'] = 'actions'; + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Save order'), + '#button_type' => 'primary', + ); + + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, array &$form_state) { + // No validation. + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + foreach ($form_state['values'][$this->entitiesKey] as $id => $value) { + if (isset($this->entities[$id]) && $this->entities[$id]->get($this->weightKey) != $value['weight']) { + // Save entity only when its weight was changed. + $this->entities[$id]->set($this->weightKey, $value['weight']); + $this->entities[$id]->save(); + } + } + } + + /** + * Returns the form builder. + * + * @return \Drupal\Core\Form\FormBuilderInterface + * The form builder. + */ + protected function formBuilder() { + if (!$this->formBuilder) { + $this->formBuilder = \Drupal::formBuilder(); + } + return $this->formBuilder; + } + +} diff --git a/core/lib/Drupal/Core/CoreServiceProvider.php b/core/lib/Drupal/Core/CoreServiceProvider.php index 01ab877..d835f6e 100644 --- a/core/lib/Drupal/Core/CoreServiceProvider.php +++ b/core/lib/Drupal/Core/CoreServiceProvider.php @@ -7,7 +7,6 @@ namespace Drupal\Core; -use Drupal\Core\Cache\CacheContextsPass; use Drupal\Core\Cache\ListCacheBinsPass; use Drupal\Core\Config\ConfigFactoryOverridePass; use Drupal\Core\DependencyInjection\ServiceProviderInterface; @@ -73,7 +72,6 @@ public function register(ContainerBuilder $container) { $container->addCompilerPass(new RegisterPathProcessorsPass()); $container->addCompilerPass(new RegisterRouteProcessorsPass()); $container->addCompilerPass(new ListCacheBinsPass()); - $container->addCompilerPass(new CacheContextsPass()); // Add the compiler pass for appending string translators. $container->addCompilerPass(new RegisterStringTranslatorsPass()); // Add the compiler pass that will process the tagged breadcrumb builder diff --git a/core/lib/Drupal/Core/Entity/Controller/EntityListController.php b/core/lib/Drupal/Core/Entity/Controller/EntityListController.php index 1b081bb..7a07a38 100644 --- a/core/lib/Drupal/Core/Entity/Controller/EntityListController.php +++ b/core/lib/Drupal/Core/Entity/Controller/EntityListController.php @@ -25,7 +25,7 @@ class EntityListController extends ControllerBase { * A render array as expected by drupal_render(). */ public function listing($entity_type) { - return $this->entityManager()->getListBuilder($entity_type)->render(); + return $this->entityManager()->getListController($entity_type)->render(); } } diff --git a/core/lib/Drupal/Core/Entity/Controller/EntityViewController.php b/core/lib/Drupal/Core/Entity/Controller/EntityViewController.php index aac92bc..31672c0 100644 --- a/core/lib/Drupal/Core/Entity/Controller/EntityViewController.php +++ b/core/lib/Drupal/Core/Entity/Controller/EntityViewController.php @@ -25,7 +25,7 @@ class EntityViewController implements ContainerInjectionInterface { protected $entityManager; /** - * Creates an EntityViewController object. + * Creates an EntityListController object. * * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager * The entity manager. diff --git a/core/lib/Drupal/Core/Entity/EntityListBuilder.php b/core/lib/Drupal/Core/Entity/EntityListBuilder.php deleted file mode 100644 index 626c275..0000000 --- a/core/lib/Drupal/Core/Entity/EntityListBuilder.php +++ /dev/null @@ -1,207 +0,0 @@ -get('entity.manager')->getStorageController($entity_type->id()) - ); - } - - /** - * Constructs a new EntityListBuilder object. - * - * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type - * The entity type definition. - * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage - * The entity storage controller class. - */ - public function __construct(EntityTypeInterface $entity_type, EntityStorageControllerInterface $storage) { - $this->entityTypeId = $entity_type->id(); - $this->storage = $storage; - $this->entityType = $entity_type; - } - - /** - * {@inheritdoc} - */ - public function getStorageController() { - return $this->storage; - } - - /** - * {@inheritdoc} - */ - public function load() { - return $this->storage->loadMultiple(); - } - - /** - * Returns the escaped label of an entity. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity being listed. - * - * @return string - * The escaped entity label. - */ - protected function getLabel(EntityInterface $entity) { - return String::checkPlain($entity->label()); - } - - /** - * {@inheritdoc} - */ - public function getOperations(EntityInterface $entity) { - $operations = array(); - if ($entity->access('update') && $entity->hasLinkTemplate('edit-form')) { - $operations['edit'] = array( - 'title' => $this->t('Edit'), - 'weight' => 10, - ) + $entity->urlInfo('edit-form'); - } - if ($entity->access('delete') && $entity->hasLinkTemplate('delete-form')) { - $operations['delete'] = array( - 'title' => $this->t('Delete'), - 'weight' => 100, - ) + $entity->urlInfo('delete-form'); - } - - return $operations; - } - - /** - * Builds the header row for the entity listing. - * - * @return array - * A render array structure of header strings. - * - * @see \Drupal\Core\Entity\EntityListBuilder::render() - */ - public function buildHeader() { - $row['operations'] = $this->t('Operations'); - return $row; - } - - /** - * Builds a row for an entity in the entity listing. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity for this row of the list. - * - * @return array - * A render array structure of fields for this entity. - * - * @see \Drupal\Core\Entity\EntityListBuilder::render() - */ - public function buildRow(EntityInterface $entity) { - $row['operations']['data'] = $this->buildOperations($entity); - return $row; - } - - /** - * Builds a renderable list of operation links for the entity. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity on which the linked operations will be performed. - * - * @return array - * A renderable array of operation links. - * - * @see \Drupal\Core\Entity\EntityListBuilder::buildRow() - */ - public function buildOperations(EntityInterface $entity) { - // Retrieve and sort operations. - $operations = $this->getOperations($entity); - $this->moduleHandler()->alter('entity_operation', $operations, $entity); - uasort($operations, array('Drupal\Component\Utility\SortArray', 'sortByWeightElement')); - $build = array( - '#type' => 'operations', - '#links' => $operations, - ); - return $build; - } - - /** - * {@inheritdoc} - * - * Builds the entity listing as renderable array for theme_table(). - * - * @todo Add a link to add a new item to the #empty text. - */ - public function render() { - $build = array( - '#type' => 'table', - '#header' => $this->buildHeader(), - '#title' => $this->getTitle(), - '#rows' => array(), - '#empty' => $this->t('There is no @label yet.', array('@label' => $this->entityType->getLabel())), - ); - foreach ($this->load() as $entity) { - if ($row = $this->buildRow($entity)) { - $build['#rows'][$entity->id()] = $row; - } - } - return $build; - } - - /** - * Translates a string to the current language or to a given language. - * - * See the t() documentation for details. - */ - protected function t($string, array $args = array(), array $options = array()) { - return $this->translationManager()->translate($string, $args, $options); - } - - /** - * Returns the title of the page. - * - * @return string - * A string title of the page. - */ - protected function getTitle() { - return; - } - -} diff --git a/core/lib/Drupal/Core/Entity/EntityListBuilderInterface.php b/core/lib/Drupal/Core/Entity/EntityListBuilderInterface.php deleted file mode 100644 index 99f5935..0000000 --- a/core/lib/Drupal/Core/Entity/EntityListBuilderInterface.php +++ /dev/null @@ -1,58 +0,0 @@ -get('entity.manager')->getStorageController($entity_type->id()) + ); + } + + /** + * Constructs a new EntityListController object. + * + * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type + * The entity type definition. + * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage + * The entity storage controller class. + */ + public function __construct(EntityTypeInterface $entity_type, EntityStorageControllerInterface $storage) { + $this->entityTypeId = $entity_type->id(); + $this->storage = $storage; + $this->entityType = $entity_type; + } + + /** + * Implements \Drupal\Core\Entity\EntityListControllerInterface::getStorageController(). + */ + public function getStorageController() { + return $this->storage; + } + + /** + * Implements \Drupal\Core\Entity\EntityListControllerInterface::load(). + */ + public function load() { + return $this->storage->loadMultiple(); + } + + /** + * Returns the escaped label of an entity. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity being listed. + * + * @return string + * The escaped entity label. + */ + protected function getLabel(EntityInterface $entity) { + return String::checkPlain($entity->label()); + } + + /** + * {@inheritdoc} + */ + public function getOperations(EntityInterface $entity) { + $operations = array(); + if ($entity->access('update') && $entity->hasLinkTemplate('edit-form')) { + $operations['edit'] = array( + 'title' => $this->t('Edit'), + 'weight' => 10, + ) + $entity->urlInfo('edit-form'); + } + if ($entity->access('delete') && $entity->hasLinkTemplate('delete-form')) { + $operations['delete'] = array( + 'title' => $this->t('Delete'), + 'weight' => 100, + ) + $entity->urlInfo('delete-form'); + } + + return $operations; + } + + /** + * Builds the header row for the entity listing. + * + * @return array + * A render array structure of header strings. + * + * @see \Drupal\Core\Entity\EntityListController::render() + */ + public function buildHeader() { + $row['operations'] = $this->t('Operations'); + return $row; + } + + /** + * Builds a row for an entity in the entity listing. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity for this row of the list. + * + * @return array + * A render array structure of fields for this entity. + * + * @see \Drupal\Core\Entity\EntityListController::render() + */ + public function buildRow(EntityInterface $entity) { + $row['operations']['data'] = $this->buildOperations($entity); + return $row; + } + + /** + * Builds a renderable list of operation links for the entity. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity on which the linked operations will be performed. + * + * @return array + * A renderable array of operation links. + * + * @see \Drupal\Core\Entity\EntityListController::render() + */ + public function buildOperations(EntityInterface $entity) { + // Retrieve and sort operations. + $operations = $this->getOperations($entity); + $this->moduleHandler()->alter('entity_operation', $operations, $entity); + uasort($operations, array('Drupal\Component\Utility\SortArray', 'sortByWeightElement')); + $build = array( + '#type' => 'operations', + '#links' => $operations, + ); + return $build; + } + + /** + * Implements \Drupal\Core\Entity\EntityListControllerInterface::render(). + * + * Builds the entity list as renderable array for theme_table(). + * + * @todo Add a link to add a new item to the #empty text. + */ + public function render() { + $build = array( + '#type' => 'table', + '#header' => $this->buildHeader(), + '#title' => $this->getTitle(), + '#rows' => array(), + '#empty' => $this->t('There is no @label yet.', array('@label' => $this->entityType->getLabel())), + ); + foreach ($this->load() as $entity) { + if ($row = $this->buildRow($entity)) { + $build['#rows'][$entity->id()] = $row; + } + } + return $build; + } + + /** + * Translates a string to the current language or to a given language. + * + * See the t() documentation for details. + */ + protected function t($string, array $args = array(), array $options = array()) { + return $this->translationManager()->translate($string, $args, $options); + } + + /** + * Returns the title of the page. + * + * @return string + * A string title of the page. + * + */ + protected function getTitle() { + return; + } + +} diff --git a/core/lib/Drupal/Core/Entity/EntityListControllerInterface.php b/core/lib/Drupal/Core/Entity/EntityListControllerInterface.php new file mode 100644 index 0000000..775445e --- /dev/null +++ b/core/lib/Drupal/Core/Entity/EntityListControllerInterface.php @@ -0,0 +1,58 @@ +getController($entity_type, 'list_builder', 'getListBuilderClass'); + public function getListController($entity_type) { + return $this->getController($entity_type, 'list', 'getListClass'); } /** diff --git a/core/lib/Drupal/Core/Entity/EntityManagerInterface.php b/core/lib/Drupal/Core/Entity/EntityManagerInterface.php index 9a65866..e40ff94 100644 --- a/core/lib/Drupal/Core/Entity/EntityManagerInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityManagerInterface.php @@ -119,15 +119,15 @@ public function clearCachedDefinitions(); public function getViewBuilder($entity_type); /** - * Creates a new entity list builder. + * Creates a new list controller instance. * * @param string $entity_type - * The entity type for this list builder. + * The entity type for this list controller. * - * @return \Drupal\Core\Entity\EntityListBuilderInterface - * An entity list builder instance. + * @return \Drupal\Core\Entity\EntityListControllerInterface + * A list controller instance. */ - public function getListBuilder($entity_type); + public function getListController($entity_type); /** * Creates a new form controller instance. diff --git a/core/lib/Drupal/Core/Entity/EntityType.php b/core/lib/Drupal/Core/Entity/EntityType.php index 93f6062..4eae0df 100644 --- a/core/lib/Drupal/Core/Entity/EntityType.php +++ b/core/lib/Drupal/Core/Entity/EntityType.php @@ -365,23 +365,23 @@ public function hasFormClasses() { /** * {@inheritdoc} */ - public function getListBuilderClass() { - return $this->getControllerClass('list_builder'); + public function getListClass() { + return $this->getControllerClass('list'); } /** * {@inheritdoc} */ - public function setListBuilderClass($class) { - $this->controllers['list_builder'] = $class; + public function setListClass($class) { + $this->controllers['list'] = $class; return $this; } /** * {@inheritdoc} */ - public function hasListBuilderClass() { - return $this->hasControllerClass('list_builder'); + public function hasListClass() { + return $this->hasControllerClass('list'); } /** diff --git a/core/lib/Drupal/Core/Entity/EntityTypeInterface.php b/core/lib/Drupal/Core/Entity/EntityTypeInterface.php index 5934322..226dc91 100644 --- a/core/lib/Drupal/Core/Entity/EntityTypeInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityTypeInterface.php @@ -194,7 +194,7 @@ public function getControllerClass($controller_type); * entity forms when the forms are similar. The classes must implement * \Drupal\Core\Entity\EntityFormControllerInterface. * - list: The name of the class that provides listings of the entities. The - * class must implement \Drupal\Core\Entity\EntityListBuilderInterface. + * class must implement \Drupal\Core\Entity\EntityListControllerInterface. * - render: The name of the class that is used to render the entities. The * class must implement \Drupal\Core\Entity\EntityViewBuilderInterface. * - access: The name of the class that is used for access checks. The class @@ -263,7 +263,7 @@ public function hasFormClasses(); * @return string * The class for this entity type's list. */ - public function getListBuilderClass(); + public function getListClass(); /** * Sets the list class. @@ -273,7 +273,7 @@ public function getListBuilderClass(); * * @return static */ - public function setListBuilderClass($class); + public function setListClass($class); /** * Indicates if this entity type has a list class. @@ -281,7 +281,7 @@ public function setListBuilderClass($class); * @return bool * TRUE if there is a list for this entity type, FALSE otherwise. */ - public function hasListBuilderClass(); + public function hasListClass(); /** * Returns the view builder class. diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php index 2e48ecc..7cbadb2 100644 --- a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php +++ b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php @@ -158,14 +158,8 @@ protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langco // type configuration. if ($this->isViewModeCacheable($view_mode) && !$entity->isNew() && $entity->isDefaultRevision() && $this->entityType->isRenderCacheable()) { $return['#cache'] += array( - 'keys' => array( - 'entity_view', - $this->entityTypeId, - $entity->id(), - $view_mode, - 'cache_context.theme', - 'cache_context.user.roles', - ), + 'keys' => array('entity_view', $this->entityTypeId, $entity->id(), $view_mode), + 'granularity' => DRUPAL_CACHE_PER_ROLE, 'bin' => $this->cacheBin, ); diff --git a/core/modules/action/action.module b/core/modules/action/action.module index e765a24..ee2f628 100644 --- a/core/modules/action/action.module +++ b/core/modules/action/action.module @@ -67,7 +67,7 @@ function action_entity_type_build(array &$entity_types) { ->setFormClass('add', 'Drupal\action\ActionAddFormController') ->setFormClass('edit', 'Drupal\action\ActionEditFormController') ->setFormClass('delete', 'Drupal\action\Form\ActionDeleteForm') - ->setListBuilderClass('Drupal\action\ActionListBuilder') + ->setListClass('Drupal\action\ActionListController') ->setLinkTemplate('delete-form', 'action.delete') ->setLinkTemplate('edit-form', 'action.admin_configure'); } diff --git a/core/modules/action/lib/Drupal/action/ActionListBuilder.php b/core/modules/action/lib/Drupal/action/ActionListBuilder.php deleted file mode 100644 index 7ef6e19..0000000 --- a/core/modules/action/lib/Drupal/action/ActionListBuilder.php +++ /dev/null @@ -1,125 +0,0 @@ -actionManager = $action_manager; - } - - /** - * {@inheritdoc} - */ - public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { - return new static( - $entity_type, - $container->get('entity.manager')->getStorageController($entity_type->id()), - $container->get('plugin.manager.action') - ); - } - - /** - * {@inheritdoc} - */ - public function load() { - $entities = parent::load(); - foreach ($entities as $entity) { - if ($entity->isConfigurable()) { - $this->hasConfigurableActions = TRUE; - continue; - } - } - return $entities; - } - - /** - * {@inheritdoc} - */ - public function buildRow(EntityInterface $entity) { - $row['type'] = $entity->getType(); - $row['label'] = $this->getLabel($entity); - if ($this->hasConfigurableActions) { - $row += parent::buildRow($entity); - } - return $row; - } - - /** - * {@inheritdoc} - */ - public function buildHeader() { - $header = array( - 'type' => t('Action type'), - 'label' => t('Label'), - ) + parent::buildHeader(); - return $header; - } - - /** - * {@inheritdoc} - */ - public function getOperations(EntityInterface $entity) { - $operations = $entity->isConfigurable() ? parent::getOperations($entity) : array(); - if (isset($operations['edit'])) { - $operations['edit']['title'] = t('Configure'); - } - return $operations; - } - - /** - * {@inheritdoc} - */ - public function render() { - $build['action_header']['#markup'] = '

' . t('Available actions:') . '

'; - $build['action_table'] = parent::render(); - if (!$this->hasConfigurableActions) { - unset($build['action_table']['#header']['operations']); - } - $build['action_admin_manage_form'] = drupal_get_form('Drupal\action\Form\ActionAdminManageForm'); - return $build; - } - -} diff --git a/core/modules/action/lib/Drupal/action/ActionListController.php b/core/modules/action/lib/Drupal/action/ActionListController.php new file mode 100644 index 0000000..946bcca --- /dev/null +++ b/core/modules/action/lib/Drupal/action/ActionListController.php @@ -0,0 +1,123 @@ +actionManager = $action_manager; + } + + /** + * {@inheritdoc} + */ + public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { + return new static( + $entity_type, + $container->get('entity.manager')->getStorageController($entity_type->id()), + $container->get('plugin.manager.action') + ); + } + + /** + * {@inheritdoc} + */ + public function load() { + $entities = parent::load(); + foreach ($entities as $entity) { + if ($entity->isConfigurable()) { + $this->hasConfigurableActions = TRUE; + continue; + } + } + return $entities; + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + $row['type'] = $entity->getType(); + $row['label'] = $this->getLabel($entity); + if ($this->hasConfigurableActions) { + $row += parent::buildRow($entity); + } + return $row; + } + + /** + * {@inheritdoc} + */ + public function buildHeader() { + $header = array( + 'type' => t('Action type'), + 'label' => t('Label'), + ) + parent::buildHeader(); + return $header; + } + + /** + * {@inheritdoc} + */ + public function getOperations(EntityInterface $entity) { + $operations = $entity->isConfigurable() ? parent::getOperations($entity) : array(); + if (isset($operations['edit'])) { + $operations['edit']['title'] = t('Configure'); + } + return $operations; + } + + /** + * {@inheritdoc} + */ + public function render() { + $build['action_header']['#markup'] = '

' . t('Available actions:') . '

'; + $build['action_table'] = parent::render(); + if (!$this->hasConfigurableActions) { + unset($build['action_table']['#header']['operations']); + } + $build['action_admin_manage_form'] = drupal_get_form('Drupal\action\Form\ActionAdminManageForm'); + return $build; + } + +} diff --git a/core/modules/block/block.module b/core/modules/block/block.module index 0aab348..37998b1 100644 --- a/core/modules/block/block.module +++ b/core/modules/block/block.module @@ -169,16 +169,52 @@ function block_page_build(&$page) { function block_get_blocks_by_region($region) { $build = array(); if ($list = block_list($region)) { - foreach ($list as $key => $block) { + $build = _block_get_renderable_region($list); + } + return $build; +} + +/** + * Gets an array of blocks suitable for drupal_render(). + * + * @param $list + * A list of blocks such as that returned by block_list(). + * + * @return + * A renderable array. + */ +function _block_get_renderable_region($list = array()) { + $build = array(); + // Block caching is not compatible with node_access modules. We also + // preserve the submission of forms in blocks, by fetching from cache + // only if the request method is 'GET' (or 'HEAD'). User 1 being out of + // the regular 'roles define permissions' schema, it brings too many + // chances of having unwanted output get in the cache and later be served + // to other users. We therefore exclude user 1 from block caching. + $not_cacheable = \Drupal::currentUser()->id() == 1 || + count(\Drupal::moduleHandler()->getImplementations('node_grants')) || + !\Drupal::request()->isMethodSafe(); + + foreach ($list as $key => $block) { + $settings = $block->get('settings'); + if ($not_cacheable || in_array($settings['cache'], array(DRUPAL_NO_CACHE, DRUPAL_CACHE_CUSTOM))) { + // Non-cached blocks get built immediately. if ($block->access()) { $build[$key] = entity_view($block, 'block'); } } - // If none of the blocks in this region are visible, then don't set anything - // else in the render array, because that would cause the region to show up. - if (!empty($build)) { - // block_list() already returned the blocks in sorted order. - $build['#sorted'] = TRUE; + else { + $build[$key] = array( + '#block' => $block, + '#weight' => $block->get('weight'), + '#pre_render' => array('_block_get_renderable_block'), + '#cache' => array( + 'keys' => array($key, $settings['module']), + 'granularity' => $settings['cache'], + 'bin' => 'block', + 'tags' => array('content' => TRUE), + ), + ); } } return $build; @@ -306,7 +342,9 @@ function block_list($region) { $blocks[$region] = array(); } - uasort($blocks[$region], 'Drupal\block\Entity\Block::sort'); + uasort($blocks[$region], function($first, $second) { + return $first->weight === $second->weight ? 0 : ($first->weight < $second->weight ? -1 : 1); + }); return $blocks[$region]; } @@ -327,6 +365,26 @@ function block_load($entity_id) { } /** + * Builds the content and label for a block. + * + * For cacheable blocks, this is called during #pre_render. + * + * @param $element + * A renderable array. + * + * @return + * A renderable array. + */ +function _block_get_renderable_block($element) { + $block = $element['#block']; + // Don't bother to build blocks that aren't accessible. + if ($element['#access'] = $block->access()) { + $element += entity_view($block, 'block'); + } + return $element; +} + +/** * Implements hook_rebuild(). */ function block_rebuild() { @@ -398,11 +456,6 @@ function template_preprocess_block(&$variables) { $variables['derivative_plugin_id'] = $variables['elements']['#derivative_plugin_id']; $variables['label'] = !empty($variables['configuration']['label_display']) ? $variables['configuration']['label'] : ''; $variables['content'] = $variables['elements']['content']; - // A block's label is configuration: it is static. Allow dynamic labels to be - // set in the render array. - if (isset($variables['elements']['content']['#title']) && !empty($variables['configuration']['label_display'])) { - $variables['label'] = $variables['elements']['content']['#title']; - } $variables['attributes']['class'][] = 'block'; $variables['attributes']['class'][] = drupal_html_class('block-' . $variables['configuration']['module']); diff --git a/core/modules/block/config/schema/block.schema.yml b/core/modules/block/config/schema/block.schema.yml index a8b1a01..01784bd 100644 --- a/core/modules/block/config/schema/block.schema.yml +++ b/core/modules/block/config/schema/block.schema.yml @@ -73,18 +73,8 @@ block.block.*: type: string label: 'Display title' cache: - type: mapping - label: 'Cache settings' - mapping: - max_age: - type: integer - label: 'Maximum age' - contexts: - type: sequence - label: 'Vary by context' - sequence: - - type: string - label: 'Context' + type: integer + label: 'Cache' status: type: boolean label: 'Status' diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockListBuilder.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockListBuilder.php deleted file mode 100644 index 94c9e31..0000000 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockListBuilder.php +++ /dev/null @@ -1,47 +0,0 @@ -getLabel($entity); - return $row + parent::buildRow($entity); - } - - /** - * {@inheritdoc} - */ - public function getOperations(EntityInterface $entity) { - $operations = parent::getOperations($entity); - if (isset($operations['edit'])) { - $operations['edit']['query']['destination'] = 'admin/structure/block/custom-blocks'; - } - return $operations; - } - -} diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockListController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockListController.php new file mode 100644 index 0000000..1f49a87 --- /dev/null +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockListController.php @@ -0,0 +1,45 @@ +getLabel($entity); + return $row + parent::buildRow($entity); + } + + /** + * {@inheritdoc} + */ + public function getOperations(EntityInterface $entity) { + $operations = parent::getOperations($entity); + if (isset($operations['edit'])) { + $operations['edit']['query']['destination'] = 'admin/structure/block/custom-blocks'; + } + return $operations; + } + +} diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListBuilder.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListBuilder.php deleted file mode 100644 index 901ef6f..0000000 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListBuilder.php +++ /dev/null @@ -1,59 +0,0 @@ -urlInfo(); - $row['type'] = \Drupal::l($entity->label(), $uri['route_name'], $uri['route_parameters'], $uri['options']); - $row['description'] = filter_xss_admin($entity->description); - return $row + parent::buildRow($entity); - } - - /** - * {@inheritdoc} - */ - protected function getTitle() { - return $this->t('Custom block types'); - } - -} diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListController.php new file mode 100644 index 0000000..84a8ad9 --- /dev/null +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListController.php @@ -0,0 +1,57 @@ +urlInfo(); + $row['type'] = \Drupal::l($entity->label(), $uri['route_name'], $uri['route_parameters'], $uri['options']); + $row['description'] = filter_xss_admin($entity->description); + return $row + parent::buildRow($entity); + } + + /** + * {@inheritdoc} + */ + protected function getTitle() { + return $this->t('Custom block types'); + } + +} diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php index ea20a79..88d232b 100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php @@ -22,7 +22,7 @@ * bundle_label = @Translation("Custom Block type"), * controllers = { * "access" = "Drupal\custom_block\CustomBlockAccessController", - * "list_builder" = "Drupal\custom_block\CustomBlockListBuilder", + * "list" = "Drupal\custom_block\CustomBlockListController", * "view_builder" = "Drupal\custom_block\CustomBlockViewBuilder", * "form" = { * "add" = "Drupal\custom_block\CustomBlockFormController", diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlockType.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlockType.php index 57ed007..59a4735 100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlockType.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlockType.php @@ -24,7 +24,7 @@ * "edit" = "Drupal\custom_block\CustomBlockTypeFormController", * "delete" = "Drupal\custom_block\Form\CustomBlockTypeDeleteForm" * }, - * "list_builder" = "Drupal\custom_block\CustomBlockTypeListBuilder" + * "list" = "Drupal\custom_block\CustomBlockTypeListController" * }, * admin_permission = "administer blocks", * config_prefix = "type", diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Block/CustomBlockBlock.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Block/CustomBlockBlock.php index dab9b26..fe7f461 100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Block/CustomBlockBlock.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Block/CustomBlockBlock.php @@ -93,12 +93,6 @@ public function defaultConfiguration() { 'status' => TRUE, 'info' => '', 'view_mode' => 'full', - // Modify the default max age for custom block blocks: modifications made - // to them will automatically invalidate corresponding cache tags, thus - // allowing us to cache custom block blocks forever. - 'cache' => array( - 'max_age' => \Drupal\Core\Cache\Cache::PERMANENT, - ), ); } diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockListTest.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockListTest.php index fa7cc8f..3678a23 100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockListTest.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockListTest.php @@ -12,7 +12,7 @@ /** * Tests the listing of custom blocks. * - * @see \Drupal\block\CustomBlockListBuilder + * @see \Drupal\block\CustomBlockListController */ class CustomBlockListTest extends WebTestBase { diff --git a/core/modules/block/lib/Drupal/block/BlockBase.php b/core/modules/block/lib/Drupal/block/BlockBase.php index 2dd5cde..d278663 100644 --- a/core/modules/block/lib/Drupal/block/BlockBase.php +++ b/core/modules/block/lib/Drupal/block/BlockBase.php @@ -10,10 +10,7 @@ use Drupal\Core\Plugin\PluginBase; use Drupal\block\BlockInterface; use Drupal\Component\Utility\Unicode; -use Drupal\Component\Utility\NestedArray; use Drupal\Core\Language\Language; -use Drupal\Core\Cache\Cache; -use Drupal\Core\Cache\CacheableInterface; use Drupal\Core\Session\AccountInterface; /** @@ -31,7 +28,12 @@ public function __construct(array $configuration, $plugin_id, array $plugin_definition) { parent::__construct($configuration, $plugin_id, $plugin_definition); - $this->setConfiguration($configuration); + $this->configuration += $this->defaultConfiguration() + array( + 'label' => '', + 'module' => $plugin_definition['module'], + 'label_display' => BlockInterface::BLOCK_LABEL_VISIBLE, + 'cache' => DRUPAL_NO_CACHE, + ); } /** @@ -45,29 +47,7 @@ public function getConfiguration() { * {@inheritdoc} */ public function setConfiguration(array $configuration) { - $this->configuration = NestedArray::mergeDeep( - $this->baseConfigurationDefaults(), - $this->defaultConfiguration(), - $configuration - ); - } - - /** - * Returns generic default configuration for block plugins. - * - * @return array - * An associative array with the default configuration. - */ - protected function baseConfigurationDefaults() { - return array( - 'label' => '', - 'module' => $this->pluginDefinition['module'], - 'label_display' => BlockInterface::BLOCK_LABEL_VISIBLE, - 'cache' => array( - 'max_age' => 0, - 'contexts' => array(), - ), - ); + $this->configuration = $configuration; } /** @@ -128,50 +108,10 @@ public function buildConfigurationForm(array $form, array &$form_state) { '#default_value' => ($this->configuration['label_display'] === BlockInterface::BLOCK_LABEL_VISIBLE), '#return_value' => BlockInterface::BLOCK_LABEL_VISIBLE, ); - // Identical options to the ones for page caching. - // @see \Drupal\system\Form\PerformanceForm::buildForm() - $period = array(0, 60, 180, 300, 600, 900, 1800, 2700, 3600, 10800, 21600, 32400, 43200, 86400); - $period = array_map('format_interval', array_combine($period, $period)); - $period[0] = '<' . t('no caching') . '>'; - $period[\Drupal\Core\Cache\Cache::PERMANENT] = t('Forever'); $form['cache'] = array( - '#type' => 'details', - '#title' => t('Cache settings'), - ); - $form['cache']['max_age'] = array( - '#type' => 'select', - '#title' => t('Maximum age'), - '#description' => t('The maximum time this block may be cached.'), - '#default_value' => $this->configuration['cache']['max_age'], - '#options' => $period, - ); - $contexts = \Drupal::service("cache_contexts")->getLabels(); - // Blocks are always rendered in a "per theme" cache context. No need to - // show that option to the end user. - unset($contexts['cache_context.theme']); - $form['cache']['contexts'] = array( - '#type' => 'checkboxes', - '#title' => t('Vary by context'), - '#description' => t('The contexts this cached block must be varied by.'), - '#default_value' => $this->configuration['cache']['contexts'], - '#options' => $contexts, - '#states' => array( - 'disabled' => array( - ':input[name="settings[cache][max_age]"]' => array('value' => (string) 0), - ), - ), + '#type' => 'value', + '#value' => $this->configuration['cache'], ); - if (count($this->getRequiredCacheContexts()) > 0) { - // Remove the required cache contexts from the list of contexts a user can - // choose to modify by: they must always be applied. - $context_labels = array(); - foreach ($this->getRequiredCacheContexts() as $context) { - $context_labels[] = $form['cache']['contexts']['#options'][$context]; - unset($form['cache']['contexts']['#options'][$context]); - } - $required_context_list = implode(', ', $context_labels); - $form['cache']['contexts']['#description'] .= ' ' . t('This block is always varied by the following contexts: %required-context-list.', array('%required-context-list' => $required_context_list)); - } // Add plugin-specific settings for this block type. $form += $this->blockForm($form, $form_state); @@ -194,9 +134,6 @@ public function blockForm($form, &$form_state) { * @see \Drupal\block\BlockBase::blockValidate() */ public function validateConfigurationForm(array &$form, array &$form_state) { - // Transform the #type = checkboxes value to a numerically indexed array. - $form_state['values']['cache']['contexts'] = array_values(array_filter($form_state['values']['cache']['contexts'])); - $this->blockValidate($form, $form_state); } @@ -219,7 +156,6 @@ public function submitConfigurationForm(array &$form, array &$form_state) { $this->configuration['label'] = $form_state['values']['label']; $this->configuration['label_display'] = $form_state['values']['label_display']; $this->configuration['module'] = $form_state['values']['module']; - $this->configuration['cache'] = $form_state['values']['cache']; $this->blockSubmit($form, $form_state); } } @@ -253,59 +189,4 @@ public function getMachineNameSuggestion() { return $transliterated; } - /** - * Returns the cache contexts required for this block. - * - * @return array - * The required cache contexts IDs. - */ - protected function getRequiredCacheContexts() { - return array(); - } - - /** - * {@inheritdoc} - */ - public function getCacheKeys() { - // Return the required cache contexts, merged with the user-configured cache - // contexts, if any. - return array_merge($this->getRequiredCacheContexts(), $this->configuration['cache']['contexts']); - } - - /** - * {@inheritdoc} - */ - public function getCacheTags() { - // If a block plugin's output changes, then it must be able to invalidate a - // cache tag that affects all instances of this block: across themes and - // across regions. - $block_plugin_cache_tag = str_replace(':', '__', $this->getPluginID()); - return array('block_plugin' => array($block_plugin_cache_tag)); - } - - /** - * {@inheritdoc} - */ - public function getCacheBin() { - return 'block'; - } - - /** - * {@inheritdoc} - */ - public function getCacheMaxAge() { - return (int)$this->configuration['cache']['max_age']; - } - - /** - * {@inheritdoc} - */ - public function isCacheable() { - // Similar to the page cache, a block is cacheable if it has a max age. - // Blocks that should never be cached can override this method to simply - // return FALSE. - $max_age = $this->getCacheMaxAge(); - return $max_age === Cache::PERMANENT || $max_age > 0; - } - } diff --git a/core/modules/block/lib/Drupal/block/BlockListBuilder.php b/core/modules/block/lib/Drupal/block/BlockListBuilder.php deleted file mode 100644 index 31b3286..0000000 --- a/core/modules/block/lib/Drupal/block/BlockListBuilder.php +++ /dev/null @@ -1,420 +0,0 @@ -blockManager = $block_manager; - } - - /** - * {@inheritdoc} - */ - public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { - return new static( - $entity_type, - $container->get('entity.manager')->getStorageController($entity_type->id()), - $container->get('plugin.manager.block') - ); - } - - /** - * {@inheritdoc} - */ - public function load() { - // If no theme was specified, use the current theme. - if (!$this->theme) { - $this->theme = $GLOBALS['theme']; - } - - // Store the region list. - $this->regions = system_region_list($this->theme, REGIONS_VISIBLE); - - // Load only blocks for this theme, and sort them. - // @todo Move the functionality of _block_rehash() out of the listing page. - $entities = _block_rehash($this->theme); - - // Sort the blocks using \Drupal\block\Entity\Block::sort(). - uasort($entities, array($this->entityType->getClass(), 'sort')); - return $entities; - } - - /** - * {@inheritdoc} - * - * @param string|null $theme - * (optional) The theme to display the blocks for. If NULL, the current - * theme will be used. - * @param \Symfony\Component\HttpFoundation\Request $request - * The current request. - * - * @return array - * The block list as a renderable array. - */ - public function render($theme = NULL, Request $request = NULL) { - $this->request = $request; - // If no theme was specified, use the current theme. - $this->theme = $theme ?: $GLOBALS['theme_key']; - - return drupal_get_form($this); - } - - /** - * {@inheritdoc} - */ - public function getFormId() { - return 'block_admin_display_form'; - } - - /** - * Implements \Drupal\Core\Form\FormInterface::buildForm(). - * - * Form constructor for the main block administration form. - */ - public function buildForm(array $form, array &$form_state) { - $placement = FALSE; - if ($this->request->query->has('block-placement')) { - $placement = $this->request->query->get('block-placement'); - $form['#attached']['js'][] = array( - 'type' => 'setting', - 'data' => array('blockPlacement' => $placement), - ); - } - $entities = $this->load(); - $form['#theme'] = array('block_list'); - $form['#attached']['library'][] = 'core/drupal.tableheader'; - $form['#attached']['library'][] = 'block/drupal.block'; - $form['#attached']['library'][] = 'block/drupal.block.admin'; - $form['#attributes']['class'][] = 'clearfix'; - - // Add a last region for disabled blocks. - $block_regions_with_disabled = $this->regions + array(BlockInterface::BLOCK_REGION_NONE => BlockInterface::BLOCK_REGION_NONE); - $form['block_regions'] = array( - '#type' => 'value', - '#value' => $block_regions_with_disabled, - ); - - // Weights range from -delta to +delta, so delta should be at least half - // of the amount of blocks present. This makes sure all blocks in the same - // region get an unique weight. - $weight_delta = round(count($entities) / 2); - - // Build the form tree. - $form['edited_theme'] = array( - '#type' => 'value', - '#value' => $this->theme, - ); - $form['blocks'] = array( - '#type' => 'table', - '#header' => array( - t('Block'), - t('Category'), - t('Region'), - t('Weight'), - t('Operations'), - ), - '#attributes' => array( - 'id' => 'blocks', - ), - ); - - // Build blocks first for each region. - foreach ($entities as $entity_id => $entity) { - $definition = $entity->getPlugin()->getPluginDefinition(); - $blocks[$entity->get('region')][$entity_id] = array( - 'label' => $entity->label(), - 'entity_id' => $entity_id, - 'weight' => $entity->get('weight'), - 'entity' => $entity, - 'category' => $definition['category'], - ); - } - - // Loop over each region and build blocks. - foreach ($block_regions_with_disabled as $region => $title) { - $form['blocks']['#tabledrag'][] = array( - 'action' => 'match', - 'relationship' => 'sibling', - 'group' => 'block-region-select', - 'subgroup' => 'block-region-' . $region, - 'hidden' => FALSE, - ); - $form['blocks']['#tabledrag'][] = array( - 'action' => 'order', - 'relationship' => 'sibling', - 'group' => 'block-weight', - 'subgroup' => 'block-weight-' . $region, - ); - - $form['blocks'][$region] = array( - '#attributes' => array( - 'class' => array('region-title', 'region-title-' . $region), - 'no_striping' => TRUE, - ), - ); - $form['blocks'][$region]['title'] = array( - '#markup' => $region != BlockInterface::BLOCK_REGION_NONE ? $title : t('Disabled'), - '#wrapper_attributes' => array( - 'colspan' => 5, - ), - ); - - $form['blocks'][$region . '-message'] = array( - '#attributes' => array( - 'class' => array( - 'region-message', - 'region-' . $region . '-message', - empty($blocks[$region]) ? 'region-empty' : 'region-populated', - ), - ), - ); - $form['blocks'][$region . '-message']['message'] = array( - '#markup' => '' . t('No blocks in this region') . '', - '#wrapper_attributes' => array( - 'colspan' => 5, - ), - ); - - if (isset($blocks[$region])) { - foreach ($blocks[$region] as $info) { - $entity_id = $info['entity_id']; - - $form['blocks'][$entity_id] = array( - '#attributes' => array( - 'class' => array('draggable'), - ), - ); - if ($placement && $placement == drupal_html_class($entity_id)) { - $form['blocks'][$entity_id]['#attributes']['id'] = 'block-placed'; - } - - $form['blocks'][$entity_id]['info'] = array( - '#markup' => String::checkPlain($info['label']), - '#wrapper_attributes' => array( - 'class' => array('block'), - ), - ); - $form['blocks'][$entity_id]['type'] = array( - '#markup' => $info['category'], - ); - $form['blocks'][$entity_id]['region-theme']['region'] = array( - '#type' => 'select', - '#default_value' => $region, - '#empty_value' => BlockInterface::BLOCK_REGION_NONE, - '#title' => t('Region for @block block', array('@block' => $info['label'])), - '#title_display' => 'invisible', - '#options' => $this->regions, - '#attributes' => array( - 'class' => array('block-region-select', 'block-region-' . $region), - ), - '#parents' => array('blocks', $entity_id, 'region'), - ); - $form['blocks'][$entity_id]['region-theme']['theme'] = array( - '#type' => 'hidden', - '#value' => $this->theme, - '#parents' => array('blocks', $entity_id, 'theme'), - ); - $form['blocks'][$entity_id]['weight'] = array( - '#type' => 'weight', - '#default_value' => $info['weight'], - '#delta' => $weight_delta, - '#title' => t('Weight for @block block', array('@block' => $info['label'])), - '#title_display' => 'invisible', - '#attributes' => array( - 'class' => array('block-weight', 'block-weight-' . $region), - ), - ); - $form['blocks'][$entity_id]['operations'] = $this->buildOperations($info['entity']); - } - } - } - - // Do not allow disabling the main system content block when it is present. - if (isset($form['blocks']['system_main']['region'])) { - $form['blocks']['system_main']['region']['#required'] = TRUE; - } - - $form['actions'] = array( - '#tree' => FALSE, - '#type' => 'actions', - ); - $form['actions']['submit'] = array( - '#type' => 'submit', - '#value' => t('Save blocks'), - '#button_type' => 'primary', - ); - - $form['place_blocks']['title'] = array( - '#type' => 'container', - '#children' => '

' . t('Place blocks') . '

', - '#attributes' => array( - 'class' => array( - 'entity-meta-header', - ), - ), - ); - - $form['place_blocks']['filter'] = array( - '#type' => 'search', - '#title' => t('Filter'), - '#title_display' => 'invisible', - '#size' => 30, - '#placeholder' => t('Filter by block name'), - '#attributes' => array( - 'class' => array('block-filter-text'), - 'data-element' => '.entity-meta', - 'title' => t('Enter a part of the block name to filter by.'), - ), - ); - - $form['place_blocks']['list']['#type'] = 'container'; - $form['place_blocks']['list']['#attributes']['class'][] = 'entity-meta'; - - // Sort the plugins first by category, then by label. - $plugins = $this->blockManager->getDefinitions(); - uasort($plugins, function ($a, $b) { - if ($a['category'] != $b['category']) { - return strnatcasecmp($a['category'], $b['category']); - } - return strnatcasecmp($a['admin_label'], $b['admin_label']); - }); - foreach ($plugins as $plugin_id => $plugin_definition) { - $category = String::checkPlain($plugin_definition['category']); - $category_key = 'category-' . $category; - if (!isset($form['place_blocks']['list'][$category_key])) { - $form['place_blocks']['list'][$category_key] = array( - '#type' => 'details', - '#title' => $category, - '#open' => TRUE, - 'content' => array( - '#theme' => 'links', - '#links' => array(), - '#attributes' => array( - 'class' => array( - 'block-list', - ), - ), - ), - ); - } - $form['place_blocks']['list'][$category_key]['content']['#links'][$plugin_id] = array( - 'title' => $plugin_definition['admin_label'], - 'href' => 'admin/structure/block/add/' . $plugin_id . '/' . $this->theme, - 'attributes' => array( - 'class' => array('use-ajax', 'block-filter-text-source'), - 'data-accepts' => 'application/vnd.drupal-modal', - 'data-dialog-options' => Json::encode(array( - 'width' => 700, - )), - ), - ); - } - return $form; - } - - /** - * {@inheritdoc} - */ - public function getOperations(EntityInterface $entity) { - $operations = parent::getOperations($entity); - - if (isset($operations['edit'])) { - $operations['edit']['title'] = t('Configure'); - } - - return $operations; - } - - /** - * Implements \Drupal\Core\Form\FormInterface::validateForm(). - */ - public function validateForm(array &$form, array &$form_state) { - // No validation. - } - - /** - * Implements \Drupal\Core\Form\FormInterface::submitForm(). - * - * Form submission handler for the main block administration form. - */ - public function submitForm(array &$form, array &$form_state) { - $entities = entity_load_multiple('block', array_keys($form_state['values']['blocks'])); - foreach ($entities as $entity_id => $entity) { - $entity->set('weight', $form_state['values']['blocks'][$entity_id]['weight']); - $entity->set('region', $form_state['values']['blocks'][$entity_id]['region']); - if ($entity->get('region') == BlockInterface::BLOCK_REGION_NONE) { - $entity->disable(); - } - else { - $entity->enable(); - } - $entity->save(); - } - drupal_set_message(t('The block settings have been updated.')); - Cache::invalidateTags(array('content' => TRUE)); - } - -} diff --git a/core/modules/block/lib/Drupal/block/BlockListController.php b/core/modules/block/lib/Drupal/block/BlockListController.php new file mode 100644 index 0000000..65db261 --- /dev/null +++ b/core/modules/block/lib/Drupal/block/BlockListController.php @@ -0,0 +1,420 @@ +blockManager = $block_manager; + } + + /** + * {@inheritdoc} + */ + public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { + return new static( + $entity_type, + $container->get('entity.manager')->getStorageController($entity_type->id()), + $container->get('plugin.manager.block') + ); + } + + /** + * Overrides \Drupal\Core\Config\Entity\ConfigEntityListController::load(). + */ + public function load() { + // If no theme was specified, use the current theme. + if (!$this->theme) { + $this->theme = $GLOBALS['theme']; + } + + // Store the region list. + $this->regions = system_region_list($this->theme, REGIONS_VISIBLE); + + // Load only blocks for this theme, and sort them. + // @todo Move the functionality of _block_rehash() out of the listing page. + $entities = _block_rehash($this->theme); + + // Sort the blocks using \Drupal\block\Entity\Block::sort(). + uasort($entities, array($this->entityType->getClass(), 'sort')); + return $entities; + } + + /** + * Overrides \Drupal\Core\Entity\EntityListController::render(). + * + * @param string|null $theme + * (optional) The theme to display the blocks for. If NULL, the current + * theme will be used. + * @param \Symfony\Component\HttpFoundation\Request $request + * The current request. + * + * @return array + * The block list as a renderable array. + */ + public function render($theme = NULL, Request $request = NULL) { + $this->request = $request; + // If no theme was specified, use the current theme. + $this->theme = $theme ?: $GLOBALS['theme_key']; + + return drupal_get_form($this); + } + + /** + * {@inheritdoc} + */ + public function getFormId() { + return 'block_admin_display_form'; + } + + /** + * Implements \Drupal\Core\Form\FormInterface::buildForm(). + * + * Form constructor for the main block administration form. + */ + public function buildForm(array $form, array &$form_state) { + $placement = FALSE; + if ($this->request->query->has('block-placement')) { + $placement = $this->request->query->get('block-placement'); + $form['#attached']['js'][] = array( + 'type' => 'setting', + 'data' => array('blockPlacement' => $placement), + ); + } + $entities = $this->load(); + $form['#theme'] = array('block_list'); + $form['#attached']['library'][] = 'core/drupal.tableheader'; + $form['#attached']['library'][] = 'block/drupal.block'; + $form['#attached']['library'][] = 'block/drupal.block.admin'; + $form['#attributes']['class'][] = 'clearfix'; + + // Add a last region for disabled blocks. + $block_regions_with_disabled = $this->regions + array(BlockInterface::BLOCK_REGION_NONE => BlockInterface::BLOCK_REGION_NONE); + $form['block_regions'] = array( + '#type' => 'value', + '#value' => $block_regions_with_disabled, + ); + + // Weights range from -delta to +delta, so delta should be at least half + // of the amount of blocks present. This makes sure all blocks in the same + // region get an unique weight. + $weight_delta = round(count($entities) / 2); + + // Build the form tree. + $form['edited_theme'] = array( + '#type' => 'value', + '#value' => $this->theme, + ); + $form['blocks'] = array( + '#type' => 'table', + '#header' => array( + t('Block'), + t('Category'), + t('Region'), + t('Weight'), + t('Operations'), + ), + '#attributes' => array( + 'id' => 'blocks', + ), + ); + + // Build blocks first for each region. + foreach ($entities as $entity_id => $entity) { + $definition = $entity->getPlugin()->getPluginDefinition(); + $blocks[$entity->get('region')][$entity_id] = array( + 'label' => $entity->label(), + 'entity_id' => $entity_id, + 'weight' => $entity->get('weight'), + 'entity' => $entity, + 'category' => $definition['category'], + ); + } + + // Loop over each region and build blocks. + foreach ($block_regions_with_disabled as $region => $title) { + $form['blocks']['#tabledrag'][] = array( + 'action' => 'match', + 'relationship' => 'sibling', + 'group' => 'block-region-select', + 'subgroup' => 'block-region-' . $region, + 'hidden' => FALSE, + ); + $form['blocks']['#tabledrag'][] = array( + 'action' => 'order', + 'relationship' => 'sibling', + 'group' => 'block-weight', + 'subgroup' => 'block-weight-' . $region, + ); + + $form['blocks'][$region] = array( + '#attributes' => array( + 'class' => array('region-title', 'region-title-' . $region), + 'no_striping' => TRUE, + ), + ); + $form['blocks'][$region]['title'] = array( + '#markup' => $region != BlockInterface::BLOCK_REGION_NONE ? $title : t('Disabled'), + '#wrapper_attributes' => array( + 'colspan' => 5, + ), + ); + + $form['blocks'][$region . '-message'] = array( + '#attributes' => array( + 'class' => array( + 'region-message', + 'region-' . $region . '-message', + empty($blocks[$region]) ? 'region-empty' : 'region-populated', + ), + ), + ); + $form['blocks'][$region . '-message']['message'] = array( + '#markup' => '' . t('No blocks in this region') . '', + '#wrapper_attributes' => array( + 'colspan' => 5, + ), + ); + + if (isset($blocks[$region])) { + foreach ($blocks[$region] as $info) { + $entity_id = $info['entity_id']; + + $form['blocks'][$entity_id] = array( + '#attributes' => array( + 'class' => array('draggable'), + ), + ); + if ($placement && $placement == drupal_html_class($entity_id)) { + $form['blocks'][$entity_id]['#attributes']['id'] = 'block-placed'; + } + + $form['blocks'][$entity_id]['info'] = array( + '#markup' => String::checkPlain($info['label']), + '#wrapper_attributes' => array( + 'class' => array('block'), + ), + ); + $form['blocks'][$entity_id]['type'] = array( + '#markup' => $info['category'], + ); + $form['blocks'][$entity_id]['region-theme']['region'] = array( + '#type' => 'select', + '#default_value' => $region, + '#empty_value' => BlockInterface::BLOCK_REGION_NONE, + '#title' => t('Region for @block block', array('@block' => $info['label'])), + '#title_display' => 'invisible', + '#options' => $this->regions, + '#attributes' => array( + 'class' => array('block-region-select', 'block-region-' . $region), + ), + '#parents' => array('blocks', $entity_id, 'region'), + ); + $form['blocks'][$entity_id]['region-theme']['theme'] = array( + '#type' => 'hidden', + '#value' => $this->theme, + '#parents' => array('blocks', $entity_id, 'theme'), + ); + $form['blocks'][$entity_id]['weight'] = array( + '#type' => 'weight', + '#default_value' => $info['weight'], + '#delta' => $weight_delta, + '#title' => t('Weight for @block block', array('@block' => $info['label'])), + '#title_display' => 'invisible', + '#attributes' => array( + 'class' => array('block-weight', 'block-weight-' . $region), + ), + ); + $form['blocks'][$entity_id]['operations'] = $this->buildOperations($info['entity']); + } + } + } + + // Do not allow disabling the main system content block when it is present. + if (isset($form['blocks']['system_main']['region'])) { + $form['blocks']['system_main']['region']['#required'] = TRUE; + } + + $form['actions'] = array( + '#tree' => FALSE, + '#type' => 'actions', + ); + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Save blocks'), + '#button_type' => 'primary', + ); + + $form['place_blocks']['title'] = array( + '#type' => 'container', + '#children' => '

' . t('Place blocks') . '

', + '#attributes' => array( + 'class' => array( + 'entity-meta-header', + ), + ), + ); + + $form['place_blocks']['filter'] = array( + '#type' => 'search', + '#title' => t('Filter'), + '#title_display' => 'invisible', + '#size' => 30, + '#placeholder' => t('Filter by block name'), + '#attributes' => array( + 'class' => array('block-filter-text'), + 'data-element' => '.entity-meta', + 'title' => t('Enter a part of the block name to filter by.'), + ), + ); + + $form['place_blocks']['list']['#type'] = 'container'; + $form['place_blocks']['list']['#attributes']['class'][] = 'entity-meta'; + + // Sort the plugins first by category, then by label. + $plugins = $this->blockManager->getDefinitions(); + uasort($plugins, function ($a, $b) { + if ($a['category'] != $b['category']) { + return strnatcasecmp($a['category'], $b['category']); + } + return strnatcasecmp($a['admin_label'], $b['admin_label']); + }); + foreach ($plugins as $plugin_id => $plugin_definition) { + $category = String::checkPlain($plugin_definition['category']); + $category_key = 'category-' . $category; + if (!isset($form['place_blocks']['list'][$category_key])) { + $form['place_blocks']['list'][$category_key] = array( + '#type' => 'details', + '#title' => $category, + '#open' => TRUE, + 'content' => array( + '#theme' => 'links', + '#links' => array(), + '#attributes' => array( + 'class' => array( + 'block-list', + ), + ), + ), + ); + } + $form['place_blocks']['list'][$category_key]['content']['#links'][$plugin_id] = array( + 'title' => $plugin_definition['admin_label'], + 'href' => 'admin/structure/block/add/' . $plugin_id . '/' . $this->theme, + 'attributes' => array( + 'class' => array('use-ajax', 'block-filter-text-source'), + 'data-accepts' => 'application/vnd.drupal-modal', + 'data-dialog-options' => Json::encode(array( + 'width' => 700, + )), + ), + ); + } + return $form; + } + + /** + * {@inheritdoc} + */ + public function getOperations(EntityInterface $entity) { + $operations = parent::getOperations($entity); + + if (isset($operations['edit'])) { + $operations['edit']['title'] = t('Configure'); + } + + return $operations; + } + + /** + * Implements \Drupal\Core\Form\FormInterface::validateForm(). + */ + public function validateForm(array &$form, array &$form_state) { + // No validation. + } + + /** + * Implements \Drupal\Core\Form\FormInterface::submitForm(). + * + * Form submission handler for the main block administration form. + */ + public function submitForm(array &$form, array &$form_state) { + $entities = entity_load_multiple('block', array_keys($form_state['values']['blocks'])); + foreach ($entities as $entity_id => $entity) { + $entity->set('weight', $form_state['values']['blocks'][$entity_id]['weight']); + $entity->set('region', $form_state['values']['blocks'][$entity_id]['region']); + if ($entity->get('region') == BlockInterface::BLOCK_REGION_NONE) { + $entity->disable(); + } + else { + $entity->enable(); + } + $entity->save(); + } + drupal_set_message(t('The block settings have been updated.')); + Cache::invalidateTags(array('content' => TRUE)); + } + +} diff --git a/core/modules/block/lib/Drupal/block/BlockPluginInterface.php b/core/modules/block/lib/Drupal/block/BlockPluginInterface.php index 4f6bdc2..047efd9 100644 --- a/core/modules/block/lib/Drupal/block/BlockPluginInterface.php +++ b/core/modules/block/lib/Drupal/block/BlockPluginInterface.php @@ -7,7 +7,6 @@ namespace Drupal\block; -use Drupal\Core\Cache\CacheableInterface; use Drupal\Component\Plugin\PluginInspectionInterface; use Drupal\Component\Plugin\ConfigurablePluginInterface; use Drupal\Core\Plugin\PluginFormInterface; @@ -21,7 +20,7 @@ * brif references to the important components that are not coupled to the * interface. */ -interface BlockPluginInterface extends ConfigurablePluginInterface, PluginFormInterface, PluginInspectionInterface, CacheableInterface { +interface BlockPluginInterface extends ConfigurablePluginInterface, PluginFormInterface, PluginInspectionInterface { /** * Indicates whether the block should be shown. diff --git a/core/modules/block/lib/Drupal/block/BlockViewBuilder.php b/core/modules/block/lib/Drupal/block/BlockViewBuilder.php index a6a925a..a076dc9 100644 --- a/core/modules/block/lib/Drupal/block/BlockViewBuilder.php +++ b/core/modules/block/lib/Drupal/block/BlockViewBuilder.php @@ -7,9 +7,7 @@ namespace Drupal\block; -use Drupal\Component\Utility\NestedArray; use Drupal\Component\Utility\String; -use Drupal\Core\Cache\Cache; use Drupal\Core\Entity\EntityViewBuilder; use Drupal\Core\Entity\EntityViewBuilderInterface; use Drupal\Core\Entity\EntityInterface; @@ -45,126 +43,61 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la $plugin_id = $plugin->getPluginId(); $base_id = $plugin->getBasePluginId(); $derivative_id = $plugin->getDerivativeId(); - $configuration = $plugin->getConfiguration(); - // Create the render array for the block as a whole. - // @see template_preprocess_block(). - $build[$entity_id] = array( - '#theme' => 'block', - '#attributes' => array(), - // All blocks get a "Configure block" contextual link. - '#contextual_links' => array( - 'block' => array( - 'route_parameters' => array('block' => $entity->id()), + if ($content = $plugin->build()) { + $configuration = $plugin->getConfiguration(); + + // Create the render array for the block as a whole. + // @see template_preprocess_block(). + $build[$key] = array( + '#theme' => 'block', + '#attributes' => array(), + '#contextual_links' => array( + 'block' => array( + 'route_parameters' => array('block' => $entity_id), + ), ), - ), - '#weight' => $entity->get('weight'), - '#configuration' => $configuration, - '#plugin_id' => $plugin_id, - '#base_plugin_id' => $base_id, - '#derivative_plugin_id' => $derivative_id, - // @todo Remove after fixing http://drupal.org/node/1989568. - '#block' => $entity, - ); - $build[$entity_id]['#configuration']['label'] = check_plain($configuration['label']); - - // Set cache tags; these always need to be set, whether the block is - // cacheable or not, so that the page cache is correctly informed. - $default_cache_tags = array( - 'content' => TRUE, - 'block_view' => TRUE, - 'block' => array($entity->id()), - ); - $build[$entity_id]['#cache']['tags'] = NestedArray::mergeDeep($default_cache_tags, $plugin->getCacheTags()); - - - if ($plugin->isCacheable()) { - $build[$entity_id]['#pre_render'][] = array($this, 'buildBlock'); - // Generic cache keys, with the block plugin's custom keys appended - // (usually cache context keys like 'cache_context.user.roles'). - $default_cache_keys = array( - 'entity_view', - 'block', - $entity->id(), - $entity->langcode, - // Blocks are always rendered in a "per theme" cache context. - 'cache_context.theme', - ); - $max_age = $plugin->getCacheMaxAge(); - $build[$entity_id]['#cache'] += array( - 'keys' => array_merge($default_cache_keys, $plugin->getCacheKeys()), - 'bin' => $plugin->getCacheBin(), - 'expire' => ($max_age === Cache::PERMANENT) ? Cache::PERMANENT : REQUEST_TIME + $max_age, + '#configuration' => $configuration, + '#plugin_id' => $plugin_id, + '#base_plugin_id' => $base_id, + '#derivative_plugin_id' => $derivative_id, ); + $build[$key]['#configuration']['label'] = String::checkPlain($configuration['label']); + + // Place the $content returned by the block plugin into a 'content' + // child element, as a way to allow the plugin to have complete control + // of its properties and rendering (e.g., its own #theme) without + // conflicting with the properties used above, or alternate ones used + // by alternate block rendering approaches in contrib (e.g., Panels). + // However, the use of a child element is an implementation detail of + // this particular block rendering approach. Semantically, the content + // returned by the plugin "is the" block, and in particular, + // #attributes and #contextual_links is information about the *entire* + // block. Therefore, we must move these properties from $content and + // merge them into the top-level element. + foreach (array('#attributes', '#contextual_links') as $property) { + if (isset($content[$property])) { + $build[$key][$property] += $content[$property]; + unset($content[$property]); + } + } + $build[$key]['content'] = $content; } else { - $build[$entity_id] = $this->buildBlock($build[$entity_id]); + $build[$key] = array(); } + $this->moduleHandler()->alter(array('block_view', "block_view_$base_id"), $build[$key], $plugin); + // @todo Remove after fixing http://drupal.org/node/1989568. $build[$key]['#block'] = $entity; - - // Don't run in ::buildBlock() to ensure cache keys can be altered. If an - // alter hook wants to modify the block contents, it can append another - // #pre_render hook. - $this->moduleHandler()->alter(array('block_view', "block_view_$base_id"), $build[$entity_id], $plugin); } return $build; } /** - * #pre_render callback for building a block. - * - * Renders the content using the provided block plugin, and then: - * - if there is no content, aborts rendering, and makes sure the block won't - * be rendered. - * - if there is content, moves the contextual links from the block content to - * the block itself. - */ - public function buildBlock($build) { - $content = $build['#block']->getPlugin()->build(); - if (!empty($content)) { - // Place the $content returned by the block plugin into a 'content' child - // element, as a way to allow the plugin to have complete control of its - // properties and rendering (e.g., its own #theme) without conflicting - // with the properties used above, or alternate ones used by alternate - // block rendering approaches in contrib (e.g., Panels). However, the use - // of a child element is an implementation detail of this particular block - // rendering approach. Semantically, the content returned by the plugin - // "is the" block, and in particular, #attributes and #contextual_links is - // information about the *entire* block. Therefore, we must move these - // properties from $content and merge them into the top-level element. - foreach (array('#attributes', '#contextual_links') as $property) { - if (isset($content[$property])) { - $build[$property] += $content[$property]; - unset($content[$property]); - } - } - $build['content'] = $content; - } - else { - // Abort rendering: render as the empty string and ensure this block is - // render cached, so we can avoid the work of having to repeatedly - // determine whether the block is empty. E.g. modifying or adding entities - // could cause the block to no longer be empty. - $build = array( - '#markup' => '', - '#cache' => $build['#cache'], - ); - } - return $build; - } - - /** * {@inheritdoc} */ - public function resetCache(array $entities = NULL) { - if (isset($entities)) { - Cache::invalidateTags(array('block' => array_keys($entities))); - } - else { - Cache::invalidateTags(array('block_view' => TRUE)); - } - } + public function resetCache(array $ids = NULL) { } } diff --git a/core/modules/block/lib/Drupal/block/Controller/BlockListController.php b/core/modules/block/lib/Drupal/block/Controller/BlockListController.php index 72aa445..2852970 100644 --- a/core/modules/block/lib/Drupal/block/Controller/BlockListController.php +++ b/core/modules/block/lib/Drupal/block/Controller/BlockListController.php @@ -8,6 +8,7 @@ namespace Drupal\block\Controller; use Drupal\Core\Entity\Controller\EntityListController; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; /** @@ -28,7 +29,7 @@ class BlockListController extends EntityListController { */ public function listing($theme = NULL, Request $request = NULL) { $theme = $theme ?: $this->config('system.theme')->get('default'); - return $this->entityManager()->getListBuilder('block')->render($theme, $request); + return $this->entityManager()->getListController('block')->render($theme, $request); } } diff --git a/core/modules/block/lib/Drupal/block/Entity/Block.php b/core/modules/block/lib/Drupal/block/Entity/Block.php index 6caab04..ea3a98a 100644 --- a/core/modules/block/lib/Drupal/block/Entity/Block.php +++ b/core/modules/block/lib/Drupal/block/Entity/Block.php @@ -7,7 +7,6 @@ namespace Drupal\block\Entity; -use Drupal\Core\Cache\Cache; use Drupal\Core\Config\Entity\ConfigEntityBase; use Drupal\block\BlockPluginBag; use Drupal\block\BlockInterface; @@ -23,7 +22,7 @@ * controllers = { * "access" = "Drupal\block\BlockAccessController", * "view_builder" = "Drupal\block\BlockViewBuilder", - * "list_builder" = "Drupal\block\BlockListBuilder", + * "list" = "Drupal\block\BlockListController", * "form" = { * "default" = "Drupal\block\BlockFormController", * "delete" = "Drupal\block\Form\BlockDeleteForm" @@ -148,32 +147,6 @@ public function toArray() { } /** - * {@inheritdoc} - */ - public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) { - parent::postSave($storage_controller, $update); - - if ($update) { - Cache::invalidateTags(array('block' => $this->id())); - } - // When placing a new block, invalidate all cache entries for this theme, - // since any page that uses this theme might be affected. - else { - // @todo Replace with theme cache tag: https://drupal.org/node/2185617 - Cache::invalidateTags(array('content' => TRUE)); - } - } - - /** - * {@inheritdoc} - */ - public static function postDelete(EntityStorageControllerInterface $storage_controller, array $entities) { - parent::postDelete($storage_controller, $entities); - - Cache::invalidateTags(array('block' => array_keys($entities))); - } - - /** * Sorts active blocks by weight; sorts inactive blocks by name. */ public static function sort($a, $b) { diff --git a/core/modules/block/lib/Drupal/block/Plugin/views/display/Block.php b/core/modules/block/lib/Drupal/block/Plugin/views/display/Block.php index 94bea95..657b635 100644 --- a/core/modules/block/lib/Drupal/block/Plugin/views/display/Block.php +++ b/core/modules/block/lib/Drupal/block/Plugin/views/display/Block.php @@ -46,6 +46,7 @@ protected function defineOptions() { $options['block_description'] = array('default' => '', 'translatable' => TRUE); $options['block_category'] = array('default' => 'Lists (Views)', 'translatable' => TRUE); + $options['block_caching'] = array('default' => DRUPAL_NO_CACHE); $options['block_hide_empty'] = array('default' => FALSE); $options['allow'] = array( @@ -130,6 +131,13 @@ public function optionsSummary(&$categories, &$options) { 'value' => empty($filtered_allow) ? t('None') : t('Items per page'), ); + $types = $this->blockCachingModes(); + $options['block_caching'] = array( + 'category' => 'other', + 'title' => t('Block caching'), + 'value' => $types[$this->getCacheType()], + ); + $options['block_hide_empty'] = array( 'category' => 'other', 'title' => t('Hide block if the view output is empty'), @@ -138,6 +146,33 @@ public function optionsSummary(&$categories, &$options) { } /** + * Provide a list of core's block caching modes. + */ + protected function blockCachingModes() { + return array( + DRUPAL_NO_CACHE => t('Do not cache'), + DRUPAL_CACHE_GLOBAL => t('Cache once for everything (global)'), + DRUPAL_CACHE_PER_PAGE => t('Per page'), + DRUPAL_CACHE_PER_ROLE => t('Per role'), + DRUPAL_CACHE_PER_ROLE | DRUPAL_CACHE_PER_PAGE => t('Per role per page'), + DRUPAL_CACHE_PER_USER => t('Per user'), + DRUPAL_CACHE_PER_USER | DRUPAL_CACHE_PER_PAGE => t('Per user per page'), + ); + } + + /** + * Provide a single method to figure caching type, keeping a sensible default + * for when it's unset. + */ + public function getCacheType() { + $cache_type = $this->getOption('block_caching'); + if (empty($cache_type)) { + $cache_type = DRUPAL_NO_CACHE; + } + return $cache_type; + } + + /** * Provide the default form for setting options. */ public function buildOptionsForm(&$form, &$form_state) { @@ -161,6 +196,16 @@ public function buildOptionsForm(&$form, &$form_state) { '#default_value' => $this->getOption('block_category'), ); break; + case 'block_caching': + $form['#title'] .= t('Block caching type'); + + $form['block_caching'] = array( + '#type' => 'radios', + '#description' => t("This sets the default status for Drupal's built-in block caching method; this requires that caching be turned on in block administration, and be careful because you have little control over when this cache is flushed."), + '#options' => $this->blockCachingModes(), + '#default_value' => $this->getCacheType(), + ); + break; case 'block_hide_empty': $form['#title'] .= t('Block empty settings'); @@ -206,6 +251,7 @@ public function submitOptionsForm(&$form, &$form_state) { switch ($form_state['section']) { case 'block_description': case 'block_category': + case 'block_caching': case 'allow': case 'block_hide_empty': $this->setOption($form_state['section'], $form_state['values'][$form_state['section']]); diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockCacheTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockCacheTest.php index ce78720..7414efd 100644 --- a/core/modules/block/lib/Drupal/block/Tests/BlockCacheTest.php +++ b/core/modules/block/lib/Drupal/block/Tests/BlockCacheTest.php @@ -61,13 +61,10 @@ function setUp() { } /** - * Test "cache_context.user.roles" cache context. + * Test DRUPAL_CACHE_PER_ROLE. */ function testCachePerRole() { - $this->setBlockCacheConfig(array( - 'max_age' => 600, - 'contexts' => array('cache_context.user.roles'), - )); + $this->setCacheMode(DRUPAL_CACHE_PER_ROLE); // Enable our test block. Set some content for it to display. $current_content = $this->randomName(); @@ -111,13 +108,10 @@ function testCachePerRole() { } /** - * Test a cacheable block without any cache context. + * Test DRUPAL_CACHE_GLOBAL. */ function testCacheGlobal() { - $this->setBlockCacheConfig(array( - 'max_age' => 600, - )); - + $this->setCacheMode(DRUPAL_CACHE_GLOBAL); $current_content = $this->randomName(); \Drupal::state()->set('block_test.content', $current_content); @@ -130,21 +124,18 @@ function testCacheGlobal() { $this->drupalLogout(); $this->drupalGet('user'); - $this->assertText($old_content, 'Block content served from cache.'); + $this->assertText($old_content, 'Block content served from global cache.'); } /** - * Test non-cacheable block. + * Test DRUPAL_NO_CACHE. */ function testNoCache() { - $this->setBlockCacheConfig(array( - 'max_age' => 0, - )); - + $this->setCacheMode(DRUPAL_NO_CACHE); $current_content = $this->randomName(); \Drupal::state()->set('block_test.content', $current_content); - // If max_age = 0 has no effect, the next request would be cached. + // If DRUPAL_NO_CACHE has no effect, the next request would be cached. $this->drupalGet(''); $this->assertText($current_content, 'Block content displays.'); @@ -152,18 +143,14 @@ function testNoCache() { $current_content = $this->randomName(); \Drupal::state()->set('block_test.content', $current_content); $this->drupalGet(''); - $this->assertText($current_content, 'Maximum age of zero prevents blocks from being cached.'); + $this->assertText($current_content, 'DRUPAL_NO_CACHE prevents blocks from being cached.'); } /** - * Test "cache_context.user" cache context. + * Test DRUPAL_CACHE_PER_USER. */ function testCachePerUser() { - $this->setBlockCacheConfig(array( - 'max_age' => 600, - 'contexts' => array('cache_context.user'), - )); - + $this->setCacheMode(DRUPAL_CACHE_PER_USER); $current_content = $this->randomName(); \Drupal::state()->set('block_test.content', $current_content); $this->drupalLogin($this->normal_user); @@ -188,14 +175,10 @@ function testCachePerUser() { } /** - * Test "cache_context.url" cache context. + * Test DRUPAL_CACHE_PER_PAGE. */ function testCachePerPage() { - $this->setBlockCacheConfig(array( - 'max_age' => 600, - 'contexts' => array('cache_context.url'), - )); - + $this->setCacheMode(DRUPAL_CACHE_PER_PAGE); $current_content = $this->randomName(); \Drupal::state()->set('block_test.content', $current_content); @@ -213,11 +196,10 @@ function testCachePerPage() { } /** - * Private helper method to set the test block's cache configuration. + * Private helper method to set the test block's cache mode. */ - private function setBlockCacheConfig($cache_config) { - $block = $this->block->getPlugin(); - $block->setConfigurationValue('cache', $cache_config); + private function setCacheMode($cache_mode) { + $this->block->getPlugin()->setConfigurationValue('cache', $cache_mode); $this->block->save(); } diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockInterfaceTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockInterfaceTest.php index 5e7d9d0..a694b4e 100644 --- a/core/modules/block/lib/Drupal/block/Tests/BlockInterfaceTest.php +++ b/core/modules/block/lib/Drupal/block/Tests/BlockInterfaceTest.php @@ -45,13 +45,10 @@ public function testBlockInterface() { ); $expected_configuration = array( 'label' => 'Custom Display Message', + 'display_message' => 'no message set', 'module' => 'block_test', 'label_display' => BlockInterface::BLOCK_LABEL_VISIBLE, - 'cache' => array( - 'max_age' => 0, - 'contexts' => array(), - ), - 'display_message' => 'no message set', + 'cache' => DRUPAL_NO_CACHE, ); // Initial configuration of the block at construction time. $display_block = $manager->createInstance('test_block_instantiation', $configuration); @@ -63,12 +60,6 @@ public function testBlockInterface() { $this->assertIdentical($display_block->getConfiguration(), $expected_configuration, 'The block configuration was updated correctly.'); $definition = $display_block->getPluginDefinition(); - $period = array(0, 60, 180, 300, 600, 900, 1800, 2700, 3600, 10800, 21600, 32400, 43200, 86400); - $period = array_map('format_interval', array_combine($period, $period)); - $period[0] = '<' . t('no caching') . '>'; - $period[\Drupal\Core\Cache\Cache::PERMANENT] = t('Forever'); - $contexts = \Drupal::service("cache_contexts")->getLabels(); - unset($contexts['cache_context.theme']); $expected_form = array( 'module' => array( '#type' => 'value', @@ -93,27 +84,8 @@ public function testBlockInterface() { '#return_value' => 'visible', ), 'cache' => array( - '#type' => 'details', - '#title' => t('Cache settings'), - 'max_age' => array( - '#type' => 'select', - '#title' => t('Maximum age'), - '#description' => t('The maximum time this block may be cached.'), - '#default_value' => 0, - '#options' => $period, - ), - 'contexts' => array( - '#type' => 'checkboxes', - '#title' => t('Vary by context'), - '#description' => t('The contexts this cached block must be varied by.'), - '#default_value' => array(), - '#options' => $contexts, - '#states' => array( - 'disabled' => array( - ':input[name="settings[cache][max_age]"]' => array('value' => (string) 0), - ), - ), - ), + '#type' => 'value', + '#value' => DRUPAL_NO_CACHE, ), 'display_message' => array( '#type' => 'textfield', diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockRenderOrderTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockRenderOrderTest.php index 1a7ea82..0521aa9 100644 --- a/core/modules/block/lib/Drupal/block/Tests/BlockRenderOrderTest.php +++ b/core/modules/block/lib/Drupal/block/Tests/BlockRenderOrderTest.php @@ -48,24 +48,21 @@ function testBlockRenderOrder() { 'stark_powered' => array( 'weight' => '-3', 'id' => 'stark_powered', - 'label' => 'Test block A', ), 'stark_by' => array( 'weight' => '3', 'id' => 'stark_by', - 'label' => 'Test block C', ), 'stark_drupal' => array( 'weight' => '3', 'id' => 'stark_drupal', - 'label' => 'Test block B', ), ); // Place the test blocks. foreach ($test_blocks as $test_block) { $this->drupalPlaceBlock('system_powered_by_block', array( - 'label' => $test_block['label'], + 'label' => 'Test Block', 'region' => $region, 'weight' => $test_block['weight'], 'id' => $test_block['id'], @@ -84,6 +81,6 @@ function testBlockRenderOrder() { } } $this->assertTrue($position['stark_powered'] < $position['stark_by'], 'Blocks with different weight are rendered in the correct order.'); - $this->assertTrue($position['stark_drupal'] < $position['stark_by'], 'Blocks with identical weight are rendered in alphabetical order.'); + $this->assertTrue($position['stark_drupal'] < $position['stark_by'], 'Blocks with identical weight are rendered in reverse alphabetical order.'); } } diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockStorageUnitTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockStorageUnitTest.php index e63fb2b..aff9d70 100644 --- a/core/modules/block/lib/Drupal/block/Tests/BlockStorageUnitTest.php +++ b/core/modules/block/lib/Drupal/block/Tests/BlockStorageUnitTest.php @@ -56,6 +56,7 @@ public function testBlockCRUD() { // Run each test method in the same installation. $this->createTests(); $this->loadTests(); + $this->renderTests(); $this->deleteTests(); } @@ -102,10 +103,7 @@ protected function createTests() { 'label' => '', 'module' => 'block_test', 'label_display' => BlockInterface::BLOCK_LABEL_VISIBLE, - 'cache' => array( - 'max_age' => 0, - 'contexts' => array(), - ), + 'cache' => DRUPAL_NO_CACHE, ), 'visibility' => NULL, ); @@ -115,7 +113,7 @@ protected function createTests() { } /** - * Tests the loading of blocks. + * Tests the rendering of blocks. */ protected function loadTests() { $entity = $this->controller->load('test_block'); @@ -130,6 +128,57 @@ protected function loadTests() { } /** + * Tests the rendering of blocks. + */ + protected function renderTests() { + // Test the rendering of a block. + $entity = entity_load('block', 'test_block'); + $output = entity_view($entity, 'block'); + $expected = array(); + $expected[] = '
'; + $expected[] = ' '; + $expected[] = ' '; + $expected[] = ''; + $expected[] = '
'; + $expected[] = ' '; + $expected[] = '
'; + $expected[] = '
'; + $expected[] = ''; + $expected_output = implode("\n", $expected); + $this->assertEqual(drupal_render($output), $expected_output); + + // Reset the HTML IDs so that the next render is not affected. + drupal_static_reset('drupal_html_id'); + + // Test the rendering of a block with a given title. + $entity = $this->controller->create(array( + 'id' => 'test_block2', + 'theme' => 'stark', + 'plugin' => 'test_html', + 'settings' => array( + 'label' => 'Powered by Bananas', + ), + )); + $entity->save(); + $output = entity_view($entity, 'block'); + $expected = array(); + $expected[] = '
'; + $expected[] = ' '; + $expected[] = '

Powered by Bananas

'; + $expected[] = ' '; + $expected[] = ''; + $expected[] = '
'; + $expected[] = ' '; + $expected[] = '
'; + $expected[] = '
'; + $expected[] = ''; + $expected_output = implode("\n", $expected); + $this->assertEqual(drupal_render($output), $expected_output); + // Clean up this entity. + $entity->delete(); + } + + /** * Tests the deleting of blocks. */ protected function deleteTests() { diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockTest.php index cc25986..e7b99e1 100644 --- a/core/modules/block/lib/Drupal/block/Tests/BlockTest.php +++ b/core/modules/block/lib/Drupal/block/Tests/BlockTest.php @@ -7,7 +7,6 @@ namespace Drupal\block\Tests; -use Drupal\Core\Cache\Cache; use Drupal\simpletest\WebTestBase; /** @@ -250,106 +249,35 @@ function moveBlockToRegion(array $block, $region) { } /** - * Test that cache tags are properly set and bubbled up to the page cache. - * - * Verify that invalidation of these cache tags works: - * - "block:" - * - "block_plugin:" + * Test _block_rehash(). */ - public function testBlockCacheTags() { - // The page cache only works for anonymous users. - $this->drupalLogout(); + function testBlockRehash() { + \Drupal::moduleHandler()->install(array('block_test')); + $this->assertTrue(\Drupal::moduleHandler()->moduleExists('block_test'), 'Test block module enabled.'); - // Enable page caching. - $config = \Drupal::config('system.performance'); - $config->set('cache.page.use_internal', 1); - $config->set('cache.page.max_age', 300); - $config->save(); - - // Place the "Powered by Drupal" block. - $block = $this->drupalPlaceBlock('system_powered_by_block', array('id' => 'powered', 'cache' => array('max_age' => 315360000))); - - // Prime the page cache. - $this->drupalGet(''); - $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS'); - - // Verify a cache hit, but also the presence of the correct cache tags in - // both the page and block caches. - $this->drupalGet(''); - $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT'); - $cid_parts = array(url('', array('absolute' => TRUE)), 'html'); - $cid = sha1(implode(':', $cid_parts)); - $cache_entry = \Drupal::cache('page')->get($cid); - $expected_cache_tags = array( - 'content:1', - 'block_view:1', - 'block:powered', - 'block_plugin:system_powered_by_block', - ); - $this->assertIdentical($cache_entry->tags, $expected_cache_tags); - $cache_entry = \Drupal::cache('block')->get('entity_view:block:powered:en:stark'); - $this->assertIdentical($cache_entry->tags, $expected_cache_tags); + // Clear the block cache to load the block_test module's block definitions. + $this->container->get('plugin.manager.block')->clearCachedDefinitions(); - // The "Powered by Drupal" block is modified; verify a cache miss. - $block->set('region', 'content'); + // Add a test block. + $block = array(); + $block['id'] = 'test_cache'; + $block['theme'] = \Drupal::config('system.theme')->get('default'); + $block['region'] = 'header'; + $block = $this->drupalPlaceBlock('test_cache', array('region' => 'header')); + + // Our test block's caching should default to DRUPAL_CACHE_PER_ROLE. + $settings = $block->get('settings'); + $this->assertEqual($settings['cache'], DRUPAL_CACHE_PER_ROLE, 'Test block cache mode defaults to DRUPAL_CACHE_PER_ROLE.'); + + // Disable caching for this block. + $block->getPlugin()->setConfigurationValue('cache', DRUPAL_NO_CACHE); $block->save(); - $this->drupalGet(''); - $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS'); - - // Now we should have a cache hit again. - $this->drupalGet(''); - $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT'); - - // Place the "Powered by Drupal" block another time; verify a cache miss. - $block_2 = $this->drupalPlaceBlock('system_powered_by_block', array('id' => 'powered-2', 'cache' => array('max_age' => 315360000))); - $this->drupalGet(''); - $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS'); - - // Verify a cache hit, but also the presence of the correct cache tags. - $this->drupalGet(''); - $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT'); - $cid_parts = array(url('', array('absolute' => TRUE)), 'html'); - $cid = sha1(implode(':', $cid_parts)); - $cache_entry = \Drupal::cache('page')->get($cid); - $expected_cache_tags = array( - 'content:1', - 'block_view:1', - 'block:powered-2', - 'block:powered', - 'block_plugin:system_powered_by_block', - ); - $this->assertEqual($cache_entry->tags, $expected_cache_tags); - $expected_cache_tags = array( - 'content:1', - 'block_view:1', - 'block:powered', - 'block_plugin:system_powered_by_block', - ); - $cache_entry = \Drupal::cache('block')->get('entity_view:block:powered:en:stark'); - $this->assertIdentical($cache_entry->tags, $expected_cache_tags); - $expected_cache_tags = array( - 'content:1', - 'block_view:1', - 'block:powered-2', - 'block_plugin:system_powered_by_block', - ); - $cache_entry = \Drupal::cache('block')->get('entity_view:block:powered-2:en:stark'); - $this->assertIdentical($cache_entry->tags, $expected_cache_tags); - - // The plugin providing the "Powered by Drupal" block is modified; verify a - // cache miss. - Cache::invalidateTags(array('block_plugin:system_powered_by_block')); - $this->drupalGet(''); - $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS'); - - // Now we should have a cache hit again. - $this->drupalGet(''); - $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT'); - - // Delete the "Powered by Drupal" blocks; verify a cache miss. - entity_delete_multiple('block', array('powered', 'powered-2')); - $this->drupalGet(''); - $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS'); + // Flushing all caches should call _block_rehash(). + $this->resetAll(); + // Verify that block is updated with the new caching mode. + $block = entity_load('block', $block->id()); + $settings = $block->get('settings'); + $this->assertEqual($settings['cache'], DRUPAL_NO_CACHE, "Test block's database entry updated to DRUPAL_NO_CACHE."); } } diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockViewBuilderTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockViewBuilderTest.php deleted file mode 100644 index aa7dd2e..0000000 --- a/core/modules/block/lib/Drupal/block/Tests/BlockViewBuilderTest.php +++ /dev/null @@ -1,346 +0,0 @@ - 'Block rendering', - 'description' => 'Tests the block view builder.', - 'group' => 'Block', - ); - } - - /** - * {@inheritdoc} - */ - public function setUp() { - parent::setUp(); - - $this->controller = $this->container - ->get('entity.manager') - ->getStorageController('block'); - - \Drupal::state()->set('block_test.content', 'Llamas > unicorns!'); - - // Create a block with only required values. - $this->block = $this->controller->create(array( - 'id' => 'test_block', - 'theme' => 'stark', - 'plugin' => 'test_cache', - )); - $this->block->save(); - - $this->container->get('cache.block')->deleteAll(); - } - - /** - * Tests the rendering of blocks. - */ - public function testBasicRendering() { - \Drupal::state()->set('block_test.content', ''); - - $entity = $this->controller->create(array( - 'id' => 'test_block1', - 'theme' => 'stark', - 'plugin' => 'test_html', - )); - $entity->save(); - - // Test the rendering of a block. - $entity = entity_load('block', 'test_block1'); - $output = entity_view($entity, 'block'); - $expected = array(); - $expected[] = '
'; - $expected[] = ' '; - $expected[] = ' '; - $expected[] = ''; - $expected[] = '
'; - $expected[] = ' '; - $expected[] = '
'; - $expected[] = '
'; - $expected[] = ''; - $expected_output = implode("\n", $expected); - $this->assertEqual(drupal_render($output), $expected_output); - - // Reset the HTML IDs so that the next render is not affected. - drupal_static_reset('drupal_html_id'); - - // Test the rendering of a block with a given title. - $entity = $this->controller->create(array( - 'id' => 'test_block2', - 'theme' => 'stark', - 'plugin' => 'test_html', - 'settings' => array( - 'label' => 'Powered by Bananas', - ), - )); - $entity->save(); - $output = entity_view($entity, 'block'); - $expected = array(); - $expected[] = '
'; - $expected[] = ' '; - $expected[] = '

Powered by Bananas

'; - $expected[] = ' '; - $expected[] = ''; - $expected[] = '
'; - $expected[] = ' '; - $expected[] = '
'; - $expected[] = '
'; - $expected[] = ''; - $expected_output = implode("\n", $expected); - $this->assertEqual(drupal_render($output), $expected_output); - } - - /** - * Tests block render cache handling. - */ - public function testBlockViewBuilderCache() { - // Verify cache handling for a non-empty block. - $this->verifyRenderCacheHandling(); - - // Create an empty block. - $this->block = $this->controller->create(array( - 'id' => 'test_block', - 'theme' => 'stark', - 'plugin' => 'test_cache', - )); - $this->block->save(); - \Drupal::state()->set('block_test.content', NULL); - - // Verify cache handling for an empty block. - $this->verifyRenderCacheHandling(); - } - - /** - * Verifies render cache handling of the block being tested. - * - * @see ::testBlockViewBuilderCache() - */ - protected function verifyRenderCacheHandling() { - // Force a request via GET so we can get drupal_render() cache working. - $request_method = \Drupal::request()->server->get('REQUEST_METHOD'); - $this->container->get('request')->setMethod('GET'); - - // Test that entities with caching disabled do not generate a cache entry. - $build = $this->getBlockRenderArray(); - $this->assertTrue(isset($build['#cache']) && array_keys($build['#cache']) == array('tags'), 'The render array element of uncacheable blocks is not cached, but does have cache tags set.'); - - // Enable block caching. - $this->setBlockCacheConfig(array( - 'max_age' => 600, - )); - - // Test that a cache entry is created. - $build = $this->getBlockRenderArray(); - $cid = drupal_render_cid_create($build); - drupal_render($build); - $this->assertTrue($this->container->get('cache.block')->get($cid), 'The block render element has been cached.'); - - // Re-save the block and check that the cache entry has been deleted. - $this->block->save(); - $this->assertFalse($this->container->get('cache.block')->get($cid), 'The block render cache entry has been cleared when the block was saved.'); - - // Rebuild the render array (creating a new cache entry in the process) and - // delete the block to check the cache entry is deleted. - unset($build['#printed']); - drupal_render($build); - $this->assertTrue($this->container->get('cache.block')->get($cid), 'The block render element has been cached.'); - $this->block->delete(); - $this->assertFalse($this->container->get('cache.block')->get($cid), 'The block render cache entry has been cleared when the block was deleted.'); - - // Restore the previous request method. - $this->container->get('request')->setMethod($request_method); - } - - /** - * Tests block view altering. - */ - public function testBlockViewBuilderAlter() { - // Establish baseline. - $build = $this->getBlockRenderArray(); - $this->assertIdentical(drupal_render($build), 'Llamas > unicorns!'); - - // Enable the block view alter hook that adds a suffix, for basic testing. - \Drupal::state()->set('block_test_view_alter_suffix', TRUE); - - // Basic: non-empty block. - $build = $this->getBlockRenderArray(); - $this->assertTrue(isset($build['#suffix']) && $build['#suffix'] === '
Goodbye!', 'A block with content is altered.'); - $this->assertIdentical(drupal_render($build), 'Llamas > unicorns!
Goodbye!'); - - // Basic: empty block. - \Drupal::state()->set('block_test.content', NULL); - $build = $this->getBlockRenderArray(); - $this->assertTrue(isset($build['#suffix']) && $build['#suffix'] === '
Goodbye!', 'A block without content is altered.'); - $this->assertIdentical(drupal_render($build), '
Goodbye!'); - - // Disable the block view alter hook that adds a suffix, for basic testing. - \Drupal::state()->set('block_test_view_alter_suffix', FALSE); - - // Force a request via GET so we can get drupal_render() cache working. - $request_method = \Drupal::request()->server->get('REQUEST_METHOD'); - $this->container->get('request')->setMethod('GET'); - - $default_keys = array('entity_view', 'block', 'test_block', 'en', 'cache_context.theme'); - $default_tags = array('content' => TRUE, 'block_view' => TRUE, 'block' => array('test_block'), 'block_plugin' => array('test_cache')); - - // Advanced: cached block, but an alter hook adds an additional cache key. - $this->setBlockCacheConfig(array( - 'max_age' => 600, - )); - $alter_add_key = $this->randomName(); - \Drupal::state()->set('block_test_view_alter_cache_key', $alter_add_key); - $expected_keys = array_merge($default_keys, array($alter_add_key)); - $build = $this->getBlockRenderArray(); - $this->assertIdentical($expected_keys, $build['#cache']['keys'], 'An altered cacheable block has the expected cache keys.'); - $cid = drupal_render_cid_create(array('#cache' => array('keys' => $expected_keys))); - $this->assertIdentical(drupal_render($build), ''); - $cache_entry = $this->container->get('cache.block')->get($cid); - $this->assertTrue($cache_entry, 'The block render element has been cached with the expected cache ID.'); - $expected_flattened_tags = array('content:1', 'block_view:1', 'block:test_block', 'block_plugin:test_cache'); - $this->assertIdentical($cache_entry->tags, array_combine($expected_flattened_tags, $expected_flattened_tags)); //, 'The block render element has been cached with the expected cache tags.'); - $this->container->get('cache.block')->delete($cid); - - // Advanced: cached block, but an alter hook adds an additional cache tag. - $alter_add_tag = $this->randomName(); - \Drupal::state()->set('block_test_view_alter_cache_tag', $alter_add_tag); - $expected_tags = NestedArray::mergeDeep($default_tags, array($alter_add_tag => TRUE)); - $build = $this->getBlockRenderArray(); - $this->assertIdentical($expected_tags, $build['#cache']['tags'], 'An altered cacheable block has the expected cache tags.'); - $cid = drupal_render_cid_create(array('#cache' => array('keys' => $expected_keys))); - $this->assertIdentical(drupal_render($build), ''); - $cache_entry = $this->container->get('cache.block')->get($cid); - $this->assertTrue($cache_entry, 'The block render element has been cached with the expected cache ID.'); - $expected_flattened_tags = array('content:1', 'block_view:1', 'block:test_block', 'block_plugin:test_cache', $alter_add_tag . ':1'); - $this->assertIdentical($cache_entry->tags, array_combine($expected_flattened_tags, $expected_flattened_tags)); //, 'The block render element has been cached with the expected cache tags.'); - $this->container->get('cache.block')->delete($cid); - - // Advanced: cached block, but an alter hook adds a #pre_render callback to - // alter the eventual content. - \Drupal::state()->set('block_test_view_alter_append_pre_render_prefix', TRUE); - $build = $this->getBlockRenderArray(); - $this->assertFalse(isset($build['#prefix']), 'The appended #pre_render callback has not yet run before calling drupal_render().'); - $this->assertIdentical(drupal_render($build), 'Hiya!
'); - $this->assertTrue(isset($build['#prefix']) && $build['#prefix'] === 'Hiya!
', 'A cached block without content is altered.'); - - // Restore the previous request method. - $this->container->get('request')->setMethod($request_method); - } - - /** - * Tests block render cache handling with configurable cache contexts. - * - * This is only intended to test that an existing block can be configured with - * additional contexts, not to test that each context works correctly. - * - * @see \Drupal\block\Tests\BlockCacheTest - */ - public function testBlockViewBuilderCacheContexts() { - // Force a request via GET so we can get drupal_render() cache working. - $request_method = \Drupal::request()->server->get('REQUEST_METHOD'); - $this->container->get('request')->setMethod('GET'); - - // First: no cache context. - $this->setBlockCacheConfig(array( - 'max_age' => 600, - )); - $build = $this->getBlockRenderArray(); - $cid = drupal_render_cid_create($build); - drupal_render($build); - $this->assertTrue($this->container->get('cache.block', $cid), 'The block render element has been cached.'); - - // Second: the "per URL" cache context. - $this->setBlockCacheConfig(array( - 'max_age' => 600, - 'contexts' => array('cache_context.url'), - )); - $old_cid = $cid; - $build = $this->getBlockRenderArray(); - $cid = drupal_render_cid_create($build); - drupal_render($build); - $this->assertTrue($this->container->get('cache.block', $cid), 'The block render element has been cached.'); - $this->assertNotEqual($cid, $old_cid, 'The cache ID has changed.'); - - // Third: the same block configuration, but a different URL. - $original_url_cache_context = $this->container->get('cache_context.url'); - $temp_context = new UrlCacheContext(Request::create('/foo')); - $this->container->set('cache_context.url', $temp_context); - $old_cid = $cid; - $build = $this->getBlockRenderArray(); - $cid = drupal_render_cid_create($build); - drupal_render($build); - $this->assertTrue($this->container->get('cache.block', $cid), 'The block render element has been cached.'); - $this->assertNotEqual($cid, $old_cid, 'The cache ID has changed.'); - $this->container->set('cache_context.url', $original_url_cache_context); - - // Restore the previous request method. - $this->container->get('request')->setMethod($request_method); - } - - /** - * Sets the test block's cache configuration. - * - * @param array $cache_config - * The desired cache configuration. - */ - protected function setBlockCacheConfig(array $cache_config) { - $block = $this->block->getPlugin(); - $block->setConfigurationValue('cache', $cache_config); - $this->block->save(); - } - - /** - * Get a fully built render array for a block. - * - * @return array - * The render array. - */ - protected function getBlockRenderArray() { - $build = $this->container->get('entity.manager')->getViewBuilder('block')->view($this->block, 'block'); - - // Mock the build array to not require the theme registry. - unset($build['#theme']); - - return $build; - } - -} diff --git a/core/modules/block/lib/Drupal/block/Tests/Views/DisplayBlockTest.php b/core/modules/block/lib/Drupal/block/Tests/Views/DisplayBlockTest.php index ab13127..c43f640 100644 --- a/core/modules/block/lib/Drupal/block/Tests/Views/DisplayBlockTest.php +++ b/core/modules/block/lib/Drupal/block/Tests/Views/DisplayBlockTest.php @@ -177,6 +177,19 @@ protected function testDeleteBlockDisplay() { } /** + * Tests views block plugin definitions. + */ + public function testViewsBlockPlugins() { + // Ensures that the cache setting gets to the block settings. + $instance = $this->container->get('plugin.manager.block')->createInstance('views_block:test_view_block2-block_2'); + $configuration = $instance->getConfiguration(); + $this->assertEqual($configuration['cache'], DRUPAL_NO_CACHE); + $instance = $this->container->get('plugin.manager.block')->createInstance('views_block:test_view_block2-block_3'); + $configuration = $instance->getConfiguration(); + $this->assertEqual($configuration['cache'], DRUPAL_CACHE_PER_USER); + } + + /** * Test the block form for a Views block. */ public function testViewsBlockForm() { @@ -270,23 +283,19 @@ public function testBlockRendering() { public function testBlockContextualLinks() { $this->drupalLogin($this->drupalCreateUser(array('administer views', 'access contextual links', 'administer blocks'))); $block = $this->drupalPlaceBlock('views_block:test_view_block-block_1'); - $cached_block = $this->drupalPlaceBlock('views_block:test_view_block-block_1', array('cache' => array('max_age' => 3600))); $this->drupalGet('test-page'); $id = 'block:block=' . $block->id() . ':|views_ui_edit:view=test_view_block:location=block&name=test_view_block&display_id=block_1'; - $cached_id = 'block:block=' . $cached_block->id() . ':|views_ui_edit:view=test_view_block:location=block&name=test_view_block&display_id=block_1'; // @see \Drupal\contextual\Tests\ContextualDynamicContextTest:assertContextualLinkPlaceHolder() $this->assertRaw(' $id)) . '>', format_string('Contextual link placeholder with id @id exists.', array('@id' => $id))); - $this->assertRaw(' $cached_id)) . '>', format_string('Contextual link placeholder with id @id exists.', array('@id' => $cached_id))); // Get server-rendered contextual links. // @see \Drupal\contextual\Tests\ContextualDynamicContextTest:renderContextualLinks() - $post = array('ids[0]' => $id, 'ids[1]' => $cached_id); + $post = array('ids[0]' => $id); $response = $this->drupalPost('contextual/render', 'application/json', $post, array('query' => array('destination' => 'test-page'))); $this->assertResponse(200); $json = Json::decode($response); $this->assertIdentical($json[$id], ''); - $this->assertIdentical($json[$cached_id], ''); } } diff --git a/core/modules/block/tests/Drupal/block/Tests/BlockBaseTest.php b/core/modules/block/tests/Drupal/block/Tests/BlockBaseTest.php index 8d96c33..f0d04ec 100644 --- a/core/modules/block/tests/Drupal/block/Tests/BlockBaseTest.php +++ b/core/modules/block/tests/Drupal/block/Tests/BlockBaseTest.php @@ -12,6 +12,11 @@ use Drupal\Core\Transliteration\PHPTransliteration; use Drupal\Tests\UnitTestCase; +// @todo Remove once the constants are replaced with constants on classes. +if (!defined('DRUPAL_NO_CACHE')) { + define('DRUPAL_NO_CACHE', -1); +} + /** * Tests the base block plugin. * diff --git a/core/modules/block/tests/modules/block_test/block_test.module b/core/modules/block/tests/modules/block_test/block_test.module index a527ae1..1530f2c 100644 --- a/core/modules/block/tests/modules/block_test/block_test.module +++ b/core/modules/block/tests/modules/block_test/block_test.module @@ -5,8 +5,6 @@ * Provide test blocks. */ -use Drupal\block\BlockPluginInterface; - /** * Implements hook_block_alter(). */ @@ -15,29 +13,3 @@ function block_test_block_alter(&$block_info) { $block_info['test_block_instantiation']['category'] = t('Custom category'); } } - -/** - * Implements hook_block_view_BASE_BLOCK_ID_alter(). - */ -function block_test_block_view_test_cache_alter(array &$build, BlockPluginInterface $block) { - if (\Drupal::state()->get('block_test_view_alter_suffix') !== NULL) { - $build['#suffix'] = '
Goodbye!'; - } - if (\Drupal::state()->get('block_test_view_alter_cache_key') !== NULL) { - $build['#cache']['keys'][] = \Drupal::state()->get('block_test_view_alter_cache_key'); - } - if (\Drupal::state()->get('block_test_view_alter_cache_tag') !== NULL) { - $build['#cache']['tags'][\Drupal::state()->get('block_test_view_alter_cache_tag')] = TRUE; - } - if (\Drupal::state()->get('block_test_view_alter_append_pre_render_prefix') !== NULL) { - $build['#pre_render'][] = 'block_test_pre_render_alter_content'; - } -} - -/** - * #pre_render callback for a block to alter its content. - */ -function block_test_pre_render_alter_content($build) { - $build['#prefix'] = 'Hiya!
'; - return $build; -} diff --git a/core/modules/block/tests/modules/block_test/config/block.block.test_block.yml b/core/modules/block/tests/modules/block_test/config/block.block.test_block.yml index 2b89519..a9eb247 100644 --- a/core/modules/block/tests/modules/block_test/config/block.block.test_block.yml +++ b/core/modules/block/tests/modules/block_test/config/block.block.test_block.yml @@ -9,6 +9,7 @@ settings: label: 'Test HTML block' module: block_test label_display: 'hidden' + cache: 1 visibility: path: visibility: 0 diff --git a/core/modules/block/tests/modules/block_test/lib/Drupal/block_test/Plugin/Block/TestCacheBlock.php b/core/modules/block/tests/modules/block_test/lib/Drupal/block_test/Plugin/Block/TestCacheBlock.php index b6508a8..2fa6122 100644 --- a/core/modules/block/tests/modules/block_test/lib/Drupal/block_test/Plugin/Block/TestCacheBlock.php +++ b/core/modules/block/tests/modules/block_test/lib/Drupal/block_test/Plugin/Block/TestCacheBlock.php @@ -21,15 +21,22 @@ class TestCacheBlock extends BlockBase { /** * {@inheritdoc} + * + * Sets a different caching strategy for testing purposes. */ - public function build() { - $content = \Drupal::state()->get('block_test.content'); + public function defaultConfiguration() { + return array( + 'cache' => DRUPAL_CACHE_PER_ROLE, + ); + } - $build = array(); - if (!empty($content)) { - $build['#markup'] = $content; - } - return $build; + /** + * {@inheritdoc} + */ + public function build() { + return array( + '#children' => \Drupal::state()->get('block_test.content'), + ); } } diff --git a/core/modules/block/tests/modules/block_test/lib/Drupal/block_test/Plugin/Block/TestXSSTitleBlock.php b/core/modules/block/tests/modules/block_test/lib/Drupal/block_test/Plugin/Block/TestXSSTitleBlock.php index 3146b59..156abf9 100644 --- a/core/modules/block/tests/modules/block_test/lib/Drupal/block_test/Plugin/Block/TestXSSTitleBlock.php +++ b/core/modules/block/tests/modules/block_test/lib/Drupal/block_test/Plugin/Block/TestXSSTitleBlock.php @@ -16,4 +16,16 @@ * ) */ class TestXSSTitleBlock extends TestCacheBlock { + + /** + * {@inheritdoc} + * + * Sets a different caching strategy for testing purposes. + */ + public function defaultConfiguration() { + return array( + 'cache' => DRUPAL_NO_CACHE, + ); + } + } diff --git a/core/modules/book/lib/Drupal/book/Plugin/Block/BookNavigationBlock.php b/core/modules/book/lib/Drupal/book/Plugin/Block/BookNavigationBlock.php index 6a9cfff..4350e53 100644 --- a/core/modules/book/lib/Drupal/book/Plugin/Block/BookNavigationBlock.php +++ b/core/modules/book/lib/Drupal/book/Plugin/Block/BookNavigationBlock.php @@ -65,6 +65,7 @@ public static function create(ContainerInterface $container, array $configuratio */ public function defaultConfiguration() { return array( + 'cache' => DRUPAL_CACHE_PER_PAGE | DRUPAL_CACHE_PER_ROLE, 'block_mode' => "all pages", ); } @@ -100,7 +101,6 @@ public function blockSubmit($form, &$form_state) { */ public function build() { $current_bid = 0; - if ($node = $this->request->get('node')) { $current_bid = empty($node->book['bid']) ? 0 : $node->book['bid']; } @@ -145,21 +145,15 @@ public function build() { $data = array_shift($tree); $below = \Drupal::service('book.manager')->bookTreeOutput($data['below']); if (!empty($below)) { - return $below; + $book_title_link = array('#theme' => 'book_title_link', '#link' => $data['link']); + return array( + '#title' => drupal_render($book_title_link), + $below, + ); } } } return array(); } - /** - * {@inheritdoc} - */ - protected function getRequiredCacheContexts() { - // The "Book navigation" block must be cached per URL and per role: the - // "active" menu link may differ per URL and different roles may have access - // to different menu links. - return array('cache_context.url', 'cache_context.user.roles'); - } - } diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListTest.php index 710cc0d..682aeef 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListTest.php @@ -32,10 +32,10 @@ public static function getInfo() { } /** - * Tests entity list builder methods. + * Tests entity list controller methods. */ function testList() { - $controller = \Drupal::entityManager()->getListBuilder('config_test'); + $controller = \Drupal::entityManager()->getListController('config_test'); // Test getStorageController() method. $this->assertTrue($controller->getStorageController() instanceof EntityStorageControllerInterface, 'EntityStorageController instance in storage.'); @@ -116,7 +116,7 @@ function testList() { // Test that config entities that do not support status, do not have // enable/disable operations. $controller = $this->container->get('entity.manager') - ->getListBuilder('config_test_no_status'); + ->getListController('config_test_no_status'); $list = $controller->load(); $entity = $list['default']; diff --git a/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestListBuilder.php b/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestListBuilder.php deleted file mode 100644 index 8634b96..0000000 --- a/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestListBuilder.php +++ /dev/null @@ -1,38 +0,0 @@ -getLabel($entity); - $row['id'] = $entity->id(); - return $row + parent::buildRow($entity); - } - -} diff --git a/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestListController.php b/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestListController.php new file mode 100644 index 0000000..564876a --- /dev/null +++ b/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestListController.php @@ -0,0 +1,36 @@ +getLabel($entity); + $row['id'] = $entity->id(); + return $row + parent::buildRow($entity); + } + +} diff --git a/core/modules/config/tests/config_test/lib/Drupal/config_test/Entity/ConfigQueryTest.php b/core/modules/config/tests/config_test/lib/Drupal/config_test/Entity/ConfigQueryTest.php index 53cd76d..c3528f9 100644 --- a/core/modules/config/tests/config_test/lib/Drupal/config_test/Entity/ConfigQueryTest.php +++ b/core/modules/config/tests/config_test/lib/Drupal/config_test/Entity/ConfigQueryTest.php @@ -15,7 +15,7 @@ * label = @Translation("Test configuration for query"), * controllers = { * "storage" = "Drupal\config_test\ConfigTestStorageController", - * "list_builder" = "Drupal\Core\Config\Entity\ConfigEntityListBuilder", + * "list" = "Drupal\Core\Config\Entity\ConfigEntityListController", * "form" = { * "default" = "Drupal\config_test\ConfigTestFormController" * } diff --git a/core/modules/config/tests/config_test/lib/Drupal/config_test/Entity/ConfigTest.php b/core/modules/config/tests/config_test/lib/Drupal/config_test/Entity/ConfigTest.php index 336afb8..3449b51 100644 --- a/core/modules/config/tests/config_test/lib/Drupal/config_test/Entity/ConfigTest.php +++ b/core/modules/config/tests/config_test/lib/Drupal/config_test/Entity/ConfigTest.php @@ -18,7 +18,7 @@ * label = @Translation("Test configuration"), * controllers = { * "storage" = "Drupal\config_test\ConfigTestStorageController", - * "list_builder" = "Drupal\config_test\ConfigTestListBuilder", + * "list" = "Drupal\config_test\ConfigTestListController", * "form" = { * "default" = "Drupal\config_test\ConfigTestFormController", * "delete" = "Drupal\config_test\Form\ConfigTestDeleteForm" diff --git a/core/modules/config_translation/config_translation.module b/core/modules/config_translation/config_translation.module index e500b9d..2204689 100644 --- a/core/modules/config_translation/config_translation.module +++ b/core/modules/config_translation/config_translation.module @@ -78,15 +78,15 @@ function config_translation_entity_type_alter(array &$entity_types) { foreach ($entity_types as $entity_type_id => $entity_type) { if ($entity_type->isSubclassOf('Drupal\Core\Config\Entity\ConfigEntityInterface')) { if ($entity_type_id == 'block') { - $class = 'Drupal\config_translation\Controller\ConfigTranslationBlockListBuilder'; + $class = 'Drupal\config_translation\Controller\ConfigTranslationBlockListController'; } elseif ($entity_type_id == 'field_instance_config') { - $class = 'Drupal\config_translation\Controller\ConfigTranslationFieldInstanceListBuilder'; + $class = 'Drupal\config_translation\Controller\ConfigTranslationFieldInstanceListController'; // Will be filled in dynamically, see \Drupal\field\Entity\FieldInstanceConfig::linkTemplates(). $entity_type->setLinkTemplate('drupal:config-translation-overview', 'config_translation.item.overview.'); } else { - $class = 'Drupal\config_translation\Controller\ConfigTranslationEntityListBuilder'; + $class = 'Drupal\config_translation\Controller\ConfigTranslationEntityListController'; } $entity_type->setControllerClass('config_translation_list', $class); diff --git a/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationBlockListBuilder.php b/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationBlockListBuilder.php deleted file mode 100644 index 90d61bb..0000000 --- a/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationBlockListBuilder.php +++ /dev/null @@ -1,105 +0,0 @@ -themes = $theme_handler->listInfo(); - } - - /** - * {@inheritdoc} - */ - public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { - return new static( - $entity_type, - $container->get('entity.manager')->getStorageController($entity_type->id()), - $container->get('theme_handler') - ); - } - - /** - * {@inheritdoc} - */ - public function getFilterLabels() { - $info = parent::getFilterLabels(); - - $info['placeholder'] = $this->t('Enter block, theme or category'); - $info['description'] = $this->t('Enter a part of the block, theme or category to filter by.'); - - return $info; - } - - /** - * {@inheritdoc} - */ - public function buildRow(EntityInterface $entity) { - $theme = $entity->get('theme'); - $plugin_definition = $entity->getPlugin()->getPluginDefinition(); - - $row['label'] = array( - 'data' => $this->getLabel($entity), - 'class' => 'table-filter-text-source', - ); - - $row['theme'] = array( - 'data' => String::checkPlain($this->themes[$theme]->info['name']), - 'class' => 'table-filter-text-source', - ); - - $row['category'] = array( - 'data' => String::checkPlain($plugin_definition['category']), - 'class' => 'table-filter-text-source', - ); - - $row['operations']['data'] = $this->buildOperations($entity); - - return $row; - } - - /** - * {@inheritdoc} - */ - public function buildHeader() { - $header['label'] = $this->t('Block'); - $header['theme'] = $this->t('Theme'); - $header['category'] = $this->t('Category'); - $header['operations'] = $this->t('Operations'); - return $header; - } - - /** - * {@inheritdoc} - */ - public function sortRows($a, $b) { - return $this->sortRowsMultiple($a, $b, array('theme', 'category', 'label')); - } - -} diff --git a/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationBlockListController.php b/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationBlockListController.php new file mode 100644 index 0000000..c69dcde --- /dev/null +++ b/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationBlockListController.php @@ -0,0 +1,105 @@ +themes = $theme_handler->listInfo(); + } + + /** + * {@inheritdoc} + */ + public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { + return new static( + $entity_type, + $container->get('entity.manager')->getStorageController($entity_type->id()), + $container->get('theme_handler') + ); + } + + /** + * {@inheritdoc} + */ + public function getFilterLabels() { + $info = parent::getFilterLabels(); + + $info['placeholder'] = $this->t('Enter block, theme or category'); + $info['description'] = $this->t('Enter a part of the block, theme or category to filter by.'); + + return $info; + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + $theme = $entity->get('theme'); + $plugin_definition = $entity->getPlugin()->getPluginDefinition(); + + $row['label'] = array( + 'data' => $this->getLabel($entity), + 'class' => 'table-filter-text-source', + ); + + $row['theme'] = array( + 'data' => String::checkPlain($this->themes[$theme]->info['name']), + 'class' => 'table-filter-text-source', + ); + + $row['category'] = array( + 'data' => String::checkPlain($plugin_definition['category']), + 'class' => 'table-filter-text-source', + ); + + $row['operations']['data'] = $this->buildOperations($entity); + + return $row; + } + + /** + * {@inheritdoc} + */ + public function buildHeader() { + $header['label'] = $this->t('Block'); + $header['theme'] = $this->t('Theme'); + $header['category'] = $this->t('Category'); + $header['operations'] = $this->t('Operations'); + return $header; + } + + /** + * {@inheritdoc} + */ + public function sortRows($a, $b) { + return $this->sortRowsMultiple($a, $b, array('theme', 'category', 'label')); + } + +} diff --git a/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationEntityListBuilder.php b/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationEntityListBuilder.php deleted file mode 100644 index 44f5aad..0000000 --- a/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationEntityListBuilder.php +++ /dev/null @@ -1,138 +0,0 @@ - $this->t('Enter label'), - 'description' => $this->t('Enter a part of the label or description to filter by.'), - ); - } - - /** - * {@inheritdoc} - */ - public function render() { - $table = parent::render(); - $filter = $this->getFilterLabels(); - - usort($table['#rows'], array($this, 'sortRows')); - - $build['filters'] = array( - '#type' => 'container', - '#attributes' => array( - 'class' => array('table-filter', 'js-show'), - ), - ); - - $build['filters']['text'] = array( - '#type' => 'search', - '#title' => $this->t('Search'), - '#size' => 30, - '#placeholder' => $filter['placeholder'], - '#attributes' => array( - 'class' => array('table-filter-text'), - 'data-table' => '.config-translation-entity-list', - 'autocomplete' => 'off', - 'title' => $filter['description'], - ), - ); - - $build['table'] = $table; - $build['table']['#attributes']['class'][] = 'config-translation-entity-list'; - $build['#attached']['library'][] = 'system/drupal.system.modules'; - - return $build; - } - - /** - * {@inheritdoc} - */ - public function buildRow(EntityInterface $entity) { - $row['label']['data'] = $this->getLabel($entity); - $row['label']['class'] = 'table-filter-text-source'; - return $row + parent::buildRow($entity); - } - - /** - * {@inheritdoc} - */ - public function buildHeader() { - $header['label'] = $this->t('Label'); - return $header + parent::buildHeader(); - } - - /** - * {@inheritdoc} - */ - public function buildOperations(EntityInterface $entity) { - $operations = parent::buildOperations($entity); - foreach (array_keys($operations['#links']) as $operation) { - // This is a translation UI for translators. Show the translation - // operation only. - if (!($operation == 'translate')) { - unset($operations['#links'][$operation]); - } - } - return $operations; - } - - /** - * {@inheritdoc} - */ - public function sortRows($a, $b) { - return $this->sortRowsMultiple($a, $b, array('label')); - } - - /** - * Sorts an array by multiple criteria. - * - * @param array $a - * First item for comparison. - * @param array $b - * Second item for comparison. - * @param array $keys - * The array keys to sort on. - * - * @return int - * The comparison result for uasort(). - */ - protected function sortRowsMultiple($a, $b, $keys) { - $key = array_shift($keys); - $a_value = (is_array($a) && isset($a[$key]['data'])) ? $a[$key]['data'] : ''; - $b_value = (is_array($b) && isset($b[$key]['data'])) ? $b[$key]['data'] : ''; - - if ($a_value == $b_value && !empty($keys)) { - return $this->sortRowsMultiple($a, $b, $keys); - } - - return strnatcasecmp($a_value, $b_value); - } - - /** - * {@inheritdoc} - */ - public function setMapperDefinition($mapper_definition) { - // @todo Why is this method called on all config list controllers? - return $this; - } - -} diff --git a/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationEntityListBuilderInterface.php b/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationEntityListBuilderInterface.php deleted file mode 100644 index 08791c8..0000000 --- a/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationEntityListBuilderInterface.php +++ /dev/null @@ -1,40 +0,0 @@ - $this->t('Enter label'), + 'description' => $this->t('Enter a part of the label or description to filter by.'), + ); + } + + /** + * {@inheritdoc} + */ + public function render() { + $table = parent::render(); + $filter = $this->getFilterLabels(); + + usort($table['#rows'], array($this, 'sortRows')); + + $build['filters'] = array( + '#type' => 'container', + '#attributes' => array( + 'class' => array('table-filter', 'js-show'), + ), + ); + + $build['filters']['text'] = array( + '#type' => 'search', + '#title' => $this->t('Search'), + '#size' => 30, + '#placeholder' => $filter['placeholder'], + '#attributes' => array( + 'class' => array('table-filter-text'), + 'data-table' => '.config-translation-entity-list', + 'autocomplete' => 'off', + 'title' => $filter['description'], + ), + ); + + $build['table'] = $table; + $build['table']['#attributes']['class'][] = 'config-translation-entity-list'; + $build['#attached']['library'][] = 'system/drupal.system.modules'; + + return $build; + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + $row['label']['data'] = $this->getLabel($entity); + $row['label']['class'] = 'table-filter-text-source'; + return $row + parent::buildRow($entity); + } + + /** + * {@inheritdoc} + */ + public function buildHeader() { + $header['label'] = $this->t('Label'); + return $header + parent::buildHeader(); + } + + /** + * {@inheritdoc} + */ + public function buildOperations(EntityInterface $entity) { + $operations = parent::buildOperations($entity); + foreach (array_keys($operations['#links']) as $operation) { + // This is a translation UI for translators. Show the translation + // operation only. + if (!($operation == 'translate')) { + unset($operations['#links'][$operation]); + } + } + return $operations; + } + + /** + * {@inheritdoc} + */ + public function sortRows($a, $b) { + return $this->sortRowsMultiple($a, $b, array('label')); + } + + /** + * Sorts an array by multiple criteria. + * + * @param array $a + * First item for comparison. + * @param array $b + * Second item for comparison. + * @param array $keys + * The array keys to sort on. + * + * @return int + * The comparison result for uasort(). + */ + protected function sortRowsMultiple($a, $b, $keys) { + $key = array_shift($keys); + $a_value = (is_array($a) && isset($a[$key]['data'])) ? $a[$key]['data'] : ''; + $b_value = (is_array($b) && isset($b[$key]['data'])) ? $b[$key]['data'] : ''; + + if ($a_value == $b_value && !empty($keys)) { + return $this->sortRowsMultiple($a, $b, $keys); + } + + return strnatcasecmp($a_value, $b_value); + } + + /** + * {@inheritdoc} + */ + public function setMapperDefinition($mapper_definition) { + // @todo Why is this method called on all config list controllers? + return $this; + } + +} diff --git a/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationEntityListControllerInterface.php b/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationEntityListControllerInterface.php new file mode 100644 index 0000000..f2340b3 --- /dev/null +++ b/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationEntityListControllerInterface.php @@ -0,0 +1,40 @@ +get('entity.manager'); - return new static( - $entity_type, - $entity_manager->getStorageController($entity_type->id()), - $entity_manager - ); - } - - /** - * Constructs a new ConfigTranslationFieldInstanceListBuilder object. - * - * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type - * The entity type definition. - * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage - * The entity storage controller class. - * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager - * The entity manager. - */ - public function __construct(EntityTypeInterface $entity_type, EntityStorageControllerInterface $storage, EntityManagerInterface $entity_manager) { - parent::__construct($entity_type, $storage); - $this->entityManager = $entity_manager; - } - - /** - * {@inheritdoc} - */ - public function setMapperDefinition($mapper_definition) { - $this->baseEntityType = $mapper_definition['base_entity_type']; - $this->baseEntityInfo = $this->entityManager->getDefinition($this->baseEntityType); - $this->baseEntityBundles = $this->entityManager->getBundleInfo($this->baseEntityType); - return $this; - } - - /** - * {@inheritdoc} - */ - public function load() { - $entities = array(); - // It is not possible to use the standard load method, because this needs - // all field instance entities only for the given baseEntityType. - foreach (Field::fieldInfo()->getInstances($this->baseEntityType) as $fields) { - $entities = array_merge($entities, array_values($fields)); - } - return $entities; - } - - /** - * {@inheritdoc} - */ - public function getFilterLabels() { - $info = parent::getFilterLabels(); - $bundle = $this->baseEntityInfo->getBundleLabel() ?: $this->t('Bundle'); - $bundle = Unicode::strtolower($bundle); - - $info['placeholder'] = $this->t('Enter field or @bundle', array('@bundle' => $bundle)); - $info['description'] = $this->t('Enter a part of the field or @bundle to filter by.', array('@bundle' => $bundle)); - - return $info; - } - - /** - * {@inheritdoc} - */ - public function buildRow(EntityInterface $entity) { - $row['label'] = array( - 'data' => $this->getLabel($entity), - 'class' => 'table-filter-text-source', - ); - - if ($this->displayBundle()) { - $bundle = $entity->get('bundle'); - $row['bundle'] = array( - 'data' => String::checkPlain($this->baseEntityBundles[$bundle]['label']), - 'class' => 'table-filter-text-source', - ); - } - - return $row + parent::buildRow($entity); - } - - /** - * {@inheritdoc} - */ - public function buildHeader() { - $header['label'] = $this->t('Field'); - if ($this->displayBundle()) { - $header['bundle'] = $this->baseEntityInfo->getBundleLabel() ?: $this->t('Bundle'); - } - return $header + parent::buildHeader(); - } - - /** - * Controls the visibility of the bundle column on field instance list pages. - * - * @return bool - * Whenever the bundle is displayed or not. - */ - public function displayBundle() { - // The bundle key is explicitly defined in the entity definition. - if ($this->baseEntityInfo->getKey('bundle')) { - return TRUE; - } - - // There is more than one bundle defined. - if (count($this->baseEntityBundles) > 1) { - return TRUE; - } - - // The defined bundle ones not match the entity type name. - if (!empty($this->baseEntityBundles) && !isset($this->baseEntityBundles[$this->baseEntityType])) { - return TRUE; - } - - return FALSE; - } - - /** - * {@inheritdoc} - */ - public function sortRows($a, $b) { - return $this->sortRowsMultiple($a, $b, array('bundle', 'label')); - } - -} diff --git a/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationFieldInstanceListController.php b/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationFieldInstanceListController.php new file mode 100644 index 0000000..760b8cb --- /dev/null +++ b/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationFieldInstanceListController.php @@ -0,0 +1,179 @@ +get('entity.manager'); + return new static( + $entity_type, + $entity_manager->getStorageController($entity_type->id()), + $entity_manager + ); + } + + /** + * Constructs a new ConfigTranslationFieldInstanceListController object. + * + * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type + * The entity type definition. + * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage + * The entity storage controller class. + * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager + * The entity manager. + */ + public function __construct(EntityTypeInterface $entity_type, EntityStorageControllerInterface $storage, EntityManagerInterface $entity_manager) { + parent::__construct($entity_type, $storage); + $this->entityManager = $entity_manager; + } + + /** + * {@inheritdoc} + */ + public function setMapperDefinition($mapper_definition) { + $this->baseEntityType = $mapper_definition['base_entity_type']; + $this->baseEntityInfo = $this->entityManager->getDefinition($this->baseEntityType); + $this->baseEntityBundles = $this->entityManager->getBundleInfo($this->baseEntityType); + return $this; + } + + /** + * {@inheritdoc} + */ + public function load() { + $entities = array(); + // It is not possible to use the standard load method, because this needs + // all field instance entities only for the given baseEntityType. + foreach (Field::fieldInfo()->getInstances($this->baseEntityType) as $fields) { + $entities = array_merge($entities, array_values($fields)); + } + return $entities; + } + + /** + * {@inheritdoc} + */ + public function getFilterLabels() { + $info = parent::getFilterLabels(); + $bundle = $this->baseEntityInfo->getBundleLabel() ?: $this->t('Bundle'); + $bundle = Unicode::strtolower($bundle); + + $info['placeholder'] = $this->t('Enter field or @bundle', array('@bundle' => $bundle)); + $info['description'] = $this->t('Enter a part of the field or @bundle to filter by.', array('@bundle' => $bundle)); + + return $info; + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + $row['label'] = array( + 'data' => $this->getLabel($entity), + 'class' => 'table-filter-text-source', + ); + + if ($this->displayBundle()) { + $bundle = $entity->get('bundle'); + $row['bundle'] = array( + 'data' => String::checkPlain($this->baseEntityBundles[$bundle]['label']), + 'class' => 'table-filter-text-source', + ); + } + + return $row + parent::buildRow($entity); + } + + /** + * {@inheritdoc} + */ + public function buildHeader() { + $header['label'] = $this->t('Field'); + if ($this->displayBundle()) { + $header['bundle'] = $this->baseEntityInfo->getBundleLabel() ?: $this->t('Bundle'); + } + return $header + parent::buildHeader(); + } + + /** + * Controls the visibility of the bundle column on field instance list pages. + * + * @return bool + * Whenever the bundle is displayed or not. + */ + public function displayBundle() { + // The bundle key is explicitly defined in the entity definition. + if ($this->baseEntityInfo->getKey('bundle')) { + return TRUE; + } + + // There is more than one bundle defined. + if (count($this->baseEntityBundles) > 1) { + return TRUE; + } + + // The defined bundle ones not match the entity type name. + if (!empty($this->baseEntityBundles) && !isset($this->baseEntityBundles[$this->baseEntityType])) { + return TRUE; + } + + return FALSE; + } + + /** + * {@inheritdoc} + */ + public function sortRows($a, $b) { + return $this->sortRowsMultiple($a, $b, array('bundle', 'label')); + } + +} diff --git a/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationMapperList.php b/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationMapperList.php index 23007e9..14f9724 100644 --- a/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationMapperList.php +++ b/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationMapperList.php @@ -120,7 +120,7 @@ public function buildHeader() { * @return array * A renderable array of operation links. * - * @see \Drupal\Core\Entity\EntityList::buildOperations() + * @see \Drupal\Core\Entity\EntityListController::buildOperations() */ protected function buildOperations(ConfigMapperInterface $mapper) { // Retrieve and sort operations. diff --git a/core/modules/contact/lib/Drupal/contact/CategoryListBuilder.php b/core/modules/contact/lib/Drupal/contact/CategoryListBuilder.php deleted file mode 100644 index 37169ff..0000000 --- a/core/modules/contact/lib/Drupal/contact/CategoryListBuilder.php +++ /dev/null @@ -1,49 +0,0 @@ -getLabel($entity); - // Special case the personal category. - if ($entity->id() == 'personal') { - $row['recipients'] = t('Selected user'); - $row['selected'] = t('No'); - } - else { - $row['recipients'] = String::checkPlain(implode(', ', $entity->recipients)); - $default_category = \Drupal::config('contact.settings')->get('default_category'); - $row['selected'] = ($default_category == $entity->id() ? t('Yes') : t('No')); - } - return $row + parent::buildRow($entity); - } - -} diff --git a/core/modules/contact/lib/Drupal/contact/CategoryListController.php b/core/modules/contact/lib/Drupal/contact/CategoryListController.php new file mode 100644 index 0000000..e68789b --- /dev/null +++ b/core/modules/contact/lib/Drupal/contact/CategoryListController.php @@ -0,0 +1,46 @@ +getLabel($entity); + // Special case the personal category. + if ($entity->id() == 'personal') { + $row['recipients'] = t('Selected user'); + $row['selected'] = t('No'); + } + else { + $row['recipients'] = String::checkPlain(implode(', ', $entity->recipients)); + $default_category = \Drupal::config('contact.settings')->get('default_category'); + $row['selected'] = ($default_category == $entity->id() ? t('Yes') : t('No')); + } + return $row + parent::buildRow($entity); + } + +} diff --git a/core/modules/contact/lib/Drupal/contact/Entity/Category.php b/core/modules/contact/lib/Drupal/contact/Entity/Category.php index 0fc1d7d..a2fe218 100644 --- a/core/modules/contact/lib/Drupal/contact/Entity/Category.php +++ b/core/modules/contact/lib/Drupal/contact/Entity/Category.php @@ -19,7 +19,7 @@ * label = @Translation("Contact category"), * controllers = { * "access" = "Drupal\contact\CategoryAccessController", - * "list_builder" = "Drupal\contact\CategoryListBuilder", + * "list" = "Drupal\contact\CategoryListController", * "form" = { * "add" = "Drupal\contact\CategoryFormController", * "edit" = "Drupal\contact\CategoryFormController", diff --git a/core/modules/entity/lib/Drupal/entity/Entity/EntityFormMode.php b/core/modules/entity/lib/Drupal/entity/Entity/EntityFormMode.php index 4e58485..4b57139 100644 --- a/core/modules/entity/lib/Drupal/entity/Entity/EntityFormMode.php +++ b/core/modules/entity/lib/Drupal/entity/Entity/EntityFormMode.php @@ -32,7 +32,7 @@ * label = @Translation("Form mode"), * controllers = { * "storage" = "Drupal\entity\EntityDisplayModeStorageController", - * "list_builder" = "Drupal\entity\EntityFormModeListBuilder", + * "list" = "Drupal\entity\EntityFormModeListController", * "form" = { * "add" = "Drupal\entity\Form\EntityFormModeAddForm", * "edit" = "Drupal\entity\Form\EntityDisplayModeEditForm", diff --git a/core/modules/entity/lib/Drupal/entity/Entity/EntityViewMode.php b/core/modules/entity/lib/Drupal/entity/Entity/EntityViewMode.php index df31790..2d98442 100644 --- a/core/modules/entity/lib/Drupal/entity/Entity/EntityViewMode.php +++ b/core/modules/entity/lib/Drupal/entity/Entity/EntityViewMode.php @@ -32,7 +32,7 @@ * id = "view_mode", * label = @Translation("View mode"), * controllers = { - * "list_builder" = "Drupal\entity\EntityDisplayModeListBuilder", + * "list" = "Drupal\entity\EntityDisplayModeListController", * "form" = { * "add" = "Drupal\entity\Form\EntityDisplayModeAddForm", * "edit" = "Drupal\entity\Form\EntityDisplayModeEditForm", diff --git a/core/modules/entity/lib/Drupal/entity/EntityDisplayModeListBuilder.php b/core/modules/entity/lib/Drupal/entity/EntityDisplayModeListBuilder.php deleted file mode 100644 index 67f4a2d..0000000 --- a/core/modules/entity/lib/Drupal/entity/EntityDisplayModeListBuilder.php +++ /dev/null @@ -1,148 +0,0 @@ -entityTypes = $entity_types; - } - - /** - * {@inheritdoc} - */ - public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { - $entity_manager = $container->get('entity.manager'); - return new static( - $entity_type, - $entity_manager->getStorageController($entity_type->id()), - $entity_manager->getDefinitions() - ); - } - - /** - * {@inheritdoc} - */ - public function buildHeader() { - $header['label'] = t('Label'); - return $header + parent::buildHeader(); - } - - /** - * {@inheritdoc} - */ - public function buildRow(EntityInterface $entity) { - $row['label'] = $this->getLabel($entity); - return $row + parent::buildRow($entity); - } - - /** - * {@inheritdoc} - */ - public function load() { - $entities = array(); - foreach (parent::load() as $entity) { - $entities[$entity->getTargetType()][] = $entity; - } - return $entities; - } - - /** - * {@inheritdoc} - */ - public function render() { - $build = array(); - foreach ($this->load() as $entity_type => $entities) { - if (!isset($this->entityTypes[$entity_type])) { - continue; - } - - // Filter entities - if ($this->entityTypes[$entity_type]->isFieldable() && !$this->isValidEntity($entity_type)) { - continue; - } - - $table = array( - '#prefix' => '

' . $this->entityTypes[$entity_type]->getLabel() . '

', - '#type' => 'table', - '#header' => $this->buildHeader(), - '#rows' => array(), - ); - foreach ($entities as $entity) { - if ($row = $this->buildRow($entity)) { - $table['#rows'][$entity->id()] = $row; - } - } - - // Move content at the top. - if ($entity_type == 'node') { - $table['#weight'] = -10; - } - - $short_type = str_replace('_mode', '', $this->entityTypeId); - $table['#rows']['_add_new'][] = array( - 'data' => array( - '#type' => 'link', - '#href' => "admin/structure/display-modes/$short_type/add/$entity_type", - '#title' => t('Add new %label @entity-type', array('%label' => $this->entityTypes[$entity_type]->getLabel(), '@entity-type' => $this->entityType->getLowercaseLabel())), - '#options' => array( - 'html' => TRUE, - ), - ), - 'colspan' => count($table['#header']), - ); - $build[$entity_type] = $table; - } - return $build; - } - - /** - * Filters entities based on their controllers. - * - * @param $entity_type - * The entity type of the entity that needs to be validated. - * - * @return bool - * TRUE if the entity has the correct controller, FALSE if the entity - * doesn't has the correct controller. - */ - protected function isValidEntity($entity_type) { - return $this->entityTypes[$entity_type]->hasViewBuilderClass(); - } - -} diff --git a/core/modules/entity/lib/Drupal/entity/EntityDisplayModeListController.php b/core/modules/entity/lib/Drupal/entity/EntityDisplayModeListController.php new file mode 100644 index 0000000..3e244b3 --- /dev/null +++ b/core/modules/entity/lib/Drupal/entity/EntityDisplayModeListController.php @@ -0,0 +1,146 @@ +entityTypes = $entity_types; + } + + /** + * {@inheritdoc} + */ + public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { + $entity_manager = $container->get('entity.manager'); + return new static( + $entity_type, + $entity_manager->getStorageController($entity_type->id()), + $entity_manager->getDefinitions() + ); + } + + /** + * {@inheritdoc} + */ + public function buildHeader() { + $header['label'] = t('Label'); + return $header + parent::buildHeader(); + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + $row['label'] = $this->getLabel($entity); + return $row + parent::buildRow($entity); + } + + /** + * {@inheritdoc} + */ + public function load() { + $entities = array(); + foreach (parent::load() as $entity) { + $entities[$entity->getTargetType()][] = $entity; + } + return $entities; + } + + /** + * {@inheritdoc} + */ + public function render() { + $build = array(); + foreach ($this->load() as $entity_type => $entities) { + if (!isset($this->entityTypes[$entity_type])) { + continue; + } + + // Filter entities + if ($this->entityTypes[$entity_type]->isFieldable() && !$this->isValidEntity($entity_type)) { + continue; + } + + $table = array( + '#prefix' => '

' . $this->entityTypes[$entity_type]->getLabel() . '

', + '#type' => 'table', + '#header' => $this->buildHeader(), + '#rows' => array(), + ); + foreach ($entities as $entity) { + if ($row = $this->buildRow($entity)) { + $table['#rows'][$entity->id()] = $row; + } + } + + // Move content at the top. + if ($entity_type == 'node') { + $table['#weight'] = -10; + } + + $short_type = str_replace('_mode', '', $this->entityTypeId); + $table['#rows']['_add_new'][] = array( + 'data' => array( + '#type' => 'link', + '#href' => "admin/structure/display-modes/$short_type/add/$entity_type", + '#title' => t('Add new %label @entity-type', array('%label' => $this->entityTypes[$entity_type]->getLabel(), '@entity-type' => $this->entityType->getLowercaseLabel())), + '#options' => array( + 'html' => TRUE, + ), + ), + 'colspan' => count($table['#header']), + ); + $build[$entity_type] = $table; + } + return $build; + } + + /** + * Filters entities based on their controllers. + * + * @param $entity_type + * The entity type of the entity that needs to be validated. + * + * @return bool + * TRUE if the entity has the correct controller, FALSE if the entity + * doesn't has the correct controller. + */ + protected function isValidEntity($entity_type) { + return $this->entityTypes[$entity_type]->hasViewBuilderClass(); + } + +} diff --git a/core/modules/entity/lib/Drupal/entity/EntityFormModeListBuilder.php b/core/modules/entity/lib/Drupal/entity/EntityFormModeListBuilder.php deleted file mode 100644 index 7c556ab..0000000 --- a/core/modules/entity/lib/Drupal/entity/EntityFormModeListBuilder.php +++ /dev/null @@ -1,30 +0,0 @@ -entityTypes[$entity_type]->hasFormClasses(); - } - -} diff --git a/core/modules/entity/lib/Drupal/entity/EntityFormModeListController.php b/core/modules/entity/lib/Drupal/entity/EntityFormModeListController.php new file mode 100644 index 0000000..04bc923 --- /dev/null +++ b/core/modules/entity/lib/Drupal/entity/EntityFormModeListController.php @@ -0,0 +1,28 @@ +entityTypes[$entity_type]->hasFormClasses(); + } + +} diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module index 5e218f2..a08593a 100644 --- a/core/modules/field_ui/field_ui.module +++ b/core/modules/field_ui/field_ui.module @@ -121,7 +121,7 @@ function field_ui_element_info() { function field_ui_entity_type_build(array &$entity_types) { /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */ $entity_types['field_instance_config']->setFormClass('delete', 'Drupal\field_ui\Form\FieldInstanceConfigDeleteForm'); - $entity_types['field_config']->setListBuilderClass('Drupal\field_ui\FieldConfigListBuilder'); + $entity_types['field_config']->setListClass('Drupal\field_ui\FieldConfigListController'); foreach ($entity_types as $entity_type) { if ($bundle = $entity_type->getBundleOf()) { diff --git a/core/modules/field_ui/lib/Drupal/field_ui/FieldConfigListBuilder.php b/core/modules/field_ui/lib/Drupal/field_ui/FieldConfigListBuilder.php deleted file mode 100644 index d6dfa49..0000000 --- a/core/modules/field_ui/lib/Drupal/field_ui/FieldConfigListBuilder.php +++ /dev/null @@ -1,124 +0,0 @@ -getStorageController($entity_type->id())); - - $this->entityManager = $entity_manager; - $this->bundles = entity_get_bundles(); - $this->fieldTypeManager = $field_type_manager; - $this->fieldTypes = $this->fieldTypeManager->getConfigurableDefinitions(); - } - - /** - * {@inheritdoc} - */ - public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { - return new static( - $entity_type, - $container->get('entity.manager'), - $container->get('plugin.manager.field.field_type') - ); - } - - /** - * {@inheritdoc} - */ - public function buildHeader() { - $header['id'] = t('Field name'); - $header['type'] = array( - 'data' => t('Field type'), - 'class' => array(RESPONSIVE_PRIORITY_MEDIUM), - ); - $header['usage'] = t('Used in'); - return $header; - } - - /** - * {@inheritdoc} - */ - public function buildRow(EntityInterface $field) { - if ($field->locked) { - $row['class'] = array('menu-disabled'); - $row['data']['id'] = t('@field_name (Locked)', array('@field_name' => $field->name)); - } - else { - $row['data']['id'] = $field->name; - } - - $field_type = $this->fieldTypes[$field->type]; - $row['data']['type'] = t('@type (module: @module)', array('@type' => $field_type['label'], '@module' => $field_type['provider'])); - - $usage = array(); - foreach ($field->getBundles() as $bundle) { - if ($route_info = FieldUI::getOverviewRouteInfo($field->entity_type, $bundle)) { - $usage[] = \Drupal::l($this->bundles[$field->entity_type][$bundle]['label'], $route_info['route_name'], $route_info['route_parameters'], $route_info['options']); - } - else { - $usage[] = $this->bundles[$field->entity_type][$bundle]['label']; - } - } - $row['data']['usage'] = implode(', ', $usage); - return $row; - } - -} diff --git a/core/modules/field_ui/lib/Drupal/field_ui/FieldConfigListController.php b/core/modules/field_ui/lib/Drupal/field_ui/FieldConfigListController.php new file mode 100644 index 0000000..2b473ae --- /dev/null +++ b/core/modules/field_ui/lib/Drupal/field_ui/FieldConfigListController.php @@ -0,0 +1,121 @@ +getStorageController($entity_type->id())); + + $this->entityManager = $entity_manager; + $this->bundles = entity_get_bundles(); + $this->fieldTypeManager = $field_type_manager; + $this->fieldTypes = $this->fieldTypeManager->getConfigurableDefinitions(); + } + + /** + * {@inheritdoc} + */ + public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { + return new static( + $entity_type, + $container->get('entity.manager'), + $container->get('plugin.manager.field.field_type') + ); + } + + /** + * {@inheritdoc} + */ + public function buildHeader() { + $header['id'] = t('Field name'); + $header['type'] = array( + 'data' => t('Field type'), + 'class' => array(RESPONSIVE_PRIORITY_MEDIUM), + ); + $header['usage'] = t('Used in'); + return $header; + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $field) { + if ($field->locked) { + $row['class'] = array('menu-disabled'); + $row['data']['id'] = t('@field_name (Locked)', array('@field_name' => $field->name)); + } + else { + $row['data']['id'] = $field->name; + } + + $field_type = $this->fieldTypes[$field->type]; + $row['data']['type'] = t('@type (module: @module)', array('@type' => $field_type['label'], '@module' => $field_type['provider'])); + + $usage = array(); + foreach ($field->getBundles() as $bundle) { + if ($route_info = FieldUI::getOverviewRouteInfo($field->entity_type, $bundle)) { + $usage[] = \Drupal::l($this->bundles[$field->entity_type][$bundle]['label'], $route_info['route_name'], $route_info['route_parameters'], $route_info['options']); + } + else { + $usage[] = $this->bundles[$field->entity_type][$bundle]['label']; + } + } + $row['data']['usage'] = implode(', ', $usage); + return $row; + } + +} diff --git a/core/modules/filter/lib/Drupal/filter/Entity/FilterFormat.php b/core/modules/filter/lib/Drupal/filter/Entity/FilterFormat.php index 8e0aadd..cf3bd07 100644 --- a/core/modules/filter/lib/Drupal/filter/Entity/FilterFormat.php +++ b/core/modules/filter/lib/Drupal/filter/Entity/FilterFormat.php @@ -27,7 +27,7 @@ * "edit" = "Drupal\filter\FilterFormatEditFormController", * "disable" = "Drupal\filter\Form\FilterDisableForm" * }, - * "list_builder" = "Drupal\filter\FilterFormatListBuilder", + * "list" = "Drupal\filter\FilterFormatListController", * "access" = "Drupal\filter\FilterFormatAccessController", * }, * config_prefix = "format", diff --git a/core/modules/filter/lib/Drupal/filter/FilterFormatListBuilder.php b/core/modules/filter/lib/Drupal/filter/FilterFormatListBuilder.php deleted file mode 100644 index 7ba51af..0000000 --- a/core/modules/filter/lib/Drupal/filter/FilterFormatListBuilder.php +++ /dev/null @@ -1,154 +0,0 @@ -configFactory = $config_factory; - } - - /** - * {@inheritdoc} - */ - public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { - return new static( - $entity_type, - $container->get('entity.manager')->getStorageController($entity_type->id()), - $container->get('config.factory') - ); - } - - /** - * {@inheritdoc} - */ - public function getFormId() { - return 'filter_admin_overview'; - } - - /** - * {@inheritdoc} - */ - public function load() { - // Only list enabled filters. - return array_filter(parent::load(), function ($entity) { - return $entity->status(); - }); - } - - /** - * {@inheritdoc} - */ - public function buildHeader() { - $header['label'] = t('Name'); - $header['roles'] = t('Roles'); - return $header + parent::buildHeader(); - } - - /** - * {@inheritdoc} - */ - public function buildRow(EntityInterface $entity) { - // Check whether this is the fallback text format. This format is available - // to all roles and cannot be disabled via the admin interface. - if ($entity->isFallbackFormat()) { - $row['label'] = String::placeholder($entity->label()); - - $fallback_choice = $this->configFactory->get('filter.settings')->get('always_show_fallback_choice'); - if ($fallback_choice) { - $roles_markup = String::placeholder(t('All roles may use this format')); - } - else { - $roles_markup = String::placeholder(t('This format is shown when no other formats are available')); - } - } - else { - $row['label'] = $this->getLabel($entity); - $roles = array_map('\Drupal\Component\Utility\String::checkPlain', filter_get_roles_by_format($entity)); - $roles_markup = $roles ? implode(', ', $roles) : t('No roles may use this format'); - } - - $row['roles'] = !empty($this->weightKey) ? array('#markup' => $roles_markup) : $roles_markup; - - return $row + parent::buildRow($entity); - } - - /** - * {@inheritdoc} - */ - public function getOperations(EntityInterface $entity) { - $operations = parent::getOperations($entity); - - if (isset($operations['edit'])) { - $operations['edit']['title'] = t('Configure'); - } - - // The fallback format may not be disabled. - if ($entity->isFallbackFormat()) { - unset($operations['disable']); - } - - return $operations; - } - - /** - * {@inheritdoc} - */ - public function buildForm(array $form, array &$form_state) { - $form = parent::buildForm($form, $form_state); - $form['actions']['submit']['#value'] = t('Save changes'); - return $form; - } - /** - * {@inheritdoc} - */ - public function submitForm(array &$form, array &$form_state) { - parent::submitForm($form, $form_state); - - filter_formats_reset(); - drupal_set_message(t('The text format ordering has been saved.')); - } - -} diff --git a/core/modules/filter/lib/Drupal/filter/FilterFormatListController.php b/core/modules/filter/lib/Drupal/filter/FilterFormatListController.php new file mode 100644 index 0000000..e64dce8 --- /dev/null +++ b/core/modules/filter/lib/Drupal/filter/FilterFormatListController.php @@ -0,0 +1,153 @@ +configFactory = $config_factory; + } + + /** + * {@inheritdoc} + */ + public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { + return new static( + $entity_type, + $container->get('entity.manager')->getStorageController($entity_type->id()), + $container->get('config.factory') + ); + } + + /** + * {@inheritdoc} + */ + public function getFormId() { + return 'filter_admin_overview'; + } + + /** + * {@inheritdoc} + */ + public function load() { + // Only list enabled filters. + return array_filter(parent::load(), function ($entity) { + return $entity->status(); + }); + } + + /** + * {@inheritdoc} + */ + public function buildHeader() { + $header['label'] = t('Name'); + $header['roles'] = t('Roles'); + return $header + parent::buildHeader(); + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + // Check whether this is the fallback text format. This format is available + // to all roles and cannot be disabled via the admin interface. + if ($entity->isFallbackFormat()) { + $row['label'] = String::placeholder($entity->label()); + + $fallback_choice = $this->configFactory->get('filter.settings')->get('always_show_fallback_choice'); + if ($fallback_choice) { + $roles_markup = String::placeholder(t('All roles may use this format')); + } + else { + $roles_markup = String::placeholder(t('This format is shown when no other formats are available')); + } + } + else { + $row['label'] = $this->getLabel($entity); + $roles = array_map('\Drupal\Component\Utility\String::checkPlain', filter_get_roles_by_format($entity)); + $roles_markup = $roles ? implode(', ', $roles) : t('No roles may use this format'); + } + + $row['roles'] = !empty($this->weightKey) ? array('#markup' => $roles_markup) : $roles_markup; + + return $row + parent::buildRow($entity); + } + + /** + * {@inheritdoc} + */ + public function getOperations(EntityInterface $entity) { + $operations = parent::getOperations($entity); + + if (isset($operations['edit'])) { + $operations['edit']['title'] = t('Configure'); + } + + // The fallback format may not be disabled. + if ($entity->isFallbackFormat()) { + unset($operations['disable']); + } + + return $operations; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, array &$form_state) { + $form = parent::buildForm($form, $form_state); + $form['actions']['submit']['#value'] = t('Save changes'); + return $form; + } + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + parent::submitForm($form, $form_state); + + filter_formats_reset(); + drupal_set_message(t('The text format ordering has been saved.')); + } + +} diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module index c0e8d3a..959a700 100644 --- a/core/modules/forum/forum.module +++ b/core/modules/forum/forum.module @@ -539,6 +539,23 @@ function forum_form_node_form_alter(&$form, &$form_state, $form_id) { } /** + * Render API callback: Lists nodes based on the element's #query property. + * + * This function can be used as a #pre_render callback. + * + * @see \Drupal\forum\Plugin\block\block\NewTopicsBlock::build() + * @see \Drupal\forum\Plugin\block\block\ActiveTopicsBlock::build() + */ +function forum_block_view_pre_render($elements) { + $result = $elements['#query']->execute(); + if ($node_title_list = node_title_list($result)) { + $elements['forum_list'] = $node_title_list; + $elements['forum_more'] = array('#theme' => 'more_link', '#url' => 'forum', '#title' => t('Read the latest forum topics.')); + } + return $elements; +} + +/** * Implements hook_preprocess_HOOK() for block templates. */ function forum_preprocess_block(&$variables) { diff --git a/core/modules/forum/lib/Drupal/forum/Plugin/Block/ActiveTopicsBlock.php b/core/modules/forum/lib/Drupal/forum/Plugin/Block/ActiveTopicsBlock.php index 133529a..d83f736 100644 --- a/core/modules/forum/lib/Drupal/forum/Plugin/Block/ActiveTopicsBlock.php +++ b/core/modules/forum/lib/Drupal/forum/Plugin/Block/ActiveTopicsBlock.php @@ -21,13 +21,17 @@ class ActiveTopicsBlock extends ForumBlockBase { /** * {@inheritdoc} */ - protected function buildForumQuery() { - return db_select('forum_index', 'f') + public function build() { + $query = db_select('forum_index', 'f') ->fields('f') ->addTag('node_access') ->addMetaData('base_table', 'forum_index') ->orderBy('f.last_comment_timestamp', 'DESC') ->range(0, $this->configuration['block_count']); + + return array( + drupal_render_cache_by_query($query, 'forum_block_view'), + ); } } diff --git a/core/modules/forum/lib/Drupal/forum/Plugin/Block/ForumBlockBase.php b/core/modules/forum/lib/Drupal/forum/Plugin/Block/ForumBlockBase.php index 6b760a9..f1c2f4e 100644 --- a/core/modules/forum/lib/Drupal/forum/Plugin/Block/ForumBlockBase.php +++ b/core/modules/forum/lib/Drupal/forum/Plugin/Block/ForumBlockBase.php @@ -9,7 +9,6 @@ use Drupal\block\BlockBase; use Drupal\Core\Session\AccountInterface; -use Drupal\Core\Cache\Cache; /** * Provides a base class for Forum blocks. @@ -19,32 +18,9 @@ /** * {@inheritdoc} */ - public function build() { - $result = $this->buildForumQuery()->execute(); - if ($node_title_list = node_title_list($result)) { - $elements['forum_list'] = $node_title_list; - $elements['forum_more'] = array( - '#theme' => 'more_link', - '#url' => 'forum', - '#title' => t('Read the latest forum topics.') - ); - } - return $elements; - } - - /** - * Builds the select query to use for this forum block. - * - * @return \Drupal\Core\Database\Query\Select - * A Select object. - */ - abstract protected function buildForumQuery(); - - /** - * {@inheritdoc} - */ public function defaultConfiguration() { return array( + 'cache' => DRUPAL_CACHE_CUSTOM, 'properties' => array( 'administrative' => TRUE, ), @@ -80,11 +56,4 @@ public function blockSubmit($form, &$form_state) { $this->configuration['block_count'] = $form_state['values']['block_count']; } - /** - * {@inheritdoc} - */ - public function getCacheKeys() { - return array_merge(parent::getCacheKeys(), Cache::keyFromQuery($this->buildForumQuery())); - } - } diff --git a/core/modules/forum/lib/Drupal/forum/Plugin/Block/NewTopicsBlock.php b/core/modules/forum/lib/Drupal/forum/Plugin/Block/NewTopicsBlock.php index 635dab4..8b75a83 100644 --- a/core/modules/forum/lib/Drupal/forum/Plugin/Block/NewTopicsBlock.php +++ b/core/modules/forum/lib/Drupal/forum/Plugin/Block/NewTopicsBlock.php @@ -21,12 +21,17 @@ class NewTopicsBlock extends ForumBlockBase { /** * {@inheritdoc} */ - protected function buildForumQuery() { - return db_select('forum_index', 'f') + public function build() { + $query = db_select('forum_index', 'f') ->fields('f') ->addTag('node_access') ->addMetaData('base_table', 'forum_index') ->orderBy('f.created', 'DESC') ->range(0, $this->configuration['block_count']); + + return array( + drupal_render_cache_by_query($query, 'forum_block_view'), + ); } + } diff --git a/core/modules/image/lib/Drupal/image/Entity/ImageStyle.php b/core/modules/image/lib/Drupal/image/Entity/ImageStyle.php index 55f19a6..2aef8fc 100644 --- a/core/modules/image/lib/Drupal/image/Entity/ImageStyle.php +++ b/core/modules/image/lib/Drupal/image/Entity/ImageStyle.php @@ -30,7 +30,7 @@ * "delete" = "Drupal\image\Form\ImageStyleDeleteForm", * "flush" = "Drupal\image\Form\ImageStyleFlushForm" * }, - * "list_builder" = "Drupal\image\ImageStyleListBuilder", + * "list" = "Drupal\image\ImageStyleListController", * }, * admin_permission = "administer image styles", * config_prefix = "style", diff --git a/core/modules/image/lib/Drupal/image/ImageStyleListBuilder.php b/core/modules/image/lib/Drupal/image/ImageStyleListBuilder.php deleted file mode 100644 index e6eac9e..0000000 --- a/core/modules/image/lib/Drupal/image/ImageStyleListBuilder.php +++ /dev/null @@ -1,97 +0,0 @@ -urlGenerator = $url_generator; - } - - /** - * {@inheritdoc} - */ - public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { - return new static( - $entity_type, - $container->get('entity.manager')->getStorageController($entity_type->id()), - $container->get('url_generator'), - $container->get('string_translation') - ); - } - - /** - * {@inheritdoc} - */ - public function buildHeader() { - $header['label'] = $this->t('Style name'); - return $header + parent::buildHeader(); - } - - /** - * {@inheritdoc} - */ - public function buildRow(EntityInterface $entity) { - $row['label'] = $this->getLabel($entity); - return $row + parent::buildRow($entity); - } - - /** - * {@inheritdoc} - */ - public function getOperations(EntityInterface $entity) { - $flush = array( - 'title' => t('Flush'), - 'weight' => 200, - ) + $entity->urlInfo('flush-form'); - - return parent::getOperations($entity) + array('flush' => $flush); - } - - /** - * {@inheritdoc} - */ - public function render() { - $build = parent::render(); - $build['#empty'] = $this->t('There are currently no styles. Add a new one.', array( - '!url' => $this->urlGenerator->generateFromPath('admin/config/media/image-styles/add'), - )); - return $build; - } - -} diff --git a/core/modules/image/lib/Drupal/image/ImageStyleListController.php b/core/modules/image/lib/Drupal/image/ImageStyleListController.php new file mode 100644 index 0000000..8d9de4d --- /dev/null +++ b/core/modules/image/lib/Drupal/image/ImageStyleListController.php @@ -0,0 +1,97 @@ +urlGenerator = $url_generator; + } + + /** + * {@inheritdoc} + */ + public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { + return new static( + $entity_type, + $container->get('entity.manager')->getStorageController($entity_type->id()), + $container->get('url_generator'), + $container->get('string_translation') + ); + } + + /** + * {@inheritdoc} + */ + public function buildHeader() { + $header['label'] = $this->t('Style name'); + return $header + parent::buildHeader(); + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + $row['label'] = $this->getLabel($entity); + return $row + parent::buildRow($entity); + } + + /** + * {@inheritdoc} + */ + public function getOperations(EntityInterface $entity) { + $flush = array( + 'title' => t('Flush'), + 'weight' => 200, + ) + $entity->urlInfo('flush-form'); + + return parent::getOperations($entity) + array('flush' => $flush); + } + + /** + * {@inheritdoc} + */ + public function render() { + $build = parent::render(); + $build['#empty'] = $this->t('There are currently no styles. Add a new one.', array( + '!url' => $this->urlGenerator->generateFromPath('admin/config/media/image-styles/add'), + )); + return $build; + } + +} diff --git a/core/modules/language/lib/Drupal/language/Entity/Language.php b/core/modules/language/lib/Drupal/language/Entity/Language.php index 244607f..e168aa5 100644 --- a/core/modules/language/lib/Drupal/language/Entity/Language.php +++ b/core/modules/language/lib/Drupal/language/Entity/Language.php @@ -19,7 +19,7 @@ * id = "language_entity", * label = @Translation("Language"), * controllers = { - * "list_builder" = "Drupal\language\LanguageListBuilder", + * "list" = "Drupal\language\LanguageListController", * "access" = "Drupal\language\LanguageAccessController", * "form" = { * "add" = "Drupal\language\Form\LanguageAddForm", diff --git a/core/modules/language/lib/Drupal/language/LanguageListBuilder.php b/core/modules/language/lib/Drupal/language/LanguageListBuilder.php deleted file mode 100644 index 99fb967..0000000 --- a/core/modules/language/lib/Drupal/language/LanguageListBuilder.php +++ /dev/null @@ -1,100 +0,0 @@ -storage->loadByProperties(array('locked' => FALSE)); - - // Sort the entities using the entity class's sort() method. - // See \Drupal\Core\Config\Entity\ConfigEntityBase::sort(). - uasort($entities, array($this->entityType->getClass(), 'sort')); - return $entities; - } - - /** - * {@inheritdoc} - */ - public function getFormId() { - return 'language_admin_overview_form'; - } - - /** - * {@inheritdoc} - */ - public function getOperations(EntityInterface $entity) { - $operations = parent::getOperations($entity); - $default = language_default(); - - // Deleting the site default language is not allowed. - if ($entity->id() == $default->id) { - unset($operations['delete']); - } - - return $operations; - } - - /** - * {@inheritdoc} - */ - public function buildHeader() { - $header['label'] = t('Name'); - return $header + parent::buildHeader(); - } - - /** - * {@inheritdoc} - */ - public function buildRow(EntityInterface $entity) { - $row['label'] = $this->getLabel($entity); - return $row + parent::buildRow($entity); - } - - /** - * {@inheritdoc} - */ - public function buildForm(array $form, array &$form_state) { - $form = parent::buildForm($form, $form_state); - $form[$this->entitiesKey]['#languages'] = $this->entities; - $form['actions']['submit']['#value'] = t('Save configuration'); - return $form; - } - - /** - * {@inheritdoc} - */ - public function submitForm(array &$form, array &$form_state) { - parent::submitForm($form, $form_state); - - $language_manager = \Drupal::languageManager(); - $language_manager->reset(); - if ($language_manager instanceof ConfigurableLanguageManagerInterface) { - $language_manager->updateLockedLanguageWeights(); - } - - drupal_set_message(t('Configuration saved.')); - } - -} diff --git a/core/modules/language/lib/Drupal/language/LanguageListController.php b/core/modules/language/lib/Drupal/language/LanguageListController.php new file mode 100644 index 0000000..da1454f --- /dev/null +++ b/core/modules/language/lib/Drupal/language/LanguageListController.php @@ -0,0 +1,97 @@ +storage->loadByProperties(array('locked' => FALSE)); + + // Sort the entities using the entity class's sort() method. + // See \Drupal\Core\Config\Entity\ConfigEntityBase::sort(). + uasort($entities, array($this->entityType->getClass(), 'sort')); + return $entities; + } + + /** + * {@inheritdoc} + */ + public function getFormId() { + return 'language_admin_overview_form'; + } + + /** + * {@inheritdoc} + */ + public function getOperations(EntityInterface $entity) { + $operations = parent::getOperations($entity); + $default = language_default(); + + // Deleting the site default language is not allowed. + if ($entity->id() == $default->id) { + unset($operations['delete']); + } + + return $operations; + } + + /** + * {@inheritdoc} + */ + public function buildHeader() { + $header['label'] = t('Name'); + return $header + parent::buildHeader(); + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + $row['label'] = $this->getLabel($entity); + return $row + parent::buildRow($entity); + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, array &$form_state) { + $form = parent::buildForm($form, $form_state); + $form[$this->entitiesKey]['#languages'] = $this->entities; + $form['actions']['submit']['#value'] = t('Save configuration'); + return $form; + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + parent::submitForm($form, $form_state); + + $language_manager = \Drupal::languageManager(); + $language_manager->reset(); + if ($language_manager instanceof ConfigurableLanguageManagerInterface) { + $language_manager->updateLockedLanguageWeights(); + } + + drupal_set_message(t('Configuration saved.')); + } + +} diff --git a/core/modules/language/lib/Drupal/language/Plugin/Derivative/LanguageBlock.php b/core/modules/language/lib/Drupal/language/Plugin/Derivative/LanguageBlock.php index b673d66..88c0736 100644 --- a/core/modules/language/lib/Drupal/language/Plugin/Derivative/LanguageBlock.php +++ b/core/modules/language/lib/Drupal/language/Plugin/Derivative/LanguageBlock.php @@ -27,6 +27,7 @@ public function getDerivativeDefinitions($base_plugin_definition) { foreach ($configurable_types as $type) { $this->derivatives[$type] = $base_plugin_definition; $this->derivatives[$type]['admin_label'] = t('Language switcher (!type)', array('!type' => $info[$type]['name'])); + $this->derivatives[$type]['cache'] = DRUPAL_NO_CACHE; } // If there is just one configurable type then change the title of the // block. diff --git a/core/modules/locale/lib/Drupal/locale/Form/ImportForm.php b/core/modules/locale/lib/Drupal/locale/Form/ImportForm.php new file mode 100644 index 0000000..32afb37 --- /dev/null +++ b/core/modules/locale/lib/Drupal/locale/Form/ImportForm.php @@ -0,0 +1,191 @@ +get('module_handler'), + $container->get('language_manager') + ); + } + /** + * Constructs an ImportForm. + * + * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler + */ + public function __construct(ModuleHandlerInterface $module_handler, LanguageManager $language_manager) { + $this->moduleHandler = $module_handler; + $this->languageManager = $language_manager; + } + + /** + * {@inheritdoc} + */ + public function getFormID() { + return 'locale_translate_import_form'; + } + + /** + * Form constructor for the translation import screen. + * + * @ingroup forms + */ + public function buildForm(array $form, array &$form_state) { + $this->languageManager->reset(); + $languages = $this->languageManager->getLanguages(); + + // Initialize a language list to the ones available, including English if we + // are to translate Drupal to English as well. + $existing_languages = array(); + foreach ($languages as $langcode => $language) { + if ($langcode != 'en' || locale_translate_english()) { + $existing_languages[$langcode] = $language->name; + } + } + + // If we have no languages available, present the list of predefined + // languages only. If we do have already added languages, set up two option + // groups with the list of existing and then predefined languages. + form_load_include($form_state, 'inc', 'language', 'language.admin'); + if (empty($existing_languages)) { + $language_options = language_admin_predefined_list(); + $default = key($language_options); + } + else { + $default = key($existing_languages); + $language_options = array( + $this->t('Existing languages') => $existing_languages, + $this->t('Languages not yet added') => language_admin_predefined_list() + ); + } + + $validators = array( + 'file_validate_extensions' => array('po'), + 'file_validate_size' => array(file_upload_max_size()), + ); + $form['file'] = array( + '#type' => 'file', + '#title' => $this->t('Translation file'), + '#description' => array( + '#theme' => 'file_upload_help', + '#description' => $this->t('A Gettext Portable Object file.'), + '#upload_validators' => $validators, + ), + '#size' => 50, + '#upload_validators' => $validators, + '#attributes' => array('class' => array('file-import-input')), + '#attached' => array( + 'js' => array( + drupal_get_path('module', 'locale') . '/locale.bulk.js' => array(), + ), + ), + ); + $form['langcode'] = array( + '#type' => 'select', + '#title' => $this->t('Language'), + '#options' => $language_options, + '#default_value' => $default, + '#attributes' => array('class' => array('langcode-input')), + ); + + $form['customized'] = array( + '#title' => $this->t('Treat imported strings as custom translations'), + '#type' => 'checkbox', + ); + $form['overwrite_options'] = array( + '#type' => 'container', + '#tree' => TRUE, + ); + $form['overwrite_options']['not_customized'] = array( + '#title' => $this->t('Overwrite non-customized translations'), + '#type' => 'checkbox', + '#states' => array( + 'checked' => array( + ':input[name="customized"]' => array('checked' => TRUE), + ), + ), + ); + $form['overwrite_options']['customized'] = array( + '#title' => $this->t('Overwrite existing customized translations'), + '#type' => 'checkbox', + ); + + $form['actions'] = array( + '#type' => 'actions' + ); + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => $this->t('Import') + ); + return $form; + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + // Ensure we have the file uploaded. + if ($file = file_save_upload('file', $form_state, $form['file']['#upload_validators'], 'translations://', 0)) { + + // Add language, if not yet supported. + $language = language_load($form_state['values']['langcode']); + if (empty($language)) { + $language = new Language(array( + 'id' => $form_state['values']['langcode'] + )); + $language = language_save($language); + drupal_set_message(t('The language %language has been created.', array('%language' => t($language->name)))); + } + $options = array( + 'langcode' => $form_state['values']['langcode'], + 'overwrite_options' => $form_state['values']['overwrite_options'], + 'customized' => $form_state['values']['customized'] ? LOCALE_CUSTOMIZED : LOCALE_NOT_CUSTOMIZED, + ); + $this->moduleHandler->loadInclude('locale', 'bulk.inc'); + $file = locale_translate_file_attach_properties($file, $options); + $batch = locale_translate_batch_build(array($file->uri => $file), $options); + batch_set($batch); + } + else { + $this->setFormError('file', $form_state, $this->t('File to import not found.')); + $form_state['rebuild'] = TRUE; + return; + } + + $form_state['redirect_route']['route_name'] = 'locale.translate_page'; + } +} diff --git a/core/modules/locale/lib/Drupal/locale/Form/LocaleForm.php b/core/modules/locale/lib/Drupal/locale/Form/LocaleForm.php index aaa0bfa..c06a4aa 100644 --- a/core/modules/locale/lib/Drupal/locale/Form/LocaleForm.php +++ b/core/modules/locale/lib/Drupal/locale/Form/LocaleForm.php @@ -22,6 +22,16 @@ public function import() { } /** + * Wraps locale_translate_export_form(). + * + * @todo Remove locale_translate_export_form(). + */ + public function export() { + module_load_include('bulk.inc', 'locale'); + return drupal_get_form('locale_translate_export_form'); + } + + /** * Wraps locale_translation_status_form(). * * @todo Remove locale_translation_status_form(). diff --git a/core/modules/locale/locale.bulk.inc b/core/modules/locale/locale.bulk.inc index 5f72ad8..af27887 100644 --- a/core/modules/locale/locale.bulk.inc +++ b/core/modules/locale/locale.bulk.inc @@ -10,96 +10,70 @@ use Drupal\file\FileInterface; /** - * Form constructor for the translation import screen. + * Form constructor for the Gettext translation files export form. * - * @see locale_translate_import_form_submit() + * @see locale_translate_export_form_submit() * @ingroup forms * - * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0. - * Use \Drupal\locale\Form\LocaleForm::import(). + * @deprecated Use \Drupal\locale\Form\LocaleForm::export() */ -function locale_translate_import_form($form, &$form_state) { - Drupal::languageManager()->reset(); +function locale_translate_export_form($form, &$form_state) { $languages = language_list(); - - // Initialize a language list to the ones available, including English if we - // are to translate Drupal to English as well. - $existing_languages = array(); + $language_options = array(); foreach ($languages as $langcode => $language) { if ($langcode != 'en' || locale_translate_english()) { - $existing_languages[$langcode] = $language->name; + $language_options[$langcode] = $language->name; } } + $language_default = language_default(); - // If we have no languages available, present the list of predefined languages - // only. If we do have already added languages, set up two option groups with - // the list of existing and then predefined languages. - form_load_include($form_state, 'inc', 'language', 'language.admin'); - if (empty($existing_languages)) { - $language_options = language_admin_predefined_list(); - $default = key($language_options); + if (empty($language_options)) { + $form['langcode'] = array( + '#type' => 'value', + '#value' => Language::LANGCODE_SYSTEM, + ); + $form['langcode_text'] = array( + '#type' => 'item', + '#title' => t('Language'), + '#markup' => t('No language available. The export will only contain source strings.'), + ); } else { - $default = key($existing_languages); - $language_options = array( - t('Existing languages') => $existing_languages, - t('Languages not yet added') => language_admin_predefined_list() + $form['langcode'] = array( + '#type' => 'select', + '#title' => t('Language'), + '#options' => $language_options, + '#default_value' => $language_default->id, + '#empty_option' => t('Source text only, no translations'), + '#empty_value' => Language::LANGCODE_SYSTEM, ); - } - - $validators = array( - 'file_validate_extensions' => array('po'), - 'file_validate_size' => array(file_upload_max_size()), - ); - $file_description = array( - '#theme' => 'file_upload_help', - '#description' => t('A Gettext Portable Object file.'), - '#upload_validators' => $validators, - ); - - $form['file'] = array( - '#type' => 'file', - '#title' => t('Translation file'), - '#description' => drupal_render($file_description), - '#size' => 50, - '#upload_validators' => $validators, - '#attributes' => array('class' => array('file-import-input')), - '#attached' => array( - 'js' => array( - drupal_get_path('module', 'locale') . '/locale.bulk.js' => array(), + $form['content_options'] = array( + '#type' => 'details', + '#title' => t('Export options'), + '#collapsed' => TRUE, + '#tree' => TRUE, + '#states' => array( + 'invisible' => array( + ':input[name="langcode"]' => array('value' => Language::LANGCODE_SYSTEM), + ), ), - ), - ); - $form['langcode'] = array( - '#type' => 'select', - '#title' => t('Language'), - '#options' => $language_options, - '#default_value' => $default, - '#attributes' => array('class' => array('langcode-input')), - ); - - $form['customized'] = array( - '#title' => t('Treat imported strings as custom translations'), - '#type' => 'checkbox', - ); - $form['overwrite_options'] = array( - '#type' => 'container', - '#tree' => TRUE, - ); - $form['overwrite_options']['not_customized'] = array( - '#title' => t('Overwrite non-customized translations'), - '#type' => 'checkbox', - '#states' => array( - 'checked' => array( - ':input[name="customized"]' => array('checked' => TRUE), - ), - ), - ); - $form['overwrite_options']['customized'] = array( - '#title' => t('Overwrite existing customized translations'), - '#type' => 'checkbox', - ); - + ); + $form['content_options']['not_customized'] = array( + '#type' => 'checkbox', + '#title' => t('Include non-customized translations'), + '#default_value' => TRUE, + ); + $form['content_options']['customized'] = array( + '#type' => 'checkbox', + '#title' => t('Include customized translations'), + '#default_value' => TRUE, + ); + $form['content_options']['not_translated'] = array( + '#type' => 'checkbox', + '#title' => t('Include untranslated text'), + '#default_value' => TRUE, + ); + } $form['actions'] = array( '#type' => 'actions' ); @@ -111,38 +85,56 @@ function locale_translate_import_form($form, &$form_state) { } /** - * Form submission handler for locale_translate_import_form(). + * Form submission handler for locale_translate_export_form(). */ -function locale_translate_import_form_submit($form, &$form_state) { - // Ensure we have the file uploaded. - if ($file = file_save_upload('file', $form_state, $form['file']['#upload_validators'], 'translations://', 0)) { - - // Add language, if not yet supported. +function locale_translate_export_form_submit($form, &$form_state) { + // If template is required, language code is not given. + if ($form_state['values']['langcode'] != Language::LANGCODE_SYSTEM) { $language = language_load($form_state['values']['langcode']); - if (empty($language)) { - $language = new Language(array( - 'id' => $form_state['values']['langcode'] - )); - $language = language_save($language); - drupal_set_message(t('The language %language has been created.', array('%language' => t($language->name)))); - } - $options = array( - 'langcode' => $form_state['values']['langcode'], - 'overwrite_options' => $form_state['values']['overwrite_options'], - 'customized' => $form_state['values']['customized'] ? LOCALE_CUSTOMIZED : LOCALE_NOT_CUSTOMIZED, - ); - $file = locale_translate_file_attach_properties($file, $options); - $batch = locale_translate_batch_build(array($file->uri => $file), $options); - batch_set($batch); } else { - form_set_error('file', $form_state, t('File to import not found.')); - $form_state['rebuild'] = TRUE; - return; + $language = NULL; + } + $content_options = isset($form_state['values']['content_options']) ? $form_state['values']['content_options'] : array(); + $reader = new PoDatabaseReader(); + $languageName = ''; + if ($language != NULL) { + $reader->setLangcode($language->id); + $reader->setOptions($content_options); + $languages = language_list(); + $languageName = isset($languages[$language->id]) ? $languages[$language->id]->name : ''; + $filename = $language->id .'.po'; + } + else { + // Template required. + $filename = 'drupal.pot'; } - $form_state['redirect_route']['route_name'] = 'locale.translate_page'; - return; + $item = $reader->readItem(); + if (!empty($item)) { + $uri = tempnam('temporary://', 'po_'); + $header = $reader->getHeader(); + $header->setProjectName(\Drupal::config('system.site')->get('name')); + $header->setLanguageName($languageName); + + $writer = new PoStreamWriter; + $writer->setUri($uri); + $writer->setHeader($header); + + $writer->open(); + $writer->writeItem($item); + $writer->writeItems($reader); + $writer->close(); + + $response = new BinaryFileResponse($uri); + $response->setContentDisposition('attachment', $filename); + // @todo remove lines below once converted to new routing system. + $response->prepare(\Drupal::request()) + ->send(); + } + else { + drupal_set_message('Nothing to export.'); + } } /** diff --git a/core/modules/locale/locale.routing.yml b/core/modules/locale/locale.routing.yml index 6658dad..705d5ea 100644 --- a/core/modules/locale/locale.routing.yml +++ b/core/modules/locale/locale.routing.yml @@ -24,7 +24,7 @@ locale.translate_page: locale.translate_import: path: '/admin/config/regional/translate/import' defaults: - _content: '\Drupal\locale\Form\LocaleForm::import' + _form: '\Drupal\locale\Form\ImportForm' _title: 'Import' requirements: _permission: 'translate interface' diff --git a/core/modules/menu/lib/Drupal/menu/MenuListBuilder.php b/core/modules/menu/lib/Drupal/menu/MenuListBuilder.php deleted file mode 100644 index 282ce00..0000000 --- a/core/modules/menu/lib/Drupal/menu/MenuListBuilder.php +++ /dev/null @@ -1,73 +0,0 @@ - t('Description'), - 'class' => array(RESPONSIVE_PRIORITY_MEDIUM), - ); - return $header + parent::buildHeader(); - } - - /** - * {@inheritdoc} - */ - public function buildRow(EntityInterface $entity) { - $row['title'] = array( - 'data' => $this->getLabel($entity), - 'class' => array('menu-label'), - ); - $row['description'] = filter_xss_admin($entity->description); - return $row + parent::buildRow($entity); - } - - /** - * {@inheritdoc} - */ - public function getOperations(EntityInterface $entity) { - $operations = parent::getOperations($entity); - - if (isset($operations['edit'])) { - $operations['edit']['title'] = t('Edit menu'); - $operations['add'] = array( - 'title' => t('Add link'), - 'weight' => 20, - ) + $entity->urlInfo('add-form'); - } - if (isset($operations['delete'])) { - $operations['delete']['title'] = t('Delete menu'); - } - return $operations; - } - - /** - * {@inheritdoc} - */ - public function render() { - $build = parent::render(); - $build['#attached']['css'][] = drupal_get_path('module', 'menu') . '/css/menu.admin.css'; - return $build; - } - -} diff --git a/core/modules/menu/lib/Drupal/menu/MenuListController.php b/core/modules/menu/lib/Drupal/menu/MenuListController.php new file mode 100644 index 0000000..18a3732 --- /dev/null +++ b/core/modules/menu/lib/Drupal/menu/MenuListController.php @@ -0,0 +1,69 @@ + t('Description'), + 'class' => array(RESPONSIVE_PRIORITY_MEDIUM), + ); + return $header + parent::buildHeader(); + } + + /** + * Overrides \Drupal\Core\Entity\EntityListController::buildRow(). + */ + public function buildRow(EntityInterface $entity) { + $row['title'] = array( + 'data' => $this->getLabel($entity), + 'class' => array('menu-label'), + ); + $row['description'] = filter_xss_admin($entity->description); + return $row + parent::buildRow($entity); + } + + /** + * {@inheritdoc} + */ + public function getOperations(EntityInterface $entity) { + $operations = parent::getOperations($entity); + + if (isset($operations['edit'])) { + $operations['edit']['title'] = t('Edit menu'); + $operations['add'] = array( + 'title' => t('Add link'), + 'weight' => 20, + ) + $entity->urlInfo('add-form'); + } + if (isset($operations['delete'])) { + $operations['delete']['title'] = t('Delete menu'); + } + return $operations; + } + + /** + * Overrides \Drupal\Core\Entity\EntityListController::render(); + */ + public function render() { + $build = parent::render(); + $build['#attached']['css'][] = drupal_get_path('module', 'menu') . '/css/menu.admin.css'; + return $build; + } + +} diff --git a/core/modules/menu/lib/Drupal/menu/Tests/MenuCacheTagsTest.php b/core/modules/menu/lib/Drupal/menu/Tests/MenuCacheTagsTest.php index e8f00a3..c09875c 100644 --- a/core/modules/menu/lib/Drupal/menu/Tests/MenuCacheTagsTest.php +++ b/core/modules/menu/lib/Drupal/menu/Tests/MenuCacheTagsTest.php @@ -58,14 +58,7 @@ public function testMenuBlock() { $this->verifyPageCache($path, 'MISS'); // Verify a cache hit, but also the presence of the correct cache tags. - $expected_tags = array( - 'content:1', - 'block_view:1', - 'block:' . $block->id(), - 'block_plugin:system_menu_block__llama', - 'menu:llama', - ); - $this->verifyPageCache($path, 'HIT', $expected_tags); + $this->verifyPageCache($path, 'HIT', array('content:1', 'menu:llama')); // Verify that after modifying the menu, there is a cache miss. @@ -108,7 +101,7 @@ public function testMenuBlock() { $this->verifyPageCache($path, 'MISS'); // Verify a cache hit. - $this->verifyPageCache($path, 'HIT', $expected_tags); + $this->verifyPageCache($path, 'HIT', array('content:1', 'menu:llama')); // Verify that after deleting the menu, there is a cache miss. diff --git a/core/modules/menu/menu.module b/core/modules/menu/menu.module index 9f84463..660e1df 100644 --- a/core/modules/menu/menu.module +++ b/core/modules/menu/menu.module @@ -84,7 +84,7 @@ function menu_entity_type_build(array &$entity_types) { ->setFormClass('add', 'Drupal\menu\MenuFormController') ->setFormClass('edit', 'Drupal\menu\MenuFormController') ->setFormClass('delete', 'Drupal\menu\Form\MenuDeleteForm') - ->setListBuilderClass('Drupal\menu\MenuListBuilder') + ->setListClass('Drupal\menu\MenuListController') ->setLinkTemplate('add-form', 'menu.link_add') ->setLinkTemplate('delete-form', 'menu.delete_menu') ->setLinkTemplate('edit-form', 'menu.menu_edit'); diff --git a/core/modules/node/lib/Drupal/node/Entity/Node.php b/core/modules/node/lib/Drupal/node/Entity/Node.php index da4b174..a80577c 100644 --- a/core/modules/node/lib/Drupal/node/Entity/Node.php +++ b/core/modules/node/lib/Drupal/node/Entity/Node.php @@ -31,7 +31,7 @@ * "delete" = "Drupal\node\Form\NodeDeleteForm", * "edit" = "Drupal\node\NodeFormController" * }, - * "list_builder" = "Drupal\node\NodeListBuilder", + * "list" = "Drupal\node\NodeListController", * "translation" = "Drupal\node\NodeTranslationController" * }, * base_table = "node", diff --git a/core/modules/node/lib/Drupal/node/Entity/NodeType.php b/core/modules/node/lib/Drupal/node/Entity/NodeType.php index b187c75..021ee7d 100644 --- a/core/modules/node/lib/Drupal/node/Entity/NodeType.php +++ b/core/modules/node/lib/Drupal/node/Entity/NodeType.php @@ -26,7 +26,7 @@ * "edit" = "Drupal\node\NodeTypeFormController", * "delete" = "Drupal\node\Form\NodeTypeDeleteConfirm" * }, - * "list_builder" = "Drupal\node\NodeTypeListBuilder", + * "list" = "Drupal\node\NodeTypeListController", * }, * admin_permission = "administer content types", * config_prefix = "type", diff --git a/core/modules/node/lib/Drupal/node/NodeListBuilder.php b/core/modules/node/lib/Drupal/node/NodeListBuilder.php deleted file mode 100644 index d80b6b2..0000000 --- a/core/modules/node/lib/Drupal/node/NodeListBuilder.php +++ /dev/null @@ -1,137 +0,0 @@ -dateService = $date_service; - } - - /** - * {@inheritdoc} - */ - public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { - return new static( - $entity_type, - $container->get('entity.manager')->getStorageController($entity_type->id()), - $container->get('date') - ); - } - - /** - * {@inheritdoc} - */ - public function buildHeader() { - // Enable language column and filter if multiple languages are enabled. - $header = array( - 'title' => $this->t('Title'), - 'type' => array( - 'data' => $this->t('Content type'), - 'class' => array(RESPONSIVE_PRIORITY_MEDIUM), - ), - 'author' => array( - 'data' => $this->t('Author'), - 'class' => array(RESPONSIVE_PRIORITY_LOW), - ), - 'status' => $this->t('Status'), - 'changed' => array( - 'data' => $this->t('Updated'), - 'class' => array(RESPONSIVE_PRIORITY_LOW), - ), - ); - if (\Drupal::languageManager()->isMultilingual()) { - $header['language_name'] = array( - 'data' => $this->t('Language'), - 'class' => array(RESPONSIVE_PRIORITY_LOW), - ); - } - return $header + parent::buildHeader(); - } - - /** - * {@inheritdoc} - */ - public function buildRow(EntityInterface $entity) { - /** @var \Drupal\node\NodeInterface $entity */ - $mark = array( - '#theme' => 'mark', - '#mark_type' => node_mark($entity->id(), $entity->getChangedTime()), - ); - $langcode = $entity->language()->id; - $uri = $entity->urlInfo(); - $row['title']['data'] = array( - '#type' => 'link', - '#title' => $entity->label(), - '#route_name' => $uri['route_name'], - '#route_parameters' => $uri['route_parameters'], - '#options' => $uri['options'] + ($langcode != Language::LANGCODE_NOT_SPECIFIED && isset($languages[$langcode]) ? array('language' => $languages[$langcode]) : array()), - '#suffix' => ' ' . drupal_render($mark), - ); - $row['type'] = String::checkPlain(node_get_type_label($entity)); - $row['author']['data'] = array( - '#theme' => 'username', - '#account' => $entity->getOwner(), - ); - $row['status'] = $entity->isPublished() ? $this->t('published') : $this->t('not published'); - $row['changed'] = $this->dateService->format($entity->getChangedTime(), 'short'); - $language_manager = \Drupal::languageManager(); - if ($language_manager->isMultilingual()) { - $row['language_name'] = $language_manager->getLanguageName($langcode); - } - $row['operations']['data'] = $this->buildOperations($entity); - return $row + parent::buildRow($entity); - } - - /** - * {@inheritdoc} - */ - public function getOperations(EntityInterface $entity) { - $operations = parent::getOperations($entity); - - $destination = drupal_get_destination(); - foreach ($operations as $key => $operation) { - $operations[$key]['query'] = $destination; - } - return $operations; - } - -} diff --git a/core/modules/node/lib/Drupal/node/NodeListController.php b/core/modules/node/lib/Drupal/node/NodeListController.php new file mode 100644 index 0000000..4ac1ebb --- /dev/null +++ b/core/modules/node/lib/Drupal/node/NodeListController.php @@ -0,0 +1,136 @@ +dateService = $date_service; + } + + /** + * {@inheritdoc} + */ + public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { + return new static( + $entity_type, + $container->get('entity.manager')->getStorageController($entity_type->id()), + $container->get('date') + ); + } + + /** + * {@inheritdoc} + */ + public function buildHeader() { + // Enable language column and filter if multiple languages are enabled. + $header = array( + 'title' => $this->t('Title'), + 'type' => array( + 'data' => $this->t('Content type'), + 'class' => array(RESPONSIVE_PRIORITY_MEDIUM), + ), + 'author' => array( + 'data' => $this->t('Author'), + 'class' => array(RESPONSIVE_PRIORITY_LOW), + ), + 'status' => $this->t('Status'), + 'changed' => array( + 'data' => $this->t('Updated'), + 'class' => array(RESPONSIVE_PRIORITY_LOW), + ), + ); + if (\Drupal::languageManager()->isMultilingual()) { + $header['language_name'] = array( + 'data' => $this->t('Language'), + 'class' => array(RESPONSIVE_PRIORITY_LOW), + ); + } + return $header + parent::buildHeader(); + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + /** @var \Drupal\node\NodeInterface $entity */ + $mark = array( + '#theme' => 'mark', + '#mark_type' => node_mark($entity->id(), $entity->getChangedTime()), + ); + $langcode = $entity->language()->id; + $uri = $entity->urlInfo(); + $row['title']['data'] = array( + '#type' => 'link', + '#title' => $entity->label(), + '#route_name' => $uri['route_name'], + '#route_parameters' => $uri['route_parameters'], + '#options' => $uri['options'] + ($langcode != Language::LANGCODE_NOT_SPECIFIED && isset($languages[$langcode]) ? array('language' => $languages[$langcode]) : array()), + '#suffix' => ' ' . drupal_render($mark), + ); + $row['type'] = String::checkPlain(node_get_type_label($entity)); + $row['author']['data'] = array( + '#theme' => 'username', + '#account' => $entity->getOwner(), + ); + $row['status'] = $entity->isPublished() ? $this->t('published') : $this->t('not published'); + $row['changed'] = $this->dateService->format($entity->getChangedTime(), 'short'); + $language_manager = \Drupal::languageManager(); + if ($language_manager->isMultilingual()) { + $row['language_name'] = $language_manager->getLanguageName($langcode); + } + $row['operations']['data'] = $this->buildOperations($entity); + return $row + parent::buildRow($entity); + } + + /** + * {@inheritdoc} + */ + public function getOperations(EntityInterface $entity) { + $operations = parent::getOperations($entity); + + $destination = drupal_get_destination(); + foreach ($operations as $key => $operation) { + $operations[$key]['query'] = $destination; + } + return $operations; + } + +} diff --git a/core/modules/node/lib/Drupal/node/NodeTypeListBuilder.php b/core/modules/node/lib/Drupal/node/NodeTypeListBuilder.php deleted file mode 100644 index 681fff4..0000000 --- a/core/modules/node/lib/Drupal/node/NodeTypeListBuilder.php +++ /dev/null @@ -1,107 +0,0 @@ -urlGenerator = $url_generator; - } - - /** - * {@inheritdoc} - */ - public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { - return new static( - $entity_type, - $container->get('entity.manager')->getStorageController($entity_type->id()), - $container->get('url_generator') - ); - } - - /** - * {@inheritdoc} - */ - public function buildHeader() { - $header['title'] = t('Name'); - $header['description'] = array( - 'data' => t('Description'), - 'class' => array(RESPONSIVE_PRIORITY_MEDIUM), - ); - return $header + parent::buildHeader(); - } - - /** - * {@inheritdoc} - */ - public function buildRow(EntityInterface $entity) { - $row['title'] = array( - 'data' => $this->getLabel($entity), - 'class' => array('menu-label'), - ); - $row['description'] = Xss::filterAdmin($entity->description); - return $row + parent::buildRow($entity); - } - - /** - * {@inheritdoc} - */ - public function getOperations(EntityInterface $entity) { - $operations = parent::getOperations($entity); - // Place the edit operation after the operations added by field_ui.module - // which have the weights 15, 20, 25. - if (isset($operations['edit'])) { - $operations['edit']['weight'] = 30; - } - return $operations; - } - - /** - * {@inheritdoc} - */ - public function render() { - $build = parent::render(); - $build['#empty'] = t('No content types available. Add content type.', array( - '@link' => $this->urlGenerator->generateFromPath('admin/structure/types/add'), - )); - return $build; - } - -} diff --git a/core/modules/node/lib/Drupal/node/NodeTypeListController.php b/core/modules/node/lib/Drupal/node/NodeTypeListController.php new file mode 100644 index 0000000..b1829f6 --- /dev/null +++ b/core/modules/node/lib/Drupal/node/NodeTypeListController.php @@ -0,0 +1,105 @@ +urlGenerator = $url_generator; + } + + /** + * {@inheritdoc} + */ + public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { + return new static( + $entity_type, + $container->get('entity.manager')->getStorageController($entity_type->id()), + $container->get('url_generator') + ); + } + + /** + * {@inheritdoc} + */ + public function buildHeader() { + $header['title'] = t('Name'); + $header['description'] = array( + 'data' => t('Description'), + 'class' => array(RESPONSIVE_PRIORITY_MEDIUM), + ); + return $header + parent::buildHeader(); + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + $row['title'] = array( + 'data' => $this->getLabel($entity), + 'class' => array('menu-label'), + ); + $row['description'] = Xss::filterAdmin($entity->description); + return $row + parent::buildRow($entity); + } + + /** + * {@inheritdoc} + */ + public function getOperations(EntityInterface $entity) { + $operations = parent::getOperations($entity); + // Place the edit operation after the operations added by field_ui.module + // which have the weights 15, 20, 25. + if (isset($operations['edit'])) { + $operations['edit']['weight'] = 30; + } + return $operations; + } + + /** + * {@inheritdoc} + */ + public function render() { + $build = parent::render(); + $build['#empty'] = t('No content types available. Add content type.', array( + '@link' => $this->urlGenerator->generateFromPath('admin/structure/types/add'), + )); + return $build; + } + +} diff --git a/core/modules/responsive_image/lib/Drupal/responsive_image/Entity/ResponsiveImageMapping.php b/core/modules/responsive_image/lib/Drupal/responsive_image/Entity/ResponsiveImageMapping.php index 658ad5d..408e417 100644 --- a/core/modules/responsive_image/lib/Drupal/responsive_image/Entity/ResponsiveImageMapping.php +++ b/core/modules/responsive_image/lib/Drupal/responsive_image/Entity/ResponsiveImageMapping.php @@ -17,7 +17,7 @@ * id = "responsive_image_mapping", * label = @Translation("Responsive image mapping"), * controllers = { - * "list_builder" = "Drupal\responsive_image\ResponsiveImageMappingListBuilder", + * "list" = "Drupal\responsive_image\ResponsiveImageMappingListController", * "form" = { * "edit" = "Drupal\responsive_image\ResponsiveImageMappingFormController", * "add" = "Drupal\responsive_image\ResponsiveImageMappingFormController", diff --git a/core/modules/responsive_image/lib/Drupal/responsive_image/ResponsiveImageMappingListBuilder.php b/core/modules/responsive_image/lib/Drupal/responsive_image/ResponsiveImageMappingListBuilder.php deleted file mode 100644 index 1de736b..0000000 --- a/core/modules/responsive_image/lib/Drupal/responsive_image/ResponsiveImageMappingListBuilder.php +++ /dev/null @@ -1,48 +0,0 @@ -getLabel($entity); - $row['id'] = $entity->id(); - return $row + parent::buildRow($entity); - } - - /** - * {@inheritdoc} - */ - public function getOperations(EntityInterface $entity) { - $operations = parent::getOperations($entity); - $operations['duplicate'] = array( - 'title' => t('Duplicate'), - 'weight' => 15, - ) + $entity->urlInfo('duplicate-form'); - return $operations; - } - -} diff --git a/core/modules/responsive_image/lib/Drupal/responsive_image/ResponsiveImageMappingListController.php b/core/modules/responsive_image/lib/Drupal/responsive_image/ResponsiveImageMappingListController.php new file mode 100644 index 0000000..7d392b8 --- /dev/null +++ b/core/modules/responsive_image/lib/Drupal/responsive_image/ResponsiveImageMappingListController.php @@ -0,0 +1,48 @@ +getLabel($entity); + $row['id'] = $entity->id(); + return $row + parent::buildRow($entity); + } + + /** + * {@inheritdoc} + */ + public function getOperations(EntityInterface $entity) { + $operations = parent::getOperations($entity); + $operations['duplicate'] = array( + 'title' => t('Duplicate'), + 'weight' => 15, + ) + $entity->urlInfo('duplicate-form'); + return $operations; + } + +} diff --git a/core/modules/search/lib/Drupal/search/Entity/SearchPage.php b/core/modules/search/lib/Drupal/search/Entity/SearchPage.php index 18a1807..ab902b5 100644 --- a/core/modules/search/lib/Drupal/search/Entity/SearchPage.php +++ b/core/modules/search/lib/Drupal/search/Entity/SearchPage.php @@ -24,7 +24,7 @@ * controllers = { * "access" = "Drupal\search\SearchPageAccessController", * "storage" = "Drupal\Core\Config\Entity\ConfigStorageController", - * "list_builder" = "Drupal\search\SearchPageListBuilder", + * "list" = "Drupal\search\SearchPageListController", * "form" = { * "add" = "Drupal\search\Form\SearchPageAddForm", * "edit" = "Drupal\search\Form\SearchPageEditForm", diff --git a/core/modules/search/lib/Drupal/search/SearchPageListBuilder.php b/core/modules/search/lib/Drupal/search/SearchPageListBuilder.php deleted file mode 100644 index e2c61cd..0000000 --- a/core/modules/search/lib/Drupal/search/SearchPageListBuilder.php +++ /dev/null @@ -1,343 +0,0 @@ -configFactory = $config_factory; - $this->searchManager = $search_manager; - } - - /** - * {@inheritdoc} - */ - public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { - return new static( - $entity_type, - $container->get('entity.manager')->getStorageController($entity_type->id()), - $container->get('plugin.manager.search'), - $container->get('config.factory') - ); - } - - /** - * {@inheritdoc} - */ - public function getFormID() { - return 'search_admin_settings'; - } - - /** - * {@inheritdoc} - */ - public function buildHeader() { - $header['label'] = array( - 'data' => $this->t('Label'), - ); - $header['url'] = array( - 'data' => $this->t('URL'), - 'class' => array(RESPONSIVE_PRIORITY_LOW), - ); - $header['plugin'] = array( - 'data' => $this->t('Type'), - 'class' => array(RESPONSIVE_PRIORITY_LOW), - ); - $header['status'] = array( - 'data' => $this->t('Status'), - 'class' => array(RESPONSIVE_PRIORITY_LOW), - ); - return $header + parent::buildHeader(); - } - - /** - * {@inheritdoc} - */ - public function buildRow(EntityInterface $entity) { - /** @var $entity \Drupal\search\SearchPageInterface */ - $row['label'] = $this->getLabel($entity); - $row['url']['#markup'] = 'search/' . $entity->getPath(); - // If the search page is active, link to it. - if ($entity->status()) { - $row['url'] = array( - '#type' => 'link', - '#title' => $row['url'], - '#route_name' => 'search.view_' . $entity->id(), - ); - } - - $definition = $entity->getPlugin()->getPluginDefinition(); - $row['plugin']['#markup'] = $definition['title']; - - if ($entity->isDefaultSearch()) { - $status = $this->t('Default'); - } - elseif ($entity->status()) { - $status = $this->t('Enabled'); - } - else { - $status = $this->t('Disabled'); - } - $row['status']['#markup'] = $status; - return $row + parent::buildRow($entity); - } - - /** - * {@inheritdoc} - */ - public function buildForm(array $form, array &$form_state) { - $form = parent::buildForm($form, $form_state); - $old_state = $this->configFactory->getOverrideState(); - $search_settings = $this->configFactory->setOverrideState(FALSE)->get('search.settings'); - $this->configFactory->setOverrideState($old_state); - // Collect some stats. - $remaining = 0; - $total = 0; - foreach ($this->entities as $entity) { - if ($entity->isIndexable() && $status = $entity->getPlugin()->indexStatus()) { - $remaining += $status['remaining']; - $total += $status['total']; - } - } - - $this->moduleHandler->loadAllIncludes('admin.inc'); - $count = format_plural($remaining, 'There is 1 item left to index.', 'There are @count items left to index.'); - $percentage = ((int) min(100, 100 * ($total - $remaining) / max(1, $total))) . '%'; - $status = '

' . $this->t('%percentage of the site has been indexed.', array('%percentage' => $percentage)) . ' ' . $count . '

'; - $form['status'] = array( - '#type' => 'details', - '#title' => $this->t('Indexing status'), - '#open' => TRUE, - ); - $form['status']['status'] = array('#markup' => $status); - $form['status']['wipe'] = array( - '#type' => 'submit', - '#value' => $this->t('Re-index site'), - '#submit' => array(array($this, 'searchAdminReindexSubmit')), - ); - - $items = array(10, 20, 50, 100, 200, 500); - $items = array_combine($items, $items); - - // Indexing throttle: - $form['indexing_throttle'] = array( - '#type' => 'details', - '#title' => $this->t('Indexing throttle'), - '#open' => TRUE, - ); - $form['indexing_throttle']['cron_limit'] = array( - '#type' => 'select', - '#title' => $this->t('Number of items to index per cron run'), - '#default_value' => $search_settings->get('index.cron_limit'), - '#options' => $items, - '#description' => $this->t('The maximum number of items indexed in each pass of a cron maintenance task. If necessary, reduce the number of items to prevent timeouts and memory errors while indexing.', array('@cron' => url('admin/reports/status'))), - ); - // Indexing settings: - $form['indexing_settings'] = array( - '#type' => 'details', - '#title' => $this->t('Indexing settings'), - '#open' => TRUE, - ); - $form['indexing_settings']['info'] = array( - '#markup' => $this->t('

Changing the settings below will cause the site index to be rebuilt. The search index is not cleared but systematically updated to reflect the new settings. Searching will continue to work but new content won\'t be indexed until all existing content has been re-indexed.

The default settings should be appropriate for the majority of sites.

') - ); - $form['indexing_settings']['minimum_word_size'] = array( - '#type' => 'number', - '#title' => $this->t('Minimum word length to index'), - '#default_value' => $search_settings->get('index.minimum_word_size'), - '#min' => 1, - '#max' => 1000, - '#description' => $this->t('The number of characters a word has to be to be indexed. A lower setting means better search result ranking, but also a larger database. Each search query must contain at least one keyword that is this size (or longer).') - ); - $form['indexing_settings']['overlap_cjk'] = array( - '#type' => 'checkbox', - '#title' => $this->t('Simple CJK handling'), - '#default_value' => $search_settings->get('index.overlap_cjk'), - '#description' => $this->t('Whether to apply a simple Chinese/Japanese/Korean tokenizer based on overlapping sequences. Turn this off if you want to use an external preprocessor for this instead. Does not affect other languages.') - ); - - $form['search_pages'] = array( - '#type' => 'details', - '#title' => $this->t('Search pages'), - '#open' => TRUE, - ); - $form['search_pages']['add_page'] = array( - '#type' => 'container', - '#attributes' => array( - 'class' => array('container-inline'), - ), - '#attached' => array( - 'css' => array( - drupal_get_path('module', 'search') . '/css/search.admin.css', - ), - ), - ); - // In order to prevent validation errors for the parent form, this cannot be - // required, see self::validateAddSearchPage(). - $form['search_pages']['add_page']['search_type'] = array( - '#type' => 'select', - '#title' => $this->t('Search page type'), - '#empty_option' => $this->t('- Choose page type -'), - '#options' => array_map(function ($definition) { - return $definition['title']; - }, $this->searchManager->getDefinitions()), - ); - $form['search_pages']['add_page']['add_search_submit'] = array( - '#type' => 'submit', - '#value' => $this->t('Add new page'), - '#validate' => array(array($this, 'validateAddSearchPage')), - '#submit' => array(array($this, 'submitAddSearchPage')), - '#limit_validation_errors' => array(array('search_type')), - ); - - // Move the listing into the search_pages element. - $form['search_pages'][$this->entitiesKey] = $form[$this->entitiesKey]; - $form['search_pages'][$this->entitiesKey]['#empty'] = $this->t('No search pages have been configured.'); - unset($form[$this->entitiesKey]); - - $form['actions']['#type'] = 'actions'; - $form['actions']['submit'] = array( - '#type' => 'submit', - '#value' => $this->t('Save configuration'), - '#button_type' => 'primary', - ); - - return $form; - } - - /** - * {@inheritdoc} - */ - public function getOperations(EntityInterface $entity) { - /** @var $entity \Drupal\search\SearchPageInterface */ - $operations = parent::getOperations($entity); - - // Prevent the default search from being disabled or deleted. - if ($entity->isDefaultSearch()) { - unset($operations['disable'], $operations['delete']); - } - else { - $operations['default'] = array( - 'title' => $this->t('Set as default'), - 'route_name' => 'search.set_default', - 'route_parameters' => array( - 'search_page' => $entity->id(), - ), - 'weight' => 50, - ); - } - - return $operations; - } - - /** - * {@inheritdoc} - */ - public function validateForm(array &$form, array &$form_state) { - } - - /** - * {@inheritdoc} - */ - public function submitForm(array &$form, array &$form_state) { - parent::submitForm($form, $form_state); - - $search_settings = $this->configFactory->get('search.settings'); - // If these settings change, the index needs to be rebuilt. - if (($search_settings->get('index.minimum_word_size') != $form_state['values']['minimum_word_size']) || ($search_settings->get('index.overlap_cjk') != $form_state['values']['overlap_cjk'])) { - $search_settings->set('index.minimum_word_size', $form_state['values']['minimum_word_size']); - $search_settings->set('index.overlap_cjk', $form_state['values']['overlap_cjk']); - drupal_set_message($this->t('The index will be rebuilt.')); - search_reindex(); - } - - $search_settings - ->set('index.cron_limit', $form_state['values']['cron_limit']) - ->save(); - - drupal_set_message($this->t('The configuration options have been saved.')); - } - - /** - * Form submission handler for the reindex button on the search admin settings - * form. - */ - public function searchAdminReindexSubmit(array &$form, array &$form_state) { - // Send the user to the confirmation page. - $form_state['redirect_route']['route_name'] = 'search.reindex_confirm'; - } - - /** - * Form validation handler for adding a new search page. - */ - public function validateAddSearchPage(array &$form, array &$form_state) { - if (empty($form_state['values']['search_type'])) { - $this->formBuilder()->setErrorByName('search_type', $form_state, $this->t('You must select the new search page type.')); - } - } - - /** - * Form submission handler for adding a new search page. - */ - public function submitAddSearchPage(array &$form, array &$form_state) { - $form_state['redirect_route'] = array( - 'route_name' => 'search.add_type', - 'route_parameters' => array( - 'search_plugin_id' => $form_state['values']['search_type'], - ), - ); - } - -} diff --git a/core/modules/search/lib/Drupal/search/SearchPageListController.php b/core/modules/search/lib/Drupal/search/SearchPageListController.php new file mode 100644 index 0000000..a497507 --- /dev/null +++ b/core/modules/search/lib/Drupal/search/SearchPageListController.php @@ -0,0 +1,341 @@ +configFactory = $config_factory; + $this->searchManager = $search_manager; + } + + /** + * {@inheritdoc} + */ + public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { + return new static( + $entity_type, + $container->get('entity.manager')->getStorageController($entity_type->id()), + $container->get('plugin.manager.search'), + $container->get('config.factory') + ); + } + + /** + * {@inheritdoc} + */ + public function getFormID() { + return 'search_admin_settings'; + } + + /** + * {@inheritdoc} + */ + public function buildHeader() { + $header['label'] = array( + 'data' => $this->t('Label'), + ); + $header['url'] = array( + 'data' => $this->t('URL'), + 'class' => array(RESPONSIVE_PRIORITY_LOW), + ); + $header['plugin'] = array( + 'data' => $this->t('Type'), + 'class' => array(RESPONSIVE_PRIORITY_LOW), + ); + $header['status'] = array( + 'data' => $this->t('Status'), + 'class' => array(RESPONSIVE_PRIORITY_LOW), + ); + return $header + parent::buildHeader(); + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + /** @var $entity \Drupal\search\SearchPageInterface */ + $row['label'] = $this->getLabel($entity); + $row['url']['#markup'] = 'search/' . $entity->getPath(); + // If the search page is active, link to it. + if ($entity->status()) { + $row['url'] = array( + '#type' => 'link', + '#title' => $row['url'], + '#route_name' => 'search.view_' . $entity->id(), + ); + } + + $definition = $entity->getPlugin()->getPluginDefinition(); + $row['plugin']['#markup'] = $definition['title']; + + if ($entity->isDefaultSearch()) { + $status = $this->t('Default'); + } + elseif ($entity->status()) { + $status = $this->t('Enabled'); + } + else { + $status = $this->t('Disabled'); + } + $row['status']['#markup'] = $status; + return $row + parent::buildRow($entity); + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, array &$form_state) { + $form = parent::buildForm($form, $form_state); + $old_state = $this->configFactory->getOverrideState(); + $search_settings = $this->configFactory->setOverrideState(FALSE)->get('search.settings'); + $this->configFactory->setOverrideState($old_state); + // Collect some stats. + $remaining = 0; + $total = 0; + foreach ($this->entities as $entity) { + if ($entity->isIndexable() && $status = $entity->getPlugin()->indexStatus()) { + $remaining += $status['remaining']; + $total += $status['total']; + } + } + + $this->moduleHandler->loadAllIncludes('admin.inc'); + $count = format_plural($remaining, 'There is 1 item left to index.', 'There are @count items left to index.'); + $percentage = ((int) min(100, 100 * ($total - $remaining) / max(1, $total))) . '%'; + $status = '

' . $this->t('%percentage of the site has been indexed.', array('%percentage' => $percentage)) . ' ' . $count . '

'; + $form['status'] = array( + '#type' => 'details', + '#title' => $this->t('Indexing status'), + '#open' => TRUE, + ); + $form['status']['status'] = array('#markup' => $status); + $form['status']['wipe'] = array( + '#type' => 'submit', + '#value' => $this->t('Re-index site'), + '#submit' => array(array($this, 'searchAdminReindexSubmit')), + ); + + $items = array(10, 20, 50, 100, 200, 500); + $items = array_combine($items, $items); + + // Indexing throttle: + $form['indexing_throttle'] = array( + '#type' => 'details', + '#title' => $this->t('Indexing throttle'), + '#open' => TRUE, + ); + $form['indexing_throttle']['cron_limit'] = array( + '#type' => 'select', + '#title' => $this->t('Number of items to index per cron run'), + '#default_value' => $search_settings->get('index.cron_limit'), + '#options' => $items, + '#description' => $this->t('The maximum number of items indexed in each pass of a cron maintenance task. If necessary, reduce the number of items to prevent timeouts and memory errors while indexing.', array('@cron' => url('admin/reports/status'))), + ); + // Indexing settings: + $form['indexing_settings'] = array( + '#type' => 'details', + '#title' => $this->t('Indexing settings'), + '#open' => TRUE, + ); + $form['indexing_settings']['info'] = array( + '#markup' => $this->t('

Changing the settings below will cause the site index to be rebuilt. The search index is not cleared but systematically updated to reflect the new settings. Searching will continue to work but new content won\'t be indexed until all existing content has been re-indexed.

The default settings should be appropriate for the majority of sites.

') + ); + $form['indexing_settings']['minimum_word_size'] = array( + '#type' => 'number', + '#title' => $this->t('Minimum word length to index'), + '#default_value' => $search_settings->get('index.minimum_word_size'), + '#min' => 1, + '#max' => 1000, + '#description' => $this->t('The number of characters a word has to be to be indexed. A lower setting means better search result ranking, but also a larger database. Each search query must contain at least one keyword that is this size (or longer).') + ); + $form['indexing_settings']['overlap_cjk'] = array( + '#type' => 'checkbox', + '#title' => $this->t('Simple CJK handling'), + '#default_value' => $search_settings->get('index.overlap_cjk'), + '#description' => $this->t('Whether to apply a simple Chinese/Japanese/Korean tokenizer based on overlapping sequences. Turn this off if you want to use an external preprocessor for this instead. Does not affect other languages.') + ); + + $form['search_pages'] = array( + '#type' => 'details', + '#title' => $this->t('Search pages'), + '#open' => TRUE, + ); + $form['search_pages']['add_page'] = array( + '#type' => 'container', + '#attributes' => array( + 'class' => array('container-inline'), + ), + '#attached' => array( + 'css' => array( + drupal_get_path('module', 'search') . '/css/search.admin.css', + ), + ), + ); + // In order to prevent validation errors for the parent form, this cannot be + // required, see self::validateAddSearchPage(). + $form['search_pages']['add_page']['search_type'] = array( + '#type' => 'select', + '#title' => $this->t('Search page type'), + '#empty_option' => $this->t('- Choose page type -'), + '#options' => array_map(function ($definition) { + return $definition['title']; + }, $this->searchManager->getDefinitions()), + ); + $form['search_pages']['add_page']['add_search_submit'] = array( + '#type' => 'submit', + '#value' => $this->t('Add new page'), + '#validate' => array(array($this, 'validateAddSearchPage')), + '#submit' => array(array($this, 'submitAddSearchPage')), + '#limit_validation_errors' => array(array('search_type')), + ); + + // Move the listing into the search_pages element. + $form['search_pages'][$this->entitiesKey] = $form[$this->entitiesKey]; + $form['search_pages'][$this->entitiesKey]['#empty'] = $this->t('No search pages have been configured.'); + unset($form[$this->entitiesKey]); + + $form['actions']['#type'] = 'actions'; + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => $this->t('Save configuration'), + '#button_type' => 'primary', + ); + + return $form; + } + + /** + * {@inheritdoc} + */ + public function getOperations(EntityInterface $entity) { + /** @var $entity \Drupal\search\SearchPageInterface */ + $operations = parent::getOperations($entity); + + // Prevent the default search from being disabled or deleted. + if ($entity->isDefaultSearch()) { + unset($operations['disable'], $operations['delete']); + } + else { + $operations['default'] = array( + 'title' => $this->t('Set as default'), + 'route_name' => 'search.set_default', + 'route_parameters' => array( + 'search_page' => $entity->id(), + ), + 'weight' => 50, + ); + } + + return $operations; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, array &$form_state) { + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + parent::submitForm($form, $form_state); + + $search_settings = $this->configFactory->get('search.settings'); + // If these settings change, the index needs to be rebuilt. + if (($search_settings->get('index.minimum_word_size') != $form_state['values']['minimum_word_size']) || ($search_settings->get('index.overlap_cjk') != $form_state['values']['overlap_cjk'])) { + $search_settings->set('index.minimum_word_size', $form_state['values']['minimum_word_size']); + $search_settings->set('index.overlap_cjk', $form_state['values']['overlap_cjk']); + drupal_set_message($this->t('The index will be rebuilt.')); + search_reindex(); + } + + $search_settings + ->set('index.cron_limit', $form_state['values']['cron_limit']) + ->save(); + + drupal_set_message($this->t('The configuration options have been saved.')); + } + + /** + * Form submission handler for the reindex button on the search admin settings + * form. + */ + public function searchAdminReindexSubmit(array &$form, array &$form_state) { + // Send the user to the confirmation page. + $form_state['redirect_route']['route_name'] = 'search.reindex_confirm'; + } + + /** + * Form validation handler for adding a new search page. + */ + public function validateAddSearchPage(array &$form, array &$form_state) { + if (empty($form_state['values']['search_type'])) { + $this->formBuilder()->setErrorByName('search_type', $form_state, $this->t('You must select the new search page type.')); + } + } + + /** + * Form submission handler for adding a new search page. + */ + public function submitAddSearchPage(array &$form, array &$form_state) { + $form_state['redirect_route'] = array( + 'route_name' => 'search.add_type', + 'route_parameters' => array( + 'search_plugin_id' => $form_state['values']['search_type'], + ), + ); + } + +} diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Entity/ShortcutSet.php b/core/modules/shortcut/lib/Drupal/shortcut/Entity/ShortcutSet.php index f7f400c..fea529b 100644 --- a/core/modules/shortcut/lib/Drupal/shortcut/Entity/ShortcutSet.php +++ b/core/modules/shortcut/lib/Drupal/shortcut/Entity/ShortcutSet.php @@ -20,7 +20,7 @@ * controllers = { * "storage" = "Drupal\shortcut\ShortcutSetStorageController", * "access" = "Drupal\shortcut\ShortcutSetAccessController", - * "list_builder" = "Drupal\shortcut\ShortcutSetListBuilder", + * "list" = "Drupal\shortcut\ShortcutSetListController", * "form" = { * "default" = "Drupal\shortcut\ShortcutSetFormController", * "add" = "Drupal\shortcut\ShortcutSetFormController", diff --git a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListBuilder.php b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListBuilder.php deleted file mode 100644 index 45b6a5f..0000000 --- a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListBuilder.php +++ /dev/null @@ -1,52 +0,0 @@ - t('List links'), - ) + $entity->urlInfo('customize-form'); - return $operations; - } - - /** - * {@inheritdoc} - */ - public function buildRow(EntityInterface $entity) { - $row['name'] = $this->getLabel($entity); - return $row + parent::buildRow($entity); - } - -} diff --git a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListController.php b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListController.php new file mode 100644 index 0000000..6741ed2 --- /dev/null +++ b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListController.php @@ -0,0 +1,50 @@ + t('List links'), + ) + $entity->urlInfo('customize-form'); + return $operations; + } + + /** + * Overrides \Drupal\Core\Entity\EntityListController::buildRow(). + */ + public function buildRow(EntityInterface $entity) { + $row['name'] = $this->getLabel($entity); + return $row + parent::buildRow($entity); + } + +} diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php index 8efa40a..3e8f51b 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php @@ -354,7 +354,6 @@ protected function drupalCreateContentType(array $values = array()) { * - region: 'sidebar_first'. * - theme: The default theme. * - visibility: Empty array. - * - cache: array('max_age' => 0). * * @return \Drupal\block\Entity\Block * The block entity. @@ -371,9 +370,6 @@ protected function drupalPlaceBlock($plugin_id, array $settings = array()) { 'label' => $this->randomName(8), 'visibility' => array(), 'weight' => 0, - 'cache' => array( - 'max_age' => 0, - ), ); foreach (array('region', 'id', 'theme', 'plugin', 'visibility', 'weight') as $key) { $values[$key] = $settings[$key]; diff --git a/core/modules/system/entity.api.php b/core/modules/system/entity.api.php index ab25a74..c0203bd 100644 --- a/core/modules/system/entity.api.php +++ b/core/modules/system/entity.api.php @@ -760,7 +760,7 @@ function hook_entity_bundle_field_info_alter(&$fields, \Drupal\Core\Entity\Entit * * @param array $operations * Operations array as returned by - * \Drupal\Core\Entity\EntityListBuilderInterface::getOperations(). + * \Drupal\Core\Entity\EntityListControllerInterface::getOperations(). * @param \Drupal\Core\Entity\EntityInterface $entity * The entity on which the linked operations will be performed. */ diff --git a/core/modules/system/lib/Drupal/system/DateFormatListBuilder.php b/core/modules/system/lib/Drupal/system/DateFormatListBuilder.php deleted file mode 100644 index be83cd9..0000000 --- a/core/modules/system/lib/Drupal/system/DateFormatListBuilder.php +++ /dev/null @@ -1,88 +0,0 @@ -dateService = $date_service; - } - - /** - * {@inheritdoc} - */ - public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { - return new static( - $entity_type, - $container->get('entity.manager')->getStorageController($entity_type->id()), - $container->get('date') - ); - } - - /** - * {@inheritdoc} - */ - public function load() { - return array_filter(parent::load(), function ($entity) { - return !$entity->isLocked(); - }); - } - - /** - * {@inheritdoc} - */ - public function buildHeader() { - $header['id'] = t('Machine name'); - $header['label'] = t('Name'); - $header['pattern'] = t('Pattern'); - return $header + parent::buildHeader(); - } - - /** - * {@inheritdoc} - */ - public function buildRow(EntityInterface $entity) { - $row['id'] = $entity->id(); - $row['label'] = $this->getLabel($entity); - $row['pattern'] = $this->dateService->format(REQUEST_TIME, $entity->id()); - return $row + parent::buildRow($entity); - } - -} diff --git a/core/modules/system/lib/Drupal/system/DateFormatListController.php b/core/modules/system/lib/Drupal/system/DateFormatListController.php new file mode 100644 index 0000000..9472d8c --- /dev/null +++ b/core/modules/system/lib/Drupal/system/DateFormatListController.php @@ -0,0 +1,86 @@ +dateService = $date_service; + } + + /** + * {@inheritdoc} + */ + public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { + return new static( + $entity_type, + $container->get('entity.manager')->getStorageController($entity_type->id()), + $container->get('date') + ); + } + + /** + * {@inheritdoc} + */ + public function load() { + return array_filter(parent::load(), function ($entity) { + return !$entity->isLocked(); + }); + } + + /** + * {@inheritdoc} + */ + public function buildHeader() { + $header['id'] = t('Machine name'); + $header['label'] = t('Name'); + $header['pattern'] = t('Pattern'); + return $header + parent::buildHeader(); + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + $row['id'] = $entity->id(); + $row['label'] = $this->getLabel($entity); + $row['pattern'] = $this->dateService->format(REQUEST_TIME, $entity->id()); + return $row + parent::buildRow($entity); + } + +} diff --git a/core/modules/system/lib/Drupal/system/Entity/DateFormat.php b/core/modules/system/lib/Drupal/system/Entity/DateFormat.php index 21d8035..a03cac3 100644 --- a/core/modules/system/lib/Drupal/system/Entity/DateFormat.php +++ b/core/modules/system/lib/Drupal/system/Entity/DateFormat.php @@ -20,7 +20,7 @@ * label = @Translation("Date format"), * controllers = { * "access" = "Drupal\system\DateFormatAccessController", - * "list_builder" = "Drupal\system\DateFormatListBuilder", + * "list" = "Drupal\system\DateFormatListController", * "form" = { * "add" = "Drupal\system\Form\DateFormatAddForm", * "edit" = "Drupal\system\Form\DateFormatEditForm", diff --git a/core/modules/system/lib/Drupal/system/Form/PerformanceForm.php b/core/modules/system/lib/Drupal/system/Form/PerformanceForm.php index 27d628a..fe689d0 100644 --- a/core/modules/system/lib/Drupal/system/Form/PerformanceForm.php +++ b/core/modules/system/lib/Drupal/system/Form/PerformanceForm.php @@ -79,12 +79,10 @@ public function buildForm(array $form, array &$form_state) { '#title' => t('Caching'), '#open' => TRUE, ); - // Identical options to the ones for block caching. - // @see \Drupal\block\BlockBase::buildConfigurationForm() + $period = array(0, 60, 180, 300, 600, 900, 1800, 2700, 3600, 10800, 21600, 32400, 43200, 86400); $period = array_map('format_interval', array_combine($period, $period)); - $period[0] = '<' . t('no caching') . '>'; - $period[\Drupal\Core\Cache\Cache::PERMANENT] = t('Forever'); + $period[0] = '<' . t('none') . '>'; $form['caching']['page_cache_maximum_age'] = array( '#type' => 'select', '#title' => t('Page cache maximum age'), diff --git a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemHelpBlock.php b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemHelpBlock.php index c594b98..f669e61 100644 --- a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemHelpBlock.php +++ b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemHelpBlock.php @@ -117,24 +117,4 @@ public function build() { ); } - /** - * {@inheritdoc} - */ - public function defaultConfiguration() { - // Modify the default max age for the System Help block: help text is static - // for a given URL, except when a module is updated, in which case - // update.php must be run, which clears all caches. Thus it's safe to cache - // the output for this block forever on a per-URL basis. - return array('cache' => array('max_age' => \Drupal\Core\Cache\Cache::PERMANENT)); - } - - /** - * {@inheritdoc} - */ - protected function getRequiredCacheContexts() { - // The "System Help" block must be cached per URL: help is defined for a - // given path, and does not come with any access restrictions. - return array('cache_context.url'); - } - } diff --git a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMainBlock.php b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMainBlock.php index 666b515..a64951a 100644 --- a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMainBlock.php +++ b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMainBlock.php @@ -28,26 +28,4 @@ public function build() { ); } - /** - * {@inheritdoc} - */ - public function buildConfigurationForm(array $form, array &$form_state) { - $form = parent::buildConfigurationForm($form, $form_state); - - // The main content block is never cacheable, because it may be dynamic. - $form['cache']['#disabled'] = TRUE; - $form['cache']['#description'] = t('This block is never cacheable, it is not configurable.'); - $form['cache']['max_age']['#value'] = 0; - - return $form; - } - - /** - * {@inheritdoc} - */ - public function isCacheable() { - // The main content block is never cacheable, because it may be dynamic. - return FALSE; - } - } diff --git a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php index 15cb1d8..8298193 100644 --- a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php +++ b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php @@ -7,8 +7,8 @@ namespace Drupal\system\Plugin\Block; -use Drupal\Component\Utility\NestedArray; use Drupal\block\BlockBase; +use Drupal\Core\Session\AccountInterface; /** * Provides a generic Menu block. @@ -30,41 +30,4 @@ public function build() { return menu_tree($menu); } - /** - * {@inheritdoc} - */ - public function defaultConfiguration() { - // Modify the default max age for menu blocks: modifications made to menus, - // menu links and menu blocks will automatically invalidate corresponding - // cache tags, therefore allowing us to cache menu blocks forever. This is - // only not the case if there are user-specific or dynamic alterations (e.g. - // hook_node_access()), but in that: - // 1) it is possible to set a different max age for individual blocks, since - // this is just the default value. - // 2) modules can modify caching by implementing hook_block_view_alter() - return array('cache' => array('max_age' => \Drupal\Core\Cache\Cache::PERMANENT)); - } - - /** - * {@inheritdoc} - */ - public function getCacheTags() { - // Even when the menu block renders to the empty string for a user, we want - // the cache tag for this menu to be set: whenever the menu is changed, this - // menu block must also be re-rendered for that user, because maybe a menu - // link that is accessible for that user has been added. - $tags = array('menu' => array($this->getDerivativeId())); - return NestedArray::mergeDeep(parent::getCacheTags(), $tags); - } - - /** - * {@inheritdoc} - */ - protected function getRequiredCacheContexts() { - // Menu blocks must be cached per URL and per role: the "active" menu link - // may differ per URL and different roles may have access to different menu - // links. - return array('cache_context.url', 'cache_context.user.roles'); - } - } diff --git a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemPoweredByBlock.php b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemPoweredByBlock.php index b0878f8..742af7b 100644 --- a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemPoweredByBlock.php +++ b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemPoweredByBlock.php @@ -8,7 +8,6 @@ namespace Drupal\system\Plugin\Block; use Drupal\block\BlockBase; -use Drupal\Core\Cache\Cache; /** * Provides a 'Powered by Drupal' block. @@ -27,34 +26,4 @@ public function build() { return array('#markup' => '' . t('Powered by Drupal', array('@poweredby' => 'http://drupal.org')) . ''); } - - /** - * {@inheritdoc} - */ - public function buildConfigurationForm(array $form, array &$form_state) { - $form = parent::buildConfigurationForm($form, $form_state); - - // The 'Powered by Drupal' block is permanently cacheable, because its - // contents can never change. - $form['cache']['#disabled'] = TRUE; - $form['cache']['max_age']['#value'] = Cache::PERMANENT; - $form['cache']['#description'] = t('This block is always cached forever, it is not configurable.'); - - return $form; - } - - /** - * {@inheritdoc} - */ - public function getCacheMaxAge() { - return Cache::PERMANENT; - } - - /** - * {@inheritdoc} - */ - public function isCacheable() { - return TRUE; - } - } diff --git a/core/modules/system/lib/Drupal/system/Plugin/Derivative/SystemMenuBlock.php b/core/modules/system/lib/Drupal/system/Plugin/Derivative/SystemMenuBlock.php index 72a4c49..372de9b 100644 --- a/core/modules/system/lib/Drupal/system/Plugin/Derivative/SystemMenuBlock.php +++ b/core/modules/system/lib/Drupal/system/Plugin/Derivative/SystemMenuBlock.php @@ -52,6 +52,7 @@ public function getDerivativeDefinitions($base_plugin_definition) { foreach ($this->menuStorage->loadMultiple() as $menu => $entity) { $this->derivatives[$menu] = $base_plugin_definition; $this->derivatives[$menu]['admin_label'] = $entity->label(); + $this->derivatives[$menu]['cache'] = DRUPAL_NO_CACHE; } return $this->derivatives; } diff --git a/core/modules/system/lib/Drupal/system/Tests/Cache/PageCacheTagsIntegrationTest.php b/core/modules/system/lib/Drupal/system/Tests/Cache/PageCacheTagsIntegrationTest.php index cc584a3..b245c34 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Cache/PageCacheTagsIntegrationTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Cache/PageCacheTagsIntegrationTest.php @@ -64,35 +64,13 @@ function testPageCacheTags() { 'promote' => NODE_PROMOTED, )); - // Place a block, but only make it visible on full node page 2. - $block = $this->drupalPlaceBlock('views_block:comments_recent-block_1', array( - 'visibility' => array( - 'path' => array( - 'visibility' => BLOCK_VISIBILITY_LISTED, - 'pages' => 'node/' . $node_2->id(), - ), - ) - )); - // Full node page 1. $this->verifyPageCacheTags('node/' . $node_1->id(), array( 'content:1', - 'block_view:1', - 'block:bartik_content', - 'block:bartik_tools', - 'block:bartik_login', - 'block:bartik_footer', - 'block:bartik_powered', - 'block_plugin:system_main_block', - 'block_plugin:system_menu_block__tools', - 'block_plugin:user_login_block', - 'block_plugin:system_menu_block__footer', - 'block_plugin:system_powered_by_block', 'node_view:1', 'node:' . $node_1->id(), 'user:' . $author_1->id(), 'filter_format:basic_html', - 'menu:tools', 'menu:footer', 'menu:main', )); @@ -100,24 +78,10 @@ function testPageCacheTags() { // Full node page 2. $this->verifyPageCacheTags('node/' . $node_2->id(), array( 'content:1', - 'block_view:1', - 'block:bartik_content', - 'block:bartik_tools', - 'block:bartik_login', - 'block:' . $block->id(), - 'block:bartik_footer', - 'block:bartik_powered', - 'block_plugin:system_main_block', - 'block_plugin:system_menu_block__tools', - 'block_plugin:user_login_block', - 'block_plugin:views_block__comments_recent-block_1', - 'block_plugin:system_menu_block__footer', - 'block_plugin:system_powered_by_block', 'node_view:1', 'node:' . $node_2->id(), 'user:' . $author_2->id(), 'filter_format:full_html', - 'menu:tools', 'menu:footer', 'menu:main', )); diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityViewBuilderTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityViewBuilderTest.php index 0379aa7..2d0369b 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityViewBuilderTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityViewBuilderTest.php @@ -144,7 +144,7 @@ public function testEntityViewBuilderCacheToggling() { // Test a view mode in default conditions: render caching is enabled for // the entity type and the view mode. $build = $this->container->get('entity.manager')->getViewBuilder('entity_test')->view($entity_test, 'full'); - $this->assertTrue(isset($build['#cache']) && array_keys($build['#cache']) == array('tags', 'keys', 'bin') , 'A view mode with render cache enabled has the correct output (cache tags, keys and bin).'); + $this->assertTrue(isset($build['#cache']) && array_keys($build['#cache']) == array('tags', 'keys', 'granularity', 'bin') , 'A view mode with render cache enabled has the correct output (cache tags, keys, granularity and bin).'); // Test that a view mode can opt out of render caching. $build = $this->container->get('entity.manager')->getViewBuilder('entity_test')->view($entity_test, 'test'); diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTest.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTest.php index 357b77e..d55bb8d 100644 --- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTest.php +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTest.php @@ -22,7 +22,7 @@ * id = "entity_test", * label = @Translation("Test entity"), * controllers = { - * "list_builder" = "Drupal\entity_test\EntityTestListBuilder", + * "list" = "Drupal\entity_test\EntityTestListController", * "view_builder" = "Drupal\entity_test\EntityTestViewBuilder", * "access" = "Drupal\entity_test\EntityTestAccessController", * "form" = { diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestListBuilder.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestListBuilder.php deleted file mode 100644 index 1fbc8a1..0000000 --- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestListBuilder.php +++ /dev/null @@ -1,38 +0,0 @@ -getLabel($entity); - $row['id'] = $entity->id(); - return $row + parent::buildRow($entity); - } - -} diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestListController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestListController.php new file mode 100644 index 0000000..fddc724 --- /dev/null +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestListController.php @@ -0,0 +1,36 @@ +getLabel($entity); + $row['id'] = $entity->id(); + return $row + parent::buildRow($entity); + } + +} diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Vocabulary.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Vocabulary.php index f7e3f91..ee3d8f3 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Vocabulary.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Vocabulary.php @@ -20,7 +20,7 @@ * label = @Translation("Taxonomy vocabulary"), * controllers = { * "storage" = "Drupal\taxonomy\VocabularyStorageController", - * "list_builder" = "Drupal\taxonomy\VocabularyListBuilder", + * "list" = "Drupal\taxonomy\VocabularyListController", * "form" = { * "default" = "Drupal\taxonomy\VocabularyFormController", * "reset" = "Drupal\taxonomy\Form\VocabularyResetForm", diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListBuilder.php b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListBuilder.php deleted file mode 100644 index 2823551..0000000 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListBuilder.php +++ /dev/null @@ -1,106 +0,0 @@ - t('list terms'), - 'weight' => 0, - ) + $entity->urlInfo('overview-form'); - $operations['add'] = array( - 'title' => t('add terms'), - 'weight' => 10, - ) + $entity->urlInfo('add-form'); - unset($operations['delete']); - - return $operations; - } - - /** - * {@inheritdoc} - */ - public function buildHeader() { - $header['label'] = t('Vocabulary name'); - return $header + parent::buildHeader(); - } - - /** - * {@inheritdoc} - */ - public function buildRow(EntityInterface $entity) { - $row['label'] = $this->getLabel($entity); - return $row + parent::buildRow($entity); - } - - /** - * {@inheritdoc} - */ - public function render() { - $entities = $this->load(); - // If there are not multiple vocabularies, disable dragging by unsetting the - // weight key. - if (count($entities) <= 1) { - unset($this->weightKey); - } - $build = parent::render(); - $build['#empty'] = t('No vocabularies available. Add vocabulary.', array('@link' => url('admin/structure/taxonomy/add'))); - return $build; - } - - /** - * {@inheritdoc} - */ - public function buildForm(array $form, array &$form_state) { - $form = parent::buildForm($form, $form_state); - $form['vocabularies']['#attributes'] = array('id' => 'taxonomy'); - $form['actions']['submit']['#value'] = t('Save'); - - return $form; - } - - /** - * {@inheritdoc} - */ - public function submitForm(array &$form, array &$form_state) { - parent::submitForm($form, $form_state); - - drupal_set_message(t('The configuration options have been saved.')); - } - -} diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListController.php new file mode 100644 index 0000000..104b360 --- /dev/null +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListController.php @@ -0,0 +1,104 @@ + t('list terms'), + 'weight' => 0, + ) + $entity->urlInfo('overview-form'); + $operations['add'] = array( + 'title' => t('add terms'), + 'weight' => 10, + ) + $entity->urlInfo('add-form'); + unset($operations['delete']); + + return $operations; + } + + /** + * {@inheritdoc} + */ + public function buildHeader() { + $header['label'] = t('Vocabulary name'); + return $header + parent::buildHeader(); + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + $row['label'] = $this->getLabel($entity); + return $row + parent::buildRow($entity); + } + + /** + * {@inheritdoc} + */ + public function render() { + $entities = $this->load(); + // If there are not multiple vocabularies, disable dragging by unsetting the + // weight key. + if (count($entities) <= 1) { + unset($this->weightKey); + } + $build = parent::render(); + $build['#empty'] = t('No vocabularies available. Add vocabulary.', array('@link' => url('admin/structure/taxonomy/add'))); + return $build; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, array &$form_state) { + $form = parent::buildForm($form, $form_state); + $form['vocabularies']['#attributes'] = array('id' => 'taxonomy'); + $form['actions']['submit']['#value'] = t('Save'); + + return $form; + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + parent::submitForm($form, $form_state); + + drupal_set_message(t('The configuration options have been saved.')); + } + +} diff --git a/core/modules/user/lib/Drupal/user/Cache/UserCacheContext.php b/core/modules/user/lib/Drupal/user/Cache/UserCacheContext.php deleted file mode 100644 index d9d880e..0000000 --- a/core/modules/user/lib/Drupal/user/Cache/UserCacheContext.php +++ /dev/null @@ -1,42 +0,0 @@ -user = $user; - } - - /** - * {@inheritdoc} - */ - public static function getLabel() { - return t('User'); - } - - /** - * {@inheritdoc} - */ - public function getContext() { - return "u." . $this->user->id(); - } - -} diff --git a/core/modules/user/lib/Drupal/user/Cache/UserRolesCacheContext.php b/core/modules/user/lib/Drupal/user/Cache/UserRolesCacheContext.php deleted file mode 100644 index 0f7975d..0000000 --- a/core/modules/user/lib/Drupal/user/Cache/UserRolesCacheContext.php +++ /dev/null @@ -1,42 +0,0 @@ -user = $user; - } - - /** - * {@inheritdoc} - */ - public static function getLabel() { - return t("User's roles"); - } - - /** - * {@inheritdoc} - */ - public function getContext() { - return 'r.' . implode(',', $this->user->getRoles()); - } - -} diff --git a/core/modules/user/lib/Drupal/user/Controller/UserListController.php b/core/modules/user/lib/Drupal/user/Controller/UserListController.php new file mode 100644 index 0000000..72c1a84 --- /dev/null +++ b/core/modules/user/lib/Drupal/user/Controller/UserListController.php @@ -0,0 +1,160 @@ +queryFactory = $query_factory; + } + + /** + * {@inheritdoc} + */ + public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { + return new static( + $entity_type, + $container->get('entity.manager')->getStorageController($entity_type->id()), + $container->get('entity.query') + ); + } + + /** + * {@inheritdoc} + */ + public function load() { + $entity_query = $this->queryFactory->get('user'); + $entity_query->condition('uid', 0, '<>'); + $entity_query->pager(50); + $header = $this->buildHeader(); + $entity_query->tableSort($header); + $uids = $entity_query->execute(); + return $this->storage->loadMultiple($uids); + } + + /** + * {@inheritdoc} + */ + public function buildHeader() { + $header = array( + 'username' => array( + 'data' => $this->t('Username'), + 'field' => 'name', + 'specifier' => 'name', + ), + 'status' => array( + 'data' => $this->t('Status'), + 'field' => 'status', + 'specifier' => 'status', + 'class' => array(RESPONSIVE_PRIORITY_LOW), + ), + 'roles' => array( + 'data' => $this->t('Roles'), + 'class' => array(RESPONSIVE_PRIORITY_LOW), + ), + 'member_for' => array( + 'data' => $this->t('Member for'), + 'field' => 'created', + 'specifier' => 'created', + 'sort' => 'desc', + 'class' => array(RESPONSIVE_PRIORITY_LOW), + ), + 'access' => array( + 'data' => $this->t('Last access'), + 'field' => 'access', + 'specifier' => 'access', + 'class' => array(RESPONSIVE_PRIORITY_LOW), + ), + ); + return $header + parent::buildHeader(); + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + $row['username']['data'] = array( + '#theme' => 'username', + '#account' => $entity, + ); + $row['status'] = $entity->isActive() ? $this->t('active') : $this->t('blocked'); + + $roles = array_map('\Drupal\Component\Utility\String::checkPlain', user_role_names(TRUE)); + unset($roles[DRUPAL_AUTHENTICATED_RID]); + $users_roles = array(); + foreach ($entity->getRoles() as $role) { + if (isset($roles[$role])) { + $users_roles[] = $roles[$role]; + } + } + asort($users_roles); + $row['roles']['data'] = array( + '#theme' => 'item_list', + '#items' => $users_roles, + ); + $row['member_for'] = format_interval(REQUEST_TIME - $entity->getCreatedTime()); + $row['access'] = $entity->access ? $this->t('@time ago', array( + '@time' => format_interval(REQUEST_TIME - $entity->getLastAccessedTime()), + )) : t('never'); + return $row + parent::buildRow($entity); + } + + /** + * {@inheritdoc} + */ + public function getOperations(EntityInterface $entity) { + $operations = parent::getOperations($entity); + if (isset($operations['edit'])) { + $destination = drupal_get_destination(); + $operations['edit']['query'] = $destination; + } + return $operations; + } + + /** + * {@inheritdoc} + */ + public function render() { + $build['accounts'] = parent::render(); + $build['accounts']['#empty'] = $this->t('No people available.'); + $build['pager']['#theme'] = 'pager'; + return $build; + } + +} diff --git a/core/modules/user/lib/Drupal/user/Entity/Role.php b/core/modules/user/lib/Drupal/user/Entity/Role.php index 0ce5186..2a025d9 100644 --- a/core/modules/user/lib/Drupal/user/Entity/Role.php +++ b/core/modules/user/lib/Drupal/user/Entity/Role.php @@ -21,7 +21,7 @@ * controllers = { * "storage" = "Drupal\user\RoleStorageController", * "access" = "Drupal\user\RoleAccessController", - * "list_builder" = "Drupal\user\RoleListBuilder", + * "list" = "Drupal\user\RoleListController", * "form" = { * "default" = "Drupal\user\RoleFormController", * "delete" = "Drupal\user\Form\UserRoleDelete" diff --git a/core/modules/user/lib/Drupal/user/Entity/User.php b/core/modules/user/lib/Drupal/user/Entity/User.php index 8cac65c..49c66fd 100644 --- a/core/modules/user/lib/Drupal/user/Entity/User.php +++ b/core/modules/user/lib/Drupal/user/Entity/User.php @@ -24,7 +24,7 @@ * controllers = { * "storage" = "Drupal\user\UserStorageController", * "access" = "Drupal\user\UserAccessController", - * "list_builder" = "Drupal\user\UserListBuilder", + * "list" = "Drupal\user\Controller\UserListController", * "view_builder" = "Drupal\Core\Entity\EntityViewBuilder", * "form" = { * "default" = "Drupal\user\ProfileFormController", diff --git a/core/modules/user/lib/Drupal/user/RoleListBuilder.php b/core/modules/user/lib/Drupal/user/RoleListBuilder.php deleted file mode 100644 index 2d2b9be..0000000 --- a/core/modules/user/lib/Drupal/user/RoleListBuilder.php +++ /dev/null @@ -1,67 +0,0 @@ -getLabel($entity); - return $row + parent::buildRow($entity); - } - - /** - * {@inheritdoc} - */ - public function getOperations(EntityInterface $entity) { - $operations = parent::getOperations($entity); - - if ($entity->hasLinkTemplate('edit-permissions-form')) { - $operations['permissions'] = array( - 'title' => t('Edit permissions'), - 'weight' => 20, - ) + $entity->urlInfo('edit-permissions-form'); - } - return $operations; - } - - /** - * {@inheritdoc} - */ - public function submitForm(array &$form, array &$form_state) { - parent::submitForm($form, $form_state); - - drupal_set_message(t('The role settings have been updated.')); - } - -} diff --git a/core/modules/user/lib/Drupal/user/RoleListController.php b/core/modules/user/lib/Drupal/user/RoleListController.php new file mode 100644 index 0000000..c2cd9b9 --- /dev/null +++ b/core/modules/user/lib/Drupal/user/RoleListController.php @@ -0,0 +1,65 @@ +getLabel($entity); + return $row + parent::buildRow($entity); + } + + /** + * {@inheritdoc} + */ + public function getOperations(EntityInterface $entity) { + $operations = parent::getOperations($entity); + + if ($entity->hasLinkTemplate('edit-permissions-form')) { + $operations['permissions'] = array( + 'title' => t('Edit permissions'), + 'weight' => 20, + ) + $entity->urlInfo('edit-permissions-form'); + } + return $operations; + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + parent::submitForm($form, $form_state); + + drupal_set_message(t('The role settings have been updated.')); + } + +} diff --git a/core/modules/user/lib/Drupal/user/UserListBuilder.php b/core/modules/user/lib/Drupal/user/UserListBuilder.php deleted file mode 100644 index d2fcd3a..0000000 --- a/core/modules/user/lib/Drupal/user/UserListBuilder.php +++ /dev/null @@ -1,159 +0,0 @@ -queryFactory = $query_factory; - } - - /** - * {@inheritdoc} - */ - public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { - return new static( - $entity_type, - $container->get('entity.manager')->getStorageController($entity_type->id()), - $container->get('entity.query') - ); - } - - /** - * {@inheritdoc} - */ - public function load() { - $entity_query = $this->queryFactory->get('user'); - $entity_query->condition('uid', 0, '<>'); - $entity_query->pager(50); - $header = $this->buildHeader(); - $entity_query->tableSort($header); - $uids = $entity_query->execute(); - return $this->storage->loadMultiple($uids); - } - - /** - * {@inheritdoc} - */ - public function buildHeader() { - $header = array( - 'username' => array( - 'data' => $this->t('Username'), - 'field' => 'name', - 'specifier' => 'name', - ), - 'status' => array( - 'data' => $this->t('Status'), - 'field' => 'status', - 'specifier' => 'status', - 'class' => array(RESPONSIVE_PRIORITY_LOW), - ), - 'roles' => array( - 'data' => $this->t('Roles'), - 'class' => array(RESPONSIVE_PRIORITY_LOW), - ), - 'member_for' => array( - 'data' => $this->t('Member for'), - 'field' => 'created', - 'specifier' => 'created', - 'sort' => 'desc', - 'class' => array(RESPONSIVE_PRIORITY_LOW), - ), - 'access' => array( - 'data' => $this->t('Last access'), - 'field' => 'access', - 'specifier' => 'access', - 'class' => array(RESPONSIVE_PRIORITY_LOW), - ), - ); - return $header + parent::buildHeader(); - } - - /** - * {@inheritdoc} - */ - public function buildRow(EntityInterface $entity) { - $row['username']['data'] = array( - '#theme' => 'username', - '#account' => $entity, - ); - $row['status'] = $entity->isActive() ? $this->t('active') : $this->t('blocked'); - - $roles = array_map('\Drupal\Component\Utility\String::checkPlain', user_role_names(TRUE)); - unset($roles[DRUPAL_AUTHENTICATED_RID]); - $users_roles = array(); - foreach ($entity->getRoles() as $role) { - if (isset($roles[$role])) { - $users_roles[] = $roles[$role]; - } - } - asort($users_roles); - $row['roles']['data'] = array( - '#theme' => 'item_list', - '#items' => $users_roles, - ); - $row['member_for'] = format_interval(REQUEST_TIME - $entity->getCreatedTime()); - $row['access'] = $entity->access ? $this->t('@time ago', array( - '@time' => format_interval(REQUEST_TIME - $entity->getLastAccessedTime()), - )) : t('never'); - return $row + parent::buildRow($entity); - } - - /** - * {@inheritdoc} - */ - public function getOperations(EntityInterface $entity) { - $operations = parent::getOperations($entity); - if (isset($operations['edit'])) { - $destination = drupal_get_destination(); - $operations['edit']['query'] = $destination; - } - return $operations; - } - - /** - * {@inheritdoc} - */ - public function render() { - $build['accounts'] = parent::render(); - $build['accounts']['#empty'] = $this->t('No people available.'); - $build['pager']['#theme'] = 'pager'; - return $build; - } - -} diff --git a/core/modules/user/user.services.yml b/core/modules/user/user.services.yml index 17229ed..bfd7ad1 100644 --- a/core/modules/user/user.services.yml +++ b/core/modules/user/user.services.yml @@ -15,16 +15,6 @@ services: class: Drupal\user\Access\LoginStatusCheck tags: - { name: access_check, applies_to: _user_is_logged_in } - cache_context.user: - class: Drupal\user\Cache\UserCacheContext - arguments: ['@current_user'] - tags: - - { name: cache.context} - cache_context.user.roles: - class: Drupal\user\Cache\UserRolesCacheContext - arguments: ['@current_user'] - tags: - - { name: cache.context} user.data: class: Drupal\user\UserData arguments: ['@database'] diff --git a/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlock.php b/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlock.php index 2648919..482c25f 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlock.php +++ b/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlock.php @@ -29,11 +29,13 @@ public function build() { $this->view->display_handler->preBlockBuild($this); if ($output = $this->view->executeDisplay($this->displayID)) { - // Override the label to the dynamic title configured in the view. - if (empty($this->configuration['views_label']) && $this->view->getTitle()) { - $output['#title'] = Xss::filterAdmin($this->view->getTitle()); + // Set the label to the title configured in the view. + if (empty($this->configuration['views_label'])) { + $this->configuration['label'] = Xss::filterAdmin($this->view->getTitle()); + } + else { + $this->configuration['label'] = $this->configuration['views_label']; } - // Before returning the block output, convert it to a renderable array // with contextual links. $this->addContextualLinks($output); @@ -46,20 +48,6 @@ public function build() { /** * {@inheritdoc} */ - public function getConfiguration() { - $configuration = parent::getConfiguration(); - - // Set the label to the static title configured in the view. - if (!empty($configuration['views_label'])) { - $configuration['label'] = $configuration['views_label']; - } - - return $configuration; - } - - /** - * {@inheritdoc} - */ public function defaultConfiguration() { $settings = parent::defaultConfiguration(); diff --git a/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlockBase.php b/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlockBase.php index 3c228d1..56f3c86 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlockBase.php +++ b/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlockBase.php @@ -99,7 +99,10 @@ public function access(AccountInterface $account) { * {@inheritdoc} */ public function defaultConfiguration() { - return array('views_label' => ''); + $settings = array(); + $settings['views_label'] = ''; + + return $settings; } /** diff --git a/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsBlock.php b/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsBlock.php index 9541124..a7fb041 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsBlock.php +++ b/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsBlock.php @@ -102,6 +102,7 @@ public function getDerivativeDefinitions($base_plugin_definition) { $this->derivatives[$delta] = array( 'category' => $display->getOption('block_category'), 'admin_label' => $desc, + 'cache' => $display->getCacheType() ); $this->derivatives[$delta] += $base_plugin_definition; } diff --git a/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsExposedFilterBlock.php b/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsExposedFilterBlock.php index 29439a6..0423bb5 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsExposedFilterBlock.php +++ b/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsExposedFilterBlock.php @@ -93,6 +93,7 @@ public function getDerivativeDefinitions($base_plugin_definition) { $desc = t('Exposed form: @view-@display_id', array('@view' => $view->id(), '@display_id' => $display->display['id'])); $this->derivatives[$delta] = array( 'admin_label' => $desc, + 'cache' => DRUPAL_NO_CACHE, ); $this->derivatives[$delta] += $base_plugin_definition; } diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php index b18fff3..bc99b02 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php @@ -2383,6 +2383,7 @@ public function getSpecialBlocks() { $blocks[$delta] = array( 'info' => $desc, + 'cache' => DRUPAL_NO_CACHE, ); } diff --git a/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayFeedTest.php b/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayFeedTest.php index fe101d8..484734e 100644 --- a/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayFeedTest.php +++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayFeedTest.php @@ -51,7 +51,7 @@ protected function setUp() { public function testFeedUI() { $this->drupalGet('admin/structure/views'); // Verify that the page lists the test_display_feed view. - // Regression test: ViewListBuilder::getDisplayPaths() did not properly + // Regression test: ViewsListController::getDisplayPaths() did not properly // check whether a DisplayBag was returned in iterating over all displays. $this->assertText('test_display_feed'); diff --git a/core/modules/views/tests/Drupal/views/Tests/Plugin/Block/ViewsBlockTest.php b/core/modules/views/tests/Drupal/views/Tests/Plugin/Block/ViewsBlockTest.php index ff9bc33..51254b5 100644 --- a/core/modules/views/tests/Drupal/views/Tests/Plugin/Block/ViewsBlockTest.php +++ b/core/modules/views/tests/Drupal/views/Tests/Plugin/Block/ViewsBlockTest.php @@ -15,6 +15,9 @@ if (!defined('BLOCK_LABEL_VISIBLE')) { define('BLOCK_LABEL_VISIBLE', 'visible'); } +if (!defined('DRUPAL_NO_CACHE')) { + define('DRUPAL_NO_CACHE', -1); +} /** * Tests the views block plugin. diff --git a/core/modules/views_ui/lib/Drupal/views_ui/Controller/ViewsUIController.php b/core/modules/views_ui/lib/Drupal/views_ui/Controller/ViewsUIController.php index cc6b037..018d4d9 100644 --- a/core/modules/views_ui/lib/Drupal/views_ui/Controller/ViewsUIController.php +++ b/core/modules/views_ui/lib/Drupal/views_ui/Controller/ViewsUIController.php @@ -154,7 +154,7 @@ public function ajaxOperation(ViewStorageInterface $view, $op, Request $request) // If the request is via AJAX, return the rendered list as JSON. if ($request->request->get('js')) { - $list = $this->entityManager()->getListBuilder('view')->render(); + $list = $this->entityManager()->getListController('view')->render(); $response = new AjaxResponse(); $response->addCommand(new ReplaceCommand('#views-entity-list', drupal_render($list))); return $response; diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewListBuilder.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewListBuilder.php deleted file mode 100644 index 36f20c3..0000000 --- a/core/modules/views_ui/lib/Drupal/views_ui/ViewListBuilder.php +++ /dev/null @@ -1,268 +0,0 @@ -get('entity.manager')->getStorageController($entity_type->id()), - $container->get('plugin.manager.views.display') - ); - } - - /** - * Constructs a new ViewListBuilder object. - * - * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type - * The entity type definition. - * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage. - * The entity storage controller class. - * @param \Drupal\Component\Plugin\PluginManagerInterface $display_manager - * The views display plugin manager to use. - */ - public function __construct(EntityTypeInterface $entity_type, EntityStorageControllerInterface $storage, PluginManagerInterface $display_manager) { - parent::__construct($entity_type, $storage); - - $this->displayManager = $display_manager; - } - - /** - * {@inheritdoc} - */ - public function load() { - $entities = array( - 'enabled' => array(), - 'disabled' => array(), - ); - foreach (parent::load() as $entity) { - if ($entity->status()) { - $entities['enabled'][] = $entity; - } - else { - $entities['disabled'][] = $entity; - } - } - return $entities; - } - - /** - * {@inheritdoc} - */ - public function buildRow(EntityInterface $view) { - $row = parent::buildRow($view); - return array( - 'data' => array( - 'view_name' => array( - 'data' => array( - '#theme' => 'views_ui_view_info', - '#view' => $view, - '#displays' => $this->getDisplaysList($view) - ), - ), - 'description' => array( - 'data' => array( - '#markup' => String::checkPlain($view->get('description')), - ), - 'class' => array('views-table-filter-text-source'), - ), - 'tag' => $view->get('tag'), - 'path' => implode(', ', $this->getDisplayPaths($view)), - 'operations' => $row['operations'], - ), - 'title' => $this->t('Machine name: @name', array('@name' => $view->id())), - 'class' => array($view->status() ? 'views-ui-list-enabled' : 'views-ui-list-disabled'), - ); - } - - /** - * {@inheritdoc} - */ - public function buildHeader() { - return array( - 'view_name' => array( - 'data' => $this->t('View name'), - 'class' => array('views-ui-name'), - ), - 'description' => array( - 'data' => $this->t('Description'), - 'class' => array('views-ui-description'), - ), - 'tag' => array( - 'data' => $this->t('Tag'), - 'class' => array('views-ui-tag'), - ), - 'path' => array( - 'data' => $this->t('Path'), - 'class' => array('views-ui-path'), - ), - 'operations' => array( - 'data' => $this->t('Operations'), - 'class' => array('views-ui-operations'), - ), - ); - } - - /** - * {@inheritdoc} - */ - public function getOperations(EntityInterface $entity) { - $operations = parent::getOperations($entity); - - if ($entity->hasLinkTemplate('clone')) { - $operations['clone'] = array( - 'title' => $this->t('Clone'), - 'weight' => 15, - ) + $entity->urlInfo('clone'); - } - - // Add AJAX functionality to enable/disable operations. - foreach (array('enable', 'disable') as $op) { - if (isset($operations[$op])) { - $operations[$op]['route_name'] = "views_ui.$op"; - $operations[$op]['route_parameters'] = array('view' => $entity->id()); - - // Enable and disable operations should use AJAX. - $operations[$op]['attributes']['class'][] = 'use-ajax'; - } - } - - return $operations; - } - - /** - * {@inheritdoc} - */ - public function render() { - $entities = $this->load(); - $list['#type'] = 'container'; - $list['#attributes']['id'] = 'views-entity-list'; - - $list['#attached']['css'] = ViewFormControllerBase::getAdminCSS(); - $list['#attached']['library'][] = 'core/drupal.ajax'; - $list['#attached']['library'][] = 'views_ui/views_ui.listing'; - - $form['filters'] = array( - '#type' => 'container', - '#attributes' => array( - 'class' => array('table-filter', 'js-show'), - ), - ); - - $list['filters']['text'] = array( - '#type' => 'search', - '#title' => $this->t('Search'), - '#size' => 30, - '#placeholder' => $this->t('Enter view name'), - '#attributes' => array( - 'class' => array('views-filter-text'), - 'data-table' => '.views-listing-table', - 'autocomplete' => 'off', - 'title' => $this->t('Enter a part of the view name or description to filter by.'), - ), - ); - - $list['enabled']['heading']['#markup'] = '

' . $this->t('Enabled') . '

'; - $list['disabled']['heading']['#markup'] = '

' . $this->t('Disabled') . '

'; - foreach (array('enabled', 'disabled') as $status) { - $list[$status]['#type'] = 'container'; - $list[$status]['#attributes'] = array('class' => array('views-list-section', $status)); - $list[$status]['table'] = array( - '#type' => 'table', - '#attributes' => array( - 'class' => array('views-listing-table'), - ), - '#header' => $this->buildHeader(), - '#rows' => array(), - ); - foreach ($entities[$status] as $entity) { - $list[$status]['table']['#rows'][$entity->id()] = $this->buildRow($entity); - } - } - // @todo Use a placeholder for the entity label if this is abstracted to - // other entity types. - $list['enabled']['table']['#empty'] = $this->t('There are no enabled views.'); - $list['disabled']['table']['#empty'] = $this->t('There are no disabled views.'); - - return $list; - } - - /** - * Gets a list of displays included in the view. - * - * @param \Drupal\Core\Entity\EntityInterface $view - * The view entity instance to get a list of displays for. - * - * @return array - * An array of display types that this view includes. - */ - protected function getDisplaysList(EntityInterface $view) { - $displays = array(); - foreach ($view->get('display') as $display) { - $definition = $this->displayManager->getDefinition($display['display_plugin']); - if (!empty($definition['admin'])) { - $displays[$definition['admin']] = TRUE; - } - } - - ksort($displays); - return array_keys($displays); - } - - /** - * Gets a list of paths assigned to the view. - * - * @param \Drupal\Core\Entity\EntityInterface $view - * The view entity. - * - * @return array - * An array of paths for this view. - */ - protected function getDisplayPaths(EntityInterface $view) { - $all_paths = array(); - $executable = $view->getExecutable(); - $executable->initDisplay(); - foreach ($executable->displayHandlers as $display) { - if ($display->hasPath()) { - $path = $display->getPath(); - if ($view->status() && strpos($path, '%') === FALSE) { - $all_paths[] = l('/' . $path, $path); - } - else { - $all_paths[] = String::checkPlain('/' . $path); - } - } - } - return array_unique($all_paths); - } - -} diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewListController.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewListController.php new file mode 100644 index 0000000..1facb3c --- /dev/null +++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewListController.php @@ -0,0 +1,267 @@ +get('entity.manager')->getStorageController($entity_type->id()), + $container->get('plugin.manager.views.display') + ); + } + + /** + * Constructs a new EntityListController object. + * + * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type + * The entity type definition. + * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage. + * The entity storage controller class. + * @param \Drupal\Component\Plugin\PluginManagerInterface $display_manager + * The views display plugin manager to use. + */ + public function __construct(EntityTypeInterface $entity_type, EntityStorageControllerInterface $storage, PluginManagerInterface $display_manager) { + parent::__construct($entity_type, $storage); + + $this->displayManager = $display_manager; + } + + /** + * {@inheritdoc} + */ + public function load() { + $entities = array( + 'enabled' => array(), + 'disabled' => array(), + ); + foreach (parent::load() as $entity) { + if ($entity->status()) { + $entities['enabled'][] = $entity; + } + else { + $entities['disabled'][] = $entity; + } + } + return $entities; + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $view) { + $row = parent::buildRow($view); + return array( + 'data' => array( + 'view_name' => array( + 'data' => array( + '#theme' => 'views_ui_view_info', + '#view' => $view, + '#displays' => $this->getDisplaysList($view) + ), + ), + 'description' => array( + 'data' => array( + '#markup' => String::checkPlain($view->get('description')), + ), + 'class' => array('views-table-filter-text-source'), + ), + 'tag' => $view->get('tag'), + 'path' => implode(', ', $this->getDisplayPaths($view)), + 'operations' => $row['operations'], + ), + 'title' => $this->t('Machine name: @name', array('@name' => $view->id())), + 'class' => array($view->status() ? 'views-ui-list-enabled' : 'views-ui-list-disabled'), + ); + } + + /** + * {@inheritdoc} + */ + public function buildHeader() { + return array( + 'view_name' => array( + 'data' => $this->t('View name'), + 'class' => array('views-ui-name'), + ), + 'description' => array( + 'data' => $this->t('Description'), + 'class' => array('views-ui-description'), + ), + 'tag' => array( + 'data' => $this->t('Tag'), + 'class' => array('views-ui-tag'), + ), + 'path' => array( + 'data' => $this->t('Path'), + 'class' => array('views-ui-path'), + ), + 'operations' => array( + 'data' => $this->t('Operations'), + 'class' => array('views-ui-operations'), + ), + ); + } + + /** + * {@inheritdoc} + */ + public function getOperations(EntityInterface $entity) { + $operations = parent::getOperations($entity); + + if ($entity->hasLinkTemplate('clone')) { + $operations['clone'] = array( + 'title' => $this->t('Clone'), + 'weight' => 15, + ) + $entity->urlInfo('clone'); + } + + // Add AJAX functionality to enable/disable operations. + foreach (array('enable', 'disable') as $op) { + if (isset($operations[$op])) { + $operations[$op]['route_name'] = "views_ui.$op"; + $operations[$op]['route_parameters'] = array('view' => $entity->id()); + + // Enable and disable operations should use AJAX. + $operations[$op]['attributes']['class'][] = 'use-ajax'; + } + } + + return $operations; + } + + /** + * {@inheritdoc} + */ + public function render() { + $entities = $this->load(); + $list['#type'] = 'container'; + $list['#attributes']['id'] = 'views-entity-list'; + + $list['#attached']['css'] = ViewFormControllerBase::getAdminCSS(); + $list['#attached']['library'][] = 'core/drupal.ajax'; + $list['#attached']['library'][] = 'views_ui/views_ui.listing'; + + $form['filters'] = array( + '#type' => 'container', + '#attributes' => array( + 'class' => array('table-filter', 'js-show'), + ), + ); + + $list['filters']['text'] = array( + '#type' => 'search', + '#title' => $this->t('Search'), + '#size' => 30, + '#placeholder' => $this->t('Enter view name'), + '#attributes' => array( + 'class' => array('views-filter-text'), + 'data-table' => '.views-listing-table', + 'autocomplete' => 'off', + 'title' => $this->t('Enter a part of the view name or description to filter by.'), + ), + ); + + $list['enabled']['heading']['#markup'] = '

' . $this->t('Enabled') . '

'; + $list['disabled']['heading']['#markup'] = '

' . $this->t('Disabled') . '

'; + foreach (array('enabled', 'disabled') as $status) { + $list[$status]['#type'] = 'container'; + $list[$status]['#attributes'] = array('class' => array('views-list-section', $status)); + $list[$status]['table'] = array( + '#type' => 'table', + '#attributes' => array( + 'class' => array('views-listing-table'), + ), + '#header' => $this->buildHeader(), + '#rows' => array(), + ); + foreach ($entities[$status] as $entity) { + $list[$status]['table']['#rows'][$entity->id()] = $this->buildRow($entity); + } + } + // @todo Use a placeholder for the entity label if this is abstracted to + // other entity types. + $list['enabled']['table']['#empty'] = $this->t('There are no enabled views.'); + $list['disabled']['table']['#empty'] = $this->t('There are no disabled views.'); + + return $list; + } + + /** + * Gets a list of displays included in the view. + * + * @param \Drupal\Core\Entity\EntityInterface $view + * The view entity instance to get a list of displays for. + * + * @return array + * An array of display types that this view includes. + */ + protected function getDisplaysList(EntityInterface $view) { + $displays = array(); + foreach ($view->get('display') as $display) { + $definition = $this->displayManager->getDefinition($display['display_plugin']); + if (!empty($definition['admin'])) { + $displays[$definition['admin']] = TRUE; + } + } + + ksort($displays); + return array_keys($displays); + } + + /** + * Gets a list of paths assigned to the view. + * + * @param \Drupal\Core\Entity\EntityInterface $view + * The view entity. + * + * @return array + * An array of paths for this view. + */ + protected function getDisplayPaths(EntityInterface $view) { + $all_paths = array(); + $executable = $view->getExecutable(); + $executable->initDisplay(); + foreach ($executable->displayHandlers as $display) { + if ($display->hasPath()) { + $path = $display->getPath(); + if ($view->status() && strpos($path, '%') === FALSE) { + $all_paths[] = l('/' . $path, $path); + } + else { + $all_paths[] = String::checkPlain('/' . $path); + } + } + } + return array_unique($all_paths); + } + +} diff --git a/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewListBuilderTest.php b/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewListBuilderTest.php deleted file mode 100644 index 99216db..0000000 --- a/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewListBuilderTest.php +++ /dev/null @@ -1,146 +0,0 @@ - 'Views List Builder Unit Test', - 'description' => 'Unit tests the views list builder', - 'group' => 'Views UI', - ); - } - - /** - * Tests the listing of displays on a views list builder. - * - * @see \Drupal\views_ui\ViewListBuilder::getDisplaysList() - */ - public function testBuildRowEntityList() { - $storage_controller = $this->getMockBuilder('Drupal\Core\Config\Entity\ConfigStorageController') - ->disableOriginalConstructor() - ->getMock(); - $display_manager = $this->getMockBuilder('\Drupal\views\Plugin\ViewsPluginManager') - ->disableOriginalConstructor() - ->getMock(); - - $display_manager->expects($this->any()) - ->method('getDefinition') - ->will($this->returnValueMap(array( - array( - 'default', - array( - 'id' => 'default', - 'title' => 'Master', - 'theme' => 'views_view', - 'no_ui' => TRUE, - ) - ), - array( - 'page', - array( - 'id' => 'page', - 'title' => 'Page', - 'uses_hook_menu' => TRUE, - 'uses_route' => TRUE, - 'contextual_links_locations' => array('page'), - 'theme' => 'views_view', - 'admin' => 'Page admin label', - ) - ), - array( - 'embed', - array( - 'id' => 'embed', - 'title' => 'embed', - 'theme' => 'views_view', - 'admin' => 'Embed admin label', - ) - ), - ))); - - - $default_display = $this->getMock('Drupal\views\Plugin\views\display\DefaultDisplay', - array('initDisplay'), - array(array(), 'default', $display_manager->getDefinition('default')) - ); - $route_provider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface'); - $state = $this->getMock('\Drupal\Core\KeyValueStore\StateInterface'); - $page_display = $this->getMock('Drupal\views\Plugin\views\display\Page', - array('initDisplay', 'getPath'), - array(array(), 'default', $display_manager->getDefinition('page'), $route_provider, $state) - ); - $page_display->expects($this->any()) - ->method('getPath') - ->will($this->returnValue('test_page')); - - $embed_display = $this->getMock('Drupal\views\Plugin\views\display\Embed', array('initDisplay'), - array(array(), 'default', $display_manager->getDefinition('embed')) - ); - - $values = array(); - $values['status'] = FALSE; - $values['display']['default']['id'] = 'default'; - $values['display']['default']['display_title'] = 'Display'; - $values['display']['default']['display_plugin'] = 'default'; - - $values['display']['page_1']['id'] = 'page_1'; - $values['display']['page_1']['display_title'] = 'Page 1'; - $values['display']['page_1']['display_plugin'] = 'page'; - $values['display']['page_1']['display_options']['path'] = 'test_page'; - - $values['display']['embed']['id'] = 'embed'; - $values['display']['embed']['display_title'] = 'Embedded'; - $values['display']['embed']['display_plugin'] = 'embed'; - - $display_manager->expects($this->any()) - ->method('createInstance') - ->will($this->returnValueMap(array( - array('default', $values['display']['default'], $default_display), - array('page', $values['display']['page_1'], $page_display), - array('embed', $values['display']['embed'], $embed_display), - ))); - - $container = new ContainerBuilder(); - $user = $this->getMock('Drupal\Core\Session\AccountInterface'); - $executable_factory = new ViewExecutableFactory($user); - $container->set('views.executable', $executable_factory); - $container->set('plugin.manager.views.display', $display_manager); - \Drupal::setContainer($container); - - // Setup a view list builder with a mocked buildOperations method, - // because t() is called on there. - $entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface'); - $view_list_builder = new TestViewListBuilder($entity_type, $storage_controller, $display_manager); - $view_list_builder->setTranslationManager($this->getStringTranslationStub()); - - $view = new View($values, 'view'); - - $row = $view_list_builder->buildRow($view); - - $this->assertEquals(array('Embed admin label', 'Page admin label'), $row['data']['view_name']['data']['#displays'], 'Wrong displays got added to view list'); - $this->assertEquals($row['data']['path'], '/test_page', 'The path of the page display is not added.'); - } - -} - -class TestViewListBuilder extends ViewListBuilder { - - public function buildOperations(EntityInterface $entity) { - return array(); - } - -} diff --git a/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewListControllerTest.php b/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewListControllerTest.php new file mode 100644 index 0000000..62a1586 --- /dev/null +++ b/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewListControllerTest.php @@ -0,0 +1,146 @@ + 'Views List Controller Unit Test', + 'description' => 'Unit tests the views list controller', + 'group' => 'Views UI', + ); + } + + /** + * Tests the listing of displays on a views list. + * + * @see \Drupal\views_ui\ViewListController::getDisplaysList(). + */ + public function testBuildRowEntityList() { + $storage_controller = $this->getMockBuilder('Drupal\Core\Config\Entity\ConfigStorageController') + ->disableOriginalConstructor() + ->getMock(); + $display_manager = $this->getMockBuilder('\Drupal\views\Plugin\ViewsPluginManager') + ->disableOriginalConstructor() + ->getMock(); + + $display_manager->expects($this->any()) + ->method('getDefinition') + ->will($this->returnValueMap(array( + array( + 'default', + array( + 'id' => 'default', + 'title' => 'Master', + 'theme' => 'views_view', + 'no_ui' => TRUE, + ) + ), + array( + 'page', + array( + 'id' => 'page', + 'title' => 'Page', + 'uses_hook_menu' => TRUE, + 'uses_route' => TRUE, + 'contextual_links_locations' => array('page'), + 'theme' => 'views_view', + 'admin' => 'Page admin label', + ) + ), + array( + 'embed', + array( + 'id' => 'embed', + 'title' => 'embed', + 'theme' => 'views_view', + 'admin' => 'Embed admin label', + ) + ), + ))); + + + $default_display = $this->getMock('Drupal\views\Plugin\views\display\DefaultDisplay', + array('initDisplay'), + array(array(), 'default', $display_manager->getDefinition('default')) + ); + $route_provider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface'); + $state = $this->getMock('\Drupal\Core\KeyValueStore\StateInterface'); + $page_display = $this->getMock('Drupal\views\Plugin\views\display\Page', + array('initDisplay', 'getPath'), + array(array(), 'default', $display_manager->getDefinition('page'), $route_provider, $state) + ); + $page_display->expects($this->any()) + ->method('getPath') + ->will($this->returnValue('test_page')); + + $embed_display = $this->getMock('Drupal\views\Plugin\views\display\Embed', array('initDisplay'), + array(array(), 'default', $display_manager->getDefinition('embed')) + ); + + $values = array(); + $values['status'] = FALSE; + $values['display']['default']['id'] = 'default'; + $values['display']['default']['display_title'] = 'Display'; + $values['display']['default']['display_plugin'] = 'default'; + + $values['display']['page_1']['id'] = 'page_1'; + $values['display']['page_1']['display_title'] = 'Page 1'; + $values['display']['page_1']['display_plugin'] = 'page'; + $values['display']['page_1']['display_options']['path'] = 'test_page'; + + $values['display']['embed']['id'] = 'embed'; + $values['display']['embed']['display_title'] = 'Embedded'; + $values['display']['embed']['display_plugin'] = 'embed'; + + $display_manager->expects($this->any()) + ->method('createInstance') + ->will($this->returnValueMap(array( + array('default', $values['display']['default'], $default_display), + array('page', $values['display']['page_1'], $page_display), + array('embed', $values['display']['embed'], $embed_display), + ))); + + $container = new ContainerBuilder(); + $user = $this->getMock('Drupal\Core\Session\AccountInterface'); + $executable_factory = new ViewExecutableFactory($user); + $container->set('views.executable', $executable_factory); + $container->set('plugin.manager.views.display', $display_manager); + \Drupal::setContainer($container); + + // Setup a view list controller with a mocked buildOperations method, + // because t() is called on there. + $entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface'); + $view_list_controller = new TestViewListController($entity_type, $storage_controller, $display_manager); + $view_list_controller->setTranslationManager($this->getStringTranslationStub()); + + $view = new View($values, 'view'); + + $row = $view_list_controller->buildRow($view); + + $this->assertEquals(array('Embed admin label', 'Page admin label'), $row['data']['view_name']['data']['#displays'], 'Wrong displays got added to view list'); + $this->assertEquals($row['data']['path'], '/test_page', 'The path of the page display is not added.'); + } + +} + +class TestViewListController extends ViewListController { + + public function buildOperations(EntityInterface $entity) { + return array(); + } + +} diff --git a/core/modules/views_ui/views_ui.module b/core/modules/views_ui/views_ui.module index 9f25e89..7f140d3 100644 --- a/core/modules/views_ui/views_ui.module +++ b/core/modules/views_ui/views_ui.module @@ -75,7 +75,7 @@ function views_ui_entity_type_build(array &$entity_types) { ->setFormClass('clone', 'Drupal\views_ui\ViewCloneFormController') ->setFormClass('delete', 'Drupal\views_ui\ViewDeleteFormController') ->setFormClass('break_lock', 'Drupal\views_ui\Form\BreakLockForm') - ->setListBuilderClass('Drupal\views_ui\ViewListBuilder') + ->setListClass('Drupal\views_ui\ViewListController') ->setLinkTemplate('edit-form', 'views_ui.edit') ->setLinkTemplate('edit-display-form', 'views_ui.edit_display') ->setLinkTemplate('preview-form', 'views_ui.preview') diff --git a/core/profiles/minimal/config/block.block.stark_admin.yml b/core/profiles/minimal/config/block.block.stark_admin.yml index 942d59c..68bee15 100644 --- a/core/profiles/minimal/config/block.block.stark_admin.yml +++ b/core/profiles/minimal/config/block.block.stark_admin.yml @@ -9,6 +9,7 @@ settings: label: Administration module: system label_display: visible + cache: -1 visibility: path: visibility: 0 diff --git a/core/profiles/minimal/config/block.block.stark_login.yml b/core/profiles/minimal/config/block.block.stark_login.yml index 94f2477..fb1301f 100644 --- a/core/profiles/minimal/config/block.block.stark_login.yml +++ b/core/profiles/minimal/config/block.block.stark_login.yml @@ -9,6 +9,7 @@ settings: label: 'User login' module: user label_display: visible + cache: -1 visibility: path: visibility: 0 diff --git a/core/profiles/minimal/config/block.block.stark_tools.yml b/core/profiles/minimal/config/block.block.stark_tools.yml index fb88b0e..9d53bc3 100644 --- a/core/profiles/minimal/config/block.block.stark_tools.yml +++ b/core/profiles/minimal/config/block.block.stark_tools.yml @@ -9,6 +9,7 @@ settings: label: Tools module: system label_display: visible + cache: -1 visibility: path: visibility: 0 diff --git a/core/profiles/standard/config/block.block.bartik_breadcrumbs.yml b/core/profiles/standard/config/block.block.bartik_breadcrumbs.yml index 355a3f9..b8c9eb0 100644 --- a/core/profiles/standard/config/block.block.bartik_breadcrumbs.yml +++ b/core/profiles/standard/config/block.block.bartik_breadcrumbs.yml @@ -9,6 +9,7 @@ settings: label: Breadcrumbs module: system label_display: '0' + cache: -1 visibility: path: visibility: 0 diff --git a/core/profiles/standard/config/block.block.bartik_content.yml b/core/profiles/standard/config/block.block.bartik_content.yml index 6666594..f7362e6 100644 --- a/core/profiles/standard/config/block.block.bartik_content.yml +++ b/core/profiles/standard/config/block.block.bartik_content.yml @@ -9,6 +9,7 @@ settings: label: 'Main page content' module: system label_display: '0' + cache: -1 visibility: path: visibility: 0 diff --git a/core/profiles/standard/config/block.block.bartik_footer.yml b/core/profiles/standard/config/block.block.bartik_footer.yml index 133ba67..07bdba5 100644 --- a/core/profiles/standard/config/block.block.bartik_footer.yml +++ b/core/profiles/standard/config/block.block.bartik_footer.yml @@ -9,6 +9,7 @@ settings: label: 'Footer menu' module: system label_display: visible + cache: -1 visibility: path: visibility: 0 diff --git a/core/profiles/standard/config/block.block.bartik_help.yml b/core/profiles/standard/config/block.block.bartik_help.yml index 076ee32..6ee1371 100644 --- a/core/profiles/standard/config/block.block.bartik_help.yml +++ b/core/profiles/standard/config/block.block.bartik_help.yml @@ -9,6 +9,7 @@ settings: label: 'System Help' module: system label_display: '0' + cache: -1 visibility: path: visibility: 0 diff --git a/core/profiles/standard/config/block.block.bartik_login.yml b/core/profiles/standard/config/block.block.bartik_login.yml index f654e06..235fa04 100644 --- a/core/profiles/standard/config/block.block.bartik_login.yml +++ b/core/profiles/standard/config/block.block.bartik_login.yml @@ -9,6 +9,7 @@ settings: label: 'User login' module: user label_display: visible + cache: -1 visibility: path: visibility: 0 diff --git a/core/profiles/standard/config/block.block.bartik_powered.yml b/core/profiles/standard/config/block.block.bartik_powered.yml index a2c6959..a0257a2 100644 --- a/core/profiles/standard/config/block.block.bartik_powered.yml +++ b/core/profiles/standard/config/block.block.bartik_powered.yml @@ -9,6 +9,7 @@ settings: label: 'Powered by Drupal' module: system label_display: '0' + cache: -1 visibility: path: visibility: 0 diff --git a/core/profiles/standard/config/block.block.bartik_search.yml b/core/profiles/standard/config/block.block.bartik_search.yml index aab8a85..dc39361 100644 --- a/core/profiles/standard/config/block.block.bartik_search.yml +++ b/core/profiles/standard/config/block.block.bartik_search.yml @@ -9,6 +9,7 @@ settings: label: Search module: search label_display: visible + cache: -1 visibility: path: visibility: 0 diff --git a/core/profiles/standard/config/block.block.bartik_tools.yml b/core/profiles/standard/config/block.block.bartik_tools.yml index 23cb6d9..cfe490d 100644 --- a/core/profiles/standard/config/block.block.bartik_tools.yml +++ b/core/profiles/standard/config/block.block.bartik_tools.yml @@ -9,6 +9,7 @@ settings: label: Tools module: system label_display: visible + cache: -1 visibility: path: visibility: 0 diff --git a/core/profiles/standard/config/block.block.seven_breadcrumbs.yml b/core/profiles/standard/config/block.block.seven_breadcrumbs.yml index 0a89ca3..b48f4b4 100644 --- a/core/profiles/standard/config/block.block.seven_breadcrumbs.yml +++ b/core/profiles/standard/config/block.block.seven_breadcrumbs.yml @@ -9,6 +9,7 @@ settings: label: Breadcrumbs module: system label_display: '0' + cache: -1 visibility: path: visibility: 0 diff --git a/core/profiles/standard/config/block.block.seven_content.yml b/core/profiles/standard/config/block.block.seven_content.yml index eb2fafa..1f44d0e 100644 --- a/core/profiles/standard/config/block.block.seven_content.yml +++ b/core/profiles/standard/config/block.block.seven_content.yml @@ -9,6 +9,7 @@ settings: label: 'Main page content' module: system label_display: '0' + cache: -1 visibility: path: visibility: 0 diff --git a/core/profiles/standard/config/block.block.seven_help.yml b/core/profiles/standard/config/block.block.seven_help.yml index 98f56c3..2f3121f 100644 --- a/core/profiles/standard/config/block.block.seven_help.yml +++ b/core/profiles/standard/config/block.block.seven_help.yml @@ -9,6 +9,7 @@ settings: label: 'System Help' module: system label_display: '0' + cache: -1 visibility: path: visibility: 0 diff --git a/core/profiles/standard/config/block.block.seven_login.yml b/core/profiles/standard/config/block.block.seven_login.yml index 5bbfbf9..8eae9f4 100644 --- a/core/profiles/standard/config/block.block.seven_login.yml +++ b/core/profiles/standard/config/block.block.seven_login.yml @@ -9,6 +9,7 @@ settings: label: 'User login' module: user label_display: visible + cache: -1 visibility: path: visibility: 0 diff --git a/core/tests/Drupal/Tests/Core/Cache/CacheContextsTest.php b/core/tests/Drupal/Tests/Core/Cache/CacheContextsTest.php deleted file mode 100644 index 6e5864d..0000000 --- a/core/tests/Drupal/Tests/Core/Cache/CacheContextsTest.php +++ /dev/null @@ -1,96 +0,0 @@ - 'CacheContext test', - 'description' => 'Tests cache contexts.', - 'group' => 'Cache', - ); - } - - public function testContextPlaceholdersAreReplaced() { - $container = $this->getMockContainer(); - $container->expects($this->once()) - ->method("get") - ->with("cache_context.foo") - ->will($this->returnValue(new FooCacheContext())); - - $cache_contexts = new CacheContexts($container, $this->getContextsFixture()); - - $new_keys = $cache_contexts->convertTokensToKeys( - array("non-cache-context", "cache_context.foo") - ); - - $expected = array("non-cache-context", "bar"); - $this->assertEquals($expected, $new_keys); - } - - public function testAvailableContextStrings() { - $cache_contexts = new CacheContexts($this->getMockContainer(), $this->getContextsFixture()); - $contexts = $cache_contexts->getAll(); - $this->assertEquals(array("cache_context.foo"), $contexts); - } - - public function testAvailableContextLabels() { - $container = $this->getMockContainer(); - $container->expects($this->once()) - ->method("get") - ->with("cache_context.foo") - ->will($this->returnValue(new FooCacheContext())); - - $cache_contexts = new CacheContexts($container, $this->getContextsFixture()); - $labels = $cache_contexts->getLabels(); - $expected = array("cache_context.foo" => "Foo"); - $this->assertEquals($expected, $labels); - } - - protected function getContextsFixture() { - return array('cache_context.foo'); - } - - protected function getMockContainer() { - return $this->getMockBuilder('Drupal\Core\DependencyInjection\Container') - ->disableOriginalConstructor() - ->getMock(); - } -} diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityListBuilderTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityListBuilderTest.php deleted file mode 100644 index 0d9881f..0000000 --- a/core/tests/Drupal/Tests/Core/Entity/EntityListBuilderTest.php +++ /dev/null @@ -1,122 +0,0 @@ - 'Entity list builder test', - 'description' => 'Unit test of entity list builder system.', - 'group' => 'Entity' - ); - } - - /** - * {@inheritdoc} - */ - protected function setUp() { - parent::setUp(); - - $this->role = $this->getMock('Drupal\user\RoleInterface'); - $role_storage_controller = $this->getMock('Drupal\user\RoleStorageControllerInterface'); - $module_handler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface'); - $entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface'); - $this->entityListBuilder = new TestEntityListBuilder($entity_type, $role_storage_controller, $module_handler); - } - - /** - * Tests that buildRow() returns a string which has been run through - * String::checkPlain(). - * - * @dataProvider providerTestBuildRow - * - * @param string $input - * The entity label being passed into buildRow. - * @param string $expected - * The expected output of the label from buildRow. - * @param string $message - * The message to provide as output for the test. - * @param bool $ignorewarnings - * Whether or not to ignore PHP 5.3+ invalid multibyte sequence warnings. - * - * @see \Drupal\Core\Entity\EntityListBuilder::buildRow() - */ - public function testBuildRow($input, $expected, $message, $ignorewarnings = FALSE) { - $this->role->expects($this->any()) - ->method('label') - ->will($this->returnValue($input)); - - if ($ignorewarnings) { - $built_row = @$this->entityListBuilder->buildRow($this->role); - } - else { - $built_row = $this->entityListBuilder->buildRow($this->role); - } - - $this->assertEquals($built_row['label'], $expected, $message); - } - - /** - * Data provider for testBuildRow(). - * - * @see self::testBuildRow() - * @see \Drupal\Tests\Component\Utility\StringTest::providerCheckPlain() - * - * @return array - * An array containing a string, the expected return from - * String::checkPlain, a message to be output for failures, and whether the - * test should be processed as multibyte. - */ - public function providerTestBuildRow() { - $tests = array(); - // Checks that invalid multi-byte sequences are rejected. - $tests[] = array("Foo\xC0barbaz", '', 'EntityTestListBuilder::buildRow() rejects invalid sequence "Foo\xC0barbaz"', TRUE); - $tests[] = array("\xc2\"", '', 'EntityTestListBuilder::buildRow() rejects invalid sequence "\xc2\""', TRUE); - $tests[] = array("Fooÿñ", "Fooÿñ", 'EntityTestListBuilder::buildRow() accepts valid sequence "Fooÿñ"'); - - // Checks that special characters are escaped. - $tests[] = array("