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.

WorkflowInstance   F
last analyzed

Complexity

Total Complexity 97

Size/Duplication

Total Lines 788
Duplicated Lines 1.78 %

Coupling/Cohesion

Components 1
Dependencies 28

Importance

Changes 0
Metric Value
wmc 97
lcom 1
cbo 28
dl 14
loc 788
rs 1.812
c 0
b 0
f 0

30 Methods

Rating   Name   Duplication   Size   Complexity  
B getCMSFields() 0 52 7
A fieldLabels() 0 10 1
A onBeforeWrite() 0 12 2
B updateWorkflow() 0 25 6
B getTarget() 0 22 8
A Target() 0 4 1
A getTargetDiff() 0 17 2
B beginWorkflow() 0 32 7
B execute() 0 48 7
A checkTransitions() 0 9 3
A performTransition() 0 32 2
A getAssignedMembers() 14 14 2
A canView() 0 21 4
A canEdit() 0 9 2
A canDelete() 0 12 3
B userHasAccess() 0 27 9
A canEditTarget() 0 6 3
A canViewTarget() 0 8 2
A canPublishTarget() 0 6 3
A validTransitions() 0 10 1
A getWorkflowFields() 0 16 1
A getFrontEndWorkflowFields() 0 9 1
A getFrontEndWorkflowActions() 0 33 5
A getFrontEndDataObject() 0 7 1
A getFrontEndRequiredFields() 0 7 1
A setFrontendFormRequirements() 0 5 1
A doFrontEndAction() 0 5 1
A getVersionedConnection() 0 13 2
A getCurrentAction() 0 13 2
B getMostRecentActionForUser() 0 30 7

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like WorkflowInstance often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use WorkflowInstance, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Symbiote\AdvancedWorkflow\DataObjects;
4
5
use Exception;
6
use SilverStripe\Control\Controller;
7
use SilverStripe\Control\HTTPRequest;
8
use SilverStripe\Core\Injector\Injector;
9
use SilverStripe\Forms\CheckboxSetField;
10
use SilverStripe\Forms\DropdownField;
11
use SilverStripe\Forms\FieldList;
12
use SilverStripe\Forms\Form;
13
use SilverStripe\Forms\FormAction;
14
use SilverStripe\Forms\GridField\GridField;
15
use SilverStripe\Forms\HeaderField;
16
use SilverStripe\Forms\HiddenField;
17
use SilverStripe\Forms\Tab;
18
use SilverStripe\Forms\TabSet;
19
use SilverStripe\Forms\TreeMultiselectField;
20
use SilverStripe\ORM\ArrayList;
21
use SilverStripe\ORM\DataObject;
22
use SilverStripe\ORM\Queries\SQLSelect;
23
use SilverStripe\Security\Group;
24
use SilverStripe\Security\Member;
25
use SilverStripe\Security\Permission;
26
use SilverStripe\Security\Security;
27
use SilverStripe\Versioned\DataDifferencer;
28
use SilverStripe\Versioned\Versioned;
29
use Symbiote\AdvancedWorkflow\Actions\AssignUsersToWorkflowAction;
30
use Symbiote\AdvancedWorkflow\Extensions\WorkflowApplicable;
31
use Symbiote\AdvancedWorkflow\Extensions\FileWorkflowApplicable;
32
use Symbiote\AdvancedWorkflow\Services\WorkflowService;
33
34
/**
35
 * A WorkflowInstance is created whenever a user 'starts' a workflow.
36
 *
37
 * This 'start' is triggered automatically when the user clicks the relevant
38
 * button (eg 'apply for approval'). This creates a standalone object
39
 * that maintains the state of the workflow process.
40
 *
41
 * @method WorkflowDefinition Definition()
42
 * @method WorkflowActionInstance CurrentAction()
43
 * @method Member Initiator()
44
 *
45
 * @author  [email protected]
46
 * @license BSD License (http://silverstripe.org/bsd-license/)
47
 * @package advancedworkflow
48
 */
49
class WorkflowInstance extends DataObject
50
{
51
    private static $db = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
52
        'Title'             => 'Varchar(128)',
53
        'WorkflowStatus'    => "Enum('Active,Paused,Complete,Cancelled','Active')",
54
        'TargetClass'       => 'Varchar(255)',
55
        'TargetID'          => 'Int',
56
    );
57
58
    private static $has_one = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
59
        'Definition'    => WorkflowDefinition::class,
60
        'CurrentAction' => WorkflowActionInstance::class,
61
        'Initiator'     => Member::class,
62
    );
