WorkflowAction   A
last analyzed

Complexity

Total Complexity 23

Size/Duplication

Total Lines 245
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 14
Metric Value
wmc 23
lcom 2
cbo 14
dl 0
loc 245
rs 10

19 Methods

Rating   Name   Duplication   Size   Complexity  
A canEditTarget() 0 3 1
A canViewTarget() 0 3 1
A canPublishTarget() 0 3 1
A canCreate() 0 3 1
A canEdit() 0 3 1
A canDelete() 0 3 1
A canAddTransition() 0 3 1
A execute() 0 3 1
A targetUpdated() 0 2 1
A numChildren() 0 3 1
A getValidator() 0 3 1
A updateFrontendWorkflowFields() 0 3 1
A Icon() 0 3 1
A getInstanceForWorkflow() 0 6 1
A onBeforeWrite() 0 7 2
B onAfterDelete() 0 22 4
A getCMSFields() 0 23 1
A summaryFields() 0 6 1
A fieldLabels() 0 12 1
1
<?php
2
/**
3
 * A workflow action describes a the 'state' a workflow can be in, and
4
 * the action(s) that occur while in that state. An action can then have
5
 * subsequent transitions out of the current state.
6
 *
7
 * @author  [email protected]
8
 * @license BSD License (http://silverstripe.org/bsd-license/)
9
 * @package advancedworkflow
10
 */
11
class WorkflowAction extends DataObject {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
12
13
	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...
Unused Code introduced by
The property $db is not used and could be removed.

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

Loading history...
14
		'Title'				=> 'Varchar(255)',
15
		'Comment'			=> 'Text',
16
		'Type'				=> "Enum('Dynamic,Manual','Manual')",  // is this used?
17
		'Executed'			=> 'Boolean',
18
		'AllowEditing'		=> "Enum('By Assignees,Content Settings,No','No')",		// can this item be edited?
19
		'Sort'				=> 'Int',
20
		'AllowCommenting'	=> 'Boolean'
21
	);
22
23
	private static $defaults = 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...
Unused Code introduced by
The property $defaults is not used and could be removed.

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

Loading history...
24
		'AllowCommenting'	=> '1',
25
	);
26
27
	private static $default_sort = 'Sort';
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...
Unused Code introduced by
The property $default_sort is not used and could be removed.

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

Loading history...
28
29
	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...
Unused Code introduced by
The property $has_one is not used and could be removed.

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

Loading history...
30
		'WorkflowDef' => 'WorkflowDefinition',
31
		'Member'      => 'Member'
32
	);
33
34
	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...
Unused Code introduced by
The property $has_many is not used and could be removed.

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

Loading history...
35
		'Transitions' => 'WorkflowTransition.Action'
36
	);
37
38
	/**
39
	 * The type of class to use for instances of this workflow action that are used for storing the
40
	 * data of the instance.
41
	 *
42
	 * @var string
43
	 */
44
	private static $instance_class = 'WorkflowActionInstance';
0 ignored issues
show
Unused Code introduced by
The property $instance_class is not used and could be removed.

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

Loading history...
45
46
	public static $icon = 'advancedworkflow/images/action.png';
47
48
	/**
49
	 * Can documents in the current workflow state be edited?
50
	 *
51
	 * Only return true or false if this is an absolute value; the WorkflowActionInstance
52
	 * will try and figure out an appropriate value for the actively running workflow
53
	 * if null is returned from this method.
54
	 *
55
	 * @param  DataObject $target
56
	 * @return bool
57
	 */
58
	public function canEditTarget(DataObject $target) {
0 ignored issues
show
Unused Code introduced by
The parameter $target is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
59
		return null;
60
	}
61
62
	/**
63
	 * Does this action restrict viewing of the document?
64
	 *
65
	 * @param  DataObject $target
66
	 * @return bool
67
	 */
68
	public function canViewTarget(DataObject $target) {
0 ignored issues
show
Unused Code introduced by
The parameter $target is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
69
		return null;
70
	}
71
72
	/**
73
	 * Does this action restrict the publishing of a document?
74
	 *
75
	 * @param  DataObject $target
76
	 * @return bool
77
	 */
