Completed
Push — 8.x-1.x ( c0c90f...8080a4 )
by Philipp
01:41
created

GraphQLTemplateTrait::setDebug()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Drupal\graphql_twig;
4
5
use Drupal\Core\Entity\EntityInterface;
6
use Drupal\Core\Template\TwigEnvironment;
7
use Drupal\graphql\GraphQL\Execution\QueryProcessor;
8
use GraphQL\Server\OperationParams;
9
10
/**
11
 * Trait that will be attached to all GraphQL enabled Twig templates.
12
 */
13
trait GraphQLTemplateTrait {
14
15
  /**
16
   * @return bool
17
   */
18
  abstract public static function hasGraphQLOperations();
19
20
  /**
21
   * @var string
22
   */
23
  abstract public static function rawGraphQLQuery();
24
25
  /**
26
   * @return string
27
   */
28
  abstract public static function rawGraphQLParent();
29
30
  /**
31
   * @return string[]
32
   */
33
  abstract public static function rawGraphQLIncludes();
34
35
  /**
36
   * @return string[]
37
   */
38
  abstract public static function rawGraphQLArguments();
39
40
  /**
41
   * The GraphQL query processor.
42
   *
43
   * @var \Drupal\graphql\GraphQL\Execution\QueryProcessor
44
   */
45
  protected $queryProcessor;
46
47
  /**
48
   * Inject the query processor.
49
   *
50
   * @param \Drupal\graphql\GraphQL\Execution\QueryProcessor $queryProcessor
51
   *   The query processor instance.
52
   */
53
  public function setQueryProcessor(QueryProcessor $queryProcessor) {
54
    $this->queryProcessor = $queryProcessor;
55
  }
56
57
  /**
58
   * {@inheritdoc}
59
   */
60
  public function display(array $context, array $blocks = array()) {
61
    if (!static::hasGraphQLOperations()) {
62
      parent::display($context, $blocks);
63
      return;
64
    }
65
66
    if (isset($context['graphql_arguments'])) {
67
      $context = $context['graphql_arguments'];
68
    }
69
70
    $query = trim($this->getGraphQLQuery());
71
72
    if (!$query) {
73
      parent::display($context, $blocks);
74
      return;
75
    }
76
77
    $arguments = [];
78
    foreach (static::rawGraphQLArguments() as $var) {
79
      if (isset($context[$var])) {
80
        $arguments[$var] = $context[$var] instanceof EntityInterface ? $context[$var]->id() : $context[$var];
0 ignored issues
show
Bug introduced by
The class Drupal\Core\Entity\EntityInterface does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
81
      }
82
    }
83
84
85
    $queryResult = $this->env->getQueryProcessor()->processQuery('default:default', OperationParams::create([
0 ignored issues
show
Bug introduced by
The property env does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
86
      'query' => $query,
87
      'variables' => $arguments,
88
    ]));
89
90
    $build = [
91
      '#cache' => [
92
        'contexts' => $queryResult->getCacheContexts(),
93
        'tags' => $queryResult->getCacheTags(),
94
        'max-age' => $queryResult->getCacheMaxAge(),
95
      ],
96
    ];
97
98
    $this->env->getRenderer()->render($build);
99
100
    if ($this->env->isDebug()) {
101
      printf(
102
        '<div class="%s" data-graphql-query="%s" data-graphql-variables="%s">',
103
        'graphql-twig-debug-wrapper',
104
        htmlspecialchars($query),
105
        htmlspecialchars(json_encode($arguments))
106
      );
107
    }
108
109
    if ($queryResult->errors) {
110
      print('<ul class="graphql-twig-errors">');
111
      foreach ($queryResult->errors as $error) {
112
        printf('<li>%s</li>', $error->message);
113
      }
114
      print('</ul>');
115
    }
116
    else {
117
      $context['graphql'] = $queryResult->data;
118
      parent::display($context, $blocks);
119
    }
120
121
    if ($this->env->isDebug()) {
122
      print('</div>');
123
    }
124
  }
125
126
  /**
127
   * Recursively build the GraphQL query.
128
   *
129
   * Builds the templates GraphQL query by iterating through all included or
130
   * embedded templates recursively.
131
   */
132
  public function getGraphQLQuery() {
133
134
    $query = '';
135
    $includes = [];
136
137
    if ($this instanceof \Twig_Template) {
0 ignored issues
show
Bug introduced by
The class Twig_Template does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
138
      $query = $this->getGraphQLFragment();
139
140
      $includes = array_keys($this->getGraphQLIncludes());
141
142
      // Recursively collect all included fragments.
143
      $includes = array_map(function ($template) {
144
        return $this->env->loadTemplate($template)->getGraphQLFragment();
145
      }, $includes);
146
147
      // Always add includes from parent templates.
148
      if ($parent = $this->getGraphQLParent()) {
149
        $includes += array_map(function ($template) {
150
          return $this->env->loadTemplate($template)->getGraphQLQuery();
151
        }, array_keys($parent->getGraphQLIncludes()));
152
      }
153
    }
154
155
156
    return implode("\n", [-1 => $query] + $includes);
157
  }
158
159
  /**
160
   * Get the files parent template.
161
   *
162
   * @return \Twig_Template|null
163
   *   The parent template or null.
164
   */
165
  protected function getGraphQLParent() {
166
    return static::rawGraphQLParent() ? $this->env->loadTemplate(static::rawGraphQLParent()) : NULL;
167
  }
168
169
  /**
170
   * Retrieve the files graphql fragment.
171
   *
172
   * @return string
173
   *   The GraphQL fragment.
174
   */
175
  public function getGraphQLFragment() {
176
    // If there is no query for this template, try to get one from the
177
    // parent template.
178
    if (!($query = static::rawGraphQLQuery()) && ($parent = $this->getGraphQLParent())) {
179
      $query = $parent->getGraphQLFragment();
180
    }
181
    return $query;
182
  }
183
184
  /**
185
   * Retrieve a list of all direct or indirect included templates.
186
   *
187
   * @param string[] $recursed
188
   *   The list of templates already recursed into. Used internally.
189
   *
190
   * @return string[]
191
   *   The list of included templates.
192
   */
193
  public function getGraphQLIncludes(&$recursed = []) {
194
195
    $includes = array_flip(static::rawGraphQLIncludes());
196
    foreach ($includes as $include => $key) {
197
      if (in_array($include, $recursed)) {
198
        continue;
199
      }
200
201
      $recursed[] = $include;
202
203
      // TODO: operate on template class instead.
204
      $includes += $this->env->loadTemplate($include)->getGraphQLIncludes($recursed);
205
    }
206
207
    return $includes;
208
  }
209
}
210