GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

getGraphQLQuerySourceContent()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 7
ccs 0
cts 3
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQLAPI\GraphQLAPI\PostTypes;
6
7
use WP_Post;
8
use PoP\ComponentModel\State\ApplicationState;
9
use GraphQLAPI\GraphQLAPI\General\BlockHelpers;
10
use GraphQLAPI\GraphQLAPI\General\RequestParams;
11
use GraphQLAPI\GraphQLAPI\PostTypes\AbstractPostType;
12
use GraphQLAPI\GraphQLAPI\Facades\ModuleRegistryFacade;
13
use GraphQLAPI\GraphQLAPI\Blocks\SchemaConfigurationBlock;
14
use PoP\ComponentModel\Facades\Instances\InstanceManagerFacade;
15
use GraphQLAPI\GraphQLAPI\EndpointResolvers\EndpointResolverTrait;
16
use GraphQLAPI\GraphQLAPI\Blocks\AbstractQueryExecutionOptionsBlock;
17
use GraphQLAPI\GraphQLAPI\ModuleResolvers\SchemaConfigurationFunctionalityModuleResolver;
18
use WP_Query;
19
20
abstract class AbstractGraphQLQueryExecutionPostType extends AbstractPostType
21
{
22
    use EndpointResolverTrait {
23
        EndpointResolverTrait::getNature as getUpstreamNature;
24
        EndpointResolverTrait::addGraphQLVars as upstreamAddGraphQLVars;
25
    }
26
27
    /**
28
     * Indicates if we executing the GraphQL query (`true`) or visualizing the query source (`false`)
29
     * It returns always `true`, unless passing ?view=source in the single post URL
30
     */
31
    protected function isGraphQLQueryExecution(): bool
32
    {
33
        return ($_REQUEST[RequestParams::VIEW] ?? null) != RequestParams::VIEW_SOURCE;
34
    }
35
36
    /**
37
     * Whenever this CPT is saved/updated, the timestamp must be regenerated,
38
     * because it contains the SchemaConfiguration block, which contains
39
     * Field Deprecation Lists, which can change the schema
40
     */
41
    protected function regenerateTimestampOnSave(): bool
42
    {
43
        return true;
44
    }
45
46
    /**
47
     * Label to show on the "execute" action in the CPT table
48
     */
49
    protected function getExecuteActionLabel(): string
50
    {
51
        return __('Execute', 'graphql-api');
52
    }
53
54
    /**
55
     * Get actions to add for this CPT
56
     * "View" action must be attached ?view=source, and the view link is called "Execute"
57
     *
58
     * @param WP_Post $post
59
     * @return array<string, string>
60
     */
61
    protected function getPostTypeTableActions($post): array
62
    {
63
        $actions = parent::getPostTypeTableActions($post);
64
        $post_type_object = \get_post_type_object($post->post_type);
65
66
        /**
67
         * Code copied from function `handle_row_actions` in file
68
         * wp-admin/includes/class-wp-posts-list-table.php
69
         */
70
        if (!is_null($post_type_object) && \is_post_type_viewable($post_type_object)) {
71
            $title = \_draft_or_post_title();
72
            $isEnabled = $this->isEnabled($post);
73
            $executeLabel = $this->getExecuteActionLabel();
74
            if (in_array($post->post_status, array('pending', 'draft', 'future'))) {
75
                $can_edit_post = \current_user_can('edit_post', $post->ID);
76
                if ($can_edit_post) {
77
                    $preview_link = \get_preview_post_link($post);
78
                    if (!is_null($preview_link)) {
79
                        $actions['view'] = sprintf(
80
                            '<a href="%s" rel="bookmark" aria-label="%s">%s</a>',
81
                            esc_url(\add_query_arg(
82
                                RequestParams::VIEW,
83
                                RequestParams::VIEW_SOURCE,
84
                                $preview_link
85
                            )),
86
                            /* translators: %s: Post title. */
87
                            esc_attr(sprintf(__('Preview source &#8220;%s&#8221;', 'graphql-api'), $title)),
88
                            __('Preview source', 'graphql-api')
89
                        );
90
                        if ($isEnabled) {
91
                            $actions['execute'] = sprintf(
92
                                '<a href="%s" rel="bookmark" aria-label="%s">%s</a>',
93
                                esc_url($preview_link),
94
                                esc_attr(sprintf(__('%s &#8220;%s&#8221;', 'graphql-api'), $executeLabel, $title)),
95
                                $executeLabel
96
                            );
97
                        }
98
                    }
99
                }
100
            } elseif ('trash' != $post->post_status) {
101
                if ($permalink = \get_permalink($post->ID)) {
102
                    $actions['view'] = sprintf(
103
                        '<a href="%s" rel="bookmark" aria-label="%s">%s</a>',
104
                        \add_query_arg(
105
                            RequestParams::VIEW,
106
                            RequestParams::VIEW_SOURCE,
107
                            $permalink
108
                        ),
109
                        esc_attr(sprintf(__('View source &#8220;%s&#8221;', 'graphql-api'), $title)),
110
                        __('View source', 'graphql-api')
111
                    );
112
                    if ($isEnabled) {
113
                        $actions['execute'] = sprintf(
114
                            '<a href="%s" rel="bookmark" aria-label="%s">%s</a>',
115
                            $permalink,
116
                            esc_attr(sprintf(__('%s &#8220;%s&#8221;', 'graphql-api'), $executeLabel, $title)),
117
                            $executeLabel
118
                        );
119
                    }
120
                }
121
            }
122
        }
123
        return $actions;
124
    }
125
126
    /**
127
     * Add the hook to initialize the different post types
128
     */
129
    public function initialize(): void
130
    {
131
        parent::initialize();
132
133
        /**
134
         * Two outputs:
135
         * 1.`isGraphQLQueryExecution` = true, then resolve the GraphQL query
136
         * 2.`isGraphQLQueryExecution` = false, then do something else (eg: view the source for the GraphQL query)
137
         */
138
        if ($this->isGraphQLQueryExecution()) {
139
            $this->executeGraphQLQuery();
140
        } else {
141
            $this->doSomethingElse();
142
        }
143
    }
144
145
    /**
146
     * Do something else, not the execution of the GraphQL query.
147
     * By default, print the Query source
148
     */
149
    protected function doSomethingElse(): void
150
    {
151
        /** Add the excerpt, which is the description of the GraphQL query */
152
        \add_filter(
153
            'the_content',
154
            [$this, 'maybeGetGraphQLQuerySourceContent']
155
        );
156
    }
157
158
    /**
159
     * Render the GraphQL Query CPT
160
     */
161
    public function maybeGetGraphQLQuerySourceContent(string $content): string
162
    {
163
        /**
164
         * Check if it is this CPT...
165
         */
166
        if (\is_singular($this->getPostType())) {
167
            $vars = ApplicationState::getVars();
168
            $customPost = $vars['routing-state']['queried-object'];
169
            // Make sure there is a post (eg: it has not been deleted)
170
            if ($customPost !== null) {
171
                return $this->getGraphQLQuerySourceContent($content, $customPost);
172
            }
173
        }
174
        return $content;
175
    }
176
177
    /**
178
     * Render the GraphQL Query CPT
179
     */
180
    protected function getGraphQLQuerySourceContent(string $content, WP_Post $graphQLQueryPost): string
181
    {
182
        /**
183
         * Prettyprint the code
184
         */
185
        $content .= '<script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>';
186
        return $content;
187
    }
188
189
    /**
190
     * Assign the single endpoint by setting it as the Home nature
191
     */
192
    public function getNature(string $nature, WP_Query $query): string
193
    {
194
        if ($query->is_singular($this->getPostType())) {
195
            return $this->getUpstreamNature($nature, $query);
196
        }
197
198
        return $nature;
199
    }
200
201
    abstract protected function getQueryExecutionOptionsBlock(): AbstractQueryExecutionOptionsBlock;
202
203
    /**
204
     * Read the options block and check the value of attribute "isEnabled"
205
     *
206
     * @param WP_Post|int $postOrID
207
     */
208
    protected function isOptionsBlockValueOn($postOrID, string $attribute, bool $default): bool
209
    {
210
        $optionsBlockDataItem = $this->getOptionsBlockDataItem($postOrID);
211
        // If there was no options block, something went wrong in the post content
212
        if (is_null($optionsBlockDataItem)) {
213
            return $default;
214
        }
215
216
        // The default value is not saved in the DB in Gutenberg!
217
        return $optionsBlockDataItem['attrs'][$attribute] ?? $default;
218
    }
219
220
    /**
221
     * Read the options block and check the value of attribute "isEnabled"
222
     *
223
     * @param WP_Post|int $postOrID
224
     */
225
    protected function isEnabled($postOrID): bool
226
    {
227
        // `true` is the default option in Gutenberg, so it's not saved to the DB!
228
        return $this->isOptionsBlockValueOn(
229
            $postOrID,
230
            AbstractQueryExecutionOptionsBlock::ATTRIBUTE_NAME_IS_ENABLED,
231
            true
232
        );
233
    }
234
235
    /**
236
     * @param WP_Post|int $postOrID
237
     * @return array<string, mixed>|null Data inside the block is saved as key (string) => value
238
     */
239
    protected function getOptionsBlockDataItem($postOrID): ?array
240
    {
241
        return BlockHelpers::getSingleBlockOfTypeFromCustomPost(
242
            $postOrID,
243
            $this->getQueryExecutionOptionsBlock()
244
        );
245
    }
246
247
    /**
248
     * Indicate if the GraphQL variables must override the URL params
249
     *
250
     * @param WP_Post|int $postOrID
251
     */
252
    protected function doURLParamsOverrideGraphQLVariables($postOrID): bool
253
    {
254
        return true;
255
    }
256
257
    /**
258
     * Check if requesting the single post of this CPT and, in this case, set the request with the needed API params
259
     *
260
     * @param array<array> $vars_in_array
261
     */
262
    public function addGraphQLVars(array $vars_in_array): void
263
    {
264
        [&$vars] = $vars_in_array;
265
        if (\is_singular($this->getPostType()) && $this->isEnabled($vars['routing-state']['queried-object-id'])) {
266
            $this->upstreamAddGraphQLVars($vars_in_array);
267
        }
268
    }
269
270
    /**
271
     * Gutenberg templates to lock down the Custom Post Type to
272
     *
273
     * @return array<array> Every element is an array with template name in first pos, and attributes then
274
     */
275
    protected function getGutenbergTemplate(): array
276
    {
277
        $template = parent::getGutenbergTemplate();
278
279
        // If enabled by module, add the Schema Configuration block to the locked Gutenberg template
280
        $this->maybeAddSchemaConfigurationBlock($template);
281
282
        return $template;
283
    }
284
285
    /**
286
     * If enabled by module, add the Schema Configuration block to the locked Gutenberg template
287
     *
288
     * @param array<array> $template Every element is an array with template name in first pos, and attributes then
289
     */
290
    protected function maybeAddSchemaConfigurationBlock(array &$template): void
291
    {
292
        $moduleRegistry = ModuleRegistryFacade::getInstance();
293
        if ($moduleRegistry->isModuleEnabled(SchemaConfigurationFunctionalityModuleResolver::SCHEMA_CONFIGURATION)) {
294
            $instanceManager = InstanceManagerFacade::getInstance();
295
            /**
296
             * @var SchemaConfigurationBlock
297
             */
298
            $schemaConfigurationBlock = $instanceManager->getInstance(SchemaConfigurationBlock::class);
299
            $template[] = [$schemaConfigurationBlock->getBlockFullName()];
300
        }
301
    }
302
}
303