78
	public function canPublishTarget(DataObject $target) {
0 ignored issues
show
Unused Code introduced by
The parameter $target is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
79
		return null;
80
	}
81
82
	/**
83
	 * Allows users who have permission to create a WorkflowDefinition, to create actions on it too.
84
	 *
85
	 * @param  Member $member
86
	 * @return bool
87
	 */
88
	public function canCreate($member = null) {
89
		return $this->WorkflowDef()->canCreate($member);
0 ignored issues
show
Documentation Bug introduced by
The method WorkflowDef does not exist on object<WorkflowAction>? 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...
90
	}
91
92
	/**
93
	 * @param  Member $member
94
	 * @return bool
95
	 */
96
	public function canEdit($member = null) {
97
		return $this->canCreate($member);
98
	}
99
100
	/**
101
	 * @param  Member $member
102
	 * @return bool
103
	 */
104
	public function canDelete($member = null) {
105
		return $this->WorkflowDef()->canDelete($member);
0 ignored issues
show
Documentation Bug introduced by
The method WorkflowDef does not exist on object<WorkflowAction>? 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...
106
	}
107
108
	/*
109
	 * If there is only a single action defined for a workflow, there's no sense
110
	 * in allowing users to add a transition to it (and causing errors).
111
	 * Hide the "Add Transition" button in this case
112
	 *
113
	 * @return boolean true if we should disable the button, false otherwise
114
	 */
115
	public function canAddTransition() {
116
		return ($this->WorkflowDef()->numChildren() >1);
0 ignored issues
show
Documentation Bug introduced by
The method WorkflowDef does not exist on object<WorkflowAction>? 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...
117
	}
118
119
	/**
120
	 * Gets an object that is used for saving the actual state of things during
121
	 * a running workflow. It still uses the workflow action def for managing the
122
	 * functional execution, however if you need to store additional data for
123
	 * the state, you can specify your own WorkflowActionInstance instead of
124
	 * the default to capture these elements
125
	 *
126
	 * @return WorkflowActionInstance
127
	 */
128
	public function getInstanceForWorkflow() {
129
		$instanceClass = $this->stat('instance_class');
130
		$instance = new $instanceClass();
131
		$instance->BaseActionID = $this->ID;
132
		return $instance;
133
	}
134
135
	/**
136
	 * Perform whatever needs to be done for this action. If this action can be considered executed, then
137
	 * return true - if not (ie it needs some user input first), return false and 'execute' will be triggered
138
	 * again at a later point in time after the user has provided more data, either directly or indirectly.
139
	 *
140
	 * @param  WorkflowInstance $workflow
141
	 * @return bool Returns true if this action has finished.
142
	 */
143
	public function execute(WorkflowInstance $workflow) {
144
		return true;
145
	}
146
147
	public function onBeforeWrite() {
148
		if(!$this->Sort) {
0 ignored issues
show
Documentation introduced by
The property Sort does not exist on object<WorkflowAction>. 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...
149
			$this->Sort = DB::query('SELECT MAX("Sort") + 1 FROM "WorkflowAction"')->value();
0 ignored issues
show
Documentation introduced by
The property Sort does not exist on object<WorkflowAction>. 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...
150
		}
151
152
		parent::onBeforeWrite();
153
	}
154
155
	/**
156
	 * When deleting an action from a workflow definition, make sure that workflows currently paused on that action
157
	 * are deleted
158
	 * Also removes all outbound transitions
159
	 */
160
	public function onAfterDelete() {
161
		parent::onAfterDelete();
162
		$wfActionInstances = WorkflowActionInstance::get()
163
				->leftJoin("WorkflowInstance",'"WorkflowInstance"."ID" = "WorkflowActionInstance"."WorkflowID"')
164
				->where(sprintf('"BaseActionID" = %d AND ("WorkflowStatus" IN (\'Active\',\'Paused\'))', $this->ID));
165
		foreach ($wfActionInstances as $wfActionInstance){
166
			$wfInstances = WorkflowInstance::get()->filter('CurrentActionID', $wfActionInstance->ID);
167
			foreach ($wfInstances as $wfInstance){
168
				$wfInstance->Groups()->removeAll();
169
				$wfInstance->Users()->removeAll();
170
				$wfInstance->delete();
171
			}
172
			$wfActionInstance->delete();
173
		}
174
		// Delete outbound transitions
175
		$transitions = WorkflowTransition::get()->filter('ActionID', $this->ID);
176
		foreach ($transitions as $transition){
177
			$transition->Groups()->removeAll();
178
			$transition->Users()->removeAll();
179
			$transition->delete();
180
		}
181
	}