63
64
    private static $has_many = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
65
        'Actions' => WorkflowActionInstance::class,
66
    );
67
68
    /**
69
     * The list of users who are responsible for performing the current WorkflowAction
70
     *
71
     * @var array
72
     */
73
    private static $many_many = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
74
        'Users'  => Member::class,
75
        'Groups' => Group::class,
76
    );
77
78
    private static $summary_fields = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
79
        'Title',
80
        'WorkflowStatus',
81
        'Created'
82
    );
83
84
    private static $default_sort = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
85
        '"Created"' => 'DESC'
86
    );
87
88
    /**
89
     * If set to true, actions that cannot be executed by the user will not show
90
     * on the frontend (just like the backend).
91
     *
92
     * @var boolean
93
     */
94
    private static $hide_disabled_actions_on_frontend = false;
95
96
    /**
97
     * Fields to ignore when generating a diff for data objects.
98
     */
99
    private static $diff_ignore_fields = array(
100
        'LastEdited',
101
        'Created',
102
        'workflowService',
103
        'ParentID',
104
        'Sort',
105
        'PublishJobID',
106
        'UnPublishJobID'
107
    );
108
109
    private static $table_name = 'WorkflowInstance';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
110
111
    /**
112
     * Get the CMS view of the instance. This is used to display the log of
113
     * this workflow, and options to reassign if the workflow hasn't been
114
     * finished yet
115
     *
116
     * @return FieldList
117
     */
118
    public function getCMSFields()
119
    {
120
        $fields = new FieldList();
121
        $fields->push(new TabSet('Root', new Tab('Main')));
122
123
        if (Permission::check('REASSIGN_ACTIVE_WORKFLOWS')) {
124
            if ($this->WorkflowStatus == 'Paused' || $this->WorkflowStatus == 'Active') {
0 ignored issues
show
Documentation introduced by
The property WorkflowStatus 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...
125
                $cmsUsers = Member::mapInCMSGroups();
126
127
                $fields->addFieldsToTab('Root.Main', array(
128
                    new HiddenField('DirectUpdate', '', 1),
129
                    new HeaderField(
130
                        'InstanceReassignHeader',
131
                        _t('WorkflowInstance.REASSIGN_HEADER', 'Reassign workflow')
132
                    ),
133
                    new CheckboxSetField('Users', _t('WorkflowDefinition.USERS', 'Users'), $cmsUsers),
134
                    new TreeMultiselectField('Groups', _t('WorkflowDefinition.GROUPS', 'Groups'), Group::class)
135
                ));
136
            }
137
        }
138
139
        if ($this->canEdit()) {
140
            $action = $this->CurrentAction();
141
            if ($action->exists()) {
142
                $actionFields = $this->getWorkflowFields();
143
                $fields->addFieldsToTab('Root.Main', $actionFields);
0 ignored issues
show
Documentation introduced by
$actionFields is of type object<SilverStripe\Forms\FieldList>, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
144
145
                $transitions = $action->getValidTransitions();
146
                if ($transitions) {
147
                    $fields->replaceField(
148
                        'TransitionID',
149
                        DropdownField::create("TransitionID", "Next action", $transitions->map())
150
                    );
151
                }
152
            }
153
        }
154
155
        $items = WorkflowActionInstance::get()->filter(array(
156
            'Finished'   => 1,
157
            'WorkflowID' => $this->ID
158
        ));
159
160
        $grid = new GridField(
161
            'Actions',
162
            _t('WorkflowInstance.ActionLogTitle', 'Log'),
163
            $items
164
        );
165
166
        $fields->addFieldsToTab('Root.Main', $grid);
0 ignored issues
show
Documentation introduced by
$grid is of type object<SilverStripe\Forms\GridField\GridField>, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
167
168
        return $fields;
169
    }
170
171
    public function fieldLabels($includerelations = true)
172
    {
173
        $labels = parent::fieldLabels($includerelations);
174
        $labels['Title'] = _t('WorkflowInstance.TitleLabel', 'Title');
175
        $labels['WorkflowStatus'] = _t('WorkflowInstance.WorkflowStatusLabel', 'Workflow Status');
176
        $labels['TargetClass'] = _t('WorkflowInstance.TargetClassLabel', 'Target Class');
177
        $labels['TargetID'] = _t('WorkflowInstance.TargetIDLabel', 'Target');
178
179
        return $labels;
180
    }
181
182
    /**
183
     * See if we've been saved in context of managing the workflow directly
184
     */
185
    public function onBeforeWrite()
