0

In my projects I often have some special node (types), for which I'm creating custom admin routes and custom edit forms. E.g. I've got a restaurant homepage offering daily lunch specials. For ease of use I've created a custom route with a custom edit mask for the lunch specials of the upcoming week

wt_lunch.routing.yml

wt_lunch.week:
  path: '/admin/lunch/week'
  defaults:
    _title: 'Edit daily specials of the week'
    _controller: '\Drupal\wt_lunch\Controller\WtLunchController::week'
  requirements:
    _node_add_access: 'node:wt_lunch'
  options:
    _node_operation_route: TRUE
    _admin_route: true

WtLunchController.php

public function week() {
  //only one node of type wt_lunch exists
  $menuNodes = \Drupal::entityTypeManager()
    ->getStorage('node')
    ->loadByProperties(['type' => 'wt_lunch']);
  $menuNode = reset($menuNodes);

  // edit the lunch node in customized "week" form display mode
  $form = \Drupal::entityTypeManager()
    ->getFormObject('node', 'week')
    ->setEntity($menuNode);

  return \Drupal::formBuilder()->getForm($form);
}

Our customers like those reduced edit forms for frequently changing content, I'm using similar variations in multiple projects. However, those routes have the disadvantage of missing a proper node route parameter. E.g. a .module function like

othermodule.module

function othermodule_theme_suggestions_alter(array &$suggestions, array $variables, $hook) {
  if ($hook == 'node_edit_form') {
    if ($node = \Drupal::routeMatch()->getParameter('node')) {
      $suggestions[] = 'node_edit_form__' . $node->bundle();
    }
  }
}

does not work.

Question:

Can my module wt_lunch somehow inject the node parameter into my custom route, so that othermodule can query the node route parameter without changing code in othermodule?

Update:

Those nodes are usually one-off nodes, so I have a constant path without a numeric ID in the path. I need a solution that works without upcasting a variable from the path and without upcasting a hard coded defaults: value from routing.yml (I already have a solution with upcasting a "magic" default value, but I want to get rid off hard coded IDs)

  • Unfortunately, I'm having troubles following what you are asking, as you have explained how you are trying to accomplish some goal, but haven't clearly stated what that goal is. So it's hard for me to figure out where you are going wrong, as I don't have the full vision of what going right is supposed to be. – Jaypan Oct 19 '18 at 11:13
  • The currently missing goal is to provide a "valid" node route parameter, which can be used by other modules (see my othermodule_theme_suggestions_alter example, using \Drupal::routeMatch()->getParameter('node')). The code in othermodule does not work with the custom route from wt_lunch module. – Hudri Oct 19 '18 at 11:16
  • In other words, I want to provide a "fake" node route parameter in my custom controller so that all other modules and themes can still use \Drupal::routeMatch()->getParameter('node') and get the same node that I'm loading programmatically in the custom controller. – Hudri Oct 19 '18 at 11:46
  • I would use an alias for the lunch of the week instead of changing the internal route. To set a display mode for a content type you don't need custom code either, see drupal.stackexchange.com/questions/230054/… – 4k4 Oct 19 '18 at 16:54
2

You can by altering the existing route.

wt_lunch/src/Routing/RouteSubscriber.php

namespace Drupal\wt_lunch\Routing;

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

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

  /**
   * {@inheritdoc}
   */
  protected function alterRoutes(RouteCollection $collection) {
    if ($route = $collection->get('wt_lunch.week')) {
      $route->setPath('/admin/lunch/week/{node}');
      $nid = // some code to get nid
      $route->setDefault('node', $nid);
    }
  }

}

wt_lunch/wt_lunch.services.yml

services:
  wt_lunch.route_subscriber:
    class: Drupal\wt_lunch\Routing\RouteSubscriber
    tags:
      - { name: event_subscriber }
  • 1
    Thanks, this did the trick. A remark from myself: To get a node object instead of a string from $route->getParameter('node'), you still need to do a parameter: type: 'entity:node' upcasting in routing.yml (for an example see link "upcasting default value" in my question) – Hudri Oct 23 '18 at 7:29
1

In the routing path you want to include the node parameter, so it would be something like this.

/admin/lunch/week/{node}

For more info look here

  • Sorry, didn't mention that I'm looking for a solution without variables in routing.yml. Updated my question. – Hudri Oct 19 '18 at 10:15

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.