1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Drupal\graphql_twig; |
4
|
|
|
|
5
|
|
|
use Drupal\Core\Cache\CacheBackendInterface; |
6
|
|
|
use Drupal\Core\Render\RendererInterface; |
7
|
|
|
use Drupal\Core\State\StateInterface; |
8
|
|
|
use Drupal\Core\Template\TwigEnvironment; |
9
|
|
|
use Drupal\graphql\GraphQL\Execution\QueryProcessor; |
10
|
|
|
|
11
|
|
|
/** |
12
|
|
|
* Enhanced Twig environment for GraphQL. |
13
|
|
|
* |
14
|
|
|
* Checks for GraphQL annotations in twig templates or matching `*.gql` and |
15
|
|
|
* adds them as `{% graphql %}` tags before passing them to the compiler. |
16
|
|
|
* |
17
|
|
|
* This is a convenience feature and also ensures that GraphQL-powered templates |
18
|
|
|
* don't break compatibility with Twig processors that don't have this extension |
19
|
|
|
* (e.g. patternlab). |
20
|
|
|
*/ |
21
|
|
|
class GraphQLTwigEnvironment extends TwigEnvironment { |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* A GraphQL query processor. |
25
|
|
|
* |
26
|
|
|
* @var \Drupal\graphql\GraphQL\Execution\QueryProcessor |
27
|
|
|
*/ |
28
|
|
|
protected $queryProcessor; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* Retrieve the query processor. |
32
|
|
|
* |
33
|
|
|
* @return \Drupal\graphql\GraphQL\Execution\QueryProcessor |
34
|
|
|
* The GraphQL query processor. |
35
|
|
|
*/ |
36
|
|
|
public function getQueryProcessor() { |
37
|
|
|
return $this->queryProcessor; |
38
|
|
|
} |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* The renderer instance. |
42
|
|
|
* |
43
|
|
|
* @var \Drupal\Core\Render\RendererInterface |
44
|
|
|
*/ |
45
|
|
|
protected $renderer; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* Retrieve the renderer instance. |
49
|
|
|
* |
50
|
|
|
* @return \Drupal\Core\Render\RendererInterface |
51
|
|
|
* The renderer instance. |
52
|
|
|
*/ |
53
|
|
|
public function getRenderer() { |
54
|
|
|
return $this->renderer; |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* {@inheritdoc} |
59
|
|
|
*/ |
60
|
|
|
public function __construct( |
61
|
|
|
string $root, |
62
|
|
|
CacheBackendInterface $cache, |
63
|
|
|
string $twig_extension_hash, |
64
|
|
|
StateInterface $state, |
65
|
|
|
\Twig_LoaderInterface $loader = NULL, |
66
|
|
|
array $options = [], |
67
|
|
|
QueryProcessor $queryProcessor = NULL, |
68
|
|
|
RendererInterface $renderer = NULL |
69
|
|
|
) { |
70
|
|
|
$this->queryProcessor = $queryProcessor; |
71
|
|
|
$this->renderer = $renderer; |
72
|
|
|
parent::__construct( |
73
|
|
|
$root, |
74
|
|
|
$cache, |
75
|
|
|
$twig_extension_hash, |
76
|
|
|
$state, |
77
|
|
|
$loader, |
78
|
|
|
$options |
79
|
|
|
); |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* Regular expression to find a GraphQL annotation in a twig comment. |
84
|
|
|
* |
85
|
|
|
* @var string |
86
|
|
|
*/ |
87
|
|
|
public static $GRAPHQL_ANNOTATION_REGEX = '/{#graphql\s+(?<query>.*?)\s+#\}/s'; |
88
|
|
|
|
89
|
|
|
/** |
90
|
|
|
* {@inheritdoc} |
91
|
|
|
*/ |
92
|
|
|
public function compileSource($source, $name = NULL) { |
93
|
|
|
if ($source instanceof \Twig_Source) { |
|
|
|
|
94
|
|
|
// Check if there is a `*.gql` file with the same name as the template. |
95
|
|
|
$graphqlFile = $source->getPath() . '.gql'; |
96
|
|
|
if (file_exists($graphqlFile)) { |
97
|
|
|
$source = new \Twig_Source( |
98
|
|
|
'{% graphql %}' . file_get_contents($graphqlFile) . '{% endgraphql %}' . $source->getCode(), |
99
|
|
|
$source->getName(), |
100
|
|
|
$source->getPath() |
101
|
|
|
); |
102
|
|
|
} |
103
|
|
|
else { |
104
|
|
|
// Else, try to find an annotation. |
105
|
|
|
$source = new \Twig_Source( |
106
|
|
|
$this->replaceAnnotation($source->getCode()), |
107
|
|
|
$source->getName(), |
108
|
|
|
$source->getPath() |
109
|
|
|
); |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
} |
113
|
|
|
else { |
114
|
|
|
// For inline templates, only comment based annotations are supported. |
115
|
|
|
$source = $this->replaceAnnotation($source); |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
// Compile the modified source. |
119
|
|
|
return parent::compileSource($source, $name); |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* Replace `{#graphql ... #}` annotations with `{% graphql ... %}` tags. |
124
|
|
|
* |
125
|
|
|
* @param string $code |
126
|
|
|
* The template code. |
127
|
|
|
* |
128
|
|
|
* @return string |
129
|
|
|
* The template code with all annotations replaced with tags. |
130
|
|
|
*/ |
131
|
|
|
public function replaceAnnotation($code) { |
132
|
|
|
return preg_replace(static::$GRAPHQL_ANNOTATION_REGEX, '{% graphql %}$1{% endgraphql %}', $code); |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
} |
136
|
|
|
|
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 thecomposer.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
orrequire-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 you have not tested against this specific condition, such errors might go unnoticed.