diff -u b/core/core.services.yml b/core/core.services.yml --- b/core/core.services.yml +++ b/core/core.services.yml @@ -306,6 +306,11 @@ tags: - { name: paramconverter } arguments: ['@plugin.manager.entity'] + route_subscriber.entity: + class: Drupal\Core\EventSubscriber\EntityRouteAlterSubscriber + tags: + - { name: event_subscriber } + arguments: ['@plugin.manager.entity'] reverse_proxy_subscriber: class: Drupal\Core\EventSubscriber\ReverseProxySubscriber tags: reverted: --- b/core/lib/Drupal/Core/Controller/ControllerResolver.php +++ a/core/lib/Drupal/Core/Controller/ControllerResolver.php @@ -7,7 +7,6 @@ namespace Drupal\Core\Controller; -use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ControllerResolver as BaseControllerResolver; use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\DependencyInjection\ContainerAwareInterface; reverted: --- b/core/modules/action/action.routing.yml +++ a/core/modules/action/action.routing.yml @@ -18,10 +18,6 @@ _entity_form: 'action.edit' requirements: _permission: 'administer actions' - options: - parameters: - action: - type: 'entity:action' action_delete: pattern: 'admin/config/system/actions/configure/{action}/delete' @@ -29,8 +25,4 @@ _entity_form: 'action.delete' requirements: _permission: 'administer actions' - options: - parameters: - action: - type: 'entity:action' reverted: --- b/core/modules/aggregator/aggregator.routing.yml +++ a/core/modules/aggregator/aggregator.routing.yml @@ -18,10 +18,6 @@ _entity_form: 'aggregator_feed.remove_items' requirements: _permission: 'administer news feeds' - options: - parameters: - aggregator_feed: - type: 'entity:aggregator_feed' aggregator_feed_delete: pattern: '/admin/config/services/aggregator/delete/feed/{aggregator_feed}' @@ -29,10 +25,6 @@ _entity_form: 'aggregator_feed.delete' requirements: _permission: 'administer news feeds' - options: - parameters: - aggregator_feed: - type: 'entity:aggregator_feed' aggregator_feed_add: pattern: '/admin/config/services/aggregator/add/feed' @@ -47,10 +39,6 @@ _controller: '\Drupal\aggregator\Controller\AggregatorController::feedRefresh' requirements: _permission: 'administer news feeds' - options: - parameters: - aggregator_feed: - type: 'entity:aggregator_feed' aggregator_opml_add: pattern: '/admin/config/services/aggregator/add/opml' reverted: --- b/core/modules/block/block.routing.yml +++ a/core/modules/block/block.routing.yml @@ -4,10 +4,6 @@ _entity_form: 'block.delete' requirements: _permission: 'administer blocks' - options: - parameters: - block: - type: 'entity:block' block_admin_edit: pattern: '/admin/structure/block/manage/{block}' @@ -15,10 +11,6 @@ _entity_form: 'block.default' requirements: _entity_access: 'block.update' - options: - parameters: - block: - type: 'entity:block' block_admin_display: pattern: '/admin/structure/block' reverted: --- b/core/modules/block/custom_block/custom_block.routing.yml +++ a/core/modules/block/custom_block/custom_block.routing.yml @@ -18,10 +18,6 @@ _content: 'Drupal\custom_block\Controller\CustomBlockController::addForm' requirements: _permission: 'administer blocks' - options: - parameters: - custom_block_type: - type: 'entity:custom_block_type' custom_block_type_delete: pattern: '/admin/structure/custom-blocks/manage/{custom_block_type}/delete' @@ -29,7 +25,3 @@ _entity_form: 'custom_block_type.delete' requirements: _permission: 'administer blocks' - options: - parameters: - custom_block_type: - type: 'entity:custom_block_type' reverted: --- b/core/modules/comment/comment.routing.yml +++ a/core/modules/comment/comment.routing.yml @@ -4,10 +4,6 @@ _entity_form: 'comment.default' requirements: _entity_access: 'comment.update' - options: - parameters: - comment: - type: 'entity:comment' comment_approve: pattern: '/comment/{comment}/approve' @@ -16,10 +12,6 @@ entity_type: 'comment' requirements: _entity_access: 'comment.approve' - options: - parameters: - comment: - type: 'entity:comment' comment_permalink: pattern: '/comment/{comment}' @@ -27,7 +19,3 @@ _controller: '\Drupal\comment\Controller\CommentController::commentPermalink' requirements: _entity_access: 'comment.view' - options: - parameters: - comment: - type: 'entity:comment' reverted: --- b/core/modules/config/tests/config_test/config_test.routing.yml +++ a/core/modules/config/tests/config_test/config_test.routing.yml @@ -19,10 +19,6 @@ entity_type: 'config_test' requirements: _access: 'TRUE' - options: - parameters: - config_test: - type: 'entity:config_test' config_test_entity_edit: pattern: 'admin/structure/config_test/manage/{config_test}/edit' @@ -31,10 +27,6 @@ entity_type: 'config_test' requirements: _access: 'TRUE' - options: - parameters: - config_test: - type: 'entity:config_test' config_test_entity_enable: pattern: 'admin/structure/config_test/manage/{config_test}/enable' @@ -43,10 +35,6 @@ entity_type: 'config_test' requirements: _access: 'TRUE' - options: - parameters: - config_test: - type: 'entity:config_test' config_test_entity_disable: pattern: 'admin/structure/config_test/manage/{config_test}/disable' @@ -55,10 +43,6 @@ entity_type: 'config_test' requirements: _access: 'TRUE' - options: - parameters: - config_test: - type: 'entity:config_test' config_test_entity_delete: pattern: 'admin/structure/config_test/manage/{config_test}/delete' @@ -67,7 +51,3 @@ entity_type: 'config_test' requirements: _access: 'TRUE' - options: - parameters: - config_test: - type: 'entity:config_test' reverted: --- b/core/modules/contact/contact.routing.yml +++ a/core/modules/contact/contact.routing.yml @@ -4,10 +4,6 @@ _entity_form: contact_category.delete requirements: _entity_access: contact_category.delete - options: - parameters: - contact_category: - type: 'entity:contact_category' contact_category_list: pattern: '/admin/structure/contact' @@ -29,7 +25,3 @@ _entity_form: contact_category.edit requirements: _entity_access: contact_category.update - options: - parameters: - contact_category: - type: 'entity:contact_category' reverted: --- b/core/modules/entity/entity.routing.yml +++ a/core/modules/entity/entity.routing.yml @@ -25,10 +25,6 @@ _entity_form: 'view_mode.edit' requirements: _entity_access: 'view_mode.update' - options: - parameters: - view_mode: - type: 'entity:view_mode' entity_view_mode.delete: pattern: '/admin/structure/display-modes/view/manage/{view_mode}/delete' @@ -36,10 +32,6 @@ _entity_form: 'view_mode.delete' requirements: _entity_access: 'view_mode.delete' - options: - parameters: - view_mode: - type: 'entity:view_mode' entity_form_mode.list: pattern: '/admin/structure/display-modes/form' @@ -68,10 +60,6 @@ _entity_form: 'form_mode.edit' requirements: _entity_access: 'form_mode.update' - options: - parameters: - form_mode: - type: 'entity:form_mode' entity_form_mode.delete: pattern: '/admin/structure/display-modes/form/manage/{form_mode}/delete' @@ -79,7 +67,3 @@ _entity_form: 'form_mode.delete' requirements: _entity_access: 'form_mode.delete' - options: - parameters: - form_mode: - type: 'entity:form_mode' reverted: --- b/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php +++ a/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php @@ -56,30 +56,21 @@ $route = new Route( "$path/fields/{field_instance}", array('_form' => '\Drupal\field_ui\Form\FieldInstanceEditForm'), + array('_permission' => 'administer ' . $entity_type . ' fields') - array('_permission' => 'administer ' . $entity_type . ' fields'), - array('parameters' => array( - 'field_instance' => array('type' => 'entity:field_instance'), - )) ); $collection->add("field_ui.instance_edit.$entity_type", $route); $route = new Route( "$path/fields/{field_instance}/field", array('_form' => '\Drupal\field_ui\Form\FieldEditForm'), + array('_permission' => 'administer ' . $entity_type . ' fields') - array('_permission' => 'administer ' . $entity_type . ' fields'), - array('parameters' => array( - 'field_instance' => array('type' => 'entity:field_instance'), - )) ); $collection->add("field_ui.field_edit.$entity_type", $route); $route = new Route( "$path/fields/{field_instance}/delete", array('_entity_form' => 'field_instance.delete'), + array('_permission' => 'administer ' . $entity_type . ' fields') - array('_permission' => 'administer ' . $entity_type . ' fields'), - array('parameters' => array( - 'field_instance' => array('type' => 'entity:field_instance'), - )) ); $collection->add("field_ui.delete.$entity_type", $route); reverted: --- b/core/modules/filter/filter.routing.yml +++ a/core/modules/filter/filter.routing.yml @@ -11,10 +11,6 @@ _content: '\Drupal\filter\Controller\FilterController::filterTips' requirements: _filter_access: 'TRUE' - options: - parameters: - filter_format: - type: 'entity:filter_format' filter_admin_overview: pattern: '/admin/config/content/formats' @@ -37,10 +33,6 @@ _entity_form: filter_format.edit requirements: _permission: 'administer filters' - options: - parameters: - filter_format: - type: 'entity:filter_format' filter_admin_disable: pattern: '/admin/config/content/formats/manage/{filter_format}/disable' @@ -48,7 +40,3 @@ _entity_form: 'filter_format.disable' requirements: _filter_disable_format_access: 'TRUE' - options: - parameters: - filter_format: - type: 'entity:filter_format' reverted: --- b/core/modules/forum/forum.routing.yml +++ a/core/modules/forum/forum.routing.yml @@ -4,11 +4,6 @@ _form: 'Drupal\forum\Form\DeleteForm' requirements: _permission: 'administer forums' - options: - parameters: - taxonomy_term: - type: 'entity:taxonomy_term' - forum_settings: pattern: '/admin/structure/forum/settings' defaults: reverted: --- b/core/modules/image/image.routing.yml +++ a/core/modules/image/image.routing.yml @@ -4,10 +4,6 @@ _entity_form: 'image_style.delete' requirements: _permission: 'administer image styles' - options: - parameters: - image_style: - type: 'entity:image_style' image_effect_delete: pattern: 'admin/config/media/image-styles/manage/{image_style}/effects/{image_effect}/delete' @@ -15,7 +11,3 @@ _form: '\Drupal\image\Form\ImageEffectDeleteForm' requirements: _permission: 'administer image styles' - options: - parameters: - image_style: - type: 'entity:image_style' reverted: --- b/core/modules/menu/menu.routing.yml +++ a/core/modules/menu/menu.routing.yml @@ -11,10 +11,6 @@ _entity_form: 'menu_link.reset' requirements: _permission: 'administer menu' - options: - parameters: - menu_link: - type: 'entity:menu_link' menu_link_delete: pattern: 'admin/structure/menu/item/{menu_link}/delete' @@ -22,10 +18,6 @@ _entity_form: 'menu_link.delete' requirements: _access_menu_delete_link: 'TRUE' - options: - parameters: - menu_link: - type: 'entity:menu_link' menu_delete_menu: pattern: 'admin/structure/menu/manage/{menu}/delete' @@ -33,7 +25,3 @@ _entity_form: 'menu.delete' requirements: _access_menu_delete_menu: 'TRUE' - options: - parameters: - menu: - type: 'entity:menu' reverted: --- b/core/modules/node/node.routing.yml +++ a/core/modules/node/node.routing.yml @@ -11,10 +11,6 @@ _entity_form: 'node.edit' requirements: _entity_access: 'node.update' - options: - parameters: - node: - type: 'entity:node' node_delete_confirm: pattern: '/node/{node}/delete' @@ -22,10 +18,6 @@ _entity_form: 'node.delete' requirements: _entity_access: 'node.delete' - options: - parameters: - node: - type: 'entity:node' node_revision_revert_confirm: pattern: '/node/{node}/revisions/{node_revision}/revert' @@ -33,10 +25,6 @@ _form: '\Drupal\node\Form\NodeRevisionRevertForm' requirements: _access_node_revision: 'update' - options: - parameters: - node: - type: 'entity:node' node_revision_delete_confirm: pattern: '/node/{node}/revisions/{node_revision}/delete' @@ -44,10 +32,6 @@ _form: '\Drupal\node\Form\NodeRevisionDeleteForm' requirements: _access_node_revision: 'delete' - options: - parameters: - node: - type: 'entity:node' node_overview_types: pattern: '/admin/structure/types' @@ -70,10 +54,6 @@ _entity_form: 'node_type.edit' requirements: _permission: 'administer content types' - options: - parameters: - node_type: - type: 'entity:node_type' node_type_edit_default: pattern: '/admin/structure/types/manage/{node_type}/edit' @@ -81,10 +61,6 @@ _entity_form: 'node_type.edit' requirements: _permission: 'administer content types' - options: - parameters: - node_type: - type: 'entity:node_type' node_type_delete_confirm: pattern: '/admin/structure/types/manage/{node_type}/delete' @@ -92,10 +68,6 @@ _entity_form: 'node_type.delete' requirements: _entity_access: 'node_type.delete' - options: - parameters: - node_type: - type: 'entity:node_type' node_configure_rebuild_confirm: pattern: '/admin/reports/status/rebuild' reverted: --- b/core/modules/picture/picture.routing.yml +++ a/core/modules/picture/picture.routing.yml @@ -18,10 +18,6 @@ _entity_form: 'picture_mapping.edit' requirements: _permission: 'administer pictures' - options: - parameters: - picture_mapping: - type: 'entity:picture_mapping' picture_mapping_page_duplicate: pattern: '/admin/config/media/picturemapping/{picture_mapping}/duplicate' @@ -29,10 +25,6 @@ _entity_form: 'picture_mapping.duplicate' requirements: _permission: 'administer pictures' - options: - parameters: - picture_mapping: - type: 'entity:picture_mapping' picture_mapping_action_confirm: pattern: '/admin/config/media/picturemapping/{picture_mapping}/delete' @@ -40,7 +32,3 @@ _entity_form: 'picture_mapping.delete' requirements: _permission: 'administer pictures' - options: - parameters: - picture_mapping: - type: 'entity:picture_mapping' reverted: --- b/core/modules/shortcut/shortcut.routing.yml +++ a/core/modules/shortcut/shortcut.routing.yml @@ -4,10 +4,6 @@ _form: 'Drupal\shortcut\Form\LinkDelete' requirements: _access_shortcut_link_delete: 'TRUE' - options: - parameters: - menu_link: - type: 'entity:menu_link' shortcut_set_delete: pattern: '/admin/config/user-interface/shortcut/manage/{shortcut}/delete' @@ -15,10 +11,6 @@ _entity_form: 'shortcut.delete' requirements: _entity_access: 'shortcut.delete' - options: - parameters: - shortcut: - type: 'entity:shortcut' shortcut_set_admin: pattern: '/admin/config/user-interface/shortcut' @@ -40,10 +32,6 @@ _entity_form: 'shortcut.edit' requirements: _entity_access: 'shortcut.update' - options: - parameters: - shortcut: - type: 'entity:shortcut' shortcut_link_add_inline: pattern: '/admin/config/user-interface/shortcut/manage/{shortcut}/add-link-inline' @@ -51,10 +39,6 @@ _controller: 'Drupal\shortcut\Controller\ShortcutController::addShortcutLinkInline' requirements: _entity_access: 'shortcut.update' - options: - parameters: - shortcut: - type: 'entity:shortcut' shortcut_set_customize: pattern: '/admin/config/user-interface/shortcut/manage/{shortcut}' @@ -62,7 +46,3 @@ _entity_form: 'shortcut.customize' requirements: _entity_access: 'shortcut.update' - options: - parameters: - shortcut: - type: 'entity:shortcut' diff -u /dev/null b/core/modules/system/lib/Drupal/system/Tests/ParamConverter/UpcastingTest.php --- /dev/null +++ b/core/modules/system/lib/Drupal/system/Tests/ParamConverter/UpcastingTest.php @@ -0,0 +1,74 @@ + 'Upcasting tests', + 'description' => 'Tests upcasting of url arguments to entities.', + 'group' => 'ParamConverter', + ); + } + + public static $modules = array('paramconverter_test'); + + /** + * Confirms that all parameters are converted as expected. + * + * All of these requests end up being proccessed by a controller with this + * the signature: f($user, $node, $foo) returning either values or labels + * like "user: Dries, node: First post, foo: bar" + * + * The tests shuffle the parameters around an checks if the right thing is + * happening. + */ + public function testUpcasting() { + $node = $this->drupalCreateNode(array('title' => $this->randomName(8))); + $user = $this->drupalCreateUser(array('access content')); + $foo = 'bar'; + + // paramconverter_test/test_user_node_foo/{user}/{node}/{foo} + $this->drupalGet("paramconverter_test/test_user_node_foo/" . $user->id() . "/{$node->nid}/$foo"); + $this->assertRaw("user: {$user->label()}, node: {$node->label()}, foo: $foo", 'user and node upcast by entity name'); + + // paramconverter_test/test_node_user_user/{node}/{foo}/{user} + // options.parameters.foo.type = entity:user + $this->drupalGet("paramconverter_test/test_node_user_user/{$node->nid}/" . $user->id() . "/" . $user->id()); + $this->assertRaw("user: {$user->label()}, node: {$node->label()}, foo: {$user->label()}", 'foo converted to user as well'); + + // paramconverter_test/test_node_node_foo/{user}/{node}/{foo} + // options.parameters.user.type = entity:node + $this->drupalGet("paramconverter_test/test_node_node_foo/{$node->nid}/{$node->nid}/$foo"); + $this->assertRaw("user: {$node->label()}, node: {$node->label()}, foo: $foo", 'user is upcast to node (rather than to user)'); + } + + /** + * Confirms we can upcast to controller arguments of the same type. + */ + public function testSameTypes() { + $node = $this->drupalCreateNode(array('title' => $this->randomName(8))); + $parent = $this->drupalCreateNode(array('title' => $this->randomName(8))); + // paramconverter_test/node/{node}/set/parent/{parent} + // options.parameters.parent.type = entity:node + $this->drupalGet("paramconverter_test/node/" . $node->nid . "/set/parent/" . $parent->nid); + $this->assertRaw("Setting '" . $parent->title . "' as parent of '" . $node->title . "'."); + } +} reverted: --- b/core/modules/system/system.routing.yml +++ a/core/modules/system/system.routing.yml @@ -101,10 +101,6 @@ _entity_form: 'date_format.edit' requirements: _entity_access: 'date_format.update' - options: - parameters: - date_format: - type: 'entity:date_format' date_format_delete: pattern: 'admin/config/regional/date-time/formats/manage/{date_format}/delete' @@ -112,10 +108,6 @@ _entity_form: 'date_format.delete' requirements: _entity_access: 'date_format.delete' - options: - parameters: - date_format: - type: 'entity:date_format' date_format_localize_reset: pattern: 'admin/config/regional/date-time/locale/{langcode}/reset' reverted: --- /dev/null +++ a/core/modules/system/tests/modules/paramconverter_test/lib/Drupal/paramconverter_test/TestControllers.php @@ -0,0 +1,27 @@ +label() : $user); + $retval .= ", node: " . (is_object($node) ? $node->label() : $node); + $retval .= ", foo: " . (is_object($foo) ? $foo->label() : $foo); + return $retval; + } + + public function testNodeSetParent(EntityInterface $node, EntityInterface $parent) { + return "Setting '{$parent->title}' as parent of '{$node->title}'."; + } +} reverted: --- /dev/null +++ a/core/modules/system/tests/modules/paramconverter_test/paramconverter_test.info.yml @@ -0,0 +1,7 @@ +name: "ParamConverter test" +type: module +description: "Support module for paramconverter testing." +package: Testing +version: VERSION +core: 8.x +hidden: TRUE reverted: --- /dev/null +++ a/core/modules/system/tests/modules/paramconverter_test/paramconverter_test.module @@ -0,0 +1,6 @@ +entityManager = $entity_manager; + } + + /** + * Applies parameter converters to route parameters. + * + * @param \Drupal\Core\Routing\RouteBuildEvent $event + * The event to process. + */ + public function onRoutingRouteAlterSetType(RouteBuildEvent $event) { + $entity_types = array_keys($this->entityManager->getDefinitions()); + foreach ($event->getRouteCollection() as $route) { + $parameter_definitions = $route->getOption('parameters') ?: array(); + // For all route parameter names that match an entity type, add the 'type' + // to the parameter definition if it's not already explicitly provided. + foreach (array_intersect($route->compile()->getVariables(), $entity_types) as $parameter_name) { + if (!isset($parameter_definitions[$parameter_name])) { + $parameter_definitions[$parameter_name] = array(); + } + $parameter_definitions[$parameter_name] += array( + 'type' => 'entity:' . $parameter_name, + ); + } + if ($parameter_definitions) { + $route->setOption('parameters', $parameter_definitions); + } + } + } + + /** + * {@inheritdoc} + */ + static function getSubscribedEvents() { + $events[RoutingEvents::ALTER][] = array('onRoutingRouteAlterSetType', 100); + return $events; + } +}