3

I have a discussion content type. I would like the primary viewing experience (at "discussion/discussion-name") to be a cacheable form using a form mode.

Basically, I'm trying to create something like a web app experience where anyone who can view it, can edit it, so there is no point to separating view and edit, a more integrated experience is desired.

It feels like it should be easy, but I haven't found anything about how to override the routing for just one content type.

How can I override the route for a content type?

4

You'll need to alter the entity.node.canonical route to do this. You can do this via a RouteSubscriber::alterRoutes() in a custom module to have the route driven by your custom logic. In src/Routing/RouteSubscriber.php:

namespace Drupal\mymodule\Routing;

use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;

/**
 * Listens to the dynamic route events.
 */
class RouteSubscriber extends RouteSubscriberBase {

  /**
   * {@inheritdoc}
   */
  public function alterRoutes(RouteCollection $collection) {

    // Alter the canonical node route to our custom route
    if ($route = $collection->get('entity.node.canonical')) {
      $route->setDefault('_controller', '\Drupal\mymodule\Controller\NodeRedirectController::view');
    }
  }
}

Then build the logic in your custom controller to redirect based on your node type, in src/Controller/NodeRedirectController.php:

namespace Drupal\mymodule\Controller;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Drupal\Core\Entity\EntityInterface;
use Drupal\node\Controller\NodeViewController;


/**
 * Custom node redirect controller
 */
class NodeRedirectController extends NodeViewController {

  public function view(EntityInterface $node, $view_mode = 'full', $langcode = NULL) {
    // Redirect to the edit path on the discussion type
    if ($node->getType() == 'discussion') {
      return new RedirectResponse('/node/' . $node->id() . '/edit');
    }
    // Otherwise, fall back to the parent route controller.
    else {
      return parent::view($node, $view_mode, $langcode);
    }
  }
}

Lastly, register your routeSubscriber service in mymodules.services.yml:

services:
  mymodule.route_subscriber:
    class: Drupal\mymodule\Routing\RouteSubscriber
    tags:
      - { name: event_subscriber }

Documentation is on drupal.org: Altering existing routes and adding new routes based on dynamic ones.

  • 1
    Thanks Shawn, that's really helpful. You saved me a lot of time with this. For benefits of future people, 2 small points: I think "namespace Drupal\test\Controller;" should be "namespace Drupal\mymodule\Controller; ", and also a mymodule.services.yml entry is needed " mymodule.route_subscriber: class: Drupal\mymodule\Routing\RouteSubscriber tags: - { name: event_subscriber }". drupal.org/node/2187643 is the docs for this approach. – Jonathan Sep 18 '16 at 20:26
  • No problem. Yeah the namespace was a typo which I've fixed. Feed free to edit the answer with any further details that help you solved the problem. – Shawn Conn Sep 18 '16 at 20:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.