Completed
Pull Request — master (#230)
by Helpful
03:29
created

WorkflowTemplate::getRemindDays()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
/**
4
 * A class that wraps around an array description of a workflow
5
 * 
6
 * array(
7
 *	'Step Name' = array(
8
 *		'type'		=> class name
9
 *		'transitions'	=> array(
10
 *			'transition name' => 'target step',
11
 *			'next name' => 'other step'
12
 *		)
13
 *	),
14
 *	'Next Step'	= array(
15
 *		
16
 *	),
17
 * )
18
 * 
19
 * This can be defined in config yml as follows
20
 * 
21
 * Injector:
22
 *   SimpleReviewApprove:
23
 *     class: WorkflowTemplate
24
 *     constructor:
25
 *       - Review and Approve
26
 *       - Description of the workflow template
27
 *       - 0.1 (version number)
28
 *     properties:
29
 *       structure:
30
 *         Apply for approval:
31
 *           type: AssignUsersToWorkflowAction
32
 *           transitions: 
33
 *             notify: Notify users
34
 *         Notify users:
35
 *           type: NotifyUsersWorkflowAction
36
 *           transitions:
37
 *             approval: Approval
38
 *         Approval:
39
 *           type: SimpleApprovalWorkflowAction
40
 *           transitions:
41
 *             Approve: Publish
42
 *             Reject: Reject
43
 *         Publish:
44
 *           type: PublishItemWorkflowAction
45
 *         Reject:
46
 *           type: CancelWorkflowAction
47
 *   WorkflowService:
48
 *     properties:
49
 *       templates:
50
 *         - %$SimpleReviewApprove
51
 * 
52
 * When updating a template, there's a few things that can be done to assist
53
 * the system when changing things around
54
 * 
55
 * 1. Update the 'version' number 
56
 * 
57
 * @author [email protected]
58
 * @license BSD License http://silverstripe.org/bsd-license/
59
 */
60
class WorkflowTemplate
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...
61
{
62
    protected $name;
63
    protected $description;
64
    protected $version;
65
    protected $remindDays;
66
    protected $sort;
67
    
68
    /**
69
     * An array representation of the structure of this workflow template
70
     * 
71
     * @var array
72
     */
73
    protected $structure;
74
    
75
    public function __construct($name, $description = '', $version = '0.0', $remindDays = 0, $sort = 0)
76
    {
77
        $this->name = $name;
78
        $this->description = $description;
79
        $this->version = $version;
80
        $this->remindDays = $remindDays;
81
        $this->sort = $sort;
82
    }
83
    
84
    public function getName()
85
    {
86
        return $this->name;
87
    }
88
    
89
    public function getVersion()
90
    {
91
        return $this->version;
92
    }
93
    
94
    public function getDescription()
95
    {
96
        return $this->description;
97
    }
98
    
99
    public function getRemindDays()
100
    {
101
        return $this->remindDays;
102
    }
103
    
104
    public function getSort()
105
    {
106
        return $this->sort;
107
    }
108
    
109
    /**
110
     * Set the structure for this template
111
     * 
112
     * @param array $structure 
113
     */
114
    public function setStructure($structure)
115
    {
116
        $this->structure = $structure;
117
    }
118
    
119
    /**
120
     * Creates the relevant data objects for this structure, returning an array
121
     * of actions in the order they've been created 
122
     * 
123
     * @param WorkflowDefinition $definitino
0 ignored issues
show
Documentation introduced by
There is no parameter named $definitino. Did you maybe mean $definition?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
124
     *				An optional workflow definition to bind the actions into
125
     * @return array
126
     */
127
    public function createRelations($definition = null)
128
    {
129
        $actions = array();
130
        $transitions = new ArrayObject();
131
        $sort = 1;
132
        foreach ($this->structure as $relationName => $relationTemplate) {
133
            $isAction = isset($relationTemplate['type']);
134
            $isUsers = ($relationName == 'users');
135
            $isGroups = ($relationName == 'groups');
136
            
137
            // Process actions on WorkflowDefinition from the template
138
            if ($isAction) {
139
                $action = $this->createAction($relationName, $relationTemplate, $definition);
140
                // add a sort value in! 
141
                $action->Sort = $sort++;
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...
142
                $action->write();
143
144
                $actions[$relationName] = $action;
145
146
                $newTransitions = $this->updateActionTransitions($relationTemplate, $action);
147
                foreach ($newTransitions as $t) {
148
                    $transitions->append($t);
149
                }
150
            }
151
            // Process users on WorkflowDefinition from the template
152
            if ($isUsers) {
153
                $this->createUsers($relationTemplate, $definition);
154
            }
155
            // Process groups on WorkflowDefinition from the template
156
            if ($isGroups) {
157
                $this->createGroups($relationTemplate, $definition);
158
            }
159
        }
160
161 View Code Duplication
        foreach ($transitions as $transition) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
162
            if (isset($actions[$transition->Target])) {
163
                $transition->NextActionID = $actions[$transition->Target]->ID;
164
            }
165
            $transition->write();
166
        }
167
        
168
        return $actions;
169
    }
170
    
171
    /**
172
     * Create a workflow action based on a template
173
     * 
174
     * @param string $name
175
     * @param array $template
0 ignored issues
show
Documentation introduced by
There is no parameter named $template. Did you maybe mean $actionTemplate?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
176
     * @param WorkflowDefinition $definition
177
     * @return WorkflowAction
178
     */
179
    protected function createAction($name, $actionTemplate, WorkflowDefinition $definition = null)
180
    {
181
        $type = $actionTemplate['type'];
182
        if (!$type || !class_exists($type)) {
183
            throw new Exception(_t('WorkflowTemplate.INVALID_TEMPLATE_ACTION', 'Invalid action class specified in template'));
184
        }
185
186
        $action = $type::create();
187
188
        $action->Title = $name;
189
190
        if (isset($actionTemplate['properties']) && is_array($actionTemplate['properties'])) {
191
            foreach ($actionTemplate['properties'] as $prop => $val) {
192
                $action->$prop = $val;
193
            }
194
        }
195
        
196
        // Deal with User + Group many_many relations on an action
197
        $this->addManyManyToObject($action, $actionTemplate);
198
199
        if ($definition) {
200
            $action->WorkflowDefID = $definition->ID;
201
        }
202
203
        $action->write();
204
        
205
        return $action;
206
    }
207
    
208
    /**
209
     * Create a WorkflowDefinition->Users relation based on template data. But only if the related groups from the
210
     * export, can be foud in the target environment's DB.
211
     * 
212
     * Note: The template gives us a Member Email to work with rather than an ID as it's arguably
213
     * more likely that Member Emails will be the same between environments than their IDs.
214
     * 
215
     * @param array $users
216
     * @param WorkflowDefinition $definition
217
     * @param boolean $clear
218
     * @return void
219
     */
220
    protected function createUsers($users, WorkflowDefinition $definition, $clear = false)
221
    {
222
        // Create the necessary relation in WorkflowDefinition_Users
223
        $source = array('users' => $users);
224
        $this->addManyManyToObject($definition, $source, $clear);
225
    }
226
    
227
    /**
228
     * Create a WorkflowDefinition->Groups relation based on template data, But only if the related groups from the
229
     * export, can be foud in the target environment's DB.
230
     * 
231
     * Note: The template gives us a Group Title to work with rther than an ID as it's arguably
232
     * more likely that Group titles will be the same between environments than their IDs.
233
     * 
234
     * @param array $groups
235
     * @param WorkflowDefinition $definition
236
     * @param boolean $clear
237
     * @return void
238
     */
239
    protected function createGroups($groups, WorkflowDefinition $definition, $clear = false)
240
    {
241
        // Create the necessary relation in WorkflowDefinition_Groups
242
        $source = array('groups' => $groups);
243
        $this->addManyManyToObject($definition, $source, $clear);
244
    }
245
    
246
    /**
247
     * Update the transitions for a given action
248
     * 
249
     * @param array $actionTemplate
250
     * @param WorkflowAction $action
251
     * 
252
     * @return array
253
     */
254
    protected function updateActionTransitions($actionTemplate, $action)
255
    {
256
        $transitions = array();
257
        if (isset($actionTemplate['transitions']) && is_array($actionTemplate['transitions'])) {
258
            $existing = $action->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...
259
            $transitionMap = array();
260
            foreach ($existing as $transition) {
261
                $transitionMap[$transition->Title] = $transition;
262
            }
263
264
            foreach ($actionTemplate['transitions'] as $transitionName => $transitionTemplate) {
265
                $target = $transitionTemplate;
266
                if (is_array($transitionTemplate)) {
267
                    $to = array_keys($transitionTemplate);
268
                    $transitionName = $to[0];
269
                    $target = $transitionTemplate[$transitionName];
270
                }
271
272
                if (isset($transitionMap[$transitionName])) {
273
                    $transition = $transitionMap[$transitionName];
274
                } else {
275
                    $transition = WorkflowTransition::create();
276
                }
277
                
278
                // Add Member and Group relations to this Transition
279
                $this->addManyManyToObject($transition, $transitionTemplate);
280
281
                $transition->Title = $transitionName;
282
                $transition->ActionID = $action->ID;
283
                // we don't have the NextAction yet other than the target name, so we store that against
284
                // the transition and do a second pass later on to match things up
285
                $transition->Target = $target;
286
                $transitions[] = $transition;
287
            }
288
        }
289
290
        return $transitions;
291
    }
292
    
293
    /**
294
     * Update a workflow definition 
295
     * 
296
     * @param WorkflowDefinition $definition
297
     *				The definition to update
298
     */
299
    public function updateDefinition(WorkflowDefinition $definition)
300
    {
301
        $existingActions = array();
302
        
303
        $existing = $definition->Actions()->column('Title');
0 ignored issues
show
Bug introduced by
The method Actions() does not exist on WorkflowDefinition. Did you maybe mean updateAdminActions()?

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...
304
        $structure = array_keys($this->structure);
305
306
        $removeNames = array_diff($existing, $structure);
307
308
        foreach ($definition->Actions() as $action) {
0 ignored issues
show
Bug introduced by
The method Actions() does not exist on WorkflowDefinition. Did you maybe mean updateAdminActions()?

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...
309
            if (in_array($action->Title, $removeNames)) {
310
                $action->delete();
311
                continue;
312
            }
313
            $existingActions[$action->Title] = $action;
314
        }
315
        
316
        $actions = array();
317
        $transitions = new ArrayObject;
318
        $sort = 1;
319
        // now, go through the structure and create/realign things
320
        foreach ($this->structure as $relationName => $relationTemplate) {
321
            $isAction = isset($relationTemplate['type']);
322
            $isUsers = ($relationName == 'users');
323
            $isGroups = ($relationName == 'groups');
324
            
325
            if ($isAction) {
326
                $action = null;
0 ignored issues
show
Unused Code introduced by
$action is not used, you could remove the assignment.

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

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

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

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

Loading history...
327
                if (isset($existingActions[$relationName])) {
328
                    $action = $existingActions[$relationName];
329
                } else {
330
                    $action = $this->createAction($relationName, $relationTemplate, $definition, $transitions);
0 ignored issues
show
Unused Code introduced by
The call to WorkflowTemplate::createAction() has too many arguments starting with $transitions.

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...
331
                }
332
333
                // add a sort value in! 
334
                $action->Sort = $sort++;
335
                $action->write();
336
337
                $actions[$relationName] = $action;
338
339
                $newTransitions = $this->updateActionTransitions($relationTemplate, $action);
340
                foreach ($newTransitions as $t) {
341
                    $transitions->append($t);
342
                }
343
            }
344
            // Process users on WorkflowDefinition from the template
345
            if ($isUsers) {
346
                $this->createUsers($relationTemplate, $definition, true);
347
            }
348
            // Process groups on WorkflowDefinition from the template
349
            if ($isGroups) {
350
                $this->createGroups($relationTemplate, $definition, true);
351
            }
352
        }
353
        
354 View Code Duplication
        foreach ($transitions as $transition) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
355
            if (isset($actions[$transition->Target])) {
356
                $transition->NextActionID = $actions[$transition->Target]->ID;
357
            }
358
            $transition->write();
359
        }
360
        
361
        // Set the version and do the write at the end so that we don't trigger an infinite loop!!
362
        $definition->Description = $this->getDescription();
0 ignored issues
show
Documentation introduced by
The property Description does not exist on object<WorkflowDefinition>. Since you implemented __set, maybe consider adding a @property annotation.

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

<?php

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

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

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

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

}

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

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

