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
Pull Request — master (#342)
by
unknown
14:18
created

WorkflowApplicable::onAfterWrite()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 8.8571
c 0
b 0
f 0
cc 6
eloc 10
nc 4
nop 0
1
<?php
2
3
namespace Symbiote\AdvancedWorkflow\Extensions;
4
5
use SilverStripe\Control\Controller;
6
use SilverStripe\Control\Director;
7
use SilverStripe\Forms\DropdownField;
8
use SilverStripe\Forms\FieldList;
9
use SilverStripe\Forms\FormAction;
10
use SilverStripe\Forms\GridField\GridField;
11
use SilverStripe\Forms\GridField\GridFieldConfig_Base;
12
use SilverStripe\Forms\GridField\GridFieldDetailForm;
13
use SilverStripe\Forms\GridField\GridFieldEditButton;
14
use SilverStripe\Forms\HiddenField;
15
use SilverStripe\Forms\ListboxField;
16
use SilverStripe\Forms\ReadonlyField;
17
use SilverStripe\Forms\Tab;
18
use SilverStripe\Forms\TabSet;
19
use SilverStripe\ORM\CMSPreviewable;
20
use SilverStripe\ORM\DataExtension;
21
use SilverStripe\Security\Permission;
22
use SilverStripe\Security\Security;
23
use Symbiote\AdvancedWorkflow\DataObjects\WorkflowDefinition;
24
use Symbiote\AdvancedWorkflow\DataObjects\WorkflowInstance;
25
use Symbiote\AdvancedWorkflow\Services\WorkflowService;
26
use Symbiote\QueuedJobs\Service\AbstractQueuedJob;
27
28
/**
29
 * DataObjects that have the WorkflowApplicable extension can have a
30
 * workflow definition applied to them. At some point, the workflow definition is then
31
 * triggered.
32
 *
33
 * @author  [email protected]
34
 * @license BSD License (http://silverstripe.org/bsd-license/)
35
 * @package advancedworkflow
36
 */
37
class WorkflowApplicable extends DataExtension
38
{
39
    private static $has_one = [
0 ignored issues
show
Unused Code introduced by
The property $has_one is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
40
        'WorkflowDefinition' => WorkflowDefinition::class,
41
    ];
42
43
    private static $many_many = [
0 ignored issues
show
Unused Code introduced by
The property $many_many is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
44
        'AdditionalWorkflowDefinitions' => WorkflowDefinition::class
45
    ];
46
47
    private static $dependencies = [
0 ignored issues
show
Unused Code introduced by
The property $dependencies is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
48
        'workflowService' => '%$' . WorkflowService::class,
49
    ];
50
51
    /**
52
     * Temporary record of items having workflow applied / removed to it.
53
     * These records should not have canPublish() = false immediately applied until refreshed.
54
     *
55
     * @var array
56
     */
57
    protected static $itemsChangingWorkflow = [];
58
59
    /**
60
     *
61
     * Used to flag to this extension if there's a WorkflowPublishTargetJob running.
62
     * @var boolean
63
     */
64
    public $isPublishJobRunning = false;
65
66
    /**
67
     *
68
     * @param boolean $truth
69
     */
70
    public function setIsPublishJobRunning($truth)
71
    {
72
        $this->isPublishJobRunning = $truth;
73
    }
74
75
    /**
76
     *
77
     * @return boolean
78
     */
79
    public function getIsPublishJobRunning()
80
    {
81
        return $this->isPublishJobRunning;
82
    }
83
84
    /**
85
     *
86
     * @see {@link $this->isPublishJobRunning}
87
     * @return boolean
88
     */
89
    public function isPublishJobRunning()
90
    {
91
        $propIsSet = $this->getIsPublishJobRunning() ? true : false;
92
        return class_exists(AbstractQueuedJob::class) && $propIsSet;
93
    }
94
95
    /**
96
     * @var WorkflowService
97
     */
98
    public $workflowService;
99
100
    /**
101
     *
102
     * A cache var for the current workflow instance
103
     *
104
     * @var WorkflowInstance
105
     */
106
    protected $currentInstance;
107
108
    public function updateSettingsFields(FieldList $fields)
109
    {
110
        $this->updateFields($fields);
111
    }
112
113
    public function updateCMSFields(FieldList $fields)
114
    {
115
        if (!$this->owner->hasMethod('getSettingsFields')) {
116
            $this->updateFields($fields);
117
        }
118
119
        // Instantiate a hidden form field to pass the triggered workflow definition through,
120
        // allowing a dynamic form action.
121
122
        $fields->push(HiddenField::create(
123
            'TriggeredWorkflowID'
124
        ));
125
    }
126
127
    public function updateFields(FieldList $fields)
128
    {
129
        if (!$this->owner->ID) {
130
            return $fields;
131
        }
132
133
        $tab = $fields->fieldByName('Root') ? $fields->findOrMakeTab('Root.Workflow') : $fields;
134
135
        if (Permission::check('APPLY_WORKFLOW')) {
136
            $definition = new DropdownField(
137
                'WorkflowDefinitionID',
138
                _t('WorkflowApplicable.DEFINITION', 'Applied Workflow')
139
            );
140
            $definitions = $this->workflowService->getDefinitions()->map()->toArray();
141
            $definition->setSource($definitions);
142
            $definition->setEmptyString(_t('WorkflowApplicable.INHERIT', 'Inherit from parent'));
143
            $tab->push($definition);
144
145
            // Allow an optional selection of additional workflow definitions.
146
147
            if ($this->owner->WorkflowDefinitionID) {
148
                $fields->removeByName('AdditionalWorkflowDefinitions');
149
                unset($definitions[$this->owner->WorkflowDefinitionID]);
150
                $tab->push($additional = ListboxField::create(
151
                    'AdditionalWorkflowDefinitions',
152
                    _t('WorkflowApplicable.ADDITIONAL_WORKFLOW_DEFINITIONS', 'Additional Workflows')
153
                ));
154
                $additional->setSource($definitions);
155
            }
156
        }
157
158
        // Display the effective workflow definition.
159
160
        if ($effective = $this->getWorkflowInstance()) {
161
            $title = $effective->Definition()->Title;
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<Symbiote\Advanced...cts\WorkflowDefinition>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
162
            $tab->push(ReadonlyField::create(
163
                'EffectiveWorkflow',
164
                _t('WorkflowApplicable.EFFECTIVE_WORKFLOW', 'Effective Workflow'),
165
                $title
166
            ));
167
        }
168
169
        if ($this->owner->ID) {
170
            $config = new GridFieldConfig_Base();
171
            $config->addComponent(new GridFieldEditButton());
172
            $config->addComponent(new GridFieldDetailForm());
173
174
            $insts = $this->owner->WorkflowInstances();
175
            $log = new GridField(
176
                'WorkflowLog',
177
                _t('WorkflowApplicable.WORKFLOWLOG', 'Workflow Log'),
178
                $insts,
179
                $config
180
            );
181
182
            $tab->push($log);
183
        }
184
    }
185
186
    public function updateCMSActions(FieldList $actions)
187
    {
188
        $active = $this->workflowService->getWorkflowFor($this->owner);
189
        $c = Controller::curr();
190
        if ($c && $c->hasExtension(AdvancedWorkflowExtension::class)) {
191
            if ($active) {
192
                if ($this->canEditWorkflow()) {
193
                    $workflowOptions = new Tab(
194
                        'WorkflowOptions',
195
                        _t(
196
                            'SiteTree.WorkflowOptions',
197
                            'Workflow options',
198
                            'Expands a view for workflow specific buttons'
199
                        )
200
                    );
201
202
                    $menu = $actions->fieldByName('ActionMenus');
203
                    if (!$menu) {
204
                        // create the menu for adding to any arbitrary non-sitetree object
205
                        $menu = $this->createActionMenu();
206
                        $actions->push($menu);
207
                    }
208
209
                    if (!$actions->fieldByName('ActionMenus.WorkflowOptions')) {
210
                        $menu->push($workflowOptions);
211
                    }
212
213
                    $transitions = $active->CurrentAction()->getValidTransitions();
214
215
                    foreach ($transitions as $transition) {
216
                        if ($transition->canExecute($active)) {
217
                            $action = FormAction::create('updateworkflow-' . $transition->ID, $transition->Title)
218
                                ->setAttribute('data-transitionid', $transition->ID);
219
                            $workflowOptions->push($action);
220
                        }
221
                    }
222
223
                    // $action = FormAction::create('updateworkflow', $active->CurrentAction() ?
0 ignored issues
show
Unused Code Comprehensibility introduced by
53% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
224
                    // $active->CurrentAction()->Title :
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
225
                    // _t('WorkflowApplicable.UPDATE_WORKFLOW', 'Update Workflow'))
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
226
                    //  ->setAttribute('data-icon', 'navigation');
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
227
228
                    // $actions->fieldByName('MajorActions') ?
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
229
                    // $actions->fieldByName('MajorActions')->push($action) :
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
230
                    // $actions->push($action);
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
231
                }
232
            } else {
233
                // Instantiate the workflow definition initial actions.
234
                $definitions = $this->workflowService->getDefinitionsFor($this->owner);
235
                if ($definitions) {
236
                    $menu = $actions->fieldByName('ActionMenus');
237
                    if (is_null($menu)) {
238
                        // Instantiate a new action menu for any data objects.
239
240
                        $menu = $this->createActionMenu();
241
                        $actions->push($menu);
242
                    }
243
                    $tab = Tab::create(
244
                        'AdditionalWorkflows'
245
                    );
246
                    $addedFirst = false;
247
                    foreach ($definitions as $definition) {
248
                        if ($definition->getInitialAction() && $this->owner->canEdit()) {
249
                            $action = FormAction::create(
250
                                "startworkflow-{$definition->ID}",
251
                                $definition->InitialActionButtonText ?
252
                                    $definition->InitialActionButtonText :
253
                                    $definition->getInitialAction()->Title
254
                            )
255
                                ->addExtraClass('start-workflow')
256
                                ->setAttribute('data-workflow', $definition->ID)
257
                                ->addExtraClass('btn-primary');
258
259
                            // The first element is the main workflow definition,
260
                            // and will be displayed as a major action.
261
                            if (!$addedFirst) {
262
                                $addedFirst = true;
263
                                $action->setAttribute('data-icon', 'navigation');
264
                                $majorActions = $actions->fieldByName('MajorActions');
265
                                $majorActions ? $majorActions->push($action) : $actions->push($action);
266
                            } else {
267
                                $tab->push($action);
268
                            }
269
                        }
270
                    }
271
                    // Only display menu if actions pushed to it
272
                    if ($tab->Fields()->exists()) {
273
                        $menu->insertBefore($tab, 'MoreOptions');
274
                    }
275
                }
276
            }
277
        }
278
    }
279
280
    protected function createActionMenu()
281
    {
282
        $rootTabSet = new TabSet('ActionMenus');
283
        $rootTabSet->addExtraClass('ss-ui-action-tabset action-menus');
284
        return $rootTabSet;
285
    }
286
287
    /**
288
     * Included in CMS-generated email templates for a NotifyUsersWorkflowAction.
289
     * Returns an absolute link to the CMS UI for a Page object
290
     *
291
     * @return string|null
292
     */
293
    public function AbsoluteEditLink()
294
    {
295
        $CMSEditLink = null;
296
297
        if ($this->owner instanceof CMSPreviewable) {
298
            $CMSEditLink = $this->owner->CMSEditLink();
299
        } elseif ($this->owner->hasMethod('WorkflowLink')) {
300
            $CMSEditLink = $this->owner->WorkflowLink();
301
        }
302
303
        if ($CMSEditLink === null) {
304
            return null;
305
        }
306
307
        return Controller::join_links(Director::absoluteBaseURL(), $CMSEditLink);
308
    }
309
310
    /**
311
     * Included in CMS-generated email templates for a NotifyUsersWorkflowAction.
312
     * Allows users to select a link in an email for direct access to the transition-selection dropdown in the CMS UI.
313
     *
314
     * @return string
315
     */
316
    public function LinkToPendingItems()
317
    {
318
        $urlBase = Director::absoluteBaseURL();
319
        $urlFrag = 'admin/workflows/WorkflowDefinition/EditForm/field';
320
        $urlInst = $this->getWorkflowInstance();
321
        return Controller::join_links($urlBase, $urlFrag, 'PendingObjects', 'item', $urlInst->ID, 'edit');
322
    }
323
324
    /**
325
     * After a workflow item is written, we notify the
326
     * workflow so that it can take action if needbe
327
     */
328
    public function onAfterWrite()
329
    {
330
        // Record changes to the workflow on this record
331
        $changed = $this->owner->getChangedFields(['WorkflowDefinitionID']);
332
        if (isset($changed['WorkflowDefinitionID']) &&
333
            (
334
                empty($changed['WorkflowDefinitionID']['before'])
335
                || empty($changed['WorkflowDefinitionID']['before'])
336
            )
337
        ) {
338
            $key = $this->owner->baseClass() . '#' . $this->owner->ID;
339
            static::$itemsChangingWorkflow[$key] = true;
340
        }
341
342
        // Get workflow instance
343
        $instance = $this->getWorkflowInstance();
344
        if ($instance && $instance->CurrentActionID) {
0 ignored issues
show
Documentation introduced by
The property CurrentActionID does not exist on object<Symbiote\Advanced...jects\WorkflowInstance>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
345
            $action = $instance->CurrentAction()->BaseAction()->targetUpdated($instance);
0 ignored issues
show
Documentation Bug introduced by
The method BaseAction does not exist on object<Symbiote\Advanced...WorkflowActionInstance>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
Unused Code introduced by
$action is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
346
        }
347
    }
348
349
    public function WorkflowInstances()
350
    {
351
        return WorkflowInstance::get()->filter([
352
            'TargetClass' => $this->owner->baseClass(),
353
            'TargetID' => $this->owner->ID
354
        ]);
355
    }
356
357
    /**
358
     * Gets the current instance of workflow
359
     *
360
     * @return WorkflowInstance
361
     */
362
    public function getWorkflowInstance()
363
    {
364
        if (!$this->currentInstance) {
365
            $this->currentInstance = $this->workflowService->getWorkflowFor($this->owner);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->workflowService->...rkflowFor($this->owner) can also be of type object<SilverStripe\ORM\DataObject>. However, the property $currentInstance is declared as type object<Symbiote\Advanced...jects\WorkflowInstance>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
366
        }
367
368
        return $this->currentInstance;
369
    }
370
371
372
    /**
373
     * Gets the history of a workflow instance
374
     *
375
     * @return DataObjectSet
376
     */
377
    public function getWorkflowHistory($limit = null)
378
    {
379
        return $this->workflowService->getWorkflowHistoryFor($this->owner, $limit);
380
    }
381
382
    /**
383
     * Check all recent WorkflowActionIntances and return the most recent one with a Comment
384
     *
385
     * @param int $limit
386
     * @return WorkflowActionInstance|null
387
     */
388
    public function RecentWorkflowComment($limit = 10)
389
    {
390
        if ($actions = $this->getWorkflowHistory($limit)) {
391
            foreach ($actions as $action) {
392
                if ($action->Comment != '') {
393
                    return $action;
394
                }
395
            }
396
        }
397
    }
398
399
    /**
400
     * Content can never be directly publishable if there's a workflow applied.
401
     *
402
     * If there's an active instance, then it 'might' be publishable
403
     */
404
    public function canPublish()
405
    {
406
        // Ignore canPublish() if in the middle of having workflow added / removed
407
        $key = $this->owner->baseClass() . '#' . $this->owner->ID;
408
        if (isset(static::$itemsChangingWorkflow[$key])) {
409
            return null;
410
        }
411
412
        // Override any default behaviour, to allow queuedjobs to complete
413
        if ($this->isPublishJobRunning()) {
414
            return true;
415
        }
416
417
        if ($active = $this->getWorkflowInstance()) {
418
            $publish = $active->canPublishTarget($this->owner);
0 ignored issues
show
Unused Code introduced by
The call to WorkflowInstance::canPublishTarget() has too many arguments starting with $this->owner.

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.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
419
            if (!is_null($publish)) {
420
                return $publish;
421
            }
422
        }
423
424
        // use definition to determine if publishing directly is allowed
425
        $definition = $this->workflowService->getDefinitionFor($this->owner);
426
427
        if ($definition) {
428
            if (!Security::getCurrentUser()) {
429
                return false;
430
            }
431
            $member = Security::getCurrentUser();
432
433
            $canPublish = $definition->canWorkflowPublish($member, $this->owner);
434
435
            return $canPublish;
436
        }
437
    }
438
439
    /**
440
     * Can only edit content that's NOT in another person's content changeset
441
     */
442
    public function canEdit($member)
443
    {
444
        // Override any default behaviour, to allow queuedjobs to complete
445
        if ($this->isPublishJobRunning()) {
446
            return true;
447
        }
448
449
        if ($active = $this->getWorkflowInstance()) {
450
            return $active->canEditTarget($this->owner);
0 ignored issues
show
Unused Code introduced by
The call to WorkflowInstance::canEditTarget() has too many arguments starting with $this->owner.

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.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
451
        }
452
    }
453
454
    /**
455
     * Can a user edit the current workflow attached to this item?
456
     */
457
    public function canEditWorkflow()
458
    {
459
        $active = $this->getWorkflowInstance();
460
        if ($active) {
461
            return $active->canEdit();
462
        }
463
        return false;
464
    }
465
}
466