186
    {
187
        parent::onBeforeWrite();
188
189
        $vars = $this->record;
190
191
        if (isset($vars['DirectUpdate'])) {
192
            // Unset now so that we don't end up in an infinite loop!
193
            unset($this->record['DirectUpdate']);
194
            $this->updateWorkflow($vars);
0 ignored issues
show
Documentation introduced by
$vars is of type array<string,?,{"DirectUpdate":"?"}>, but the function expects a object<Symbiote\Advanced...kflow\DataObjects\type>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
195
        }
196
    }
197
198
    /**
199
     * Update the current state of the workflow
200
     *
201
     * Typically, this is triggered by someone modifiying the workflow instance via the modeladmin form
202
     * side of things when administering things, such as re-assigning or manually approving a stuck workflow
203
     *
204
     * Note that this is VERY similar to AdvancedWorkflowExtension::updateworkflow
205
     * but without the formy bits. These two implementations should PROBABLY
206
     * be merged
207
     *
208
     * @todo refactor with AdvancedWorkflowExtension
209
     *
210
     * @param type $data
211
     * @return
212
     */
213
    public function updateWorkflow($data)
214
    {
215
        $action = $this->CurrentAction();
216
217
        if (!$this->getTarget() || !$this->getTarget()->canEditWorkflow()) {
218
            return;
219
        }
220
221
        $allowedFields = $this->getWorkflowFields()->saveableFields();
222
        unset($allowedFields['TransitionID']);
223
        foreach ($allowedFields as $field) {
224
            $fieldName = $field->getName();
225
            $action->$fieldName = $data[$fieldName];
226
        }
227
        $action->write();
228
229
        $svc = singleton(WorkflowService::class);
230
        if (isset($data['TransitionID']) && $data['TransitionID']) {
231
            $svc->executeTransition($this->getTarget(), $data['TransitionID']);
232
        } else {
233
            // otherwise, just try to execute the current workflow to see if it
234
            // can now proceed based on user input
235
            $this->execute();
236
        }
237
    }
238
239
    /**
240
     * Get the target-object that this WorkflowInstance "points" to.
241
     *
242
     * Workflows are not restricted to being active on SiteTree objects,
243
     * so we need to account for being attached to anything.
244
     *
245
     * Sets Versioned::set_reading_mode() to allow fetching of Draft _and_ Published
246
     * content.
247
     *
248
     * @param boolean $getLive
249
     * @return null|DataObject
250
     */
251
    public function getTarget($getLive = false)
252
    {
253
        if ($this->TargetID && $this->TargetClass) {
0 ignored issues
show
Documentation introduced by
The property TargetID 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...
Documentation introduced by
The property TargetClass 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...
254
            $versionable = Injector::inst()->get($this->TargetClass)->has_extension(Versioned::class);
0 ignored issues
show
Documentation introduced by
The property TargetClass 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...
255
            $targetObject = null;
256
257
            if (!$versionable && $getLive) {
258
                return;
259
            }
260
            if ($versionable) {
261
                $targetObject = Versioned::get_by_stage(
262
                    $this->TargetClass,
0 ignored issues
show
Documentation introduced by
The property TargetClass 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...
263
                    $getLive ? Versioned::LIVE : Versioned::DRAFT
264
                )->byID($this->TargetID);
0 ignored issues
show
Documentation introduced by
The property TargetID 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...
265
            }
266
            if (!$targetObject) {
267
                $targetObject = DataObject::get_by_id($this->TargetClass, $this->TargetID);
0 ignored issues
show
Documentation introduced by
The property TargetClass 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...
Documentation introduced by
The property TargetID 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...
268
            }
269
270
            return $targetObject;
271
        }
272
    }
273
274
    /**
275
     *
276
     * @param boolean $getLive
277
     * @see {@link {$this->getTarget()}
278
     * @return null|DataObject
279
     */
280
    public function Target($getLive = false)
281
    {
282
        return $this->getTarget($getLive);
283
    }
284
285
    /**
286
     * Returns the field differences between the older version and current version of Target
287
     *
288
     * @return ArrayList
289
     */
290
    public function getTargetDiff()
291
    {
292
        $liveTarget = $this->Target(true);
293
        $draftTarget = $this->Target();
294
295
        $diff = DataDifferencer::create($liveTarget, $draftTarget);
296
        $diff->ignoreFields($this->config()->get('diff_ignore_fields'));
297
298
        $fields = ArrayList::create();
299
        try {
300
            $fields = $diff->ChangedFields();
301
        } catch (\InvalidArgumentException $iae) {
302
            // noop
303
        }
304
305
        return $fields;
306
    }
