GridFieldRefreshButton::getHTMLFragments()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 31
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 20
nc 2
nop 1
dl 0
loc 31
rs 9.6
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);
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Core\Convert::raw2json() has been deprecated: 4.4.0:5.0.0 Use json_encode() instead ( Ignorable by Annotation )

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

143
        return /** @scrutinizer ignore-deprecated */ Convert::raw2json($isRunning);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
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);
0 ignored issues
show
Bug introduced by
Symbiote\QueuedJobs\Services\QueuedJob::IMMEDIATE of type string is incompatible with the type integer|null expected by parameter $queueName of Symbiote\QueuedJobs\Serv...dJobService::queueJob(). ( Ignorable by Annotation )

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

190
        $jobDescriptorId = $this->getQueuedJobService()->queueJob($job, null, null, /** @scrutinizer ignore-type */ QueuedJob::IMMEDIATE);
Loading history...
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