diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php index 5a5532f..01d586c 100644 --- a/core/lib/Drupal/Core/Entity/Entity.php +++ b/core/lib/Drupal/Core/Entity/Entity.php @@ -173,7 +173,7 @@ public function uri($rel = 'canonical') { // If there is a template for the given relationship type, do the // placeholder replacement and use that as the path. $replacements = $this->uriPlaceholderReplacements(); - $uri['path'] = str_replace(array_keys($replacements), array_values($replacements), $template); + $uri['path'] = \Drupal::urlGenerator()->getPathFromRoute($link_templates[$rel], $replacements); // @todo Remove this once http://drupal.org/node/1888424 is in and we can // move the BC handling of / vs. no-/ to the generator. @@ -243,12 +243,16 @@ protected function linkTemplates() { protected function uriPlaceholderReplacements() { if (empty($this->uriPlaceholderReplacements)) { $this->uriPlaceholderReplacements = array( - '{entityType}' => $this->entityType(), - '{bundle}' => $this->bundle(), - '{id}' => $this->id(), - '{uuid}' => $this->uuid(), - '{' . $this->entityType() . '}' => $this->id(), + 'entityType' => $this->entityType(), + 'bundle' => $this->bundle(), + 'id' => $this->id(), + 'uuid' => $this->uuid(), + $this->entityType() => $this->id(), ); + $entity_info = \Drupal::entityManager()->getDefinition($this->entityType()); + if (isset($entity_info['bundle_entity_type'])) { + $this->uriPlaceholderReplacements[$entity_info['bundle_entity_type']] = $this->bundle(); + } } return $this->uriPlaceholderReplacements; } diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeAccessBaseTableTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeAccessBaseTableTest.php index e78b5bc..6831705 100644 --- a/core/modules/node/lib/Drupal/node/Tests/NodeAccessBaseTableTest.php +++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessBaseTableTest.php @@ -17,7 +17,7 @@ class NodeAccessBaseTableTest extends NodeTestBase { * * @var array */ - public static $modules = array('node_access_test'); + public static $modules = array('node_access_test', 'views'); /** * The installation profile to use with this test. diff --git a/core/modules/node/node.module b/core/modules/node/node.module index 28ca4f1..22d02f1 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -1292,7 +1292,6 @@ function node_view_multiple($nodes, $view_mode = 'teaser', $langcode = NULL) { * default setting for number of posts to show on node listing pages. * * @see node_page_default() - * @see taxonomy_term_page() * @see node_form_system_site_information_settings_form_submit() */ function node_form_system_site_information_settings_form_alter(&$form, &$form_state, $form_id) { diff --git a/core/modules/path/lib/Drupal/path/Tests/PathTaxonomyTermTest.php b/core/modules/path/lib/Drupal/path/Tests/PathTaxonomyTermTest.php index c483d9e..d747ce2 100644 --- a/core/modules/path/lib/Drupal/path/Tests/PathTaxonomyTermTest.php +++ b/core/modules/path/lib/Drupal/path/Tests/PathTaxonomyTermTest.php @@ -17,7 +17,7 @@ class PathTaxonomyTermTest extends PathTestBase { * * @var array */ - public static $modules = array('taxonomy'); + public static $modules = array('taxonomy', 'views'); public static function getInfo() { return array( diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/TaxonomyAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/TaxonomyAttributesTest.php index 268a247..87469f6 100644 --- a/core/modules/rdf/lib/Drupal/rdf/Tests/TaxonomyAttributesTest.php +++ b/core/modules/rdf/lib/Drupal/rdf/Tests/TaxonomyAttributesTest.php @@ -19,7 +19,7 @@ class TaxonomyAttributesTest extends TaxonomyTestBase { * * @var array */ - public static $modules = array('rdf'); + public static $modules = array('rdf', 'views'); public static function getInfo() { return array( diff --git a/core/modules/taxonomy/config/views.view.taxonomy_term.yml b/core/modules/taxonomy/config/views.view.taxonomy_term.yml new file mode 100644 index 0000000..dbcae0d --- /dev/null +++ b/core/modules/taxonomy/config/views.view.taxonomy_term.yml @@ -0,0 +1,237 @@ +base_field: nid +base_table: node +core: '8' +description: 'Content belonging to a certain taxonomy term.' +status: '1' +display: + default: + id: default + display_title: Master + display_plugin: default + position: 1 + display_options: + query: + type: views_query + options: + query_comment: false + disable_sql_rewrite: false + distinct: false + slave: false + query_tags: { } + access: + type: none + options: { } + cache: + type: none + options: { } + exposed_form: + type: basic + options: + submit_button: Apply + reset_button: false + reset_button_label: Reset + exposed_sorts_label: 'Sort by' + expose_sort_order: true + sort_asc_label: Asc + sort_desc_label: Desc + pager: + type: mini + options: + items_per_page: 10 + offset: 0 + id: 0 + total_pages: 0 + expose: + items_per_page: '0' + items_per_page_label: 'Items per page' + items_per_page_options: '5, 10, 20, 40, 60' + items_per_page_options_all: false + items_per_page_options_all_label: '- All -' + offset: false + offset_label: Offset + tags: + previous: ‹‹ + next: ›› + sorts: + sticky: + id: sticky + table: node_field_data + field: sticky + order: DESC + plugin_id: standard + relationship: none + group_type: group + admin_label: '' + exposed: false + expose: + label: '' + provider: views + created: + id: created + table: node_field_data + field: created + order: DESC + plugin_id: date + relationship: none + group_type: group + admin_label: '' + exposed: false + expose: + label: '' + granularity: second + provider: views + arguments: + term_node_tid_depth: + id: term_node_tid_depth + table: node + field: term_node_tid_depth + default_action: 'not found' + exception: + value: all + title_enable: true + title: All + title_enable: true + title: '%1' + default_argument_type: fixed + summary: + format: default_summary + specify_validation: true + validate: + type: 'entity:taxonomy_term' + fail: 'not found' + validate_options: + access: '1' + operation: view + multiple: '1' + bundles: { } + depth: '0' + break_phrase: true + plugin_id: taxonomy_index_tid_depth + relationship: none + group_type: group + admin_label: '' + default_argument_options: + argument: '' + default_argument_skip_url: false + summary_options: + base_path: '' + count: '1' + items_per_page: '25' + override: false + provider: taxonomy + term_node_tid_depth_modifier: + id: term_node_tid_depth_modifier + table: node + field: term_node_tid_depth_modifier + exception: + title_enable: true + default_argument_type: fixed + summary: + format: default_summary + specify_validation: true + plugin_id: taxonomy_index_tid_depth_modifier + relationship: none + group_type: group + admin_label: '' + default_action: ignore + title_enable: false + title: '' + default_argument_options: { } + default_argument_skip_url: false + summary_options: { } + validate: + type: none + fail: 'not found' + validate_options: { } + provider: taxonomy + filters: + status_extra: + id: status_extra + table: node_field_data + field: status_extra + group: '0' + expose: + operator: '0' + plugin_id: node_status + provider: node + style: + type: default + options: + grouping: { } + row_class: '' + default_row_class: true + row_class_special: true + uses_fields: false + row: + type: 'entity:node' + options: + view_mode: teaser + links: '1' + comments: '0' + header: { } + footer: { } + empty: { } + relationships: { } + fields: { } + page_1: + id: page_1 + display_title: Page + display_plugin: page + position: 2 + display_options: + query: + type: views_query + options: { } + path: taxonomy/term/% + feed_1: + id: feed_1 + display_title: Feed + display_plugin: feed + position: 3 + display_options: + query: + type: views_query + options: { } + pager: + type: full + options: + items_per_page: 15 + offset: 0 + id: 0 + total_pages: 0 + expose: + items_per_page: '0' + items_per_page_label: 'Items per page' + items_per_page_options: '5, 10, 20, 40, 60' + items_per_page_options_all: false + items_per_page_options_all_label: '- All -' + offset: false + offset_label: Offset + tags: + previous: '‹ previous' + next: 'next ›' + first: '« first' + last: 'last »' + quantity: '9' + path: taxonomy/term/%/%/feed + displays: + page: page + default: '0' + style: + type: rss + options: + description: '' + grouping: { } + uses_fields: '0' + row: + type: node_rss + options: + relationship: none + item_length: default + links: '0' +label: 'Taxonomy term' +module: taxonomy +id: taxonomy_term +tag: default +uuid: e0dea92e-a4c9-4442-a518-2499bfe17d73 +langcode: en diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Controller/TaxonomyController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Controller/TaxonomyController.php index cf49ec6..2b370d9 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Controller/TaxonomyController.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Controller/TaxonomyController.php @@ -19,6 +19,19 @@ class TaxonomyController extends ControllerBase { /** + * Title callback for term pages. + * + * @param \Drupal\taxonomy\TermInterface $term + * A taxonomy term entity. + * + * @return + * The term name to be used as the page title. + */ + public function getTitle(TermInterface $term) { + return $term->label(); + } + + /** * Returns a rendered edit form to create a new term associated to the given vocabulary. * * @param \Drupal\taxonomy\VocabularyInterface $taxonomy_vocabulary @@ -36,15 +49,6 @@ public function addForm(VocabularyInterface $taxonomy_vocabulary) { } /** - * @todo Remove taxonomy_term_page(). - */ - public function termPage(TermInterface $taxonomy_term) { - module_load_include('pages.inc', 'taxonomy'); - return taxonomy_term_page($taxonomy_term); - - } - - /** * Route title callback. * * @param \Drupal\taxonomy\VocabularyInterface $taxonomy_vocabulary @@ -71,11 +75,68 @@ public function termTitle(TermInterface $taxonomy_term) { } /** - * @todo Remove taxonomy_term_feed(). + * Displays all nodes associated with a term. + * + * @param \Drupal\taxonomy\TermInterface $term + * The taxonomy term entity. + * + * @return + * A structured array to be rendered by drupal_render(). */ - public function termFeed(TermInterface $taxonomy_term) { - module_load_include('pages.inc', 'taxonomy'); - return taxonomy_term_feed($taxonomy_term); + public function termPage(TermInterface $term) { + // Assign the term name as the page title. + drupal_set_title($term->label()); + + $build['#attached']['drupal_add_feed'][] = array('taxonomy/term/' . $term->id() . '/feed', 'RSS - ' . $term->label()); + + foreach ($term->uriRelationships() as $rel) { + $uri = $term->uri($rel); + // Set the term path as the canonical URL to prevent duplicate content. + drupal_add_html_head_link(array('rel' => $rel, 'href' => url($uri['path'], $uri['options'])), TRUE); + + if ($rel == 'canonical') { + // Set the non-aliased canonical path as a default shortlink. + drupal_add_html_head_link(array('rel' => 'shortlink', 'href' => url($uri['path'], array_merge($uri['options'], array('alias' => TRUE)))), TRUE); + } + } + + $build['taxonomy_terms'] = taxonomy_term_view_multiple(array($term->id() => $term)); + if ($nids = taxonomy_select_nodes($term->id(), TRUE, \Drupal::config('node.settings')->get('items_per_page'))) { + $nodes = node_load_multiple($nids); + $build['nodes'] = node_view_multiple($nodes); + $build['pager'] = array( + '#theme' => 'pager', + '#weight' => 5, + ); + } + else { + $build['no_content'] = array( + '#prefix' => '

', + '#markup' => t('There is currently no content classified with this term.'), + '#suffix' => '

', + ); + } + return $build; + } + + /** + * Generate the content feed for a taxonomy term. + * + * @param \Drupal\taxonomy\TermInterface $term + * The taxonomy term entity. + * + * @return \Symfony\Component\HttpFoundation\Response + * A response object. + */ + public function termFeed(TermInterface $term) { + $channel['link'] = url('taxonomy/term/' . $term->id(), array('absolute' => TRUE)); + $channel['title'] = \Drupal::config('system.site')->get('name') . ' - ' . $term->label(); + // Only display the description if we have a single term, to avoid clutter and confusion. + // HTML will be removed from feed description. + $channel['description'] = check_markup($term->description->value, $term->format->value, '', TRUE); + $nids = taxonomy_select_nodes($term->id(), FALSE, \Drupal::config('system.rss')->get('items.limit')); + + return node_feed($nids, $channel); } } diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermIndexTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermIndexTest.php index c1e9bb2..0ae0f05 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermIndexTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermIndexTest.php @@ -207,6 +207,7 @@ function testTaxonomyIndex() { * Tests that there is a link to the parent term on the child term page. */ function testTaxonomyTermHierarchyBreadcrumbs() { + \Drupal::moduleHandler()->install(array('views')); // Create two taxonomy terms and set term2 as the parent of term1. $term1 = $this->createTerm($this->vocabulary); $term2 = $this->createTerm($this->vocabulary); diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php index 410ff5a..364644d 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php @@ -295,6 +295,7 @@ function testTermAutocompletion() { * Save, edit and delete a term using the user interface. */ function testTermInterface() { + \Drupal::moduleHandler()->install(array('views')); $edit = array( 'name' => $this->randomName(12), 'description[value]' => $this->randomName(100), diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/VocabularyPermissionsTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/VocabularyPermissionsTest.php index 9b4611d..34a805a 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/VocabularyPermissionsTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/VocabularyPermissionsTest.php @@ -52,7 +52,7 @@ function testVocabularyPermissionsTaxonomyTerm() { // Edit the term. $this->drupalGet('taxonomy/term/' . $term->id() . '/edit'); $this->assertResponse(200); - $this->assertText($edit['name'], 'Edit taxonomy term form opened successfully.'); + $this->assertRaw($edit['name'], 'Edit taxonomy term form opened successfully.'); $edit['name'] = $this->randomName(); $this->drupalPostForm(NULL, $edit, t('Save')); @@ -80,7 +80,7 @@ function testVocabularyPermissionsTaxonomyTerm() { // Edit the term. $this->drupalGet('taxonomy/term/' . $term->id() . '/edit'); $this->assertResponse(200); - $this->assertText($term->name->value, 'Edit taxonomy term form opened successfully.'); + $this->assertRaw($term->name->value, 'Edit taxonomy term form opened successfully.'); $edit['name'] = $this->randomName(); $this->drupalPostForm(NULL, $edit, t('Save')); diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module index fd08344..998f42e 100644 --- a/core/modules/taxonomy/taxonomy.module +++ b/core/modules/taxonomy/taxonomy.module @@ -240,14 +240,10 @@ function taxonomy_menu() { $items['taxonomy/term/%taxonomy_term'] = array( 'title' => 'Taxonomy term', - 'title callback' => 'taxonomy_term_title', - 'title arguments' => array(2), 'route_name' => 'taxonomy.term_page', ); $items['taxonomy/term/%taxonomy_term/feed'] = array( 'title' => 'Taxonomy term', - 'title callback' => 'taxonomy_term_title', - 'title arguments' => array(2), 'route_name' => 'taxonomy.term_feed', 'type' => MENU_CALLBACK, ); @@ -794,19 +790,6 @@ function taxonomy_field_widget_info_alter(&$info) { } /** - * Title callback for term pages. - * - * @param \Drupal\taxonomy\Entity\Term $term - * A taxonomy term entity. - * - * @return - * The term name to be used as the page title. - */ -function taxonomy_term_title(Term $term) { - return $term->label(); -} - -/** * Form element validate handler for taxonomy term autocomplete element. */ function taxonomy_autocomplete_validate($element, &$form_state) { diff --git a/core/modules/taxonomy/taxonomy.pages.inc b/core/modules/taxonomy/taxonomy.pages.inc deleted file mode 100644 index 79d4472..0000000 --- a/core/modules/taxonomy/taxonomy.pages.inc +++ /dev/null @@ -1,80 +0,0 @@ -id() . '/feed', 'RSS - ' . $term->label()); - - foreach ($term->uriRelationships() as $rel) { - $uri = $term->uri($rel); - // Set the term path as the canonical URL to prevent duplicate content. - $build['#attached']['drupal_add_html_head_link'][] = array( - array( - 'rel' => $rel, - 'href' => url($uri['path'], $uri['options']), - ), - TRUE, - ); - - if ($rel == 'canonical') { - // Set the non-aliased canonical path as a default shortlink. - $build['#attached']['drupal_add_html_head_link'][] = array( - array( - 'rel' => 'shortlink', - 'href' => url($uri['path'], array_merge($uri['options'], array('alias' => TRUE))), - ), - TRUE, - ); - } - } - - $build['taxonomy_terms'] = taxonomy_term_view_multiple(array($term->id() => $term)); - if ($nids = taxonomy_select_nodes($term->id(), TRUE, \Drupal::config('node.settings')->get('items_per_page'))) { - $nodes = node_load_multiple($nids); - $build['nodes'] = node_view_multiple($nodes); - $build['pager'] = array( - '#theme' => 'pager', - '#weight' => 5, - ); - } - else { - $build['no_content'] = array( - '#prefix' => '

', - '#markup' => t('There is currently no content classified with this term.'), - '#suffix' => '

', - ); - } - return $build; -} - -/** - * Generate the content feed for a taxonomy term. - * - * @param \Drupal\taxonomy\Entity\Term $term - * The taxonomy term entity. - * - * @deprecated Use \Drupal\taxonomy\Controller\TaxonomyController::termFeed() - */ -function taxonomy_term_feed(Term $term) { - $channel['link'] = url('taxonomy/term/' . $term->id(), array('absolute' => TRUE)); - $channel['title'] = \Drupal::config('system.site')->get('name') . ' - ' . $term->label(); - // Only display the description if we have a single term, to avoid clutter and confusion. - // HTML will be removed from feed description. - $channel['description'] = $term->description->processed; - $nids = taxonomy_select_nodes($term->id(), FALSE, \Drupal::config('system.rss')->get('items.limit')); - - return node_feed($nids, $channel); -} diff --git a/core/modules/taxonomy/taxonomy.views.inc b/core/modules/taxonomy/taxonomy.views.inc index d114050..ffa6426 100644 --- a/core/modules/taxonomy/taxonomy.views.inc +++ b/core/modules/taxonomy/taxonomy.views.inc @@ -465,29 +465,23 @@ function taxonomy_field_views_data_views_data_alter(array &$data, FieldInterface /** * Helper function to set a breadcrumb for taxonomy. + * + * @param array &$breadcrumb + * An array reference containing a reference to + * $view->build_info['breadcrumb']. + * @param \Drupal\views\Plugin\views\argument\ArgumentPluginBase $argument + * The argument handler instance to get the argument from. + * */ function views_taxonomy_set_breadcrumb(&$breadcrumb, &$argument) { - if (empty($argument->options['set_breadcrumb'])) { - return; - } - - $args = $argument->view->args; - $parents = taxonomy_get_parents_all($argument->argument); - foreach (array_reverse($parents) as $parent) { - // Unfortunately parents includes the current argument. Skip. - if ($parent->id() == $argument->argument) { - continue; - } - if (!empty($argument->options['use_taxonomy_term_path'])) { - $path = $parent->uri(); - $path = $path['path']; - } - else { - $args[$argument->position] = $parent->id(); - $path = $argument->view->getUrl($args); - } - $breadcrumb[$path] = check_plain($parent->label()); + $breadcrumb = array(); + $current = taxonomy_term_load($argument->argument); + while ($parents = taxonomy_term_load_parents($current->id())) { + $current = array_shift($parents); + $uri = $current->uri(); + $breadcrumb[$uri['path']] = $current->label(); } + $breadcrumb = array_reverse($breadcrumb); } /** diff --git a/core/modules/views/config/views.view.taxonomy_term.yml b/core/modules/views/config/views.view.taxonomy_term.yml deleted file mode 100644 index 40ca142..0000000 --- a/core/modules/views/config/views.view.taxonomy_term.yml +++ /dev/null @@ -1,237 +0,0 @@ -base_field: nid -base_table: node -core: '8' -description: 'Content belonging to a certain taxonomy term.' -status: false -display: - default: - id: default - display_title: Master - display_plugin: default - position: 1 - display_options: - query: - type: views_query - options: - query_comment: false - disable_sql_rewrite: false - distinct: false - slave: false - query_tags: { } - access: - type: none - options: { } - cache: - type: none - options: { } - exposed_form: - type: basic - options: - submit_button: Apply - reset_button: false - reset_button_label: Reset - exposed_sorts_label: 'Sort by' - expose_sort_order: true - sort_asc_label: Asc - sort_desc_label: Desc - pager: - type: mini - options: - items_per_page: 10 - offset: 0 - id: 0 - total_pages: 0 - expose: - items_per_page: '0' - items_per_page_label: 'Items per page' - items_per_page_options: '5, 10, 20, 40, 60' - items_per_page_options_all: false - items_per_page_options_all_label: '- All -' - offset: false - offset_label: Offset - tags: - previous: ‹‹ - next: ›› - sorts: - sticky: - id: sticky - table: node_field_data - field: sticky - order: DESC - plugin_id: standard - relationship: none - group_type: group - admin_label: '' - exposed: false - expose: - label: '' - provider: views - created: - id: created - table: node_field_data - field: created - order: DESC - plugin_id: date - relationship: none - group_type: group - admin_label: '' - exposed: false - expose: - label: '' - granularity: second - provider: views - arguments: - term_node_tid_depth: - id: term_node_tid_depth - table: node - field: term_node_tid_depth - default_action: 'not found' - exception: - value: all - title_enable: true - title: All - title_enable: true - title: '%1' - default_argument_type: fixed - summary: - format: default_summary - specify_validation: true - validate: - type: 'entity:taxonomy_term' - fail: 'not found' - validate_options: - access: '1' - operation: view - multiple: '1' - bundles: { } - depth: '0' - break_phrase: true - plugin_id: taxonomy_index_tid_depth - relationship: none - group_type: group - admin_label: '' - default_argument_options: - argument: '' - default_argument_skip_url: false - summary_options: - base_path: '' - count: '1' - items_per_page: '25' - override: false - provider: taxonomy - term_node_tid_depth_modifier: - id: term_node_tid_depth_modifier - table: node - field: term_node_tid_depth_modifier - exception: - title_enable: true - default_argument_type: fixed - summary: - format: default_summary - specify_validation: true - plugin_id: taxonomy_index_tid_depth_modifier - relationship: none - group_type: group - admin_label: '' - default_action: ignore - title_enable: false - title: '' - default_argument_options: { } - default_argument_skip_url: false - summary_options: { } - validate: - type: none - fail: 'not found' - validate_options: { } - provider: taxonomy - filters: - status_extra: - id: status_extra - table: node_field_data - field: status_extra - group: '0' - expose: - operator: '0' - plugin_id: node_status - provider: node - style: - type: default - options: - grouping: { } - row_class: '' - default_row_class: true - row_class_special: true - uses_fields: false - row: - type: 'entity:node' - options: - view_mode: teaser - links: '1' - comments: '0' - header: { } - footer: { } - empty: { } - relationships: { } - fields: { } - page_1: - id: page_1 - display_title: Page - display_plugin: page - position: 2 - display_options: - query: - type: views_query - options: { } - path: taxonomy/term/% - feed_1: - id: feed_1 - display_title: Feed - display_plugin: feed - position: 3 - display_options: - query: - type: views_query - options: { } - pager: - type: full - options: - items_per_page: 15 - offset: 0 - id: 0 - total_pages: 0 - expose: - items_per_page: '0' - items_per_page_label: 'Items per page' - items_per_page_options: '5, 10, 20, 40, 60' - items_per_page_options_all: false - items_per_page_options_all_label: '- All -' - offset: false - offset_label: Offset - tags: - previous: '‹ previous' - next: 'next ›' - first: '« first' - last: 'last »' - quantity: '9' - path: taxonomy/term/%/%/feed - displays: - page: page - default: '0' - style: - type: rss - options: - description: '' - grouping: { } - uses_fields: '0' - row: - type: node_rss - options: - relationship: none - item_length: default - links: '0' -label: 'Taxonomy term' -module: taxonomy -id: taxonomy_term -tag: default -uuid: e0dea92e-a4c9-4442-a518-2499bfe17d73 -langcode: en diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php index a84d603..04efd63 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php @@ -256,7 +256,7 @@ public function alterRoutes(RouteCollection $collection) { // We assume that the numeric ids of the parameters match the one from // the view argument handlers. foreach ($parameters as $position => $parameter_name) { - $path = str_replace('arg_' . $position, $parameter_name, $path); + $path = str_replace('{arg_' . $position . '}', '{' . $parameter_name . '}', $path); $argument_map['arg_' . $position] = $parameter_name; } // Set the corrected path and the mapping to the route object. diff --git a/core/modules/views/tests/Drupal/views/Tests/Plugin/display/PathPluginBaseTest.php b/core/modules/views/tests/Drupal/views/Tests/Plugin/display/PathPluginBaseTest.php index 96ab152..d60d8d4 100644 --- a/core/modules/views/tests/Drupal/views/Tests/Plugin/display/PathPluginBaseTest.php +++ b/core/modules/views/tests/Drupal/views/Tests/Plugin/display/PathPluginBaseTest.php @@ -252,6 +252,43 @@ public function testAlterRoutesWithParameters() { } /** + * Tests alter routes with optional parameter in the overriding route. + */ + public function testAlterRoutesWithOptionalParameters() { + $collection = new RouteCollection(); + $collection->add('test_route', new Route('test_route/{parameter}', array('_controller' => 'Drupal\Tests\Core\Controller\TestController::content'))); + + list($view) = $this->setupViewExecutableAccessPlugin(); + + // Manually setup an argument handler. + $argument = $this->getMockBuilder('Drupal\views\Plugin\views\argument\ArgumentPluginBase') + ->disableOriginalConstructor() + ->getMock(); + $view->argument['test_id'] = $argument; + $view->argument['test_id2'] = $argument; + + $display = array(); + $display['display_plugin'] = 'page'; + $display['id'] = 'page_1'; + $display['display_options'] = array( + 'path' => 'test_route/%', + ); + $this->pathPlugin->initDisplay($view, $display); + + $view_route_names = $this->pathPlugin->alterRoutes($collection); + $this->assertEquals(array('test_id.page_1' => 'test_route'), $view_route_names); + + // Ensure that the test_route is overridden. + $route = $collection->get('test_route'); + $this->assertInstanceOf('\Symfony\Component\Routing\Route', $route); + $this->assertEquals('test_id', $route->getDefault('view_id')); + $this->assertEquals('page_1', $route->getDefault('display_id')); + // Ensure that the path did not changed and placeholders are respected. + $this->assertEquals('/test_route/{parameter}/{arg_test_id2}', $route->getPath()); + $this->assertEquals(array('arg_test_id' => 'parameter'), $route->getDefault('_view_argument_map')); + } + + /** * Returns some mocked view entity, view executable, and access plugin. */ protected function setupViewExecutableAccessPlugin() {