WorkflowTemplate::addManyManyToObject()   D
last analyzed

Complexity

Conditions 18
Paths 226

Size

Total Lines 52
Code Lines 30

Duplication

Lines 28
Ratio 53.85 %
Metric Value
dl 28
loc 52
rs 4.8815
cc 18
eloc 30
nc 226
nop 3

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
	protected $name;
62
	protected $description;
63
	protected $version;
64
	protected $remindDays;
65
	protected $sort;
66
	
67
	/**
68
	 * An array representation of the structure of this workflow template
69
	 * 
70
	 * @var array
71
	 */
72
	protected $structure;
73
	
74
	public function __construct($name, $description = '', $version = '0.0', $remindDays = 0, $sort = 0) {
75
		$this->name = $name;
76
		$this->description = $description;
77
		$this->version = $version;
78
		$this->remindDays = $remindDays;
79
		$this->sort = $sort;
80
	}
81
	
82
	public function getName() {
83
		return $this->name;
84
	}
85
	
86
	public function getVersion() {
87
		return $this->version;
88
	}
89
	
90
	public function getDescription() {
91
		return $this->description;
92
	}
93
	
94
	public function getRemindDays() {
95
		return $this->remindDays;
96
	}
97
	
98
	public function getSort() {
99
		return $this->sort;
100
	}		
101
	
102
	/**
103
	 * Set the structure for this template
104
	 * 
105
	 * @param array $structure 
106
	 */
107
	public function setStructure($structure) {
108
		$this->structure = $structure;
109
	}
110
	
111
	/**
112
	 * Creates the relevant data objects for this structure, returning an array
113
	 * of actions in the order they've been created 
114
	 * 
115
	 * @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...
116
	 *				An optional workflow definition to bind the actions into
117
	 * @return array
118
	 */
119
	public function createRelations($definition = null) {
120
		$actions = array();
121
		$transitions = new ArrayObject();
122
		$sort = 1;
123
		foreach ($this->structure as $relationName => $relationTemplate) {
124
			
125
			$isAction = isset($relationTemplate['type']);
126
			$isUsers = ($relationName == 'users');
127
			$isGroups = ($relationName == 'groups');
128
			
129
			// Process actions on WorkflowDefinition from the template
130
			if($isAction) {
131
				$action = $this->createAction($relationName, $relationTemplate, $definition);
132
				// add a sort value in! 
133
				$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...
134
				$action->write();
135
136
				$actions[$relationName] = $action;
137
138
				$newTransitions = $this->updateActionTransitions($relationTemplate, $action);
139
				foreach ($newTransitions as $t) {
140
					$transitions->append($t);
141
				}
142
			}
143
			// Process users on WorkflowDefinition from the template
144
			if($isUsers) {
145
				$this->createUsers($relationTemplate, $definition);
146
			}
147
			// Process groups on WorkflowDefinition from the template
148
			if($isGroups) {
149
				$this->createGroups($relationTemplate, $definition);
150
			}			
151
		}
152
153 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...
154
			if (isset($actions[$transition->Target])) {
155
				$transition->NextActionID = $actions[$transition->Target]->ID;
156
			}
157
			$transition->write();
158
		}
159
		
160
		return $actions;
161
	}
162
	
163
	/**
164
	 * Create a workflow action based on a template
165
	 * 
166
	 * @param string $name
167
	 * @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...
168
	 * @param WorkflowDefinition $definition
169
	 * @return WorkflowAction
170
	 */
171
	protected function createAction($name, $actionTemplate, WorkflowDefinition $definition = null) {
172
		$type = $actionTemplate['type'];
173
		if (!$type || !class_exists($type)) {
174
			throw new Exception(_t('WorkflowTemplate.INVALID_TEMPLATE_ACTION', 'Invalid action class specified in template'));
175
		}
176
177
		$action = $type::create();
178
179
		$action->Title = $name;
180
181
		if (isset($actionTemplate['properties']) && is_array($actionTemplate['properties'])) {
182
			foreach ($actionTemplate['properties'] as $prop => $val) {
183
				$action->$prop = $val;
184
			}
185
		}
186
		
187
		// Deal with User + Group many_many relations on an action
188
		$this->addManyManyToObject($action, $actionTemplate);		
189
190
		if ($definition) {
191
			$action->WorkflowDefID = $definition->ID;
192
		}
193
194
		$action->write();
195
		
196
		return $action;
197
	}