See also the PhpDoc documentation for @property.

Loading history...
363
        $definition->TemplateVersion = $this->getVersion();
0 ignored issues
show
Documentation introduced by
The property TemplateVersion does not exist on object<WorkflowDefinition>. Since you implemented __set, maybe consider adding a @property annotation.

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

<?php

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

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

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

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

}

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

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

See also the PhpDoc documentation for @property.

Loading history...
364
        $definition->RemindDays = $this->getRemindDays();
0 ignored issues
show
Documentation introduced by
The property RemindDays does not exist on object<WorkflowDefinition>. Since you implemented __set, maybe consider adding a @property annotation.

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

<?php

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

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

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

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

}

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

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

See also the PhpDoc documentation for @property.

Loading history...
365
        $definition->Sort = $this->getSort();
0 ignored issues
show
Documentation introduced by
The property Sort does not exist on object<WorkflowDefinition>. Since you implemented __set, maybe consider adding a @property annotation.

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

<?php

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

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

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

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

}

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

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

See also the PhpDoc documentation for @property.

Loading history...
366
        $definition->write();
367
    }
368
    
369
    /**
370
     * Given an object, first check it has a ManyMany relation on it and add() Member and Group relations as required.
371
     * 
372
     * @param Object $object (e.g. WorkflowDefinition, WorkflowAction, WorkflowTransition)
373
     * @param array $source Usually data taken from a YAML template
374
     * @param boolean $clear Lose/keep Group/Member relations on $object (useful for reloading/refreshing definition)
375
     * @return void
376
     */