307
308
    /**
309
     * Start a workflow based on a particular definition for a particular object.
310
     *
311
     * The object is optional; if not specified, it is assumed that this workflow
312
     * is simply a task based checklist type of workflow.
313
     *
314
     * @param WorkflowDefinition $definition
315
     * @param DataObject $for
316
     */
317
    public function beginWorkflow(WorkflowDefinition $definition, DataObject $for = null)
318
    {
319
        if (!$this->ID) {
320
            $this->write();
321
        }
322
323
        if ($for
324
            && ($for->hasExtension(WorkflowApplicable::class)
325
                || $for->hasExtension(FileWorkflowApplicable::class))
326
        ) {
327
            $this->TargetClass = DataObject::getSchema()->baseDataClass($for);
0 ignored issues
show
Documentation introduced by
The property TargetClass does not exist on object<Symbiote\Advanced...jects\WorkflowInstance>. 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...
328
            $this->TargetID = $for->ID;
0 ignored issues
show
Documentation introduced by
The property TargetID does not exist on object<Symbiote\Advanced...jects\WorkflowInstance>. 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...
329
        }
330
331
        // lets create the first WorkflowActionInstance.
332
        $action = $definition->getInitialAction()->getInstanceForWorkflow();
333
        $action->WorkflowID = $this->ID;
0 ignored issues
show
Documentation introduced by
The property WorkflowID does not exist on object<Symbiote\Advanced...WorkflowActionInstance>. 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...
334
        $action->write();
335
336
        $title = $for && $for->hasField('Title')
337
            ? sprintf(_t('WorkflowInstance.TITLE_FOR_DO', '%s - %s'), $definition->Title, $for->Title)
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<Symbiote\Advanced...cts\WorkflowDefinition>. 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...
338
            : sprintf(_t('WorkflowInstance.TITLE_STUB', 'Instance #%s of %s'), $this->ID, $definition->Title);
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<Symbiote\Advanced...cts\WorkflowDefinition>. 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...
339
340
        $this->Title           = $title;
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<Symbiote\Advanced...jects\WorkflowInstance>. 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...
341
        $this->DefinitionID    = $definition->ID;
0 ignored issues
show
Documentation introduced by
The property DefinitionID does not exist on object<Symbiote\Advanced...jects\WorkflowInstance>. 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...
342
        $this->CurrentActionID = $action->ID;
0 ignored issues
show
Documentation introduced by
The property CurrentActionID does not exist on object<Symbiote\Advanced...jects\WorkflowInstance>. 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...
343
        $this->InitiatorID     = Security::getCurrentUser()->ID;
0 ignored issues
show
Documentation introduced by
The property InitiatorID does not exist on object<Symbiote\Advanced...jects\WorkflowInstance>. 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...
344
        $this->write();
345
346
        $this->Users()->addMany($definition->Users());
0 ignored issues
show
Documentation Bug introduced by
The method Users does not exist on object<Symbiote\Advanced...jects\WorkflowInstance>? 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...
Documentation Bug introduced by
The method Users does not exist on object<Symbiote\Advanced...cts\WorkflowDefinition>? 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...
347
        $this->Groups()->addMany($definition->Groups());
0 ignored issues
show
Documentation Bug introduced by
The method Groups does not exist on object<Symbiote\Advanced...jects\WorkflowInstance>? 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...
Documentation Bug introduced by
The method Groups does not exist on object<Symbiote\Advanced...cts\WorkflowDefinition>? 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...
348
    }
349
350
    /**
351
     * Execute this workflow. In rare cases this will actually execute all actions,
352
     * but typically, it will stop and wait for the user to input something
353
     *
354
     * The basic process is to get the current action, and see whether it has been finished
355
     * by some process, if not it attempts to execute it.
356
     *
357
     * If it has been finished, we check to see if there's some transitions to follow. If there's
358
     * only one transition, then we execute that immediately.
359
     *
360
     * If there's multiple transitions, we just stop and wait for the user to manually
361
     * trigger a transition.
362
     *
363
     * If there's no transitions, we make the assumption that we've finished the workflow and
364
     * mark it as such.
365
     *
366
     *
367
     */
368
    public function execute()
