Completed
Push — master ( 19c58b...139b81 )
by Tim
03:17
created

AbstractObserver   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 426
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 43
lcom 1
cbo 0
dl 0
loc 426
ccs 0
cts 148
cp 0
rs 8.3157
c 0
b 0
f 0

30 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 2
A setSubject() 0 4 1
A getSubject() 0 4 1
A setHeaders() 0 4 1
A getHeaders() 0 4 1
A setRow() 0 4 1
A getRow() 0 4 1
A isDebugMode() 0 4 1
A skipRow() 0 4 1
A getFilename() 0 4 1
A getLineNumber() 0 4 1
A getSystemLogger() 0 4 1
A getMultipleFieldDelimiter() 0 4 1
A hasHeader() 0 4 1
A getHeader() 0 4 1
A addHeader() 0 4 1
A getLastEntityId() 0 4 1
A getSourceDateFormat() 0 4 1
A castValueByBackendType() 0 4 1
A setStoreViewCode() 0 4 1
A getStoreViewCode() 0 4 1
A prepareStoreViewCode() 0 11 2
A formatDate() 0 11 2
A explode() 0 11 2
A hasValue() 0 15 3
A setValue() 0 4 1
C getValue() 0 29 8
A getCoreConfigData() 0 4 1
A initializeEntity() 0 4 1
A mergeEntity() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like AbstractObserver 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 AbstractObserver, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * TechDivision\Import\Observers\AbstractObserver
5
 *
6
 * NOTICE OF LICENSE
7
 *
8
 * This source file is subject to the Open Software License (OSL 3.0)
9
 * that is available through the world-wide-web at this URL:
10
 * http://opensource.org/licenses/osl-3.0.php
11
 *
12
 * PHP version 5
13
 *
14
 * @author    Tim Wagner <[email protected]>
15
 * @copyright 2016 TechDivision GmbH <[email protected]>
16
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
 * @link      https://github.com/techdivision/import
18
 * @link      http://www.techdivision.com
19
 */
20
21
namespace TechDivision\Import\Observers;
22
23
use TechDivision\Import\Utils\EntityStatus;
24
use TechDivision\Import\Utils\ColumnKeys;
25
use TechDivision\Import\Utils\ScopeKeys;
26
27
/**
28
 * An abstract observer implementation.
29
 *
30
 * @author    Tim Wagner <[email protected]>
31
 * @copyright 2016 TechDivision GmbH <[email protected]>
32
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
33
 * @link      https://github.com/techdivision/import
34
 * @link      http://www.techdivision.com
35
 */