198
	
199
	/**
200
	 * Create a WorkflowDefinition->Users relation based on template data. But only if the related groups from the
201
	 * export, can be foud in the target environment's DB.
202
	 * 
203
	 * Note: The template gives us a Member Email to work with rather than an ID as it's arguably
204
	 * more likely that Member Emails will be the same between environments than their IDs.
205
	 * 
206
	 * @param array $users
207
	 * @param WorkflowDefinition $definition
208
	 * @param boolean $clear
209
	 * @return void
210
	 */
211
	protected function createUsers($users, WorkflowDefinition $definition, $clear = false) {
212
		// Create the necessary relation in WorkflowDefinition_Users
213
		$source = array('users' => $users);
214
		$this->addManyManyToObject($definition, $source, $clear);
215
	}
216
	
217
	/**
218
	 * Create a WorkflowDefinition->Groups relation based on template data, But only if the related groups from the
219
	 * export, can be foud in the target environment's DB.
220
	 * 
221
	 * Note: The template gives us a Group Title to work with rther than an ID as it's arguably
222
	 * more likely that Group titles will be the same between environments than their IDs.
223
	 * 
224
	 * @param array $groups
225
	 * @param WorkflowDefinition $definition
226
	 * @param boolean $clear
227
	 * @return void
228
	 */
229
	protected function createGroups($groups, WorkflowDefinition $definition, $clear = false) {
230
		// Create the necessary relation in WorkflowDefinition_Groups
231
		$source = array('groups' => $groups);
232
		$this->addManyManyToObject($definition, $source, $clear);
233
	}	
234
	
235
	/**
236
	 * Update the transitions for a given action
237
	 * 
238
	 * @param array $actionTemplate
239
	 * @param WorkflowAction $action
240
	 * 
241
	 * @return array
242
	 */
243
	protected function updateActionTransitions($actionTemplate, $action) {
244
		$transitions = array();
245
		if (isset($actionTemplate['transitions']) && is_array($actionTemplate['transitions'])) {
246
			
247
			$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...
248
			$transitionMap = array();
249
			foreach ($existing as $transition) {
250
				$transitionMap[$transition->Title] = $transition;
251
			}
252
253
			foreach ($actionTemplate['transitions'] as $transitionName => $transitionTemplate) {
254
				$target = $transitionTemplate;
255
				if (is_array($transitionTemplate)) {
256
					$to = array_keys($transitionTemplate);
257
					$transitionName = $to[0];
258
					$target = $transitionTemplate[$transitionName];
259
				}
260
261
				if (isset($transitionMap[$transitionName])) {
262
					$transition = $transitionMap[$transitionName];
263
				} else {
264
					$transition = WorkflowTransition::create();
265
				}
266
				
267
				// Add Member and Group relations to this Transition
268
				$this->addManyManyToObject($transition, $transitionTemplate);
269
270
				$transition->Title = $transitionName;
271
				$transition->ActionID = $action->ID;
272
				// we don't have the NextAction yet other than the target name, so we store that against
273
				// the transition and do a second pass later on to match things up
274
				$transition->Target = $target;
275
				$transitions[] = $transition;
276
			}
277
		}
278
279
		return $transitions;
280
	}
281
	
282
	/**
283
	 * Update a workflow definition 
284
	 * 
285
	 * @param WorkflowDefinition $definition
286
	 *				The definition to update
287
	 */
288
	public function updateDefinition(WorkflowDefinition $definition) {
289
		$existingActions = array();
290
		
291
		$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...
292
		$structure = array_keys($this->structure);
293
294
		$removeNames = array_diff($existing, $structure);
295
296
		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...
297
			if (in_array($action->Title, $removeNames)) {
298
				$action->delete();
299
				continue;
300
			}
301
			$existingActions[$action->Title] = $action;
302
		}
