View source
<?php
namespace Drupal\rest_menu_tree\Plugin\rest\resource;
use Drupal\Core\Access\AccessibleInterface;
use Drupal\Core\Access\AccessResultInterface;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Cache\CacheableResponseInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Menu\MenuLinkInterface;
use Drupal\Core\Menu\MenuLinkTreeInterface;
use Drupal\Core\Menu\MenuTreeParameters;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Drupal\system\MenuInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Psr\Log\LoggerInterface;
class MenuTreeResource extends ResourceBase {
protected $menuTree;
protected $entityTypeManager;
public function __construct(array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $logger, MenuLinkTreeInterface $menu_tree, EntityTypeManagerInterface $entity_type_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);
$this->menuTree = $menu_tree;
$this->entityTypeManager = $entity_type_manager;
}
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->getParameter('serializer.formats'), $container
->get('logger.factory')
->get('rest'), $container
->get('menu.link_tree'), $container
->get('entity_type.manager'));
}
public function get(MenuInterface $menu) {
$params = new MenuTreeParameters();
$tree = $this->menuTree
->load($menu
->id(), $params);
$manipulators = [
[
'callable' => 'menu.default_tree_manipulators:generateIndexAndSort',
],
];
$tree = $this->menuTree
->transform($tree, $manipulators);
$this
->addAccess($tree);
$clean = $tree;
$this
->checkAccess($tree);
$this
->removeKeys($tree);
$response = new ResourceResponse($tree);
$response
->addCacheableDependency($menu);
$this
->addCacheDependencies($clean, $response);
return $response;
}
protected function removeKeys(array &$data) {
$tree = [];
foreach ($data as $value) {
if ($value->subtree) {
$this
->removeKeys($value->subtree);
}
$tree[] = $value;
}
$data = $tree;
}
protected function addAccess(array $data) {
foreach ($data as $value) {
if ($value->access === NULL && $value->link instanceof AccessibleInterface) {
$value->access = $value->link
->access('view', NULL, TRUE);
}
if ($value->subtree) {
$this
->addAccess($value->subtree);
}
}
}
protected function checkAccess(array &$data) {
foreach ($data as $key => $value) {
if ($value->access instanceof AccessResultInterface) {
if (!$value->access
->isAllowed()) {
unset($data[$key]);
continue;
}
}
elseif (!$value->link
->isEnabled()) {
unset($data[$key]);
continue;
}
if ($value->subtree) {
$this
->checkAccess($value->subtree);
}
}
}
protected function addCacheDependencies(array $data, CacheableResponseInterface $response) {
foreach ($data as $value) {
if ($value->access instanceof AccessResultInterface) {
$response
->addCacheableDependency($value->access);
}
$response
->addCacheableDependency($value->link);
$this
->addLinkCacheDependencies($value->link, $response);
if ($value->subtree) {
$this
->addCacheDependencies($value->subtree, $response);
}
}
}
protected function addLinkCacheDependencies(MenuLinkInterface $link, CacheableResponseInterface $response) {
$entity_type = NULL;
$entity_type_id = $link
->getBaseId();
$uuid = $link
->getDerivativeId();
if ($link instanceof EntityInterface) {
$entity_type = $link
->getEntityType();
}
else {
try {
$entity_type = $this->entityTypeManager
->getDefinition($entity_type_id);
} catch (\Exception $e) {
}
}
if (!$entity_type) {
return;
}
$cache = new CacheableMetadata();
$cache
->addCacheTags($entity_type
->getListCacheTags());
$response
->addCacheableDependency($cache);
if ($link instanceof EntityInterface) {
return;
}
$entity = NULL;
$storage = $this->entityTypeManager
->getStorage($entity_type_id);
$metadata = $link
->getMetaData();
if (!empty($metadata['entity_id'])) {
$entity = $storage
->load($metadata['entity_id']);
}
else {
$entities = $storage
->loadByProperties([
$entity_type
->getKey('uuid') => $uuid,
]);
$entity = reset($entities);
}
if (!$entity) {
return;
}
$response
->addCacheableDependency($entity);
}
protected function getBaseRoute($canonical_path, $method) {
$route = parent::getBaseRoute($canonical_path, $method);
$parameters = $route
->getOption('parameters') ?: array();
$parameters['menu']['type'] = 'entity:menu';
$route
->setOption('parameters', $parameters);
return $route;
}
}