Passed
Push — 4 ( c14394...7c8417 )
by Garion
06:21
created

TaskRunner::addCssToHeader()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 1
dl 0
loc 17
rs 10
c 0
b 0
f 0
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
    public function index()
60
    {
61
        $baseUrl = Director::absoluteBaseURL();
62
        $tasks = $this->getTasks();
63
64
        if (Director::is_cli()) {
65
            // CLI mode
66
            $output = 'SILVERSTRIPE DEVELOPMENT TOOLS: Tasks' . PHP_EOL . '--------------------------' . PHP_EOL . PHP_EOL;
67
68
            foreach ($tasks as $task) {
69
                $output .= sprintf(' * %s: sake dev/tasks/%s%s', $task['title'], $task['segment'], PHP_EOL);
70
            }
71
72
            return $output;
73
        }
74
75
        $list = ArrayList::create();
76
77
        foreach ($tasks as $task) {
78
            $list->push(ArrayData::create([
79
                'TaskLink' => $baseUrl . 'dev/tasks/' . $task['segment'],
80
                'Title' => $task['title'],
81
                'Description' => $task['description'],
82
            ]));
83
        }
84
85
        $renderer = DebugView::create();
86
        $header = $renderer->renderHeader();
87
        $header = $this->addCssToHeader($header);
88
89
        $data = [
90
            'Tasks' => $list,
91
            'Header' => $header,
92
            'Footer' => $renderer->renderFooter(),
93
            'Info' => $renderer->renderInfo('SilverStripe Development Tools: Tasks', $baseUrl),
94
        ];
95
96
        return ViewableData::create()->renderWith(static::class, $data);
97
    }
98
99
    /**
100
     * Runs a BuildTask
101
     * @param HTTPRequest $request
102
     */
103
    public function runTask($request)
104
    {
105
        $name = $request->param('TaskName');
106
        $tasks = $this->getTasks();
107
108
        $title = function ($content) {
109
            printf(Director::is_cli() ? "%s\n\n" : '<h1>%s</h1>', $content);
110
        };
111
112
        $message = function ($content) {
113
            printf(Director::is_cli() ? "%s\n" : '<p>%s</p>', $content);
114
        };
115
116
        foreach ($tasks as $task) {
117
            if ($task['segment'] == $name) {
118
                /** @var BuildTask $inst */
119
                $inst = Injector::inst()->create($task['class']);
120
                $title(sprintf('Running Task %s', $inst->getTitle()));
121
122
                if (!$inst->isEnabled()) {
123
                    $message('The task is disabled');
124
                    return;
125
                }
126
127
                $inst->run($request);
128
                return;
129
            }
130
        }
131
132
        $message(sprintf('The build task "%s" could not be found', Convert::raw2xml($name)));
133
    }
134
135
    /**
136
     * @return array Array of associative arrays for each task (Keys: 'class', 'title', 'description')
137
     */
138
    protected function getTasks()
139
    {
140
        $availableTasks = [];
141
142
        $taskClasses = ClassInfo::subclassesFor(BuildTask::class);
143
        // remove the base class
144
        array_shift($taskClasses);
145
146
        foreach ($taskClasses as $class) {
147
            if (!$this->taskEnabled($class)) {
148
                continue;
149
            }
150
151
            $singleton = BuildTask::singleton($class);
152
            $description = $singleton->getDescription();
153
            $description = trim($description);
154
155
            $desc = (Director::is_cli())
156
                ? Convert::html2raw($description)
157
                : $description;
158
159
            $availableTasks[] = [
160
                'class' => $class,
161
                'title' => $singleton->getTitle(),
162
                'segment' => $singleton->config()->segment ?: str_replace('\\', '-', $class),
163
                'description' => $desc,
164
            ];
165
        }
166
167
        return $availableTasks;
168
    }
169
170
    /**
171
     * @param string $class
172
     * @return boolean
173
     */
174
    protected function taskEnabled($class)
175
    {
176
        $reflectionClass = new ReflectionClass($class);
177
        if ($reflectionClass->isAbstract()) {
178
            return false;
179
        } elseif (!singleton($class)->isEnabled()) {
180
            return false;
181
        }
182
183
        return true;
184
    }
185
186
    /**
187
     * Inject task runner CSS into the heaader
188
189
     * @param string $header
190
     * @return string
191
     */
192
    protected function addCssToHeader($header)
193
    {
194
        $css = (array) $this->config()->get('css');
195
196
        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...
197
            return $header;
198
        }
199
200
        foreach ($css as $include) {
201
            $path = ModuleResourceLoader::singleton()->resolveURL($include);
202
203
            // inject CSS into the heaader
204
            $element = sprintf('<link rel="stylesheet" type="text/css" href="%s" />', $path);
205
            $header = str_replace('</head>', $element . '</head>', $header);
206
        }
207
208
        return $header;
209
    }
210
}
211