Completed
Branch BUG-9871-email-validation (e62b1a)
by
unknown
350:41 queued 333:27
created

Collection   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 336
Duplicated Lines 10.12 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
dl 34
loc 336
rs 8.3157
c 0
b 0
f 0
wmc 43
lcom 1
cbo 2

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A setCollectionInterface() 0 6 3
A add() 0 8 2
A setIdentifier() 13 13 4
A has() 11 11 3
A hasObject() 0 3 1
A remove() 0 4 1
A setCurrent() 10 10 3
A setCurrentUsingObject() 0 10 3
A previous() 0 8 2
A objectAtIndex() 0 5 1
A slice() 0 8 2
D insertAt() 0 31 9
A removeAt() 0 3 1
A indexOf() 0 11 4
A get() 0 12 3

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 Collection 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 Collection, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace EventEspresso\core\services\collections;
3
4
use  EventEspresso\core\exceptions\InvalidEntityException;
5
use  EventEspresso\core\exceptions\InvalidInterfaceException;
6
use LimitIterator;
7
8
if ( ! defined( 'EVENT_ESPRESSO_VERSION' ) ) {
9
	exit( 'No direct script access allowed' );
10
}
11
/**
12
 * Class Collection
13
 * class for managing a set of entities that all adhere to the same interface
14
 * unofficially follows Interop\Container\ContainerInterface
15
 *
16
 * @package       Event Espresso
17
 * @author        Brent Christensen
18
 * @since         4.9.0
19
 */
