Is there an equivalent to menu_get_object() in Drupal 8? I'm trying to find a way to determine whether a given URL path represents an entity, and load that entity object if it does.

How do I load an entity object given a system path (e.g. "node/123" or "some-entity-type/456").

Comments

paulmckibben’s picture

Thanks! That post explains this question for nodes, but what about other entities? Is there a way to get an entity given a system path?

ahebrank’s picture

After some time reading through the various D8 APIs, here's what I have currently to load a node from a system path (as of 8.2). In theory this could extend to other entities as long as the routes for those entities follow a consistent pattern, but I doubt this is the best replacement for menu_get_object():

$params = \Drupal\Core\Url::fromUserInput($path)->getRouteParameters();
if (isset($params['node'])) {
  $node = \Drupal\node\Entity\Node::load($params['node']);
}
ec0g’s picture

In Drupal 8.x, given an internal path of the form "/node/{id}", or "/taxonomy/term/{id}", you can use the following to get and load an entity (whether it's node, taxonomy, etc..):

    $params = Url::fromUri("internal:" . $source_uri)->getRouteParameters();
    $entity_type = key($params);
    $entity = \Drupal::entityTypeManager()->getStorage($entity_type)->load($params[$entity_type]);

Only use this in cases where you know the entity has an internal path.

mxh’s picture

<?php
$entities = [];
foreach (\Drupal::routeMatch()->getParameters() as $param) {
  if ($param instanceof \Drupal\Core\Entity\EntityInterface) {
    $entities[] = $param;
  }
}
?>

Not sure if that's properly working with the revision route though.

Anybody’s picture

@mxh's comment is great, I think and the best solution.

I just wrote a blog article about this topic, if someone is interested: https://julian.pustkuchen.com/node/780#comment-864

http://www.DROWL.de || Professionelle Drupal Lösungen aus Ostwestfalen-Lippe (OWL)
http://www.webks.de || webks: websolutions kept simple - Webbasierte Lösungen die einfach überzeugen!
http://www.drupal-theming.com || Individuelle Responsive Themes

mxh’s picture

function get_page_entity() {
  $page_entity = &drupal_static(__FUNCTION__, NULL);
  if (isset($page_entity)) {
    return $page_entity ?: NULL;
  }
  $current_route = \Drupal::routeMatch();
  foreach ($current_route->getParameters() as $param) {
    if ($param instanceof EntityInterface) {
      $page_entity = $param;
      break;
    }
  }
  if (!isset($page_entity)) {
    // Some routes don't properly define entity parameters.
    // Thus, try to load them by its raw Id, if given.
    $entity_type_manager = \Drupal::entityTypeManager();
    $types = $entity_type_manager->getDefinitions();
    foreach ($current_route->getParameters()->keys() as $param_key) {
      if (!isset($types[$param_key])) {
        continue;
      }
      if ($param = $current_route->getParameter($param_key)) {
        if (is_string($param) || is_numeric($param)) {
          try {
            $page_entity = $entity_type_manager->getStorage($param_key)->load($param);
          }
          catch (\Exception $e) {
          }
        }
        break;
      }
    }
  }
  if (!isset($page_entity) || !$page_entity->access('view')) {
    $page_entity = FALSE;
    return NULL;
  }
  return $page_entity;
}
Anybody’s picture

Thank you very much. Better use explicit

\Drupal\Core\Entity\EntityInterface

explicitly. We had an issue with using EntityInterface only... may have more than one implementation....

http://www.DROWL.de || Professionelle Drupal Lösungen aus Ostwestfalen-Lippe (OWL)
http://www.webks.de || webks: websolutions kept simple - Webbasierte Lösungen die einfach überzeugen!
http://www.drupal-theming.com || Individuelle Responsive Themes

alexrayu’s picture

Thanks @mxh,

I am using a shorted version based on your code in my module.

/**
 * Gets the current page main entity.
 *
 * @return \Drupal\Core\Entity\EntityInterface
 *   Current page main entity.
 */
function butils_page_entity() {
  $page_entity = &drupal_static(__FUNCTION__, NULL);
  if (!empty($page_entity)) {
    return $page_entity;
  }
  $types = array_keys(\Drupal::entityTypeManager()->getDefinitions());
  $route = \Drupal::routeMatch();
  $page_entity = NULL;
  $params = $route->getParameters()->all();
  foreach ($types as $type) {
    if (!empty($params[$type])) {
      $page_entity = $params[$type];
      return $page_entity;
    }
  }

  return NULL;
}
aangel’s picture

Then Drupal will fetch the entity for you (this worked in D7, too):

path: '/current/{cart}'
options:
parameters:
cart:
type: 'entity:cart'

With the above, you can then simply ask Drupal for the entity without the bother of fetching the entity via its id yourself:

$current_route = \Drupal::routeMatch();

// Drupal has fetched the entity for us already.
$cart = $current_route->getParameters()->get('cart');
james.williams’s picture

Looks as though lots of people have already posted various approaches - I blogged about another, which should work for any type of content entity (not just nodes) with a canonical page: https://www.computerminds.co.uk/drupal-code/get-entity-route

This approach checks for whether the page is the canonical page for an entity (as opposed to other routes or view modes that might be available for an entity). It could of course be tweaked to catch other routes, but the point is that you might not want to apply to all routes that an entity might be available on.

ComputerMinds

newresponsivetheme’s picture

$node = \Drupal::routeMatch()->getParameter('node');

You can get the node from the route with the above code.

Source: https://newresponsivetheme.com/drupal-get-node-route

Mokys’s picture

$route = \Drupal::routeMatch();
$entity = null;
if ($route->getRouteObject()) {
  foreach ($route->getParameters() as $name => $parameter) {
    if ($parameter instanceof \Drupal\Core\Entity\EntityInterface) {
      $entity = $parameter;
      break;
    }
  }
}