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.
Completed
Push — 3.0.x ( 484b00...326bf4 )
by Nicolas
04:23
created

ResourcesPage   C

Complexity

Total Complexity 56

Size/Duplication

Total Lines 526
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 526
rs 5.5555
wmc 56

5 Methods

Rating   Name   Duplication   Size   Complexity  
B sort() 0 33 6
A pagesFlatView() 0 9 2
D __viewIndex() 0 257 22
A getTemplate() 0 10 3
D __actionIndex() 0 136 23

How to fix   Complexity   

Complex Class

Complex classes like ResourcesPage often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ResourcesPage, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * @package toolkit
5
 */
6
/**
7
 * The `ResourcesPage` abstract class controls the way "Datasource"
8
 * and "Events" index pages are displayed in the backend. It extends the
9
 * `AdministrationPage` class.
10
 *
11
 * @since Symphony 2.3
12
 * @see toolkit.AdministrationPage
13
 */
14
15
abstract class ResourcesPage extends AdministrationPage
16
{
17
    /**
18
     * This method is invoked from the `Sortable` class and it contains the
19
     * logic for sorting (or unsorting) the resource index. It provides a basic
20
     * wrapper to the `ResourceManager`'s `fetch()` method.
21
     *
22
     * @see toolkit.ResourceManager#getSortingField
23
     * @see toolkit.ResourceManager#getSortingOrder
24
     * @see toolkit.ResourceManager#fetch
25
     * @param string $sort
26
     *  The field to sort on which should match one of the table's column names.
27
     *  If this is not provided the default will be determined by
28
     *  `ResourceManager::getSortingField`
29
     * @param string $order
30
     *  The direction to sort in, either 'asc' or 'desc'. If this is not provided
31
     *  the value will be determined by `ResourceManager::getSortingOrder`.
32
     * @param array $params
33
     *  An associative array of params (usually populated from the URL) that this
34
     *  function uses. The current implementation will use `type` and `unsort` keys
35
     * @throws Exception
36
     * @throws SymphonyErrorPage
37
     * @return array
38
     *  An associative of the resource as determined by `ResourceManager::fetch`
39
     */
40
    public function sort(&$sort, &$order, array $params)
41
    {
42
        $type = $params['type'];
43
44
        if (!is_null($sort)) {
0 ignored issues
show
introduced by
The condition is_null($sort) is always false.
Loading history...
45
            General::sanitize($sort);
46
        }
47
48
        // If `?unsort` is appended to the URL, then sorting information are reverted
49
        // to their defaults
50
        if (isset($params['unsort'])) {
51
            ResourceManager::setSortingField($type, 'name', false);
52
            ResourceManager::setSortingOrder($type, 'asc');
53
54
            redirect(Administration::instance()->getCurrentPageURL());
55
        }
56
57
        // By default, sorting information are retrieved from
58
        // the filesystem and stored inside the `Configuration` object
59
        if (is_null($sort)) {
0 ignored issues
show
introduced by
The condition is_null($sort) is always false.
Loading history...
60
            $sort = ResourceManager::getSortingField($type);
61
            $order = ResourceManager::getSortingOrder($type);
62
63
            // If the sorting field or order differs from what is saved,
64
            // update the config file and reload the page
65
        } elseif ($sort !== ResourceManager::getSortingField($type) || $order !== ResourceManager::getSortingOrder($type)) {
66
            ResourceManager::setSortingField($type, $sort, false);
67
            ResourceManager::setSortingOrder($type, $order);
68
69
            redirect(Administration::instance()->getCurrentPageURL());
70
        }
71
72
        return ResourceManager::fetch($params['type'], array(), array(), $sort . ' ' . $order);
73
    }
74
75
    /**
76
     * This function creates an array of all page titles in the system.
77
     *
78
     * @return array
79
     *  An array of page titles
80
     */
81
    public function pagesFlatView()
82
    {
83
        $pages = (new PageManager)->select(['id'])->execute()->rows();
84
85
        foreach ($pages as &$p) {
86
            $p['title'] = PageManager::resolvePageTitle($p['id']);
87
        }
88
89
        return $pages;
90
    }
91
92
    /**
93
     * This function contains the minimal amount of logic for generating the
94
     * index table of a given `$resource_type`. The table has name, source, pages
95
     * release date and author columns. The values for these columns are determined
96
     * by the resource's `about()` method.
97
     *
98
     * As Datasources types can be installed using Providers, the Source column
99
     * can be overridden with a Datasource's `getSourceColumn` method (if it exists).
100
     *
101
     * @param integer $resource_type
102
     *  Either `ResourceManager::RESOURCE_TYPE_EVENT` or `ResourceManager::RESOURCE_TYPE_DATASOURCE`
103
     * @throws InvalidArgumentException
104
     */
105
    public function __viewIndex($resource_type)
106
    {
107
        $manager = ResourceManager::getManagerFromType($resource_type);
108
        $friendly_resource = ($resource_type === ResourceManager::RESOURCE_TYPE_EVENT) ? __('Event') : __('DataSource');
109
        $context = Administration::instance()->getPageCallback();
110
111
        $this->setPageType('table');
112
113
        Sortable::initialize($this, $resources, $sort, $order, array(
114
            'type' => $resource_type,
115
        ));
116
117
        $columns = array(
118
            array(
119
                'label' => __('Name'),
120
                'sortable' => true,
121
                'handle' => 'name'
122
            ),
123
            array(
124
                'label' => __('Source'),
125
                'sortable' => true,
126
                'handle' => 'source'
127
            ),
128
            array(
129
                'label' => __('Pages'),
130
                'sortable' => false,
131
            ),
132
            array(
133
                'label' => __('Author'),
134
                'sortable' => true,
135
                'handle' => 'author'
136
            )
137
        );
138
139
        /**
140
         * Allows the creation of custom table columns for each resource. Called
141
         * after all the table headers columns have been added.
142
         *
143
         * @delegate AddCustomResourceColumn
144
         * @since Symphony 3.0.0
145
         * @param string $context
146
         *  '/blueprints/datasources/' or '/blueprints/events/'
147
         * @param array $columns
148
         *  An array of the current columns, passed by reference
149
         * @param string $sort
150
         *  The sort field
151
         * @param string $order
152
         *  The sort order
153
         * @param int $resource_type
154
         *  The resource type, i.e. `ResourceManager::RESOURCE_TYPE_EVENT` or
155
         *  `ResourceManager::RESOURCE_TYPE_DATASOURCE`.
156
         * @param array $resources
157
         *  The resources array
158
         * @param object $manager
159
         *  The resources manager
160
         */
161
        Symphony::ExtensionManager()->notifyMembers('AddCustomResourceColumn', $context['pageroot'], [
162
            'columns' => &$columns,
163
            'sort' => $sort,
164
            'order' => $order,
165
            'resource_type' => $resource_type,
166
            'resources' => $resources,
167
            'manager' => $manager,
168
        ]);
169
170
        $aTableHead = Sortable::buildTableHeaders($columns, $sort, $order, (isset($_REQUEST['filter']) ? '&amp;filter=' . $_REQUEST['filter'] : ''));
171
172
        $aTableBody = array();
173
174
        if (!is_array($resources) || empty($resources)) {
175
            $aTableBody = array(Widget::TableRow(array(Widget::TableData(__('None found.'), 'inactive', null, count($aTableHead))), 'odd'));
176
        } else {
177
            foreach ($resources as $r) {
178
                $action = 'edit';
179
                $status = null;
180
                $locked = null;
181
182
                // Locked resources
183
                if (isset($r['can_parse']) && $r['can_parse'] !== true) {
184
                    $action = 'info';
185
                    $status = 'status-notice';
186
                    $locked = array(
187
                        'data-status' => ' — ' . __('read only')
188
                    );
189
                }
190
191
                $name = Widget::TableData(
192
                    Widget::Anchor(
193
                        stripslashes($r['name']),
194
                        SYMPHONY_URL . $context['pageroot'] .  $action . '/' . $r['handle'] . '/',
0 ignored issues
show
Bug introduced by
The constant SYMPHONY_URL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
195
                        $r['handle'],
196
                        'resource-' . $action,
197
                        null,
198
                        $locked
199
                    )
200
                );
201
202
                $name->appendChild(Widget::Label(__('Select ' . $friendly_resource . ' %s', array($r['name'])), null, 'accessible', null, array(
203
                    'for' => 'resource-' . $r['handle']
204
                )));
205
                $name->appendChild(Widget::Input('items['.$r['handle'].']', 'on', 'checkbox', array(
206
                    'id' => 'resource-' . $r['handle']
207
                )));
208
209
                // Resource type/source
210
                if (isset($r['source'], $r['source']['id'])) {
211
                    $section = Widget::TableData(
212
                        Widget::Anchor(
213
                            $r['source']['name'],
214
                            SYMPHONY_URL . '/blueprints/sections/edit/' . $r['source']['id'] . '/',
215
                            $r['source']['handle']
216
                        )
217
                    );
218
                } elseif (isset($r['source']) && class_exists($r['source']['name']) && method_exists($r['source']['name'], 'getSourceColumn')) {
219
                    $class = call_user_func(array($manager, '__getClassName'), $r['handle']);
220
                    $section = Widget::TableData(call_user_func(array($class, 'getSourceColumn'), $r['handle']));
221
                } elseif (isset($r['source'], $r['source']['name'])) {
222
                    $section = Widget::TableData(stripslashes($r['source']['name']));
223
                } else {
224
                    $section = Widget::TableData(__('Unknown'), 'inactive');
225
                }
226
227
                // Attached pages
228
                $pages = ResourceManager::getAttachedPages($resource_type, $r['handle']);
229
230
                $pagelinks = array();
231
                $i = 0;
232
233
                foreach ($pages as $p) {
234
                    ++$i;
235
                    $pagelinks[] = Widget::Anchor(
236
                        $p['title'],
237
                        SYMPHONY_URL . '/blueprints/pages/edit/' . $p['id'] . '/'
238
                    )->generate() . (count($pages) > $i ? (($i % 10) == 0 ? '<br />' : ', ') : '');
239
                }
240
241
                $pages = implode('', $pagelinks);
242
243
                if ($pages == '') {
244
                    $pagelinks = Widget::TableData(__('None'), 'inactive');
245
                } else {
246
                    $pagelinks = Widget::TableData($pages, 'pages');
247
                }
248
249
                // Authors
250
                $author = $r['author']['name'];
251
252
                if ($author) {
253
                    if (isset($r['author']['website'])) {
254
                        $author = Widget::Anchor($r['author']['name'], General::validateURL($r['author']['website']));
255
                    } elseif (isset($r['author']['email'])) {
256
                        $author = Widget::Anchor($r['author']['name'], 'mailto:' . $r['author']['email']);
257
                    }
258
                }
259
260
                $author = Widget::TableData($author);
261
                $tableData = [$name, $section, $pagelinks, $author];
262
263
                /**
264
                 * Allows Extensions to inject custom table data for each Resource
265
                 * into the Resource Index
266
                 *
267
                 * @delegate AddCustomResourceColumnData
268
                 * @since Symphony 3.0.0
269
                 * @param string $context
270
                 *  '/blueprints/datasources/' or '/blueprints/events/'
271
                 * @param array $tableData
272
                 *  An array of `Widget::TableData`, passed by reference
273
                 * @param array $columns
274
                 *  An array of the current columns
275
                 * @param int $resource_type
276
                 *  The resource type, i.e. `ResourceManager::RESOURCE_TYPE_EVENT` or
277
                 *  `ResourceManager::RESOURCE_TYPE_DATASOURCE`.
278
                 * @param array $resource
279
                 *  The resource array
280
                 * @param string $action
281
                 *  The name of the action
282
                 * @param string $status
283
                 *  The status of the row
284
                 * @param bool $locked
285
                 *  If the resource is locked, i.e., read-only
286
                 */
287
                Symphony::ExtensionManager()->notifyMembers('AddCustomResourceColumnData', '/system/authors/', [
288
                    'tableData' => &$tableData,
289
                    'columns' => $columns,
290
                    'resource_type' => $resource_type,
291
                    'resource' => $r,
292
                    'action' => $action,
293
                    'status' => $status,
294
                    'locked' => $locked,
295
                ]);
296
297
                $aTableBody[] = Widget::TableRow($tableData, $status);
298
            }
299
        }
300
301
        $table = Widget::Table(
302
            Widget::TableHead($aTableHead),
303
            null,
304
            Widget::TableBody($aTableBody),
305
            'selectable',
306
            null,
307
            array('role' => 'directory', 'aria-labelledby' => 'symphony-subheading', 'data-interactive' => 'data-interactive')
308
        );
309
310
        $this->Form->appendChild($table);
311
312
        $version = new XMLElement('p', 'Symphony ' . Symphony::Configuration()->get('version', 'symphony'), array(
313
            'id' => 'version'
314
        ));
315
        $this->Form->appendChild($version);
316
317
        $tableActions = new XMLElement('div');
318
        $tableActions->setAttribute('class', 'actions');
319
320
        $options = array(
321
            array(null, false, __('With Selected...')),
322
            array('delete', false, __('Delete'), 'confirm'),
323
        );
324
325
        $pages = $this->pagesFlatView();
326
327
        $group_attach = array('label' => __('Attach to Page'), 'options' => array());
328
        $group_detach = array('label' => __('Detach from Page'), 'options' => array());
329
330
        $group_attach['options'][] = array('attach-all-pages', false, __('All'));
331
        $group_detach['options'][] = array('detach-all-pages', false, __('All'));
332
333
        foreach ($pages as $p) {
334
            $group_attach['options'][] = array('attach-to-page-' . $p['id'], false, $p['title']);
335
            $group_detach['options'][] = array('detach-from-page-' . $p['id'], false, $p['title']);
336
        }
337
338
        $options[] = $group_attach;
339
        $options[] = $group_detach;
340
341
        /**
342
         * Allows an extension to modify the existing options for this page's
343
         * With Selected menu. If the `$options` parameter is an empty array,
344
         * the 'With Selected' menu will not be rendered.
345
         *
346
         * @delegate AddCustomActions
347
         * @since Symphony 2.3.2
348
         * @param string $context
349
         *  '/blueprints/datasources/' or '/blueprints/events/'
350
         * @param array $options
351
         *  An array of arrays, where each child array represents an option
352
         *  in the With Selected menu. Options should follow the same format
353
         *  expected by `Widget::__SelectBuildOption`. Passed by reference.
354
         */
355
        Symphony::ExtensionManager()->notifyMembers('AddCustomActions', $context['pageroot'], array(
356
            'options' => &$options
357
        ));
358
359
        if (!empty($options)) {
360
            $tableActions->appendChild(Widget::Apply($options));
361
            $this->Form->appendChild($tableActions);
362
        }
363
    }
364
365
    /**
366
     * This function is called from the resources index when a user uses the
367
     * With Selected, or Apply, menu. The type of resource is given by
368
     * `$resource_type`. At this time the only two valid values,
369
     * `ResourceManager::RESOURCE_TYPE_EVENT` or `ResourceManager::RESOURCE_TYPE_DATASOURCE`.
370
     *
371
     * The function handles 'delete', 'attach', 'detach', 'attach all',
372
     * 'detach all' actions.
373
     *
374
     * @param integer $resource_type
375
     *  Either `ResourceManager::RESOURCE_TYPE_EVENT` or `ResourceManager::RESOURCE_TYPE_DATASOURCE`
376
     * @throws Exception
377
     */
378
    public function __actionIndex($resource_type)
379
    {
380
        $manager = ResourceManager::getManagerFromType($resource_type);
381
        $resource_name = str_replace('Manager', '', $manager);
382
        $delegate_path = strtolower($resource_name);
383
        $checked = (is_array($_POST['items'])) ? array_keys($_POST['items']) : null;
384
        $context = Administration::instance()->getPageCallback();
385
386
        if (isset($_POST['action']) && is_array($_POST['action'])) {
387
            /**
388
             * Extensions can listen for any custom actions that were added
389
             * through `AddCustomPreferenceFieldsets` or `AddCustomActions`
390
             * delegates.
391
             *
392
             * @delegate CustomActions
393
             * @since Symphony 2.3.2
394
             * @param string $context
395
             *  '/blueprints/datasources/' or '/blueprints/events/'
396
             * @param array $checked
397
             *  An array of the selected rows. The value is usually the ID of the
398
             *  the associated object.
399
             */
400
            Symphony::ExtensionManager()->notifyMembers('CustomActions', $context['pageroot'], array(
401
                'checked' => $checked
402
            ));
403
404
            if (is_array($checked) && !empty($checked)) {
405
                if ($_POST['with-selected'] == 'delete') {
406
                    $canProceed = true;
407
408
                    foreach ($checked as $handle) {
409
                        $path = call_user_func(array($manager, '__getDriverPath'), $handle);
410
411
                        // Don't allow Extension resources to be deleted. RE: #2027
412
                        if (stripos($path, EXTENSIONS) === 0) {
0 ignored issues
show
Bug introduced by
The constant EXTENSIONS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
413
                            continue;
414
                        }
415
                        
416
                        /**
417
                         * Prior to deleting the Resource file. Target file path is provided.
418
                         *
419
                         * @since Symphony 3.0.0
420
                         * @param string $context
421
                         * '/blueprints/{$resource_name}/'
422
                         * @param string $file
423
                         *  The path to the Resource file
424
                         * @param string $handle
425
                         *  The handle of the Resource
426
                         */
427
                        Symphony::ExtensionManager()->notifyMembers(
428
                            "{$resource_name}PreDelete",
429
                            $context['pageroot'],
430
                            array(
431
                                'file' => $path,
432
                                'handle' => $handle,
433
                            )
434
                        );
435
436
                        if (!General::deleteFile($path)) {
437
                            $folder = str_replace(DOCROOT, '', $path);
0 ignored issues
show
Bug introduced by
The constant DOCROOT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
438
                            $folder = str_replace('/' . basename($path), '', $folder);
439
440
                            $this->pageAlert(
441
                                __('Failed to delete %s.', array('<code>' . basename($path) . '</code>'))
442
                                . ' ' . __('Please check permissions on %s', array('<code>' . $folder . '</code>')),
443
                                Alert::ERROR
444
                            );
445
                            $canProceed = false;
446
                        } else {
447
                            $pages = ResourceManager::getAttachedPages($resource_type, $handle);
448
449
                            foreach ($pages as $page) {
450
                                ResourceManager::detach($resource_type, $handle, $page['id']);
451
                            }
452
453
                            /**
454
                             * After deleting the Resource file. Target file path is provided.
455
                             *
456
                             * @since Symphony 3.0.0
457
                             * @param string $context
458
                             * '/blueprints/{$resource_name}/'
459
                             * @param string $file
460
                             *  The path to the Resource file
461
                             * @param string $handle
462
                             *  The handle of the Resource
463
                             */
464
                            Symphony::ExtensionManager()->notifyMembers(
465
                                "{$resource_name}PostDelete",
466
                                "/blueprints/{$delegate_path}/",
467
                                array(
468
                                    'file' => $path,
469
                                    'handle' => $handle,
470
                                )
471
                            );
472
                        }
473
                    }
474
475
                    if ($canProceed) {
476
                        redirect(Administration::instance()->getCurrentPageURL());
477
                    }
478
                } elseif (preg_match('/^(at|de)?tach-(to|from)-page-/', $_POST['with-selected'])) {
479
                    if (substr($_POST['with-selected'], 0, 6) == 'detach') {
480
                        $page = str_replace('detach-from-page-', '', $_POST['with-selected']);
481
482
                        foreach ($checked as $handle) {
483
                            ResourceManager::detach($resource_type, $handle, $page);
484
                        }
485
                    } else {
486
                        $page = str_replace('attach-to-page-', '', $_POST['with-selected']);
487
488
                        foreach ($checked as $handle) {
489
                            ResourceManager::attach($resource_type, $handle, $page);
490
                        }
491
                    }
492
493
                    if ($canProceed) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $canProceed seems to be never defined.
Loading history...
494
                        redirect(Administration::instance()->getCurrentPageURL());
495
                    }
496
                } elseif (preg_match('/^(at|de)?tach-all-pages$/', $_POST['with-selected'])) {
497
                    $pages = (new PageManager)->select(['id'])->execute()->rows();
498
499
                    if (substr($_POST['with-selected'], 0, 6) == 'detach') {
500
                        foreach ($checked as $handle) {
501
                            foreach ($pages as $page) {
502
                                ResourceManager::detach($resource_type, $handle, $page['id']);
503
                            }
504
                        }
505
                    } else {
506
                        foreach ($checked as $handle) {
507
                            foreach ($pages as $page) {
508
                                ResourceManager::attach($resource_type, $handle, $page['id']);
509
                            }
510
                        }
511
                    }
512
513
                    redirect(Administration::instance()->getCurrentPageURL());
514
                }
515
            }
516
        }
517
    }
518
519
    /**
520
     * Returns the path to the component-template by looking at the
521
     * `WORKSPACE/template/` directory, then at the `TEMPLATES`
522
     * directory for the convention `*.tpl`. If the template
523
     * is not found, false is returned
524
     *
525
     * @param string $name
526
     *  Name of the template
527
     * @return mixed
528
     *  String, which is the path to the template if the template is found,
529
     *  false otherwise
530
     */
531
    protected function getTemplate($name)
532
    {
533
        $format = '%s/%s.tpl';
534
535
        if (file_exists($template = sprintf($format, WORKSPACE . '/template', $name))) {
0 ignored issues
show
Bug introduced by
The constant WORKSPACE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
536
            return $template;
537
        } elseif (file_exists($template = sprintf($format, TEMPLATE, $name))) {
0 ignored issues
show
Bug introduced by
The constant TEMPLATE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
538
            return $template;
539
        } else {
540
            return false;
541
        }
542
    }
543
}
544