369
    {
370
        if (!$this->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...
371
            throw new Exception(
372
                sprintf(_t(
373
                    'WorkflowInstance.EXECUTE_EXCEPTION',
374
                    'Attempted to start an invalid workflow instance #%s!'
375
                ), $this->ID)
376
            );
377
        }
378
379
        $action     = $this->CurrentAction();
380
        $transition = false;
381
382
        // if the action has already finished, it means it has either multiple (or no
383
        // transitions at the time), so a subsequent check should be run.
384
        if ($action->Finished) {
0 ignored issues
show
Documentation introduced by
The property Finished does not exist on object<Symbiote\Advanced...WorkflowActionInstance>. 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...
385
            $transition = $this->checkTransitions($action);
386
        } else {
387
            $result = $action->BaseAction()->execute($this);
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...
388
389
            // if the action was successful, then the action has finished running and
390
            // next transition should be run (if only one).
391
            // input.
392
            if ($result) {
393
                $action->MemberID = Security::getCurrentUser()->ID;
0 ignored issues
show
Documentation introduced by
The property MemberID does not exist on object<Symbiote\Advanced...WorkflowActionInstance>. 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...
394
                $action->Finished = true;
0 ignored issues
show
Documentation introduced by
The property Finished does not exist on object<Symbiote\Advanced...WorkflowActionInstance>. 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...
395
                $action->write();
396
                $transition = $this->checkTransitions($action);
397
            }
398
        }
399
400
        // if the action finished, and there's only one available transition then
401
        // move onto that step - otherwise check if the workflow has finished.
402
        if ($transition) {
403
            $this->performTransition($transition);
404
        } else {
405
            // see if there are any transitions available, even if they are not valid.
406
            if ($action->Finished && !count($action->BaseAction()->Transitions())) {
0 ignored issues
show
Documentation introduced by
The property Finished does not exist on object<Symbiote\Advanced...WorkflowActionInstance>. 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...
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...
407
                $this->WorkflowStatus  = 'Complete';
0 ignored issues
show
Documentation introduced by
The property WorkflowStatus does not exist on object<Symbiote\Advanced...jects\WorkflowInstance>. 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...
408
                $this->CurrentActionID = 0;
0 ignored issues
show
Documentation introduced by
The property CurrentActionID does not exist on object<Symbiote\Advanced...jects\WorkflowInstance>. 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...
409
            } else {
410
                $this->WorkflowStatus = 'Paused';
0 ignored issues
show
Documentation introduced by
The property WorkflowStatus does not exist on object<Symbiote\Advanced...jects\WorkflowInstance>. 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...
411
            }
412
413
            $this->write();
414
        }
415
    }
416
417
    /**
418
     * Evaluate all the transitions of an action and determine whether we should
419
     * follow any of them yet.
420
     *
421
     * @param  WorkflowActionInstance $action
422
     * @return WorkflowTransition
423
     */
424
    protected function checkTransitions(WorkflowActionInstance $action)
425
    {
426
        $transitions = $action->getValidTransitions();
427
        // if there's JUST ONE transition, then we need should
428
        // immediately follow it.
429
        if ($transitions && $transitions->count() == 1) {
430
            return $transitions->First();
431
        }
432
    }
433
434
    /**
435
     * Transitions a workflow to the next step defined by the given transition.
436
     *
437
     * After transitioning, the action is 'executed', and next steps
438
     * determined.
439
     *
440
     * @param WorkflowTransition $transition
441
     */
442
    public function performTransition(WorkflowTransition $transition)
443
    {
444
        // first make sure that the transition is valid to execute!
445
        $action          = $this->CurrentAction();
446
        $allTransitions  = $action->BaseAction()->Transitions();
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...
447
448
        $valid = $allTransitions->find('ID', $transition->ID);
449
        if (!$valid) {
450
            throw new Exception(
451
                sprintf(_t(
452
                    'WorkflowInstance.WORKFLOW_TRANSITION_EXCEPTION',
453
                    'Invalid transition state for action #%s'
454
                ), $action->ID)
455
            );
456
        }
457
458
        $action->actionComplete($transition);
459
460
        $definition = DataObject::get_by_id(WorkflowAction::class, $transition->NextActionID);
0 ignored issues
show
Documentation introduced by
The property NextActionID does not exist on object<Symbiote\Advanced...cts\WorkflowTransition>. 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...
461
        $action = $definition->getInstanceForWorkflow();
462
        $action->WorkflowID   = $this->ID;
463
        $action->write();
464
465
        $this->CurrentActionID = $action->ID;
0 ignored issues
show
Documentation introduced by
The property CurrentActionID does not exist on object<Symbiote\Advanced...jects\WorkflowInstance>. 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...
466
        $this->write();
467
        $this->components = array(); // manually clear the has_one cache
468
469
        $action->actionStart($transition);
470
471
        $transition->extend('onTransition');
472
        $this->execute();
473
    }
