Skip to content

Commit 46279d4

Browse files
committed
Adding entity query example.
1 parent 96391df commit 46279d4

4 files changed

Lines changed: 191 additions & 0 deletions

File tree

examples/graphql/example.graphqls

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,19 @@ schema {
44

55
type Query {
66
article(id: Int!): Article
7+
articles(
8+
offset: Int = 0
9+
limit: Int = 10
10+
): ArticleConnection!
711
}
812

913
type Article {
1014
id: Int!
1115
title: String!
1216
author: String
1317
}
18+
19+
type ArticleConnection {
20+
total: Int!
21+
items: [Article!]
22+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<?php
2+
3+
namespace Drupal\graphql_examples\Plugin\GraphQL\DataProducer;
4+
5+
use Drupal\Core\Cache\RefinableCacheableDependencyInterface;
6+
use Drupal\Core\Entity\EntityTypeManagerInterface;
7+
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
8+
use Drupal\graphql\Plugin\GraphQL\DataProducer\DataProducerPluginBase;
9+
use Drupal\graphql_examples\Wrappers\QueryConnection;
10+
use GraphQL\Error\UserError;
11+
use Symfony\Component\DependencyInjection\ContainerInterface;
12+
13+
/**
14+
* @DataProducer(
15+
* id = "query_articles",
16+
* name = @Translation("Load articles"),
17+
* description = @Translation("Loads a list of articles."),
18+
* produces = @ContextDefinition("any",
19+
* label = @Translation("Article connection")
20+
* ),
21+
* consumes = {
22+
* "offset" = @ContextDefinition("integer",
23+
* label = @Translation("Offset"),
24+
* required = FALSE
25+
* ),
26+
* "limit" = @ContextDefinition("integer",
27+
* label = @Translation("Limit"),
28+
* required = FALSE
29+
* )
30+
* }
31+
* )
32+
*/
33+
class QueryArticles extends DataProducerPluginBase implements ContainerFactoryPluginInterface {
34+
35+
const MAX_LIMIT = 100;
36+
37+
/**
38+
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
39+
*/
40+
protected $entityManager;
41+
42+
/**
43+
* {@inheritdoc}
44+
*
45+
* @codeCoverageIgnore
46+
*/
47+
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
48+
return new static(
49+
$configuration,
50+
$plugin_id,
51+
$plugin_definition,
52+
$container->get('entity.manager')
53+
);
54+
}
55+
56+
/**
57+
* Articles constructor.
58+
*
59+
* @param array $configuration
60+
* The plugin configuration.
61+
* @param string $pluginId
62+
* The plugin id.
63+
* @param mixed $pluginDefinition
64+
* The plugin definition.
65+
*
66+
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityManager
67+
*
68+
* @codeCoverageIgnore
69+
*/
70+
public function __construct(
71+
array $configuration,
72+
$pluginId,
73+
$pluginDefinition,
74+
EntityTypeManagerInterface $entityManager
75+
) {
76+
parent::__construct($configuration, $pluginId, $pluginDefinition);
77+
$this->entityManager = $entityManager;
78+
}
79+
80+
/**
81+
* @param $offset
82+
* @param $limit
83+
* @param \Drupal\Core\Cache\RefinableCacheableDependencyInterface $metadata
84+
*
85+
* @return \Drupal\graphql_examples\Wrappers\QueryConnection
86+
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
87+
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
88+
*/
89+
public function resolve($offset, $limit, RefinableCacheableDependencyInterface $metadata) {
90+
if (!$limit > static::MAX_LIMIT) {
91+
throw new UserError(sprintf('Exceeded maximum query limit: %s.', static::MAX_LIMIT));
92+
}
93+
94+
$storage = $this->entityManager->getStorage('node');
95+
$type = $storage->getEntityType();
96+
$query = $storage->getQuery()
97+
->currentRevision()
98+
->accessCheck();
99+
100+
$query->condition($type->getKey('bundle'), 'article');
101+
$query->range($offset, $limit);
102+
103+
$metadata->addCacheTags($type->getListCacheTags());
104+
$metadata->addCacheContexts($type->getListCacheContexts());
105+
106+
return new QueryConnection($query);
107+
}
108+
}

examples/src/Plugin/GraphQL/Schema/ExampleSchema.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Drupal\graphql\GraphQL\ResolverBuilder;
66
use Drupal\graphql\GraphQL\ResolverRegistry;
77
use Drupal\graphql\Plugin\GraphQL\Schema\SdlSchemaPluginBase;
8+
use Drupal\graphql_examples\Wrappers\QueryConnection;
89

910
/**
1011
* @Schema(
@@ -23,6 +24,7 @@ public function getResolverRegistry() {
2324

2425
$this->addQueryFields($registry, $builder);
2526
$this->addArticleFields($registry, $builder);
27+
$this->addArticleConnectionFields($registry, $builder);
2628

2729
return $registry;
2830
}
@@ -67,5 +69,29 @@ protected function addQueryFields(ResolverRegistry $registry, ResolverBuilder $b
6769
->map('bundles', $builder->fromValue(['article']))
6870
->map('id', $builder->fromArgument('id'))
6971
);
72+
73+
$registry->addFieldResolver('Query', 'articles',
74+
$builder->produce('query_articles')
75+
->map('offset', $builder->fromArgument('offset'))
76+
->map('limit', $builder->fromArgument('limit'))
77+
);
78+
}
79+
80+
/**
81+
* @param \Drupal\graphql\GraphQL\ResolverRegistry $registry
82+
* @param \Drupal\graphql\GraphQL\ResolverBuilder $builder
83+
*/
84+
protected function addArticleConnectionFields(ResolverRegistry $registry, ResolverBuilder $builder) {
85+
$registry->addFieldResolver('ArticleConnection', 'total',
86+
$builder->callback(function (QueryConnection $connection) {
87+
return $connection->total();
88+
})
89+
);
90+
91+
$registry->addFieldResolver('ArticleConnection', 'items',
92+
$builder->callback(function (QueryConnection $connection) {
93+
return $connection->items();
94+
})
95+
);
7096
}
7197
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
namespace Drupal\graphql_examples\Wrappers;
4+
5+
use Drupal\Core\Entity\Query\QueryInterface;
6+
use GraphQL\Deferred;
7+
8+
class QueryConnection {
9+
10+
/**
11+
* @var \Drupal\Core\Entity\Query\Sql\Query
12+
*/
13+
protected $query;
14+
15+
/**
16+
* QueryConnection constructor.
17+
*
18+
* @param \Drupal\Core\Entity\Query\QueryInterface $query
19+
*/
20+
public function __construct(QueryInterface $query) {
21+
$this->query = $query;
22+
}
23+
24+
/**
25+
* @return int
26+
*/
27+
public function total() {
28+
$query = clone $this->query;
29+
$query->range(NULL, NULL)->count();
30+
return $query->execute();
31+
}
32+
33+
/**
34+
* @return array|\GraphQL\Deferred
35+
*/
36+
public function items() {
37+
$result = $this->query->execute();
38+
if (empty($result)) {
39+
return [];
40+
}
41+
42+
$buffer = \Drupal::service('graphql.buffer.entity');
43+
$callback = $buffer->add($this->query->getEntityTypeId(), array_values($result));
44+
return new Deferred(function () use ($callback) {
45+
return $callback();
46+
});
47+
}
48+
}

0 commit comments

Comments
 (0)