20
 class Collection extends \SplObjectStorage implements CollectionInterface {
21
22
23
	 /**
24
	  * an interface (or class) name to be used for restricting the type of objects added to the storage
25
	  * this should be set from within the child class constructor
26
	  *
27
	  * @type string $interface
28
	  */
29
	 protected $collection_interface;
30
31
32
33
	 /**
34
	  * Collection constructor
35
	  *
36
	  * @param string $collection_interface
37
	  * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
38
	  */
39
	 public function __construct( $collection_interface ) {
40
		 $this->setCollectionInterface( $collection_interface );
41
	 }
42
43
44
45
	 /**
46
	  * setCollectionInterface
47
	  *
48
	  * @access protected
49
	  * @param  string $collection_interface
50
	  * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
51
	  */
52
	 protected function setCollectionInterface( $collection_interface ) {
53
		 if ( ! ( interface_exists( $collection_interface ) || class_exists( $collection_interface ) ) ) {
54
			 throw new InvalidInterfaceException( $collection_interface );
55
		 }
56
		 $this->collection_interface = $collection_interface;
57
	 }
58
59
60
61
	 /**
62
	  * add
63
	  * attaches an object to the Collection
64
	  * and sets any supplied data associated with the current iterator entry
65
	  * by calling EE_Object_Collection::set_identifier()
66
	  *
67
	  * @access public
68
	  * @param        $object
69
	  * @param  mixed $identifier
70
	  * @return bool
71
	  * @throws \EventEspresso\core\exceptions\InvalidEntityException
72
	  */
73
	 public function add( $object, $identifier = null ) {
74
		 if ( ! $object instanceof $this->collection_interface ) {
75
			 throw new InvalidEntityException( $object, $this->collection_interface );
76
		 }
77
		 $this->attach( $object );
78
		 $this->setIdentifier( $object, $identifier );
79
		 return $this->contains( $object );
80
	 }
81
82
83
84
	 /**
85
	  * setIdentifier
86
87
	  * Sets the data associated with an object in the Collection
88
	  * if no $identifier is supplied, then the spl_object_hash() is used
89
	  *
90
	  * @access public
91
	  * @param  $object
92
	  * @param  mixed $identifier
93
	  * @return bool
94
	  */
95 View Code Duplication
	 public function setIdentifier( $object, $identifier = null ) {
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...
96
		 $identifier = ! empty( $identifier ) ? $identifier : spl_object_hash( $object );
97
		 $this->rewind();
98
		 while ( $this->valid() ) {
99
			 if ( $object === $this->current() ) {
100
				 $this->setInfo( $identifier );
101
				 $this->rewind();
102
				 return true;
103
			 }
104
			 $this->next();
105
		 }
106
		 return false;
107
	 }
108
109
110
111
	 /**
112
	  * get
113
	  * finds and returns an object in the Collection based on the identifier that was set using addObject()
114
	  * PLZ NOTE: the pointer is reset to the beginning of the collection before returning
115
	  *
116
	  * @access public
117
	  * @param mixed $identifier
118
	  * @return mixed
119
	  */
120
	 public function get( $identifier ) {
121
		 $this->rewind();
122
		 while ( $this->valid() ) {
123
			 if ( $identifier === $this->getInfo() ) {
124
				 $object = $this->current();
125
				 $this->rewind();
126
				 return $object;
127
			 }
128
			 $this->next();
129
		 }
130
		 return null;
131
	 }
132
133
134
135
	 /**
136
	  * has
137
	  * returns TRUE or FALSE
138
	  * depending on whether the object is within the Collection
139
	  * based on the supplied $identifier
140
	  *
141
	  * @access public
142
	  * @param  mixed $identifier
143
	  * @return bool
144
	  */
145 View Code Duplication
	 public function has( $identifier ) {
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...
146
		 $this->rewind();
147
		 while ( $this->valid() ) {
148
			 if ( $identifier === $this->getInfo() ) {
149
				 $this->rewind();
150
				 return true;
151
			 }
152
			 $this->next();
153
		 }
154
		 return false;
155
	 }
156
157
158
159
	 /**
160
	  * hasObject
161
	  * returns TRUE or FALSE depending on whether the supplied object is within the Collection
162
	  *
163
	  * @access public
164
	  * @param $object
165
	  * @return bool
166
	  */
167
	 public function hasObject( $object ) {
168
		 return $this->contains( $object );
169
	 }
170
171
172
173
	 /**
174
	  * remove
175
	  * detaches an object from the Collection
176
	  *
177
	  * @access public
178
	  * @param $object
179
	  * @return bool
180
	  */
181
	 public function remove( $object ) {
182
		 $this->detach( $object );
183
		 return true;
184
	 }
185
186
187
188
	 /**
189
	  * setCurrent
190
	  * advances pointer to the object whose identifier matches that which was provided
191
	  *
192
	  * @access public
193
	  * @param mixed $identifier
194
	  * @return boolean
195
	  */
196 View Code Duplication
	 public function setCurrent( $identifier ) {
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...
197
		 $this->rewind();
198
		 while ( $this->valid() ) {
199
			 if ( $identifier === $this->getInfo() ) {
200
				 return true;
201
			 }
202
			 $this->next();
203
		 }
204
		 return false;
205
	 }
206
207
208
209
	 /**
210
	  * setCurrentUsingObject
211
	  * advances pointer to the provided object
212
	  *
213
	  * @access public
214
	  * @param $object
215
	  * @return boolean
216
	  */
217
	 public function setCurrentUsingObject( $object ) {
218
		 $this->rewind();
219
		 while ( $this->valid() ) {
220
			 if ( $this->current() === $object ) {
221
				 return true;
222
			 }
223
			 $this->next();
224
		 }
225
		 return false;
226
	 }
227
228
229
230
	 /**
231
	  * Returns the object occupying the index before the current object,
232
	  * unless this is already the first object, in which case it just returns the first object
233
	  *
234
	  * @return mixed
235
	  */
236
	 public function previous() {
237
		 $index = $this->indexOf( $this->current() );
238
		 if ( $index === 0 ) {
239
			 return $this->current();
240
		 }
241
		 $index--;
242
		 return $this->objectAtIndex( $index );
243
	 }
244
245
246
247
	 /**
248
	  * Returns the index of a given object, or false if not found
249
	  *
250
	  * @see http://stackoverflow.com/a/8736013
251
	  * @param $object
252
	  * @return boolean|int|string
253
	  */
254
	 public function indexOf( $object ) {
255
		 if ( ! $this->contains( $object ) ) {
256
			 return false;
257
		 }
258
		 foreach ( $this as $index => $obj ) {
259
			 if ( $obj === $object ) {
260
				 return $index;
261
			 }
262
		 }
263
		 return false;
264
	 }
265
266
267
268
	 /**
269
	  * Returns the object at the given index
270
	  *
271
	  * @see http://stackoverflow.com/a/8736013
272
	  * @param int $index
273
	  * @return mixed
274
	  */
275
	 public function objectAtIndex( $index ) {
276
		 $iterator = new LimitIterator( $this, $index, 1 );
277
		 $iterator->rewind();
278
		 return $iterator->current();
279
	 }
280
281
282
283
	 /**
284
	  * Returns the sequence of objects as specified by the offset and length
285
	  *
286
	  * @see http://stackoverflow.com/a/8736013
287
	  * @param int $offset
288
	  * @param int $length
289
	  * @return array
290
	  */
291
	 public function slice( $offset, $length ) {
292
		 $slice = array();
293
		 $iterator = new LimitIterator( $this, $offset, $length );
294
		 foreach ( $iterator as $object ) {
295
			 $slice[] = $object;
296
		 }
297
		 return $slice;
298
	 }
299
300
301
302
	 /**
303
	  * Inserts an object (or an array of objects) at a certain point
304
	  *
305
	  * @see http://stackoverflow.com/a/8736013
306
	  * @param mixed $objects A single object or an array of objects
307
	  * @param int $index
308
	  */
309
	 public function insertAt( $objects, $index ) {
310
		 if ( ! is_array( $objects ) ) {
311
			 $objects = array( $objects );
312
		 }
313
		 // check to ensure that objects don't already exist in the collection
314
		 foreach ( $objects as $key => $object ) {
315
			 if ( $this->contains( $object ) ) {
316
				 unset( $objects[ $key ] );
317
			 }
318
		 }
319
		 // do we have any objects left?
320
		 if ( ! $objects ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $objects of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
321
			 return;
322
		 }
323
		 // detach any objects at or past this index
324
		 $remaining = array();
325
		 if ( $index < $this->count() ) {
326
			 $remaining = $this->slice( $index, $this->count() - $index );
327
			 foreach ( $remaining as $object ) {
328
				 $this->detach( $object );
329
			 }
330
		 }
331
		 // add the new objects we're splicing in
332
		 foreach ( $objects as $object ) {
333
			 $this->attach( $object );
334
		 }
335
		 // attach the objects we previously detached
336
		 foreach ( $remaining as $object ) {
337
			 $this->attach( $object );
338
		 }
339
	 }
340
341
342
343
	 /**
344
	  * Removes the object at the given index
345
	  *
346
	  * @see http://stackoverflow.com/a/8736013
347
	  * @param int $index
348
	  */
349
	 public function removeAt( $index ) {
350
		 $this->detach( $this->objectAtIndex( $index ) );
351
	 }
352
353
354
355
 }
356
// End of file Collection.php
357
// Location: /Collection.php