303
		
304
		$actions = array();
305
		$transitions = new ArrayObject;
306
		$sort = 1;
307
		// now, go through the structure and create/realign things
308
		foreach ($this->structure as $relationName => $relationTemplate) {
309
			
310
			$isAction = isset($relationTemplate['type']);
311
			$isUsers = ($relationName == 'users');
312
			$isGroups = ($relationName == 'groups');
313
			
314
			if($isAction) {
315
				$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...
316
				if (isset($existingActions[$relationName])) {
317
					$action = $existingActions[$relationName];
318
				} else {
319
					$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...
320
				}
321
322
				// add a sort value in! 
323
				$action->Sort = $sort++;
324
				$action->write();
325
326
				$actions[$relationName] = $action;
327
328
				$newTransitions = $this->updateActionTransitions($relationTemplate, $action);
329
				foreach ($newTransitions as $t) {
330
					$transitions->append($t);
331
				}
332
			}
333
			// Process users on WorkflowDefinition from the template
334
			if($isUsers) {
335
				$this->createUsers($relationTemplate, $definition, true);
336
			}
337
			// Process groups on WorkflowDefinition from the template
338
			if($isGroups) {
339
				$this->createGroups($relationTemplate, $definition, true);
340
			}			
341
		}
342
		
343 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...
344
			if (isset($actions[$transition->Target])) {
345
				$transition->NextActionID = $actions[$transition->Target]->ID;
346
			}
347
			$transition->write();
348
		}
349
		
350
		// Set the version and do the write at the end so that we don't trigger an infinite loop!!
351
		$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...
352
		$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...
353
		$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...
354
		$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...
355
		$definition->write();
356
	}
357
	
358
	/**
359
	 * Given an object, first check it has a ManyMany relation on it and add() Member and Group relations as required.
360
	 * 
361
	 * @param Object $object (e.g. WorkflowDefinition, WorkflowAction, WorkflowTransition)
362
	 * @param array $source Usually data taken from a YAML template
363
	 * @param boolean $clear Lose/keep Group/Member relations on $object (useful for reloading/refreshing definition)
364
	 * @return void
365
	 */
366
	protected function addManyManyToObject($object, $source, $clear = false) {
367
		// Check incoming
368
		if(!is_object($object) || !is_array($source)) {
369
			return;
370
		}
371
		
372
		// Only some target class variants actually have Group/User relations
373
		$hasUsers = false;
374
		$hasGroups = false;
375
		if($manyMany = $object->stat('many_many')) {
376
			if(in_array('Member', $manyMany)) {
377
				$hasUsers = true;
378
				$userRelationName = array_keys($manyMany);
379
			}
380
			if(in_array('Group', $manyMany)) {
381
				$hasGroups = true;
382
				$groupRelationName = array_keys($manyMany);
383
			}			
384
		}
385
		
386
		// Deal with User relations on target object
387 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...
388
			if($clear) {
389
				$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...
390
				$object->$relName()->removeAll();
391
			}
392
			if(isset($source['users']) && is_array($source['users'])) {
393
				foreach ($source['users'] as $user) {
394
					$email = Convert::raw2sql($user['email']);
395
					if($_user = DataObject::get_one('Member', "Email = '".$email."'")) {
396
						$object->Users()->add($_user);
397
					}
398
				}			
399
			}
400
		}	
401
		
402
		// Deal with Group relations on target object
403 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...
404
			if($clear) {
405
				$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...
406
				$object->$relName()->removeAll();
407
			}			
408
			if(isset($source['groups']) && is_array($source['groups'])) {
409
				foreach ($source['groups'] as $group) {
410
					$title = Convert::raw2sql($group['title']);
411
					if($_group = DataObject::get_one('Group', "Title = '".$title."'")) {
412
						$object->Groups()->add($_group);
413
					}
414
				}
415
			}
416
		}		
417
	}
418
}
419