474
475
    /**
476
     * Returns a list of all Members that are assigned to this instance, either directly or via a group.
477
     *
478
     * @todo   This could be made more efficient.
479
     * @return ArrayList
480
     */
481 View Code Duplication
    public function getAssignedMembers()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
482
    {
483
        $list   = new ArrayList();
484
        $groups = $this->Groups();
0 ignored issues
show
Documentation Bug introduced by
The method Groups does not exist on object<Symbiote\Advanced...jects\WorkflowInstance>? 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...
485
486
        $list->merge($this->Users());
0 ignored issues
show
Documentation Bug introduced by
The method Users does not exist on object<Symbiote\Advanced...jects\WorkflowInstance>? 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...
487
488
        foreach ($groups as $group) {
489
            $list->merge($group->Members());
490
        }
491
492
        $list->removeDuplicates();
493
        return $list;
494
    }
495
496
    /**
497
     *
498
     * @param Member $member
499
     * @return boolean
500
     */
501
    public function canView($member = null)
502
    {
503
        $extended = $this->extendedCan(__FUNCTION__, $member);
0 ignored issues
show
Bug introduced by
It seems like $member defined by parameter $member on line 501 can be null; however, SilverStripe\ORM\DataObject::extendedCan() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
504
        if ($extended !== null) {
505
            return $extended;
506
        }
507
508
        $hasAccess = $this->userHasAccess($member);
0 ignored issues
show
Bug introduced by
It seems like $member defined by parameter $member on line 501 can be null; however, Symbiote\AdvancedWorkflo...stance::userHasAccess() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
509
        /*
510
         * If the next action is AssignUsersToWorkflowAction, execute() resets all user+group relations.
511
         * Therefore current user no-longer has permission to view this WorkflowInstance in PendingObjects
512
         * Gridfield, even though;
513
         * - She had permissions granted via the workflow definition to run the preceeding Action that took her here.
514
         */
515
        if (!$hasAccess) {
516
            if ($this->getMostRecentActionForUser($member)) {
517
                return true;
518
            }
519
        }
520
        return $hasAccess;
521
    }
522
523
    /**
524
     *
525
     * @param Member $member
526
     * @return boolean
527
     */
528
    public function canEdit($member = null)
529
    {
530
        $extended = $this->extendedCan(__FUNCTION__, $member);
0 ignored issues
show
Bug introduced by
It seems like $member defined by parameter $member on line 528 can be null; however, SilverStripe\ORM\DataObject::extendedCan() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
531
        if ($extended !== null) {
532
            return $extended;
533
        }
534
535
        return $this->userHasAccess($member);
0 ignored issues
show
Bug introduced by
It seems like $member defined by parameter $member on line 528 can be null; however, Symbiote\AdvancedWorkflo...stance::userHasAccess() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
536
    }
537
538
    /**
539
     *
540
     * @param Member $member
541
     * @return boolean
542
     */
543
    public function canDelete($member = null)
544
    {
545
        $extended = $this->extendedCan(__FUNCTION__, $member);
0 ignored issues
show
Bug introduced by
It seems like $member defined by parameter $member on line 543 can be null; however, SilverStripe\ORM\DataObject::extendedCan() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
546
        if ($extended !== null) {
547
            return $extended;
548
        }
549
550
        if (Permission::checkMember($member, "DELETE_WORKFLOW")) {
551
            return true;
552
        }
553
        return false;
554
    }
555
556
    /**
557
     * Checks whether the given user is in the list of users assigned to this
558
     * workflow
559
     *
560
     * @param Member $member
561
     */
562
    protected function userHasAccess($member)
563
    {
564
        if (!$member) {
565
            if (!Security::getCurrentUser()) {
566
                return false;
567
            }
568
            $member = Security::getCurrentUser();
569
        }
570
571
        if (Permission::checkMember($member, "ADMIN")) {
572
            return true;
573
        }
574
575
        // This method primarily "protects" access to a WorkflowInstance, but assumes access only to be granted to
576
        // users assigned-to that WorkflowInstance. However; lowly authors (users entering items into a workflow) are
577
        // not assigned - but we still wish them to see their submitted content.
578
        $inWorkflowGroupOrUserTables = ($member->inGroups($this->Groups()) || $this->Users()->find('ID', $member->ID));
0 ignored issues
show
Documentation Bug introduced by
The method Groups does not exist on object<Symbiote\Advanced...jects\WorkflowInstance>? 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...
Bug introduced by
It seems like $member is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
Documentation Bug introduced by
The method Users does not exist on object<Symbiote\Advanced...jects\WorkflowInstance>? 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...
579
        // This method is used in more than just the ModelAdmin. Check for the current controller to determine where
580
        // canView() expectations differ
581
        if ($this->getTarget() && Controller::curr()->getAction() == 'index' && !$inWorkflowGroupOrUserTables) {
582
            if ($this->getVersionedConnection($this->getTarget()->ID, $member->ID)) {
583
                return true;
584
            }
585
            return false;
586
        }
587
        return $inWorkflowGroupOrUserTables;
588
    }
