Skip to content

Commit f8ea6e8

Browse files
authored
No redundant types for entities that do not support bundles. (#512)
1 parent 93f3eb7 commit f8ea6e8

13 files changed

Lines changed: 186 additions & 89 deletions

File tree

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
namespace Drupal\graphql_core\Plugin\Deriver;
4+
5+
use Drupal\Component\Plugin\Derivative\DeriverBase;
6+
use Drupal\Core\Entity\EntityTypeInterface;
7+
use Drupal\Core\Entity\EntityTypeManagerInterface;
8+
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
9+
use Symfony\Component\DependencyInjection\ContainerInterface;
10+
11+
abstract class EntityTypeDeriverBase extends DeriverBase implements ContainerDeriverInterface {
12+
13+
/**
14+
* The entity type manager.
15+
*
16+
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
17+
*/
18+
protected $entityTypeManager;
19+
20+
/**
21+
* {@inheritdoc}
22+
*/
23+
public static function create(ContainerInterface $container, $basePluginId) {
24+
return new static(
25+
$container->get('entity_type.manager')
26+
);
27+
}
28+
29+
/**
30+
* EntityTypeDeriver constructor.
31+
*
32+
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
33+
* Instance of an entity type manager.
34+
*/
35+
public function __construct(EntityTypeManagerInterface $entityTypeManager) {
36+
$this->entityTypeManager = $entityTypeManager;
37+
}
38+
39+
/**
40+
* Retrieve the interfaces that the entity type should implement.
41+
*
42+
* @param \Drupal\Core\Entity\EntityTypeInterface $type
43+
* The entity type to retrieve the interfaces for.
44+
* @param array $basePluginDefinition
45+
* The base plugin definition array.
46+
*
47+
* @return array
48+
* The interfaces that this entity type should implement.
49+
*/
50+
protected function getInterfaces(EntityTypeInterface $type, array $basePluginDefinition) {
51+
$pairs = [
52+
'\Drupal\Core\Entity\EntityDescriptionInterface' => 'EntityDescribable',
53+
'\Drupal\Core\Entity\EntityPublishedInterface' => 'EntityPublishable',
54+
'\Drupal\Core\Entity\RevisionableInterface' => 'EntityRevisionable',
55+
'\Drupal\user\EntityOwnerInterface' => 'EntityOwnable',
56+
];
57+
58+
$interfaces = isset($basePluginDefinition['interfaces']) ? $basePluginDefinition['interfaces'] : [];
59+
foreach ($pairs as $dependency => $interface) {
60+
if ($type->entityClassImplements($dependency)) {
61+
$interfaces[] = $interface;
62+
}
63+
}
64+
65+
return array_unique($interfaces);
66+
}
67+
68+
}

modules/graphql_core/src/Plugin/Deriver/Interfaces/EntityTypeDeriver.php

Lines changed: 9 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -2,97 +2,40 @@
22

33
namespace Drupal\graphql_core\Plugin\Deriver\Interfaces;
44

5-
use Drupal\Component\Plugin\Derivative\DeriverBase;
65
use Drupal\Core\Entity\ContentEntityTypeInterface;
7-
use Drupal\Core\Entity\EntityTypeInterface;
8-
use Drupal\Core\Entity\EntityTypeManagerInterface;
9-
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
106
use Drupal\Core\StringTranslation\StringTranslationTrait;
117
use Drupal\graphql\Utility\StringHelper;
12-
use Symfony\Component\DependencyInjection\ContainerInterface;
8+
use Drupal\graphql_core\Plugin\Deriver\EntityTypeDeriverBase;
139

14-
/**
15-
* Derive GraphQL Interfaces from Drupal entity types.
16-
*/
17-
class EntityTypeDeriver extends DeriverBase implements ContainerDeriverInterface {
10+
class EntityTypeDeriver extends EntityTypeDeriverBase {
1811
use StringTranslationTrait;
1912

20-
/**
21-
* The entity type manager.
22-
*
23-
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
24-
*/
25-
protected $entityTypeManager;
26-
27-
/**
28-
* {@inheritdoc}
29-
*/
30-
public static function create(ContainerInterface $container, $basePluginId) {
31-
return new static(
32-
$container->get('entity_type.manager')
33-
);
34-
}
35-
36-
/**
37-
* EntityTypeDeriver constructor.
38-
*
39-
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
40-
* Instance of an entity type manager.
41-
*/
42-
public function __construct(EntityTypeManagerInterface $entityTypeManager) {
43-
$this->entityTypeManager = $entityTypeManager;
44-
}
45-
4613
/**
4714
* {@inheritdoc}
4815
*/
4916
public function getDerivativeDefinitions($basePluginDefinition) {
5017
foreach ($this->entityTypeManager->getDefinitions() as $typeId => $type) {
51-
if (!$type instanceof ContentEntityTypeInterface) {
18+
if (!($type instanceof ContentEntityTypeInterface)) {
5219
continue;
5320
}
5421

55-
$interfaces = isset($basePluginDefinition['interfaces']) ? $basePluginDefinition['interfaces'] : [];
56-
$interfaces = array_unique(array_merge($interfaces, $this->getInterfaces($type)));
22+
// Only create a base interface for types that support bundles.
23+
if (!$type->hasKey('bundle')) {
24+
continue;
25+
}
5726

5827
$this->derivatives[$typeId] = [
5928
'name' => StringHelper::camelCase($typeId),
6029
'description' => $this->t("The '@type' entity type.", [
6130
'@type' => $type->getLabel(),
6231
]),
6332
'type' => "entity:$typeId",
64-
'interfaces' => $interfaces,
33+
'interfaces' => $this->getInterfaces($type, $basePluginDefinition),
34+
'entity_type' => $typeId,
6535
] + $basePluginDefinition;
6636
}
6737

6838
return parent::getDerivativeDefinitions($basePluginDefinition);
6939
}
7040

71-
/**
72-
* Retrieve the interfaces that the entity type should implement.
73-
*
74-
* @param \Drupal\Core\Entity\EntityTypeInterface $type
75-
* The entity type to retrieve the interfaces for.
76-
*
77-
* @return array
78-
* The interfaces that this entity type should implement.
79-
*/
80-
protected function getInterfaces(EntityTypeInterface $type) {
81-
$pairs = [
82-
'\Drupal\Core\Entity\EntityDescriptionInterface' => 'EntityDescribable',
83-
'\Drupal\Core\Entity\EntityPublishedInterface' => 'EntityPublishable',
84-
'\Drupal\Core\Entity\RevisionableInterface' => 'EntityRevisionable',
85-
'\Drupal\user\EntityOwnerInterface' => 'EntityOwnable',
86-
];
87-
88-
$interfaces = [];
89-
foreach ($pairs as $dependency => $interface) {
90-
if ($type->entityClassImplements($dependency)) {
91-
$interfaces[] = $interface;
92-
}
93-
}
94-
95-
return $interfaces;
96-
}
97-
9841
}

modules/graphql_core/src/Plugin/Deriver/Types/EntityBundleDeriver.php

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -63,20 +63,27 @@ public function __construct(
6363
public function getDerivativeDefinitions($basePluginDefinition) {
6464
$bundles = $this->entityTypeBundleInfo->getAllBundleInfo();
6565
foreach ($this->entityTypeManager->getDefinitions() as $typeId => $type) {
66-
if ($type instanceof ContentEntityTypeInterface && array_key_exists($typeId, $bundles)) {
67-
foreach ($bundles[$typeId] as $bundle => $bundleDefinition) {
68-
$this->derivatives[$typeId . '-' . $bundle] = [
69-
'name' => StringHelper::camelCase($typeId, $bundle),
70-
'description' => $this->t("The '@bundle' bundle of the '@type' entity type.", [
71-
'@bundle' => $bundleDefinition['label'],
72-
'@type' => $type->getLabel(),
73-
]),
74-
'interfaces' => [StringHelper::camelCase($typeId)],
75-
'type' => "entity:$typeId:$bundle",
76-
'entity_type' => $typeId,
77-
'entity_bundle' => $bundle,
78-
] + $basePluginDefinition;
79-
}
66+
if (!($type instanceof ContentEntityTypeInterface)) {
67+
continue;
68+
}
69+
70+
// Only create a bundle type for entity types that support bundles.
71+
if (!$type->hasKey('bundle')) {
72+
continue;
73+
}
74+
75+
foreach ($bundles[$typeId] as $bundle => $bundleDefinition) {
76+
$this->derivatives[$typeId . '-' . $bundle] = [
77+
'name' => StringHelper::camelCase($typeId, $bundle),
78+
'description' => $this->t("The '@bundle' bundle of the '@type' entity type.", [
79+
'@bundle' => $bundleDefinition['label'],
80+
'@type' => $type->getLabel(),
81+
]),
82+
'interfaces' => [StringHelper::camelCase($typeId)],
83+
'type' => "entity:$typeId:$bundle",
84+
'entity_type' => $typeId,
85+
'entity_bundle' => $bundle,
86+
] + $basePluginDefinition;
8087
}
8188
}
8289

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace Drupal\graphql_core\Plugin\Deriver\Types;
4+
5+
use Drupal\Core\Entity\ContentEntityTypeInterface;
6+
use Drupal\Core\StringTranslation\StringTranslationTrait;
7+
use Drupal\graphql\Utility\StringHelper;
8+
use Drupal\graphql_core\Plugin\Deriver\EntityTypeDeriverBase;
9+
10+
class EntityTypeDeriver extends EntityTypeDeriverBase {
11+
use StringTranslationTrait;
12+
13+
/**
14+
* {@inheritdoc}
15+
*/
16+
public function getDerivativeDefinitions($basePluginDefinition) {
17+
foreach ($this->entityTypeManager->getDefinitions() as $typeId => $type) {
18+
if (!($type instanceof ContentEntityTypeInterface)) {
19+
continue;
20+
}
21+
22+
// Create the entity type only for types that do not support bundles. For
23+
// all others, we create common interfaces instead.
24+
if ($type->hasKey('bundle')) {
25+
continue;
26+
}
27+
28+
$this->derivatives[$typeId] = [
29+
'name' => StringHelper::camelCase($typeId),
30+
'description' => $this->t("The '@type' entity type.", [
31+
'@type' => $type->getLabel(),
32+
]),
33+
'type' => "entity:$typeId",
34+
'interfaces' => $this->getInterfaces($type, $basePluginDefinition),
35+
'entity_type' => $typeId,
36+
] + $basePluginDefinition;
37+
}
38+
39+
return parent::getDerivativeDefinitions($basePluginDefinition);
40+
}
41+
42+
}

modules/graphql_core/src/Plugin/GraphQL/Interfaces/Entity/EntityType.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
namespace Drupal\graphql_core\Plugin\GraphQL\Interfaces\Entity;
44

55
/**
6-
* Plugin for GraphQL interfaces derived from Drupal entity types.
7-
*
86
* @GraphQLInterface(
97
* id = "entity_type",
108
* schema_cache_tags = {"entity_types"},

modules/graphql_core/src/Plugin/GraphQL/Types/Entity/EntityBundle.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
use Youshido\GraphQL\Execution\ResolveInfo;
88

99
/**
10-
* Plugin for GraphQL types derived from Drupal entity bundles.
11-
*
1210
* @GraphQLType(
1311
* id = "entity_bundle",
1412
* schema_cache_tags = {"entity_types", "entity_bundles"},
@@ -21,9 +19,14 @@ class EntityBundle extends TypePluginBase {
2119
* {@inheritdoc}
2220
*/
2321
public function applies($object, ResolveInfo $info = NULL) {
24-
return $object instanceof EntityInterface
25-
&& $object->getEntityTypeId() == $this->getPluginDefinition()['entity_type']
26-
&& $object->bundle() == $this->getPluginDefinition()['entity_bundle'];
22+
if ($object instanceof EntityInterface) {
23+
$definition = $this->getPluginDefinition();
24+
if ($object->getEntityTypeId() === $definition['entity_type']) {
25+
return $object->bundle() === $definition['entity_bundle'];
26+
}
27+
}
28+
29+
return FALSE;
2730
}
2831

2932
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace Drupal\graphql_core\Plugin\GraphQL\Types\Entity;
4+
5+
use Drupal\Core\Entity\EntityInterface;
6+
use Drupal\graphql\Plugin\GraphQL\Types\TypePluginBase;
7+
use Youshido\GraphQL\Execution\ResolveInfo;
8+
9+
/**
10+
* @GraphQLType(
11+
* id = "entity_type",
12+
* schema_cache_tags = {"entity_types"},
13+
* deriver = "Drupal\graphql_core\Plugin\Deriver\Types\EntityTypeDeriver"
14+
* )
15+
*/
16+
class EntityType extends TypePluginBase {
17+
18+
/**
19+
* {@inheritdoc}
20+
*/
21+
public function applies($object, ResolveInfo $info = NULL) {
22+
if ($object instanceof EntityInterface) {
23+
$definition = $this->getPluginDefinition();
24+
return $object->getEntityTypeId() === $definition['entity_type'];
25+
}
26+
27+
return FALSE;
28+
}
29+
30+
}

modules/graphql_core/tests/src/Kernel/Breadcrumbs/BreadcrumbsTest.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ protected function setUp() {
2929
parent::setUp();
3030

3131
$breadcrumbManager = $this->prophesize('Drupal\Core\Breadcrumb\BreadcrumbManager');
32-
3332
$breadcrumbManager->build(Argument::any())
3433
->will(function ($args) {
3534
/** @var \Drupal\Core\Routing\RouteMatch $routeMatch */
@@ -38,8 +37,10 @@ protected function setUp() {
3837
if ($routeMatch->getRouteName() == 'graphql_breadcrumbs_test.test') {
3938
$breadcrumb->addLink(new Link('Test breadcrumb', Url::fromUserInput('/breadcrumbs-test')));
4039
}
40+
4141
return $breadcrumb;
4242
});
43+
4344
$this->container->set('breadcrumb', $breadcrumbManager->reveal());
4445
}
4546

@@ -51,6 +52,7 @@ public function testBreadcrumbs() {
5152

5253
// TODO: Check cache metadata.
5354
$metadata = $this->defaultCacheMetaData();
55+
$metadata->setCacheTags(array_diff($metadata->getCacheTags(), ['entity_bundles']));
5456

5557
$this->assertResults($query, ['path' => '/breadcrumbs-test'], [
5658
'route' => [

modules/graphql_core/tests/src/Kernel/Context/ContextTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public function testSimpleContext() {
2323

2424
// TODO: Check cache metadata.
2525
$metadata = $this->defaultCacheMetaData();
26+
$metadata->setCacheTags(array_diff($metadata->getCacheTags(), ['entity_bundles']));
2627

2728
$this->assertResults($query, [], [
2829
'a' => ['name' => 'graphql_context_test.a'],

modules/graphql_core/tests/src/Kernel/Languages/LanguageTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ protected function setUp() {
5858
public function testLanguageId() {
5959
// TODO: Check cache metadata.
6060
$metadata = $this->defaultCacheMetaData();
61+
$metadata->setCacheTags(array_diff($metadata->getCacheTags(), ['entity_bundles']));
6162

6263
$this->assertResults($this->getQueryFromFile('languages.gql'), [], [
6364
'languages' => [

0 commit comments

Comments
 (0)