182
183
	/**
184
	 * Called when the current target of the workflow has been updated
185
	 */
186
	public function targetUpdated(WorkflowInstance $workflow) {
0 ignored issues
show
Unused Code introduced by
The parameter $workflow is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
187
	}
188
189
	/* CMS RELATED FUNCTIONALITY... */
190
191
192
	public function numChildren() {
193
		return count($this->Transitions());
0 ignored issues
show
Documentation Bug introduced by
The method Transitions does not exist on object<WorkflowAction>? 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...
194
	}
195
196
	public function getCMSFields() {
197
198
		$fields = new FieldList(new TabSet('Root'));
199
		$typeLabel = _t('WorkflowAction.CLASS_LABEL', 'Action Class');
200
		$fields->addFieldToTab('Root.Main', new ReadOnlyField('WorkflowActionClass', $typeLabel, $this->singular_name()));
201
		$titleField = new TextField('Title', $this->fieldLabel('Title'));
202
		$titleField->setDescription(_t(
203
			'WorkflowAction.TitleDescription',
204
			'The Title is used as the button label for this Workflow Action'
205
		));
206
		$fields->addFieldToTab('Root.Main', $titleField);
207
		$fields->addFieldToTab('Root.Main', new DropdownField('AllowEditing', $this->fieldLabel('AllowEditing'),
208
			array(
209
				'By Assignees' => _t('AllowEditing.ByAssignees', 'By Assignees'),
210
				'Content Settings' => _t('AllowEditing.ContentSettings', 'Content Settings'),
211
				'No' => _t('AllowEditing.NoString', 'No')
212
			),
213
		 	_t('AllowEditing.NoString', 'No')
214
		));
215
		$fields->addFieldToTab('Root.Main', new CheckboxField('AllowCommenting', $this->fieldLabel('AllowCommenting'),$this->AllowCommenting));
0 ignored issues
show
Documentation introduced by
The property AllowCommenting does not exist on object<WorkflowAction>. 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...
216
		$this->extend('updateCMSFields', $fields);
217
		return $fields;
218
	}
219
220
	public function getValidator() {
221
		return new RequiredFields('Title');
222
	}
223
224
	public function summaryFields() {
225
		return array(
226
			'Title' => $this->fieldLabel('Title'),
227
			'Transitions' => $this->fieldLabel('Transitions'),
228
		);
229
	}
230
231
	public function fieldLabels($includerelations = true) {
232
		$labels = parent::fieldLabels($includerelations);
233
		$labels['Comment'] = _t('WorkflowAction.CommentLabel', 'Comment');
234
		$labels['Type'] = _t('WorkflowAction.TypeLabel', 'Type');
235
		$labels['Executed'] = _t('WorkflowAction.ExecutedLabel', 'Executed');
236
		$labels['AllowEditing'] = _t('WorkflowAction.ALLOW_EDITING', 'Allow editing during this step?');
237
		$labels['Title'] = _t('WorkflowAction.TITLE', 'Title');
238
		$labels['AllowCommenting'] = _t('WorkflowAction.ALLOW_COMMENTING','Allow Commenting?');
239
		$labels['Transitions'] = _t('WorkflowAction.Transitions','Transitions');
240
241
		return $labels;
242
	}
243
244
	/**
245
	 * Used for Front End Workflows
246
	 */
247
	public function updateFrontendWorkflowFields($fields, $workflow){
0 ignored issues
show
Unused Code introduced by
The parameter $fields is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $workflow is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
248
249
	}
250
251
252
	public function Icon() {
253
		return $this->stat('icon');
254
	}
255
}