Passed
Pull Request — 4 (#10242)
by Nicolaas
10:58 queued 03:37
created

TaskRunner::index()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 51
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 32
c 1
b 0
f 0
nc 8
nop 1
dl 0
loc 51
rs 8.7857

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace SilverStripe\Dev;
4
5
use ReflectionClass;
6
use SilverStripe\Control\Controller;
7
use SilverStripe\Control\Director;
8
use SilverStripe\Control\HTTPRequest;
9
use SilverStripe\Core\ClassInfo;
10
use SilverStripe\Core\Config\Configurable;
11
use SilverStripe\Core\Convert;
12
use SilverStripe\Core\Injector\Injector;
13
use SilverStripe\Core\Manifest\ModuleResourceLoader;
14
use SilverStripe\ORM\ArrayList;
15
use SilverStripe\Security\Permission;
16
use SilverStripe\Security\Security;
17
use SilverStripe\View\ArrayData;
18
use SilverStripe\View\ViewableData;
19
20
class TaskRunner extends Controller
21
{
22
23
    use Configurable;
24
25
    private static $url_handlers = [
0 ignored issues
show
introduced by
The private property $url_handlers is not used, and could be removed.
Loading history...
26
        '' => 'index',
27
        '$TaskName' => 'runTask'
28
    ];
29
30
    private static $allowed_actions = [
0 ignored issues
show
introduced by
The private property $allowed_actions is not used, and could be removed.
Loading history...
31
        'index',
32
        'runTask',
33
    ];
34
35
    /**
36
     * @var array
37
     */
38
    private static $css = [
0 ignored issues
show
introduced by
The private property $css is not used, and could be removed.
Loading history...
39
        'silverstripe/framework:client/styles/task-runner.css',
40
    ];
41
42
    protected function init()
43
    {
44
        parent::init();
45
46
        $allowAllCLI = DevelopmentAdmin::config()->get('allow_all_cli');
47
        $canAccess = (
48
            Director::isDev()
49
            // We need to ensure that DevelopmentAdminTest can simulate permission failures when running
50
            // "dev/tasks" from CLI.
51
            || (Director::is_cli() && $allowAllCLI)
52
            || Permission::check("ADMIN")
53
        );
54
        if (!$canAccess) {
55
            Security::permissionFailure($this);
56
        }
57
    }
58
59
    /**
60
     * list of options - can be filtered by adding the `q` request variable (e.g. `/dev/tasks/?q=test` OR `vendor/bin/sake dev/tasks q=test`)
61
     * @param  HTTPRequest $index
62
     * @return DBHTMLText|string - depends on whether it is `Director::is_cli()` request (returns string) or not (returns DBHTMLText)
0 ignored issues
show
Bug introduced by
The type SilverStripe\Dev\DBHTMLText was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
63
     */
64
    public function index($request = null)
65
    {
66
        $baseUrl = Director::absoluteBaseURL();
67
        $tasks = $this->getTasks();
68
        $filter = (string) trim($request->requestVar('q'));
69
        if($filter) {
70
            $tasks = array_filter(
71
                $tasks,
72
                function ($v) use ($filter) {
73
                    $t = $v['title'] ?? '';
74
                    $d = $v['description'] ?? '';
75
                    return
76
                        stripos((string) $t, $filter) !== false &&
77
                        stripos((string) $d, $filter) !== false;
78
                }
79
            );
80
        }
81
82
        if (Director::is_cli()) {
83
            // CLI mode
84
            $output = 'SILVERSTRIPE DEVELOPMENT TOOLS: Tasks' . PHP_EOL . '--------------------------' . PHP_EOL . PHP_EOL;
85
86
            foreach ($tasks as $task) {
87
                $output .= sprintf(' * %s: sake dev/tasks/%s%s', $task['title'], $task['segment'], PHP_EOL);
88
            }
89
90
            return $output;
91
        }
92
93
        $list = ArrayList::create();
94
95
        foreach ($tasks as $task) {
96
            $list->push(ArrayData::create([
97
                'TaskLink' => $baseUrl . 'dev/tasks/' . $task['segment'],
98
                'Title' => $task['title'],
99
                'Description' => $task['description'],
100
            ]));
101
        }
102
103
        $renderer = DebugView::create();
104
        $header = $renderer->renderHeader();
105
        $header = $this->addCssToHeader($header);
106
107
        $data = [
108
            'Tasks' => $list,
109
            'Header' => $header,
110
            'Footer' => $renderer->renderFooter(),
111
            'Info' => $renderer->renderInfo('SilverStripe Development Tools: Tasks', $baseUrl),
112
        ];
113
114
        return ViewableData::create()->renderWith(static::class, $data);
115
    }
116
117
    /**
118
     * Runs a BuildTask
119
     * @param HTTPRequest $request
120
     */
121
    public function runTask($request)
122
    {
123
        $name = $request->param('TaskName');
124
        $tasks = $this->getTasks();
125
126
        $title = function ($content) {
127
            printf(Director::is_cli() ? "%s\n\n" : '<h1>%s</h1>', $content);
128
        };
129
130
        $message = function ($content) {
131
            printf(Director::is_cli() ? "%s\n" : '<p>%s</p>', $content);
132
        };
133
134
        foreach ($tasks as $task) {
135
            if ($task['segment'] == $name) {
136
                /** @var BuildTask $inst */
137
                $inst = Injector::inst()->create($task['class']);
138
                $title(sprintf('Running Task %s', $inst->getTitle()));
139
140
                if (!$inst->isEnabled()) {
141
                    $message('The task is disabled');
142
                    return;
143
                }
144
145
                $inst->run($request);
146
                return;
147
            }
148
        }
149
150
        $message(sprintf('The build task "%s" could not be found', Convert::raw2xml($name)));
151
    }
152
153
    /**
154
     * @return array Array of associative arrays for each task (Keys: 'class', 'title', 'description')
155
     */
156
    protected function getTasks()
157
    {
158
        $availableTasks = [];
159
160
        $taskClasses = ClassInfo::subclassesFor(BuildTask::class);
161
        // remove the base class
162
        array_shift($taskClasses);
163
164
        foreach ($taskClasses as $class) {
165
            if (!$this->taskEnabled($class)) {
166
                continue;
167
            }
168
169
            $singleton = BuildTask::singleton($class);
170
            $description = $singleton->getDescription();
171
            $description = trim($description);
172
173
            $desc = (Director::is_cli())
174
                ? Convert::html2raw($description)
175
                : $description;
176
177
            $availableTasks[] = [
178
                'class' => $class,
179
                'title' => $singleton->getTitle(),
180
                'segment' => $singleton->config()->segment ?: str_replace('\\', '-', $class),
181
                'description' => $desc,
182
            ];
183
        }
184
185
        return $availableTasks;
186
    }
187
188
    /**
189
     * @param string $class
190
     * @return boolean
191
     */
192
    protected function taskEnabled($class)
193
    {
194
        $reflectionClass = new ReflectionClass($class);
195
        if ($reflectionClass->isAbstract()) {
196
            return false;
197
        } elseif (!singleton($class)->isEnabled()) {
198
            return false;
199
        }
200
201
        return true;
202
    }
203
204
    /**
205
     * Inject task runner CSS into the heaader
206
207
     * @param string $header
208
     * @return string
209
     */
210
    protected function addCssToHeader($header)
211
    {
212
        $css = (array) $this->config()->get('css');
213
214
        if (!$css) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $css of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
215
            return $header;
216
        }
217
218
        foreach ($css as $include) {
219
            $path = ModuleResourceLoader::singleton()->resolveURL($include);
220
221
            // inject CSS into the heaader
222
            $element = sprintf('<link rel="stylesheet" type="text/css" href="%s" />', $path);
223
            $header = str_replace('</head>', $element . '</head>', $header);
224
        }
225
226
        return $header;
227
    }
228
}
229