377
    protected function addManyManyToObject($object, $source, $clear = false)
378
    {
379
        // Check incoming
380
        if (!is_object($object) || !is_array($source)) {
381
            return;
382
        }
383
        
384
        // Only some target class variants actually have Group/User relations
385
        $hasUsers = false;
386
        $hasGroups = false;
387
        if ($manyMany = $object->stat('many_many')) {
388
            if (in_array('Member', $manyMany)) {
389
                $hasUsers = true;
390
                $userRelationName = array_keys($manyMany);
391
            }
392
            if (in_array('Group', $manyMany)) {
393
                $hasGroups = true;
394
                $groupRelationName = array_keys($manyMany);
395
            }
396
        }
397
        
398
        // Deal with User relations on target object
399 View Code Duplication
        if ($hasUsers) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
400
            if ($clear) {
401
                $relName = $userRelationName[0];
0 ignored issues
show
Bug introduced by
The variable $userRelationName does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
402
                $object->$relName()->removeAll();
403
            }
404
            if (isset($source['users']) && is_array($source['users'])) {
405
                foreach ($source['users'] as $user) {
406
                    $email = Convert::raw2sql($user['email']);
407
                    if ($_user = DataObject::get_one('Member', "Email = '".$email."'")) {
408
                        $object->Users()->add($_user);
409
                    }
410
                }
411
            }
412
        }
413
        
414
        // Deal with Group relations on target object
415 View Code Duplication
        if ($hasGroups) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
416
            if ($clear) {
417
                $relName = $groupRelationName[0];
0 ignored issues
show
Bug introduced by
The variable $groupRelationName does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
418
                $object->$relName()->removeAll();
419
            }
420
            if (isset($source['groups']) && is_array($source['groups'])) {
421
                foreach ($source['groups'] as $group) {
422
                    $title = Convert::raw2sql($group['title']);
423
                    if ($_group = DataObject::get_one('Group', "Title = '".$title."'")) {
424
                        $object->Groups()->add($_group);
425
                    }
426
                }
427
            }
428
        }
429
    }
430
}
431