589
590
    /**
591
     * Can documents in the current workflow state be edited?
592
     */
593
    public function canEditTarget()
594
    {
595
        if ($this->CurrentActionID && ($target = $this->getTarget())) {
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...
596
            return $this->CurrentAction()->canEditTarget($target);
597
        }
598
    }
599
600
    /**
601
     * Does this action restrict viewing of the document?
602
     *
603
     * @return boolean
604
     */
605
    public function canViewTarget()
606
    {
607
        $action = $this->CurrentAction();
608
        if ($action) {
609
            return $action->canViewTarget($this->getTarget());
0 ignored issues
show
Bug introduced by
It seems like $this->getTarget() can be null; however, canViewTarget() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
610
        }
611
        return true;
612
    }
613
614
    /**
615
     * Does this action restrict the publishing of a document?
616
     *
617
     * @return boolean
618
     */
619
    public function canPublishTarget()
620
    {
621
        if ($this->CurrentActionID && ($target = $this->getTarget())) {
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...
622
            return $this->CurrentAction()->canPublishTarget($target);
623
        }
624
    }
625
626
    /**
627
     * Get the current set of transitions that are valid for the current workflow state,
628
     * and are available to the current user.
629
     *
630
     * @return array
631
     */
632
    public function validTransitions()
633
    {
634
        $action    = $this->CurrentAction();
635
        $transitions = $action->getValidTransitions();
636
637
        // Filter by execute permission
638
        return $transitions->filterByCallback(function ($transition) {
639
            return $transition->canExecute($this);
640
        });
641
    }
642
643
    /* UI RELATED METHODS */
644
645
    /**
646
     * Gets fields for managing this workflow instance in its current step
647
     *
648
     * @return FieldList
649
     */
650
    public function getWorkflowFields()
651
    {
652
        $action    = $this->CurrentAction();
653
        $options   = $this->validTransitions();
654
        $wfOptions = $options->map('ID', 'Title', ' ');
0 ignored issues
show
Unused Code introduced by
The call to ArrayList::map() has too many arguments starting with ' '.

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...
Unused Code introduced by
$wfOptions 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...
655
        $fields    = new FieldList();
656
657
        $fields->push(new HeaderField('WorkflowHeader', $action->Title));
0 ignored issues
show
Documentation introduced by
The property Title does not exist on object<Symbiote\Advanced...WorkflowActionInstance>. 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...
658
659
        $fields->push(HiddenField::create('TransitionID', ''));
660
        // Let the Active Action update the fields that the user can interact with so that data can be
661
        // stored for the workflow.
662
        $action->updateWorkflowFields($fields);
663
        $action->invokeWithExtensions('updateWorkflowFields', $fields);
664
        return $fields;
665
    }
666
667
    /**
668
     * Gets Front-End form fields from current Action
669
     *
670
     * @return FieldList
671
     */
672
    public function getFrontEndWorkflowFields()
673
    {
674
        $action = $this->CurrentAction();
675
676
        $fields = new FieldList();
677
        $action->updateFrontEndWorkflowFields($fields);
678
679
        return $fields;
680
    }
681
682
    /**
683
     * Gets Transitions for display as Front-End Form Actions
684
     *
685
     * @return FieldList
686
     */
687
    public function getFrontEndWorkflowActions()
688
    {
689
        $action    = $this->CurrentAction();
690
        $options   = $action->getValidTransitions();
691
        $actions   = new FieldList();
692
693
        $hide_disabled_actions_on_frontend = $this->config()->hide_disabled_actions_on_frontend;
694
695
        foreach ($options as $option) {
696
            $btn = new FormAction("transition_{$option->ID}", $option->Title);
697
698
            // add cancel class to passive actions, this prevents js validation (using jquery.validate)
699
            if ($option->Type == 'Passive') {
700
                $btn->addExtraClass('cancel');
701
            }
702
703
            // disable the button if canExecute() returns false
704
            if (!$option->canExecute($this)) {
705
                if ($hide_disabled_actions_on_frontend) {
706
                    continue;
707
                }
708
709
                $btn = $btn->performReadonlyTransformation();
710
                $btn->addExtraClass('hide');
711
            }
712
713
            $actions->push($btn);
714
        }
715
716
        $action->updateFrontEndWorkflowActions($actions);
717
718
        return $actions;
719
    }