36
abstract class AbstractObserver implements ObserverInterface
37
{
38
39
    /**
40
     * The actual row, that has to be processed.
41
     *
42
     * @var array
43
     */
44
    protected $row = array();
45
46
    /**
47
     * The obeserver's subject instance.
48
     *
49
     * @var object
50
     */
51
    protected $subject;
52
53
    /**
54
     * Initializes the observer with the passed subject instance.
55
     *
56
     * @param object|null $subject The observer's subject instance
57
     */
58
    public function __construct($subject = null)
59
    {
60
        if ($subject != null) {
61
            $this->setSubject($subject);
62
        }
63
    }
64
65
    /**
66
     * Set's the obeserver's subject instance to initialize the observer with.
67
     *
68
     * @param object $subject The observer's subject
69
     *
70
     * @return void
71
     */
72
    public function setSubject($subject)
73
    {
74
        $this->subject = $subject;
75
    }
76
77
    /**
78
     * Return's the observer's subject instance.
79
     *
80
     * @return object The observer's subject instance
81
     */
82
    public function getSubject()
83
    {
84
        return $this->subject;
85
    }
86
87
    /**
88
     * Set's the array containing header row.
89
     *
90
     * @param array $headers The array with the header row
91
     *
92
     * @return void
93
     */
94
    public function setHeaders(array $headers)
95
    {
96
        $this->getSubject()->setHeaders($headers);
97
    }
98
99
    /**
100
     * Return's the array containing header row.
101
     *
102
     * @return array The array with the header row
103
     */
104
    public function getHeaders()
105
    {
106
        return $this->getSubject()->getHeaders();
107
    }
108
109
    /**
110
     * Set's the actual row, that has to be processed.
111
     *
112
     * @param array $row The row
113
     *
114
     * @return void
115
     */
116
    protected function setRow(array $row)
117
    {
118
        $this->row = $row;
119
    }
120
121
    /**
122
     * Return's the actual row, that has to be processed.
123
     *
124
     * @return array The row
125
     */
126
    protected function getRow()
127
    {
128
        return $this->row;
129
    }
130
131
    /**
132
     * Queries whether or not debug mode is enabled or not, default is TRUE.
133
     *
134
     * @return boolean TRUE if debug mode is enabled, else FALSE
135
     */
136
    protected function isDebugMode()
137
    {
138
        return $this->getSubject()->isDebugMode();
139
    }
140
141
    /**
142
     * Stop's observer execution on the actual row.
143
     *
144
     * @return void
145
     */
146
    protected function skipRow()
147
    {
148
        $this->getSubject()->skipRow();
149
    }
150
151
    /**
152
     * Return's the name of the file to import.
153
     *
154
     * @return string The filename
155
     */
156
    protected function getFilename()
157
    {
158
        return $this->getSubject()->getFilename();
159
    }
160
161
    /**
162
     * Return's the actual line number.
163
     *
164
     * @return integer The line number
165
     */
166
    protected function getLineNumber()
167
    {
168
        return $this->getSubject()->getLineNumber();
169
    }
170
171
    /**
172
     * Return's the system logger.
173
     *
174
     * @return \Psr\Log\LoggerInterface The system logger instance
175
     */
176
    protected function getSystemLogger()
177
    {
178
        return $this->getSubject()->getSystemLogger();
179
    }
180
181
    /**
182
     * Return's the multiple field delimiter character to use, default value is comma (,).
183
     *
184
     * @return string The multiple field delimiter character
185
     */
186
    protected function getMultipleFieldDelimiter()
187
    {
188
        return $this->getSubject()->getMultipleFieldDelimiter();
189
    }
190
191
    /**
192
     * Queries whether or not the header with the passed name is available.
193
     *
194
     * @param string $name The header name to query
195
     *
196
     * @return boolean TRUE if the header is available, else FALSE
197
     */
198
    protected function hasHeader($name)
199
    {
200
        return $this->getSubject()->hasHeader($name);
201
    }
202
203
    /**
204
     * Return's the header value for the passed name.
205
     *
206
     * @param string $name The name of the header to return the value for
207
     *
208
     * @return mixed The header value
209
     * \InvalidArgumentException Is thrown, if the header with the passed name is NOT available
210
     */
211
    protected function getHeader($name)
212
    {
213
        return $this->getSubject()->getHeader($name);
214
    }
215
216
    /**
217
     * Add's the header with the passed name and position, if not NULL.
218
     *
219
     * @param string $name The header name to add
220
     *
221
     * @return integer The new headers position
222
     */
223
    protected function addHeader($name)
224
    {
225
        return $this->getSubject()->addHeader($name);
226
    }
227
228
    /**
229
     * Return's the ID of the product that has been created recently.
230
     *
231
     * @return string The entity Id
232
     */
233
    protected function getLastEntityId()
234
    {
235
        return $this->getSubject()->getLastEntityId();
236
    }
237
238
    /**
239
     * Return's the source date format to use.
240
     *
241
     * @return string The source date format
242
     */
243
    protected function getSourceDateFormat()
244
    {
245
        return $this->getSubject()->getSourceDateFormat();
246
    }
247
248
    /**
249
     * Cast's the passed value based on the backend type information.
250
     *
251
     * @param string $backendType The backend type to cast to
252
     * @param mixed  $value       The value to be casted
253
     *
254
     * @return mixed The casted value
255
     */
256
    protected function castValueByBackendType($backendType, $value)
257
    {
258
        return $this->getSubject()->castValueByBackendType($backendType, $value);
259
    }
260
261
    /**
262
     * Set's the store view code the create the product/attributes for.
263
     *
264
     * @param string $storeViewCode The store view code
265
     *
266
     * @return void
267
     */
268
    protected function setStoreViewCode($storeViewCode)
269
    {
270
        $this->getSubject()->setStoreViewCode($storeViewCode);
271
    }
272
273
    /**
274
     * Return's the store view code the create the product/attributes for.
275
     *
276
     * @param string|null $default The default value to return, if the store view code has not been set
277
     *
278
     * @return string The store view code
279
     */
280
    protected function getStoreViewCode($default = null)
281
    {
282
        return $this->getSubject()->getStoreViewCode($default);
283
    }
284
285
    /**
286
     * Prepare's the store view code in the subject.
287
     *
288
     * @return void
289
     */
290
    protected function prepareStoreViewCode()
291
    {
292
293
        // re-set the store view code
294
        $this->setStoreViewCode(null);
295
296
        // initialize the store view code
297
        if ($storeViewCode = $this->getValue(ColumnKeys::STORE_VIEW_CODE)) {
298
            $this->setStoreViewCode($storeViewCode);
299
        }
300
    }
301
302
    /**
303
     * Tries to format the passed value to a valid date with format 'Y-m-d H:i:s'.
304
     * If the passed value is NOT a valid date, NULL will be returned.
305
     *
306
     * @param string|null $value The value to format
307
     *
308
     * @return string The formatted date
309
     */
310
    protected function formatDate($value)
311
    {
312
313
        // create a DateTime instance from the passed value
314
        if ($dateTime = \DateTime::createFromFormat($this->getSourceDateFormat(), $value)) {
315
            return $dateTime->format('Y-m-d H:i:s');
316
        }
317
318
        // return NULL, if the passed value is NOT a valid date
319
        return null;
320
    }
321
322
    /**
323
     * Extracts the elements of the passed value by exploding them
324
     * with the also passed delimiter.
325
     *
326
     * @param string      $value     The value to extract
327
     * @param string|null $delimiter The delimiter used to extrace the elements
328
     *
329
     * @return array The exploded values
330
     */
331
    protected function explode($value, $delimiter = null)
332
    {
333
334
        // load the default multiple field delimiter
335
        if ($delimiter === null) {
336
            $delimiter = $this->getMultipleFieldDelimiter();
337
        }
338
339
        // explode and return the array with the values, by using the delimiter
340
        return explode($delimiter, $value);
341
    }
342
343
    /**
344
     * Query whether or not a value for the column with the passed name exists.
345
     *
346
     * @param string $name The column name to query for a valid value
347
     *
348
     * @return boolean TRUE if the value is set, else FALSE
349
     */
350
    protected function hasValue($name)
351
    {
352
353
        // query whether or not the header is available
354
        if ($this->hasHeader($name)) {
355
            // load the key for the row
356
            $headerValue = $this->getHeader($name);
357
358
            // query whether the rows column has a vaild value
359
            return (isset($this->row[$headerValue]) && $this->row[$headerValue] != '');
360
        }
361
362
        // return FALSE if not
363
        return false;
364
    }
365
366
    /**
367
     * Set the value in the passed column name.
368
     *
369
     * @param string $name  The column name to set the value for
370
     * @param mixed  $value The value to set
371
     *
372
     * @return void
373
     */
374
    protected function setValue($name, $value)
375
    {
376
        $this->row[$this->getHeader($name)] = $value;
377
    }
378
379
    /**
380
     * Resolve's the value with the passed colum name from the actual row. If a callback will
381
     * be passed, the callback will be invoked with the found value as parameter. If
382
     * the value is NULL or empty, the default value will be returned.
383
     *
384
     * @param string        $name     The name of the column to return the value for
385
     * @param mixed|null    $default  The default value, that has to be returned, if the row's value is empty
386
     * @param callable|null $callback The callback that has to be invoked on the value, e. g. to format it
387
     *
388
     * @return mixed|null The, almost formatted, value
389
     */
390
    protected function getValue($name, $default = null, callable $callback = null)
391
    {
392
393
        // initialize the value
394
        $value = null;
395
396
        // query whether or not the header is available
397
        if ($this->hasHeader($name)) {
398
            // load the header value
399
            $headerValue = $this->getHeader($name);
400
            // query wheter or not, the value with the requested key is available
401
            if ((isset($this->row[$headerValue]) && $this->row[$headerValue] != '')) {
402
                $value = $this->row[$headerValue];
403
            }
404
        }
405
406
        // query whether or not, a callback has been passed
407
        if ($value != null && is_callable($callback)) {
408
            $value = call_user_func($callback, $value);
409
        }
410
411
        // query whether or not
412
        if ($value == null && $default !== null) {
413
            $value = $default;
414
        }
415
416
        // return the value
417
        return $value;
418
    }
419
420
    /**
421
     * Return's the Magento configuration value.
422
     *
423
     * @param string  $path    The Magento path of the requested configuration value
424
     * @param mixed   $default The default value that has to be returned, if the requested configuration value is not set
425
     * @param string  $scope   The scope the configuration value has been set
426
     * @param integer $scopeId The scope ID the configuration value has been set
427
     *
428
     * @return mixed The configuration value
429
     * @throws \Exception Is thrown, if nor a value can be found or a default value has been passed
430
     */
431
    protected function getCoreConfigData($path, $default = null, $scope = ScopeKeys::SCOPE_DEFAULT, $scopeId = 0)
432
    {
433
        return $this->getSubject()->getCoreConfigData($path, $default, $scope, $scopeId);
434
    }
435
436
    /**
437
     * Initialize's and return's a new entity with the status 'create'.
438
     *
439
     * @param array $attr The attributes to merge into the new entity
440
     *
441
     * @return array The initialized entity
442
     */
443
    protected function initializeEntity(array $attr = array())
444
    {
445
        return array_merge(array(EntityStatus::MEMBER_NAME => EntityStatus::STATUS_CREATE), $attr);
446
    }
447
448
    /**
449
     * Merge's and return's the entity with the passed attributes and set's the
450
     * status to 'update'.
451
     *
452
     * @param array $entity The entity to merge the attributes into
453
     * @param array $attr   The attributes to be merged
454
     *
455
     * @return array The merged entity
456
     */
457
    protected function mergeEntity(array $entity, array $attr)
458
    {
459
        return array_merge($entity, $attr, array(EntityStatus::MEMBER_NAME => EntityStatus::STATUS_UPDATE));
460
    }
461
}
462