Completed
Push — master ( 4c164f...b65673 )
by
unknown
02:10 queued 13s
created

GridFieldRefreshButton::setQueuedJobService()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace BringYourOwnIdeas\Maintenance\Forms;
4
5
use BringYourOwnIdeas\Maintenance\Jobs\CheckForUpdatesJob;
6
use SilverStripe\Core\Convert;
7
use SilverStripe\Core\Injector\Injector;
8
use SilverStripe\Forms\GridField\GridField;
9
use SilverStripe\Forms\GridField\GridField_ActionProvider;
10
use SilverStripe\Forms\GridField\GridField_FormAction;
11
use SilverStripe\Forms\GridField\GridField_HTMLProvider;
12
use SilverStripe\Forms\GridField\GridField_URLHandler;
13
use SilverStripe\View\ArrayData;
14
use SilverStripe\View\Requirements;
15
use Symbiote\QueuedJobs\DataObjects\QueuedJobDescriptor;
16
use Symbiote\QueuedJobs\Services\QueuedJob;
17
use Symbiote\QueuedJobs\Services\QueuedJobService;
18
19
/**
20
 * Adds a "Refresh" button to the bottom or top of a GridField.
21
 *
22
 * @package forms
23
 * @subpackage fields-gridfield
24
 */
25
class GridFieldRefreshButton implements GridField_HTMLProvider, GridField_ActionProvider, GridField_URLHandler
26
{
27
    private static $dependencies = [
0 ignored issues
show
introduced by
The private property $dependencies is not used, and could be removed.
Loading history...
28
        'QueuedJobService' => '%$' . QueuedJobService::class,
29
    ];
30
31
    /**
32
     * @var array
33
     * @config
34
     */
35
    private static $allowed_actions = ["check"];
0 ignored issues
show
introduced by
The private property $allowed_actions is not used, and could be removed.
Loading history...
36
37
    /**
38
     * Fragment to write the button to.
39
     * @var string
40
     */
41
    protected $targetFragment;
42
43
    /**
44
     * @var QueuedJobService
45
     */
46
    protected $queuedJobService;
47
48
    /**
49
     * @param string $targetFragment The HTML fragment to write the button into
50
     */
51
    public function __construct($targetFragment)
52
    {
53
        $this->targetFragment = $targetFragment;
54
    }
55
56
    /**
57
     * @param GridField $gridField
58
     * @return array
59
     */
60
    public function getHTMLFragments($gridField)
61
    {
62
        Requirements::javascript('bringyourownideas/silverstripe-maintenance: client/dist/js/bundle.js');
63
64
        $button = GridField_FormAction::create(
65
            $gridField,
66
            'refresh',
67
            _t(__CLASS__ . '.REFRESH', 'Check for updates'),
68
            'refresh',
69
            null
70
        );
71
72
        $button->addExtraClass('btn btn-primary font-icon-sync');
73
74
        $button->setAttribute('data-check', $gridField->Link('check'));
75
        $button->setAttribute(
76
            'data-message',
77
            _t(
78
                __CLASS__ . '.MESSAGE',
79
                'Updating this list may take 2-3 minutes. You can continue to use the CMS while we run the update.'
80
            )
81
        );
82
83
        if ($this->hasPendingJob()) {
84
            $button->setTitle(_t(__CLASS__ . '.UPDATE', 'Updating...'));
85
            $button->setDisabled(true);
86
        }
87
88
        return [
89
            $this->targetFragment => ArrayData::create(['Button' => $button->Field()])
90
                ->renderWith(__CLASS__)
91
        ];
92
    }
93
94
    /**
95
     * Refresh is an action button.
96
     *
97
     * @param GridField $gridField
98
     *
99
     * @return array
100
     */
101
    public function getActions($gridField)
102
    {
103
        return ['refresh'];
104
    }
105
106
    /**
107
     * Handle the refresh action.
108
     *
109
     * @param GridField $gridField
110
     * @param string $actionName
111
     * @param array $arguments
112
     * @param array $data
113
     *
114
     * @return null
115
     */
116
    public function handleAction(GridField $gridField, $actionName, $arguments, $data)
117
    {
118
        if ($actionName == 'refresh') {
119
            return $this->handleRefresh($gridField);
0 ignored issues
show
Unused Code introduced by
The call to BringYourOwnIdeas\Mainte...Button::handleRefresh() has too many arguments starting with $gridField. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

119
            return $this->/** @scrutinizer ignore-call */ handleRefresh($gridField);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
Bug introduced by
Are you sure the usage of $this->handleRefresh($gridField) targeting BringYourOwnIdeas\Mainte...Button::handleRefresh() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
120
        }
121
    }
122
123
    /**
124
     * Refresh is accessible via the url
125
     *
126
     * @param GridField $gridField
127
     * @return array
128
     */
129
    public function getURLHandlers($gridField)
130
    {
131
        return [
132
            'check' => 'handleCheck'
133
        ];
134
    }
135
136
    /**
137
     * @see hasPendingJob
138
     * @return string JSON encoded value for whether there is a job pending or in process to update the report
139
     */
140
    public function handleCheck()
141
    {
142
        $isRunning = $this->hasPendingJob();
143
        return Convert::raw2json($isRunning);
144
    }
145
146
    /**
147
     * Check the queue for refresh jobs that are not 'done'
148
     * in one manner or another (e.g. stalled or cancelled)
149
     *
150
     * @return boolean
151
     */
152
    public function hasPendingJob()
153
    {
154
        // We care about any queued job in the immediate queue, or any queue if the job is already running
155
        /** @var QueuedJobDescriptor $immediateJob */
156
        $immediateJob = $this->getQueuedJobService()
157
            ->getJobList(QueuedJob::IMMEDIATE)
158
            ->filter([
159
                'Implementation' => CheckForUpdatesJob::class
160
            ])
161
            ->exclude([
162
                'JobStatus' => [
163
                    QueuedJob::STATUS_COMPLETE,
164
                    QueuedJob::STATUS_CANCELLED,
165
                    QueuedJob::STATUS_BROKEN
166
                ]
167
            ]);
168
169
        /** @var QueuedJobDescriptor $runningJob */
170
        $runningJob = QueuedJobDescriptor::get()
171
            ->filter([
172
                'Implementation' => CheckForUpdatesJob::class,
173
                'JobStatus' => QueuedJob::STATUS_RUN,
174
            ]);
175
176
        return $immediateJob->exists() || $runningJob->exists();
177
    }
178
179
    /**
180
     * Handle the refresh, for both the action button and the URL
181
     */
182
    public function handleRefresh()
183
    {
184
        if ($this->hasPendingJob()) {
185
            return;
186
        }
187
188
        // Queue the job in the immediate queue
189
        $job = Injector::inst()->create(CheckForUpdatesJob::class);
190
        $jobDescriptorId = $this->getQueuedJobService()->queueJob($job, null, null, QueuedJob::IMMEDIATE);
191
192
        // Check the job descriptor on the queue
193
        $jobDescriptor = QueuedJobDescriptor::get()->filter('ID', $jobDescriptorId)->first();
194
195
        // If the job is not immediate, change it to immediate and reschedule it to occur immediately
196
        if ($jobDescriptor->JobType !== QueuedJob::IMMEDIATE) {
197
            $jobDescriptor->JobType = QueuedJob::IMMEDIATE;
198
            $jobDescriptor->StartAfter = null;
199
            $jobDescriptor->write();
200
        }
201
    }
202
203
    /**
204
     * @return QueuedJobService
205
     */
206
    public function getQueuedJobService()
207
    {
208
        return $this->queuedJobService;
209
    }
210
211
    /**
212
     * @param QueuedJobService $queuedJobService
213
     * @return $this
214
     */
215
    public function setQueuedJobService(QueuedJobService $queuedJobService)
216
    {
217
        $this->queuedJobService = $queuedJobService;
218
        return $this;
219
    }
220
}
221