720
721
    /**
722
     * Gets Front-End DataObject
723
     *
724
     * @return DataObject
725
     */
726
    public function getFrontEndDataObject()
727
    {
728
        $action = $this->CurrentAction();
729
        $obj = $action->getFrontEndDataObject();
730
731
        return $obj;
732
    }
733
734
    /**
735
     * Gets Front-End DataObject
736
     *
737
     * @return DataObject
738
     */
739
    public function getFrontEndRequiredFields()
740
    {
741
        $action = $this->CurrentAction();
742
        $validator = $action->getRequiredFields();
743
744
        return $validator;
745
    }
746
747
    public function setFrontendFormRequirements()
748
    {
749
        $action = $this->CurrentAction();
750
        $action->setFrontendFormRequirements();
751
    }
752
753
    public function doFrontEndAction(array $data, Form $form, HTTPRequest $request)
754
    {
755
        $action = $this->CurrentAction();
756
        $action->doFrontEndAction($data, $form, $request);
757
    }
758
759
    /**
760
     * We need a way to "associate" an author with this WorkflowInstance and its Target() to see if she is "allowed"
761
     * to view WorkflowInstances within GridFields
762
     * @see {@link $this->userHasAccess()}
763
     *
764
     * @param number $recordID
765
     * @param number $userID
766
     * @param number $wasPublished
767
     * @return boolean
768
     */
769
    public function getVersionedConnection($recordID, $userID, $wasPublished = 0)
770
    {
771
        // Turn this into an array and run through implode()
772
        $filter = "RecordID = {$recordID} AND AuthorID = {$userID} AND WasPublished = {$wasPublished}";
773
        $query = new SQLSelect();
774
        $query->setFrom('"SiteTree_Versions"')->setSelect('COUNT("ID")')->setWhere($filter);
775
        $query->firstRow();
776
        $hasAuthored = $query->execute();
777
        if ($hasAuthored) {
778
            return true;
779
        }
780
        return false;
781
    }
782
783
    /**
784
     * Simple method to retrieve the current action, on the current WorkflowInstance
785
     */
786
    public function getCurrentAction()
787
    {
788
        $join = '"WorkflowAction"."ID" = "WorkflowActionInstance"."BaseActionID"';
789
        $action = WorkflowAction::get()
790
            /** @skipUpgrade */
791
            ->leftJoin('WorkflowActionInstance', $join)
792
            ->where('"WorkflowActionInstance"."ID" = '.$this->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...
793
            ->first();
794
        if (!$action) {
795
            return 'N/A';
796
        }
797
        return $action->getField('Title');
798
    }
799
800
    /**
801
     * Tells us if $member has had permissions over some part of the current WorkflowInstance.
802
     *
803
     * @param $member
804
     * @return WorkflowAction|boolean
805
     */
806
    public function getMostRecentActionForUser($member = null)
807
    {
808
        if (!$member) {
809
            if (!Security::getCurrentUser()) {
810
                return false;
811
            }
812
            $member = Security::getCurrentUser();
813
        }
814
815
        // WorkflowActionInstances in reverse creation-order so we get the most recent one's first
816
        $history = $this->Actions()->filter(array(
0 ignored issues
show
Bug introduced by
The method Actions() does not exist on Symbiote\AdvancedWorkflo...bjects\WorkflowInstance. Did you maybe mean getFrontEndWorkflowActions()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
817
            'Finished' =>1,
818
            'BaseAction.ClassName' => AssignUsersToWorkflowAction::class
819
        ))->Sort('Created', 'DESC');
820
821
        $i = 0;
822
        foreach ($history as $inst) {
823
            /*
824
             * This iteration represents the 1st instance in the list - the most recent AssignUsersToWorkflowAction
825
             * in $history.
826
             * If there's no match for $member here or on the _previous_ AssignUsersToWorkflowAction, then bail out:
827
             */
828
            $assignedMembers = $inst->BaseAction()->getAssignedMembers();
829
            if ($i <= 1 && $assignedMembers->count() > 0 && $assignedMembers->find('ID', $member->ID)) {
830
                return $inst;
831
            }
832
            ++$i;
833
        }
834
        return false;
835
    }
836
}
837