Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • project/jsonapi_menu_items
  • issue/jsonapi_menu_items-3186804
  • issue/jsonapi_menu_items-3171184
  • issue/jsonapi_menu_items-3205065
  • issue/jsonapi_menu_items-3171371
  • issue/jsonapi_menu_items-3211656
  • issue/jsonapi_menu_items-3198306
  • issue/jsonapi_menu_items-3213317
  • issue/jsonapi_menu_items-3216818
  • issue/jsonapi_menu_items-3192576
  • issue/jsonapi_menu_items-3288144
  • issue/jsonapi_menu_items-3322768
  • issue/jsonapi_menu_items-3288143
  • issue/jsonapi_menu_items-3350524
  • issue/jsonapi_menu_items-3276561
  • issue/jsonapi_menu_items-3420066
  • issue/jsonapi_menu_items-3421504
  • issue/jsonapi_menu_items-3270141
  • issue/jsonapi_menu_items-3451149
  • issue/jsonapi_menu_items-3458524
  • issue/jsonapi_menu_items-3464587
  • issue/jsonapi_menu_items-3447727
  • issue/jsonapi_menu_items-3527213
  • issue/jsonapi_menu_items-3529854
  • issue/jsonapi_menu_items-3529865
25 results
Select Git revision
Show changes
Commits on Source (10)
Showing
with 303 additions and 105 deletions
################
# DrupalCI GitLabCI template
#
# Gitlab-ci.yml to replicate DrupalCI testing for Contrib
#
# With thanks to:
# * The GitLab Acceleration Initiative participants
# * DrupalSpoons
################
################
# Guidelines
#
# This template is designed to give any Contrib maintainer everything they need to test, without requiring modification. It is also designed to keep up to date with Core Development automatically through the use of include files that can be centrally maintained.
#
# However, you can modify this template if you have additional needs for your project.
################
################
# Includes
#
# Additional configuration can be provided through includes.
# One advantage of include files is that if they are updated upstream, the changes affect all pipelines using that include.
#
# Includes can be overridden by re-declaring anything provided in an include, here in gitlab-ci.yml
# https://docs.gitlab.com/ee/ci/yaml/includes.html#override-included-configuration-values
################
include:
################
# DrupalCI includes:
# As long as you include this, any future includes added by the Drupal Association will be accessible to your pipelines automatically.
# View these include files at https://git.drupalcode.org/project/gitlab_templates/
################
- project: $_GITLAB_TEMPLATES_REPO
ref: $_GITLAB_TEMPLATES_REF
file:
- '/includes/include.drupalci.main.yml'
- '/includes/include.drupalci.variables.yml'
- '/includes/include.drupalci.workflows.yml'
################
# Pipeline configuration variables
#
# These are the variables provided to the Run Pipeline form that a user may want to override.
#
# Docs at https://git.drupalcode.org/project/gitlab_templates/-/blob/1.0.x/includes/include.drupalci.variables.yml
################
variables:
_PHPUNIT_CONCURRENT: 1
OPT_IN_TEST_PREVIOUS_MINOR: 1
OPT_IN_TEST_NEXT_MINOR: 1
OPT_IN_TEST_NEXT_MAJOR: 1
# Use PHP 8.1 for Drupal Core 9.5.x
CORE_PREVIOUS_PHP_MIN: 8.1
_CSPELL_WORDS: 'pathmenu, pathuser'
composer (next major):
variables:
_LENIENT_ALLOW_LIST: 'jsonapi_hypermedia, menu_item_extras'
cspell:
allow_failure: false
eslint:
allow_failure: false
phpcs:
allow_failure: false
phpstan:
allow_failure: false
phpstan (next major):
allow_failure: true
stylelint:
allow_failure: false
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
- Supports `menu_link_content` and [menu_link_config](https://www.drupal.org/project/menu_link_config) menu items. - Supports `menu_link_content` and [menu_link_config](https://www.drupal.org/project/menu_link_config) menu items.
- Supports filtering by depth, parents and custom query conditions. - Supports filtering by depth, parents and custom query conditions.
- Support for [JSON:API Hypermedia](https://www.drupal.org/project/jsonapi_hypermedia) based links in `/jsonapi` root document. - Support for [JSON:API Hypermedia](https://www.drupal.org/project/jsonapi_hypermedia) based links in `/jsonapi` root document.
- Support for fields added to menu links via [Menu Item Extras](https://www.drupal.org/project/menu_item_extras).
## Filters ## Filters
......
...@@ -10,7 +10,12 @@ ...@@ -10,7 +10,12 @@
"homepage": "https://www.drupal.org/project/jsonapi_menu_items", "homepage": "https://www.drupal.org/project/jsonapi_menu_items",
"minimum-stability": "dev", "minimum-stability": "dev",
"require": { "require": {
"drupal/jsonapi_resources": "^1.0",
"drupal/core": "^9.5 || ^10 || ^11"
},
"require-dev": {
"drupal/jsonapi_hypermedia": "^1.6", "drupal/jsonapi_hypermedia": "^1.6",
"drupal/jsonapi_resources": "^1.0" "drupal/menu_link_config": "^1.0",
"drupal/menu_item_extras": "^3.0"
} }
} }
name: 'JSON:API Menu items' name: 'JSON:API Menu items'
description: Adds a JSON API resource for menu items. description: Adds a JSON API resource for menu items.
type: module type: module
core_version_requirement: ^8.8 || ^9 || ^10 core_version_requirement: ^9.5 || ^10 || ^11
dependencies: dependencies:
- drupal:menu_link_content - drupal:menu_link_content
- jsonapi_hypermedia:jsonapi_hypermedia
- jsonapi_resources:jsonapi_resources - jsonapi_resources:jsonapi_resources
<?php
/**
* @file
* Install, update and uninstall functions for the module.
*/
/**
* Install new submodule for hypermedia integration.
*/
function jsonapi_menu_items_update_8001(): void {
if (\Drupal::moduleHandler()->moduleExists('jsonapi_hypermedia')) {
\Drupal::service('module_installer')->install(['jsonapi_menu_items_hypermedia']);
}
}
menu_items: menu_items:
description: "The link's target points to a resource that provides menu items." description: "The link's target points to a resource that provides menu items."
notes: "This link relation type extends the `related` link relation type. It inherits all of the same semantics while adding new semantics of its own." notes: 'This link relation type extends the `related` link relation type. It inherits all of the same semantics while adding new semantics of its own.'
route_callbacks: jsonapi_menu_items.menu:
- '\Drupal\jsonapi_menu_items\Routing\Routes::routes' path: '/%jsonapi%/menu_items/{menu}'
defaults:
_jsonapi_resource: '\Drupal\jsonapi_menu_items\Resource\MenuItemsResource'
options:
parameters:
menu:
type: entity:menu
requirements:
_access: 'TRUE'
name: 'JSON:API Menu items Hypermedia'
description: Integrates jsonapi_menu_items and jsonapi_hypermedia.
type: module
core_version_requirement: ^9.5 || ^10 || ^11
dependencies:
- jsonapi_menu_items:jsonapi_menu_items
- jsonapi_hypermedia:jsonapi_hypermedia
<?php <?php
namespace Drupal\jsonapi_menu_items\Plugin\Derivative; namespace Drupal\jsonapi_menu_items_hypermedia\Plugin\Derivative;
use Drupal\Component\Plugin\Derivative\DeriverBase; use Drupal\Component\Plugin\Derivative\DeriverBase;
use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityStorageInterface;
...@@ -14,10 +14,8 @@ class MenuItemsLinkProviderDeriver extends DeriverBase implements ContainerDeriv ...@@ -14,10 +14,8 @@ class MenuItemsLinkProviderDeriver extends DeriverBase implements ContainerDeriv
/** /**
* The menu storage. * The menu storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/ */
protected $menuStorage; protected EntityStorageInterface $menuStorage;
/** /**
* Constructs new MenuItemsLinkProvider. * Constructs new MenuItemsLinkProvider.
......
<?php <?php
namespace Drupal\jsonapi_menu_items\Plugin\jsonapi_hypermedia\LinkProvider; namespace Drupal\jsonapi_menu_items_hypermedia\Plugin\jsonapi_hypermedia\LinkProvider;
use Drupal\Core\Access\AccessResult; use Drupal\Core\Access\AccessResult;
use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Cache\CacheableMetadata;
...@@ -16,7 +16,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; ...@@ -16,7 +16,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
* *
* @JsonapiHypermediaLinkProvider( * @JsonapiHypermediaLinkProvider(
* id = "jsonapi_menu_items.top_level.menu_items", * id = "jsonapi_menu_items.top_level.menu_items",
* deriver = "Drupal\jsonapi_menu_items\Plugin\Derivative\MenuItemsLinkProviderDeriver", * deriver = "Drupal\jsonapi_menu_items_hypermedia\Plugin\Derivative\MenuItemsLinkProviderDeriver",
* link_relation_type = "menu_items", * link_relation_type = "menu_items",
* ) * )
*/ */
......
<?php <?php
namespace Drupal\Tests\jsonapi_menu_items\Functional; namespace Drupal\Tests\jsonapi_menu_items_hypermedia\Functional;
use Drupal\Component\Serialization\Json; use Drupal\Component\Serialization\Json;
use Drupal\Core\Url; use Drupal\Core\Url;
...@@ -12,7 +12,7 @@ use GuzzleHttp\RequestOptions; ...@@ -12,7 +12,7 @@ use GuzzleHttp\RequestOptions;
/** /**
* Tests JSON:API Hypermedia integration. * Tests JSON:API Hypermedia integration.
* *
* @group jsonapi_menu_items * @group jsonapi_menu_items_hypermedia
* @requires jsonapi_hypermedia * @requires jsonapi_hypermedia
*/ */
final class HypermediaIntegrationTest extends BrowserTestBase { final class HypermediaIntegrationTest extends BrowserTestBase {
...@@ -31,12 +31,13 @@ final class HypermediaIntegrationTest extends BrowserTestBase { ...@@ -31,12 +31,13 @@ final class HypermediaIntegrationTest extends BrowserTestBase {
protected static $modules = [ protected static $modules = [
'jsonapi_hypermedia', 'jsonapi_hypermedia',
'jsonapi_menu_items', 'jsonapi_menu_items',
'jsonapi_menu_items_hypermedia',
]; ];
/** /**
* Tests the `menu_items` links. * Tests the `menu_items` links.
*/ */
public function testMenuItemsLinks() { public function testMenuItemsLinks(): void {
$url = Url::fromRoute('jsonapi.resource_list'); $url = Url::fromRoute('jsonapi.resource_list');
$request_options = []; $request_options = [];
$request_options[RequestOptions::HEADERS]['Accept'] = 'application/vnd.api+json'; $request_options[RequestOptions::HEADERS]['Accept'] = 'application/vnd.api+json';
......
...@@ -4,14 +4,24 @@ namespace Drupal\jsonapi_menu_items\Resource; ...@@ -4,14 +4,24 @@ namespace Drupal\jsonapi_menu_items\Resource;
use Drupal\Core\Access\AccessResultInterface; use Drupal\Core\Access\AccessResultInterface;
use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Cache\CacheableResponseInterface;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\GeneratedUrl; use Drupal\Core\GeneratedUrl;
use Drupal\Core\Menu\MenuLinkTreeInterface;
use Drupal\Core\Menu\MenuTreeParameters;
use Drupal\jsonapi\JsonApiResource\LinkCollection; use Drupal\jsonapi\JsonApiResource\LinkCollection;
use Drupal\jsonapi\JsonApiResource\ResourceObject; use Drupal\jsonapi\JsonApiResource\ResourceObject;
use Drupal\jsonapi\JsonApiResource\ResourceObjectData; use Drupal\jsonapi\JsonApiResource\ResourceObjectData;
use Drupal\jsonapi\ResourceResponse; use Drupal\jsonapi\ResourceResponse;
use Drupal\jsonapi_resources\Resource\ResourceBase; use Drupal\jsonapi_resources\Resource\ResourceBase;
use Drupal\Core\Menu\MenuTreeParameters; use Drupal\menu_link_content\Plugin\Menu\MenuLinkContent;
use Drupal\system\MenuInterface; use Drupal\system\MenuInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route; use Symfony\Component\Routing\Route;
...@@ -20,14 +30,74 @@ use Symfony\Component\Routing\Route; ...@@ -20,14 +30,74 @@ use Symfony\Component\Routing\Route;
* *
* @internal * @internal
*/ */
final class MenuItemsResource extends ResourceBase { final class MenuItemsResource extends ResourceBase implements ContainerInjectionInterface {
/** /**
* A list of menu items. * A list of menu items.
* *
* @var array * @var array
*/ */
protected $menuItems = []; protected array $menuItems = [];
/**
* The menu tree.
*/
private MenuLinkTreeInterface $menuLinkTree;
/**
* The entity type manager service.
*/
private EntityTypeManagerInterface $entityTypeManager;
/**
* The entity field manager service.
*/
private EntityFieldManagerInterface $entityFieldManager;
/**
* The cache backend.
*/
private CacheBackendInterface $cache;
/**
* The entity repository.
*/
private EntityRepositoryInterface $entityRepository;
/**
* Construct a new MenuItemsResource object.
*
* @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_link_tree
* The menu link tree service.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager service.
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
* The entity field manager interface.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache
* The cache backend.
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
* The entity repository.
*/
public function __construct(MenuLinkTreeInterface $menu_link_tree, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, CacheBackendInterface $cache, EntityRepositoryInterface $entity_repository) {
$this->menuLinkTree = $menu_link_tree;
$this->entityTypeManager = $entity_type_manager;
$this->entityFieldManager = $entity_field_manager;
$this->cache = $cache;
$this->entityRepository = $entity_repository;
}
/**
* {@inheritDoc}
*/
public static function create(ContainerInterface $container) {
return new self(
$container->get('menu.link_tree'),
$container->get('entity_type.manager'),
$container->get('entity_field.manager'),
$container->get('cache.discovery'),
$container->get('entity.repository')
);
}
/** /**
* Process the resource request. * Process the resource request.
...@@ -54,12 +124,13 @@ final class MenuItemsResource extends ResourceBase { ...@@ -54,12 +124,13 @@ final class MenuItemsResource extends ResourceBase {
} }
$parameters->onlyEnabledLinks(); $parameters->onlyEnabledLinks();
$menu_tree = \Drupal::menuTree(); $tree = $this->menuLinkTree->load($menu->id(), $parameters);
$tree = $menu_tree->load($menu->id(), $parameters);
if (empty($tree)) { if (empty($tree)) {
$response = $this->createJsonapiResponse(new ResourceObjectData([]), $request, 200, []); $response = $this->createJsonapiResponse(new ResourceObjectData([]), $request, 200, []);
$response->addCacheableDependency($cacheability); if ($response instanceof CacheableResponseInterface) {
$response->addCacheableDependency($cacheability);
}
return $response; return $response;
} }
...@@ -69,13 +140,15 @@ final class MenuItemsResource extends ResourceBase { ...@@ -69,13 +140,15 @@ final class MenuItemsResource extends ResourceBase {
// Use the default sorting of menu links. // Use the default sorting of menu links.
['callable' => 'menu.default_tree_manipulators:generateIndexAndSort'], ['callable' => 'menu.default_tree_manipulators:generateIndexAndSort'],
]; ];
$tree = $menu_tree->transform($tree, $manipulators); $tree = $this->menuLinkTree->transform($tree, $manipulators);
$this->getMenuItems($tree, $this->menuItems, $cacheability); $this->getMenuItems($tree, $this->menuItems, $cacheability, $menu);
$data = new ResourceObjectData($this->menuItems); $data = new ResourceObjectData($this->menuItems);
$response = $this->createJsonapiResponse($data, $request, 200, [] /* , $pagination_links */); $response = $this->createJsonapiResponse($data, $request, 200, [] /* , $pagination_links */);
$response->addCacheableDependency($cacheability); if ($response instanceof CacheableResponseInterface) {
$response->addCacheableDependency($cacheability);
}
return $response; return $response;
} }
...@@ -84,14 +157,48 @@ final class MenuItemsResource extends ResourceBase { ...@@ -84,14 +157,48 @@ final class MenuItemsResource extends ResourceBase {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getRouteResourceTypes(Route $route, string $route_name): array { public function getRouteResourceTypes(Route $route, string $route_name): array {
$resource_types = []; $map_id = "route_resource_types.resource_type.$route_name";
$cached = $this->cache->get($map_id);
if ($cached) {
return $cached->data;
}
$possible_resource_types['menu_link_content'] = ['menu_link_content'];
// If menu_link_config is enabled, gather those menu links as well.
if ($this->entityTypeManager->hasDefinition('menu_link_config')) {
$possible_resource_types['menu_link_config'] = ['menu_link_config'];
}
foreach (['menu_link_config', 'menu_link_content'] as $type) { $menu_link_content_definition = $this->entityTypeManager->getDefinition('menu_link_content');
$resource_type = $this->resourceTypeRepository->get($type, $type); $menu_link_content_bundle_entity_type = $menu_link_content_definition->get('bundle_entity_type');
if ($resource_type) { if ($this->entityTypeManager->hasDefinition($menu_link_content_bundle_entity_type)) {
$resource_types[] = $resource_type; $bundles = $this->entityTypeManager
->getStorage($menu_link_content_bundle_entity_type)
->getQuery()
->accessCheck(FALSE)
->execute();
$possible_resource_types['menu_link_content'] = $bundles;
}
// Now that we've got a list of resource types we care about, go get the
// resource type for each entity type and bundle.
$resource_types = [];
foreach ($possible_resource_types as $entity_type => $bundles) {
foreach ($bundles as $bundle) {
$resource_type = $this->resourceTypeRepository->get($entity_type, $bundle);
if (!is_null($resource_type)) {
$resource_types[] = $resource_type;
}
} }
} }
$this->cache->set($map_id, $resource_types, CacheBackendInterface::CACHE_PERMANENT, [
'jsonapi_resource_types',
'entity_field_info',
'entity_bundles',
'entity_types',
]);
return $resource_types; return $resource_types;
} }
...@@ -106,8 +213,8 @@ final class MenuItemsResource extends ResourceBase { ...@@ -106,8 +213,8 @@ final class MenuItemsResource extends ResourceBase {
* @return \Drupal\Core\Menu\MenuTreeParameters * @return \Drupal\Core\Menu\MenuTreeParameters
* The Menu Tree Parameters object. * The Menu Tree Parameters object.
*/ */
protected function applyFiltersToParams(Request $request, MenuTreeParameters $parameters) { protected function applyFiltersToParams(Request $request, MenuTreeParameters $parameters): MenuTreeParameters {
$filter = $request->query->get('filter'); $filter = $request->query->all('filter');
if (!empty($filter['min_depth'])) { if (!empty($filter['min_depth'])) {
$parameters->setMinDepth((int) $filter['min_depth']); $parameters->setMinDepth((int) $filter['min_depth']);
...@@ -142,39 +249,42 @@ final class MenuItemsResource extends ResourceBase { ...@@ -142,39 +249,42 @@ final class MenuItemsResource extends ResourceBase {
/** /**
* Generate the menu items. * Generate the menu items.
* *
* @param array $tree * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree
* The menu tree. * The menu tree.
* @param array $items * @param array $items
* The already created items. * The already created items.
* @param \Drupal\Core\Cache\CacheableMetadata $cache * @param \Drupal\Core\Cache\CacheableMetadata $cache
* The cacheable metadata. * The cacheable metadata.
* @param \Drupal\system\MenuInterface $menu
* The menu that the links belong to.
*/ */
protected function getMenuItems(array $tree, array &$items, CacheableMetadata $cache) { protected function getMenuItems(array $tree, array &$items, CacheableMetadata &$cache, MenuInterface $menu): void {
$menu_link_content_storage = $this->entityTypeManager->getStorage('menu_link_content');
foreach ($tree as $menu_link) { foreach ($tree as $menu_link) {
if ($menu_link->access !== NULL && !$menu_link->access instanceof AccessResultInterface) { if ($menu_link->access !== NULL && !$menu_link->access instanceof AccessResultInterface) {
throw new \DomainException('MenuLinkTreeElement::access must be either NULL or an AccessResultInterface object.'); throw new \DomainException('MenuLinkTreeElement::access must be either NULL or an AccessResultInterface object.');
} }
if ($menu_link->access instanceof AccessResultInterface) { if ($menu_link->access instanceof AccessResultInterface) {
$cache->merge(CacheableMetadata::createFromObject($menu_link->access)); $cache = $cache->merge(CacheableMetadata::createFromObject($menu_link->access));
} }
// Only return accessible links. // Only return accessible links.
if ($menu_link->access instanceof AccessResultInterface && !$menu_link->access->isAllowed()) { if ($menu_link->access instanceof AccessResultInterface && !$menu_link->access->isAllowed()) {
continue; continue;
} }
$id = $menu_link->link->getPluginId();
[$plugin] = explode(':', $id);
switch ($plugin) {
case 'menu_link_content':
case 'menu_link_config':
$resource_type = $this->resourceTypeRepository->get($plugin, $plugin);
break;
default: $id = $menu_link->link->getPluginId();
// @todo Use a custom resource type? [$plugin] = explode(':', $id, 2);
if ($plugin === 'menu_link_config') {
$resource_type = $this->resourceTypeRepository->get('menu_link_config', 'menu_link_config');
}
else {
$resource_type = $this->resourceTypeRepository->get('menu_link_content', $menu_link->link->getMenuName());
if ($resource_type === NULL) {
$resource_type = $this->resourceTypeRepository->get('menu_link_content', 'menu_link_content'); $resource_type = $this->resourceTypeRepository->get('menu_link_content', 'menu_link_content');
}
} }
$url = $menu_link->link->getUrlObject()->toString(TRUE); $url = $menu_link->link->getUrlObject()->toString(TRUE);
...@@ -198,15 +308,40 @@ final class MenuItemsResource extends ResourceBase { ...@@ -198,15 +308,40 @@ final class MenuItemsResource extends ResourceBase {
'url' => $url->getGeneratedUrl(), 'url' => $url->getGeneratedUrl(),
'weight' => (int) $menu_link->link->getWeight(), 'weight' => (int) $menu_link->link->getWeight(),
]; ];
$language = NULL;
if ($menu_link->link instanceof MenuLinkContent) {
// @todo once minimum supported Drupal core version is 10.2, use
// \Drupal\menu_link_content\Plugin\Menu\MenuLinkContent::getEntity.
// $link = $menu_link->link->getEntity();
$entity_id = $menu_link->link->getMetaData()['entity_id'] ?? NULL;
if ($entity_id !== NULL) {
$link = $menu_link_content_storage->load($entity_id);
if ($link !== NULL) {
$link = $this->entityRepository->getTranslationFromContext($link);
$language = $link->language();
$langcode_key = $link->getEntityType()->getKey('langcode');
$field_definitions = $this->entityFieldManager->getFieldDefinitions($link->getEntityTypeId(), $link->bundle());
foreach ($field_definitions as $field_name => $field_definition) {
if ($field_definition instanceof BaseFieldDefinition && $field_name !== $langcode_key && $field_definition->getProvider() === 'menu_link_content') {
continue;
}
$fields[$field_name] = $link->{$field_name};
}
}
}
}
$links = new LinkCollection([]); $links = new LinkCollection([]);
$resource_object_cacheability = new CacheableMetadata(); $resource_object_cacheability = new CacheableMetadata();
$resource_object_cacheability->addCacheableDependency($menu_link->access); $resource_object_cacheability->addCacheableDependency($menu_link->access);
$resource_object_cacheability->addCacheableDependency($cache); $resource_object_cacheability->addCacheableDependency($cache);
$items[$id] = new ResourceObject($resource_object_cacheability, $resource_type, $id, NULL, $fields, $links); $items[$id] = new ResourceObject($resource_object_cacheability, $resource_type, $id, NULL, $fields, $links, $language);
if ($menu_link->subtree) { if ($menu_link->subtree) {
$this->getMenuItems($menu_link->subtree, $items, $cache); $this->getMenuItems($menu_link->subtree, $items, $cache, $menu);
} }
} }
} }
......
<?php
namespace Drupal\jsonapi_menu_items\Routing;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\jsonapi_menu_items\Resource\MenuItemsResource;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
/**
* Defines dynamic routes.
*
* Each Menu will result in a jsonapi resource at:
* /{jsonapi_namespace}/menu_items/{menu_id}
*/
class Routes implements ContainerInjectionInterface {
const RESOURCE_NAME = MenuItemsResource::class;
const JSONAPI_RESOURCE_KEY = '_jsonapi_resource';
/**
* {@inheritdoc}
*/
public function __construct() {}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static();
}
/**
* {@inheritdoc}
*/
public function routes() {
$routes = new RouteCollection();
$route = new Route('/%jsonapi%/menu_items/{menu}');
$route->addDefaults([
static::JSONAPI_RESOURCE_KEY => static::RESOURCE_NAME,
]);
$route->setOption('parameters', [
'menu' => [
'type' => 'entity:menu',
],
]);
$routes->add('jsonapi_menu_items.menu', $route);
$routes->addRequirements(['_access' => 'TRUE']);
return $routes;
}
}
...@@ -41,7 +41,8 @@ ...@@ -41,7 +41,8 @@
}, },
"title": "%title", "title": "%title",
"url": "%base_pathmenu_callback_title", "url": "%base_pathmenu_callback_title",
"weight": 0 "weight": 0,
"langcode": "%langcode"
} }
}, },
{ {
......
...@@ -41,7 +41,8 @@ ...@@ -41,7 +41,8 @@
}, },
"title": "%title", "title": "%title",
"url": "%base_pathmenu_callback_title", "url": "%base_pathmenu_callback_title",
"weight": 0 "weight": 0,
"langcode": "%langcode"
} }
}, },
{ {
......
...@@ -41,7 +41,8 @@ ...@@ -41,7 +41,8 @@
}, },
"title": "%title", "title": "%title",
"url": "%base_pathmenu_callback_title", "url": "%base_pathmenu_callback_title",
"weight": 0 "weight": 0,
"langcode": "%langcode"
} }
} }
] ]
......
...@@ -20,7 +20,8 @@ ...@@ -20,7 +20,8 @@
}, },
"title": "%title", "title": "%title",
"url": "%base_pathmenu_callback_title", "url": "%base_pathmenu_callback_title",
"weight": 0 "weight": 0,
"langcode": "%langcode"
} }
}, },
{ {
......
id: jsonapi-menu-items-test2
label: JSON:API menu items test menu 2
description: 'Test menu 2'
langcode: en
locked: true
# eslint-disable yml/no-empty-document
name: JSON:API Menu items test name: JSON:API Menu items test
description: 'Test functionality for JSON:API Menu items' description: 'Test functionality for JSON:API Menu items'
core_version_requirement: ^8.8 || ^9.0 || ^10
type: module type: module
package: Testing
dependencies: dependencies:
- drupal:menu_link_content - drupal:menu_link_content
- jsonapi_menu_items:jsonapi_menu_items - jsonapi_menu_items:jsonapi_menu_items