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.

ModuleListTable::column_cb()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 1
dl 0
loc 11
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\Admin\Tables;
6
7
use GraphQLAPI\GraphQLAPI\General\RequestParams;
8
use GraphQLAPI\GraphQLAPI\Facades\ModuleRegistryFacade;
9
use GraphQLAPI\GraphQLAPI\ConditionalOnEnvironment\Admin\Services\MenuPages\ModulesMenuPage;
10
use GraphQLAPI\GraphQLAPI\ConditionalOnEnvironment\Admin\Services\MenuPages\SettingsMenuPage;
11
use GraphQLAPI\GraphQLAPI\Facades\ModuleTypeRegistryFacade;
12
use PoP\ComponentModel\Facades\Instances\InstanceManagerFacade;
13
use GraphQLAPI\GraphQLAPI\Admin\TableActions\ModuleListTableAction;
14
15
/**
16
 * Module Table
17
 */
18
class ModuleListTable extends AbstractItemListTable
19
{
20
    public const URL_PARAM_MODULE_TYPE = 'module-type';
21
22
    /**
23
     * Singular name of the listed records
24
     *
25
     * @return string
26
     */
27
    public function getItemSingularName(): string
28
    {
29
        return \__('Module', 'graphql-api');
30
    }
31
32
    /**
33
     * Plural name of the listed records
34
     *
35
     * @return string
36
     */
37
    public function getItemPluralName(): string
38
    {
39
        return \__('Modules', 'graphql-api');
40
    }
41
42
    /**
43
     * Return all the items to display on the table
44
     *
45
     * @return array<array> Each item is an array of prop => value
46
     */
47
    public function getAllItems(): array
48
    {
49
        $items = [];
50
        $moduleRegistry = ModuleRegistryFacade::getInstance();
51
        $moduleTypeRegistry = ModuleTypeRegistryFacade::getInstance();
52
        $modules = $moduleRegistry->getAllModules();
53
        $currentView = $this->getCurrentView();
54
        foreach ($modules as $module) {
55
            $moduleResolver = $moduleRegistry->getModuleResolver($module);
56
            $moduleType = $moduleResolver->getModuleType($module);
57
            $moduleTypeResolver = $moduleTypeRegistry->getModuleTypeResolver($moduleType);
58
            $moduleTypeSlug = $moduleTypeResolver->getSlug($moduleType);
59
            // If filtering the view, only add the items with that module type
60
            if (!$currentView || $currentView == $moduleTypeSlug) {
61
                $isEnabled = $moduleRegistry->isModuleEnabled($module);
62
                $items[] = [
63
                    'module' => $module,
64
                    'module-type' => $moduleTypeSlug,
65
                    'id' => $moduleResolver->getID($module),
66
                    'is-enabled' => $isEnabled,
67
                    'can-be-disabled' => $moduleResolver->canBeDisabled($module),
68
                    'can-be-enabled' => !$isEnabled && $moduleRegistry->canModuleBeEnabled($module),
69
                    'has-settings' => $moduleResolver->hasSettings($module),
70
                    'name' => $moduleResolver->getName($module),
71
                    'description' => $moduleResolver->getDescription($module),
72
                    'depends-on' => $moduleResolver->getDependedModuleLists($module),
73
                    // 'url' => $moduleResolver->getURL($module),
74
                    'slug' => $moduleResolver->getSlug($module),
75
                    'has-docs' => $moduleResolver->hasDocumentation($module),
76
                ];
77
            }
78
        }
79
        return $items;
80
    }
81
82
    /**
83
     * Gets the current filtering view
84
     *
85
     * @return string
86
     */
87
    protected function getCurrentView(): string
88
    {
89
        return !empty($_REQUEST[self::URL_PARAM_MODULE_TYPE] ?? null) ? $_REQUEST[self::URL_PARAM_MODULE_TYPE] : '';
90
    }
91
92
    /**
93
     * Gets the list of views available on this table.
94
     *
95
     * @return array<string, string>
96
     * phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
97
     */
98
    protected function get_views()
99
    {
100
        $views = [];
101
        $currentView = $this->getCurrentView();
102
103
        // Module page URL
104
        $url = admin_url(sprintf(
105
            'admin.php?page=%s',
106
            esc_attr($_REQUEST['page'] ?? '')
107
        ));
108
109
        // All entries
110
        $views['all'] = sprintf(
111
            '<a href="%s" class="%s">%s</a>',
112
            $url,
113
            $currentView == '' ? 'current' : '',
114
            \__('All', 'graphql-api')
115
        );
116
117
        // Entries for every module type: retrieve the moduleType from all modules
118
        $moduleRegistry = ModuleRegistryFacade::getInstance();
119
        $moduleTypeRegistry = ModuleTypeRegistryFacade::getInstance();
120
        $modules = $moduleRegistry->getAllModules();
121
        $moduleTypes = [];
122
        foreach ($modules as $module) {
123
            $moduleResolver = $moduleRegistry->getModuleResolver($module);
124
            $moduleTypes[] = $moduleResolver->getModuleType($module);
125
        }
126
        $moduleTypes = array_unique($moduleTypes);
127
        foreach ($moduleTypes as $moduleType) {
128
            $moduleTypeResolver = $moduleTypeRegistry->getModuleTypeResolver($moduleType);
129
            $moduleTypeSlug = $moduleTypeResolver->getSlug($moduleType);
130
            $views[$moduleTypeSlug] = sprintf(
131
                '<a href="%s" class="%s">%s</a>',
132
                \add_query_arg(self::URL_PARAM_MODULE_TYPE, $moduleTypeSlug, $url),
133
                'module-type-view module-type-' . $moduleTypeSlug . ($currentView == $moduleTypeSlug ? ' current' : ''),
134
                $moduleTypeResolver->getName($moduleType)
135
            );
136
        }
137
138
        return $views;
139
    }
140
141
    /**
142
     * List of item data
143
     *
144
     * @param int $per_page
145
     * @param int $page_number
146
     *
147
     * @return mixed
148
     */
149
    public function getItems($per_page = 5, $page_number = 1)
150
    {
151
        $results = $this->getAllItems();
152
        return array_splice(
153
            $results,
154
            ($page_number - 1) * $per_page,
155
            $per_page
156
        );
157
    }
158
159
    /**
160
     * Returns the count of records in the database.
161
     */
162
    public function getRecordCount(): int
163
    {
164
        $results = $this->getAllItems();
165
        return count($results);
166
    }
167
168
    /**
169
     * Render a column when no column specific method exist.
170
     *
171
     * @param object $item
172
     * @param string $column_name
173
     *
174
     * @return mixed
175
     * phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
176
     */
177
    protected function column_default($item, $column_name)
178
    {
179
        /**
180
         * Cast object so PHPStan doesn't throw error
181
         * @var array<string, mixed>
182
         */
183
        $item = $item;
184
        switch ($column_name) {
185
            case 'desc':
186
                $actions = [];
187
                // If it has, add a link to the documentation
188
                $instanceManager = InstanceManagerFacade::getInstance();
189
                /**
190
                 * @var ModulesMenuPage
191
                 */
192
                $modulesMenuPage = $instanceManager->getInstance(ModulesMenuPage::class);
193
                if ($item['has-docs']) {
194
                    $url = \admin_url(sprintf(
195
                        'admin.php?page=%s&%s=%s&%s=%s&TB_iframe=true&width=600&height=550',
196
                        $modulesMenuPage->getScreenID(),
197
                        RequestParams::TAB,
198
                        RequestParams::TAB_DOCS,
199
                        RequestParams::MODULE,
200
                        urlencode($item['module'])
201
                    ));
202
                    $actions['docs'] = \sprintf(
203
                        '<a href="%s" class="%s" data-title="%s">%s</a>',
204
                        \esc_url($url),
205
                        'thickbox open-plugin-details-modal',
206
                        \esc_attr($item['name']),
207
                        \__('View details', 'graphql-api')
208
                    );
209
                }
210
                return sprintf(
211
                    '<div class="plugin-description"><p>%s</p></div><div class="second">%s</div>',
212
                    $item['description'],
213
                    $this->row_actions($actions, true)
214
                );
215
            case 'depends-on':
216
                // Output the list with AND lists of dependencies
217
                // Each list is an OR list of depended modules
218
                // It's formatted like this: module1, module2, ..., module5 or module6
219
                $items = [];
220
                $moduleRegistry = ModuleRegistryFacade::getInstance();
221
                $dependedModuleLists = $item[$column_name];
222
                if (!$dependedModuleLists) {
223
                    return \__('-', 'graphql-api');
224
                }
225
                /**
226
                 * This is a list of lists of modules, as to model both OR and AND conditions
227
                 */
228
                foreach ($dependedModuleLists as $dependedModuleList) {
229
                    if (!$dependedModuleList) {
230
                        continue;
231
                    }
232
                    $dependedModuleListNames = array_map(
233
                        function ($dependedModule) use ($moduleRegistry) {
234
                            $after = '';
235
                            // Check if it has the "inverse" token at the beginning,
236
                            // then it depends on the module being disabled, not enabled
237
                            if ($moduleRegistry->isInverseDependency($dependedModule)) {
238
                                // Revert to the normal module
239
                                $dependedModule = $moduleRegistry->getInverseDependency($dependedModule);
240
                                $after = \__('⇠ as disabled', 'graphql-api');
241
                            }
242
                            $moduleResolver = $moduleRegistry->getModuleResolver($dependedModule);
243
                            return sprintf(
244
                                '%1$s %2$s %3$s',
245
                                '▹',
246
                                $moduleResolver->getName($dependedModule),
247
                                $after
248
                            );
249
                        },
250
                        $dependedModuleList
251
                    );
252
                    if (count($dependedModuleListNames) >= 2) {
253
                        $lastElem = array_pop($dependedModuleListNames);
254
                        $commaElems = implode(
255
                            \__(', ', 'graphql-api'),
256
                            $dependedModuleListNames
257
                        );
258
                        $items[] = sprintf(
259
                            \__('%s or %s', 'graphql-api'),
260
                            $commaElems,
261
                            $lastElem
262
                        );
263
                    } else {
264
                        $items[] = $dependedModuleListNames[0];
265
                    }
266
                }
267
                return implode('<br/>', $items);
268
            case 'enabled':
269
                return \sprintf(
270
                    '<span role="img" aria-label="%s">%s</span>',
271
                    $item['is-enabled'] ? \__('Yes', 'graphql-api') : \__('No', 'graphql-api'),
272
                    $item['is-enabled'] ? '✅' : '❌'
273
                );
274
        }
275
        return '';
276
    }
277
278
    /**
279
     * Render the bulk edit checkbox
280
     *
281
     * @param object $item
282
     *
283
     * @return string
284
     * phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
285
     */
286
    protected function column_cb($item)
287
    {
288
        /**
289
         * Cast object so PHPStan doesn't throw error
290
         * @var array<string, mixed>
291
         */
292
        $item = $item;
293
        return sprintf(
294
            '<input type="checkbox" name="%s[]" value="%s" />',
295
            ModuleListTableAction::INPUT_BULK_ACTION_IDS,
296
            $item['id']
297
        );
298
    }
299
300
    /**
301
     * Method for name column
302
     *
303
     * @param array<string, string> $item an array of DB data
304
     *
305
     * @return string
306
     * phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
307
     */
308
    public function column_name($item)
309
    {
310
        $nonce = \wp_create_nonce('graphql_api_enable_or_disable_module');
311
        $title = '<strong>' . $item['name'] . '</strong>';
312
        $currentView = $this->getCurrentView();
313
        $maybeCurrentViewParam = !empty($currentView) ? '&' . self::URL_PARAM_MODULE_TYPE . '=' . $currentView : '';
314
        $linkPlaceholder = '<a href="?page=%s&action=%s&item=%s&_wpnonce=%s' . ($maybeCurrentViewParam) . '">%s</a>';
315
        $page = esc_attr($_REQUEST['page'] ?? '');
316
        $actions = [];
317
        if ($item['is-enabled']) {
318
            // If it is enabled, offer to disable it
319
            // Unless the module cannot be disabled
320
            if ($item['can-be-disabled']) {
321
                $actions['disable'] = \sprintf(
322
                    $linkPlaceholder,
323
                    $page,
324
                    ModuleListTableAction::ACTION_DISABLE,
325
                    $item['id'],
326
                    $nonce,
327
                    \__('Disable', 'graphql-api')
328
                );
329
            } else {
330
                $actions['enabled'] = \__('Enabled', 'graphql-api');
331
            }
332
333
            // Maybe add settings links
334
            if ($item['has-settings']) {
335
                $instanceManager = InstanceManagerFacade::getInstance();
336
                /**
337
                 * @var SettingsMenuPage
338
                 */
339
                $settingsMenuPage = $instanceManager->getInstance(SettingsMenuPage::class);
340
                $actions['settings'] = \sprintf(
341
                    '<a href="%s">%s</a>',
342
                    sprintf(
343
                        \admin_url(sprintf(
344
                            'admin.php?page=%s&tab=%s',
345
                            $settingsMenuPage->getScreenID(),
346
                            $item['id']
347
                        ))
348
                    ),
349
                    \__('Settings', 'graphql-api')
350
                );
351
            }
352
        } elseif ($item['can-be-enabled']) {
353
            // If not enabled and can be enabled, offer to do it
354
            $actions['enable'] = \sprintf(
355
                $linkPlaceholder,
356
                $page,
357
                ModuleListTableAction::ACTION_ENABLE,
358
                $item['id'],
359
                $nonce,
360
                \__('Enable', 'graphql-api')
361
            );
362
        } else {
363
            // Not enabled and can't be enabled, mention requirements not met
364
            // Not enabled for "striped" table style because, without a link, color contrast is not good:
365
            // gray font color over gray background
366
            // if ($this->usePluginTableStyle()) {
367
            $actions['disabled'] = \__('Disabled', 'graphql-api');
368
            // }
369
        }
370
        return $title . $this->row_actions($actions/*, $this->usePluginTableStyle()*/);
371
    }
372
373
    /**
374
     * Indicate if to show the enabled column or not
375
     */
376
    protected function usePluginTableStyle(): bool
377
    {
378
        return true;
379
    }
380
381
    /**
382
     *  Associative array of columns
383
     *
384
     * @return array<string, string>
385
     * phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
386
     */
387
    public function get_columns()
388
    {
389
        return array_merge(
390
            [
391
                'cb' => '<input type="checkbox" />',
392
                'name' => \__('Module', 'graphql-api'),
393
            ],
394
            $this->usePluginTableStyle() ?
395
                [] :
396
                [
397
                    'enabled' => \__('Enabled', 'graphql-api'),
398
                ],
399
            [
400
                'desc' => \__('Description', 'graphql-api'),
401
                'depends-on' => \__('Depends on', 'graphql-api'),
402
            ]
403
        );
404
    }
405
406
    /**
407
     * Returns an associative array containing the bulk action
408
     *
409
     * @return array<string, string>
410
     * phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
411
     */
412
    public function get_bulk_actions()
413
    {
414
        return [
415
            ModuleListTableAction::ACTION_ENABLE => \__('Enable', 'graphql-api'),
416
            ModuleListTableAction::ACTION_DISABLE => \__('Disable', 'graphql-api'),
417
        ];
418
    }
419
420
    /**
421
     * Get a list of CSS classes for the WP_List_Table table tag.
422
     *
423
     * @since 3.1.0
424
     *
425
     * @return string[] Array of CSS classes for the table tag.
426
     * phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
427
     */
428
    protected function get_table_classes()
429
    {
430
        // return array_merge(
431
        //     parent::get_table_classes(),
432
        //     [
433
        //         'plugins'
434
        //     ]
435
        // );
436
        if ($this->usePluginTableStyle()) {
437
            return array( 'widefat', 'plugins', $this->_args['plural'] );
438
        }
439
        return array_diff(
440
            parent::get_table_classes(),
441
            [
442
                'fixed'
443
            ]
444
        );
445
    }
446
447
    /**
448
     * Classnames to add to the row for the item
449
     *
450
     * @param object $item The current item
451
     */
452
    protected function getTableStyleRowClassnames($item): string
453
    {
454
        /**
455
         * Cast object so PHPStan doesn't throw error
456
         * @var array<string, mixed>
457
         */
458
        $item = $item;
459
        return sprintf(
460
            'module-%s',
461
            $item['module-type']
462
        );
463
    }
464
465
    /**
466
     * Generates content for a single row of the table
467
     *
468
     * @since 3.1.0
469
     *
470
     * @param object $item The current item
471
     * @return void
472
     * phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
473
     */
474
    public function single_row($item)
475
    {
476
        /**
477
         * Cast object so PHPStan doesn't throw error
478
         * @var array<string, mixed>
479
         */
480
        $arrayItem = $item;
481
        if ($this->usePluginTableStyle()) {
482
            $classnames = sprintf(
483
                '%s %s',
484
                $this->getTableStyleRowClassnames($item),
485
                $arrayItem['is-enabled'] ? 'active' : 'inactive'
486
            );
487
            echo sprintf(
488
                '<tr class="%s">',
489
                $classnames
490
            );
491
            $this->single_row_columns($item);
492
            echo '</tr>';
493
        } else {
494
            parent::single_row($item);
495
        }
496
    }
497
498
    /**
499
     * Handles data query and filter, sorting, and pagination.
500
     *
501
     * @return void
502
     * phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
503
     */
504
    public function prepare_items()
505
    {
506
        $this->_column_headers = $this->get_column_info();
507
508
        /** Process bulk or single action */
509
        $instanceManager = InstanceManagerFacade::getInstance();
510
        /**
511
         * @var ModuleListTableAction
512
         */
513
        $tableAction = $instanceManager->getInstance(ModuleListTableAction::class);
514
        $tableAction->maybeProcessAction();
515
516
        $per_page = $this->get_items_per_page(
517
            $this->getItemsPerPageOptionName(),
518
            $this->getDefaultItemsPerPage()
519
        );
520
        $current_page = $this->get_pagenum();
521
        $total_items  = $this->getRecordCount();
522
523
        $this->set_pagination_args([
524
            'total_items' => $total_items,
525
            'per_page'    => $per_page,
526
        ]);
527
528
        $this->items = $this->getItems($per_page, $current_page);
529
    }
530
531
    /**
532
     * Enqueue the required assets
533
     *
534
     * @return void
535
     */
536
    public function enqueueAssets(): void
537
    {
538
        parent::enqueueAssets();
539
540
        /**
541
         * Fix the issues with the WP List Table
542
         */
543
        \wp_enqueue_style(
544
            'graphql-api-module-list-table',
545
            \GRAPHQL_API_URL . 'assets/css/module-list-table.css',
546
            array(),
547
            \GRAPHQL_API_VERSION
548
        );
549
    }
550
551
    /**
552
     * Customize the width of the columns
553
     */
554
    public function printStyles(): void
555
    {
556
        parent::printStyles();
557
558
        /*
559
        if ($this->usePluginTableStyle()) {
560
            ?>
561
            <style type="text/css">
562
                .wp-list-table .column-name { width: 25%; }
563
                .wp-list-table .column-description { width: 75%; }
564
            </style>
565
            <?php
566
        } else {
567
            ?>
568
            <style type="text/css">
569
                .wp-list-table .column-name { width: 25%; }
570
                .wp-list-table .column-enabled { width: 10%; }
571
                .wp-list-table .column-description { width: 65%; }
572
            </style>
573
            <?php
574
        }
575
        */
576
    }
577
}
578