Completed
Pull Request — master (#76)
by Tim
02:59
created

AbstractObserver::getSystemLoggers()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
ccs 0
cts 4
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 2
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\ScopeKeys;
24
use TechDivision\Import\Utils\LoggerKeys;
25
use TechDivision\Import\Utils\EntityStatus;
26
use TechDivision\Import\Subjects\SubjectInterface;
27
28
/**
29
 * An abstract observer implementation.
30
 *
31
 * @author    Tim Wagner <[email protected]>
32
 * @copyright 2016 TechDivision GmbH <[email protected]>
33
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
34
 * @link      https://github.com/techdivision/import
35
 * @link      http://www.techdivision.com
36
 */
37
abstract class AbstractObserver implements ObserverInterface
38
{
39
40
    /**
41
     * The actual row, that has to be processed.
42
     *
43
     * @var array
44
     */
45
    protected $row = array();
46
47
    /**
48
     * The obeserver's subject instance.
49
     *
50
     * @var \TechDivision\Import\Subjects\SubjectInterface
51
     */
52
    protected $subject;
53
54
    /**
55
     * Set's the obeserver's subject instance to initialize the observer with.
56
     *
57
     * @param object $subject The observer's subject
58
     *
59
     * @return void
60
     */
61
    public function setSubject($subject)
62
    {
63
        $this->subject = $subject;
64
    }
65
66
    /**
67
     * Return's the observer's subject instance.
68
     *
69
     * @return object The observer's subject instance
70
     */
71
    public function getSubject()
72
    {
73
        return $this->subject;
74
    }
75
76
    /**
77
     * Set's the array containing header row.
78
     *
79
     * @param array $headers The array with the header row
80
     *
81
     * @return void
82
     */
83
    public function setHeaders(array $headers)
84
    {
85
        $this->getSubject()->setHeaders($headers);
86
    }
87
88
    /**
89
     * Return's the array containing header row.
90
     *
91
     * @return array The array with the header row
92
     */
93
    public function getHeaders()
94
    {
95
        return $this->getSubject()->getHeaders();
96
    }
97
98
    /**
99
     * Return's the RegistryProcessor instance to handle the running threads.
100
     *
101
     * @return \TechDivision\Import\Services\RegistryProcessorInterface The registry processor instance
102
     */
103
    public function getRegistryProcessor()
104
    {
105
        return $this->getSubject()->getRegistryProcessor();
106
    }
107
108
    /**
109
     * Set's the actual row, that has to be processed.
110
     *
111
     * @param array $row The row
112
     *
113
     * @return void
114
     */
115
    protected function setRow(array $row)
116
    {
117
        $this->row = $row;
118
    }
119
120
    /**
121
     * Return's the actual row, that has to be processed.
122
     *
123
     * @return array The row
124
     */
125
    protected function getRow()
126
    {
127
        return $this->row;
128
    }
129
130
    /**
131
     * Append's the exception suffix containing filename and line number to the
132
     * passed message. If no message has been passed, only the suffix will be
133
     * returned
134
     *
135
     * @param string|null $message    The message to append the exception suffix to
136
     * @param string|null $filename   The filename used to create the suffix
137
     * @param string|null $lineNumber The line number used to create the suffx
138
     *
139
     * @return string The message with the appended exception suffix
140
     */
141
    protected function appendExceptionSuffix($message = null, $filename = null, $lineNumber = null)
142
    {
143
        return $this->getSubject()-> appendExceptionSuffix($message, $filename, $lineNumber);
144
    }
145
146
    /**
147
     * Wraps the passed exeception into a new one by trying to resolve the original filname,
148
     * line number and column name and use it for a detailed exception message.
149
     *
150
     * @param string     $columnName The column name that should be resolved
151
     * @param \Exception $parent     The exception we want to wrap
152
     * @param string     $className  The class name of the exception type we want to wrap the parent one
153
     *
154
     * @return \Exception the wrapped exception
155
     */
156
    protected function wrapException(
157
        $columnName,
158
        \Exception $parent = null,
159
        $className = '\TechDivision\Import\Exceptions\WrappedColumnException'
160
    ) {
161
        return $this->getSubject()->wrapException($columnName, $parent, $className);
162
    }
163
164
    /**
165
     * Queries whether or not debug mode is enabled or not, default is TRUE.
166
     *
167
     * @return boolean TRUE if debug mode is enabled, else FALSE
168
     */
169
    protected function isDebugMode()
170
    {
171
        return $this->getSubject()->isDebugMode();
172
    }
173
174
    /**
175
     * Stop's observer execution on the actual row.
176
     *
177
     * @return void
178
     */
179
    protected function skipRow()
180
    {
181
        $this->getSubject()->skipRow();
182
    }
183
184
    /**
185
     * Return's the name of the file to import.
186
     *
187
     * @return string The filename
188
     */
189
    protected function getFilename()
190
    {
191
        return $this->getSubject()->getFilename();
192
    }
193
194
    /**
195
     * Return's the actual line number.
196
     *
197
     * @return integer The line number
198
     */
199
    protected function getLineNumber()
200
    {
201
        return $this->getSubject()->getLineNumber();
202
    }
203
204
    /**
205
     * Return's the logger with the passed name, by default the system logger.
206
     *
207
     * @param string $name The name of the requested system logger
208
     *
209
     * @return \Psr\Log\LoggerInterface The logger instance
210
     * @throws \Exception Is thrown, if the requested logger is NOT available
211
     */
212
    protected function getSystemLogger($name = LoggerKeys::SYSTEM)
213
    {
214
        return $this->getSubject()->getSystemLogger($name);
215
    }
216
217
    /**
218
     * Return's the array with the system logger instances.
219
     *
220
     * @return array The logger instance
221
     */
222
    protected function getSystemLoggers()
223
    {
224
        return $this->getSubject()->getSystemLoggers();
225
    }
226
227
    /**
228
     * Return's the multiple field delimiter character to use, default value is comma (,).
229
     *
230
     * @return string The multiple field delimiter character
231
     */
232
    protected function getMultipleFieldDelimiter()
233
    {
234
        return $this->getSubject()->getMultipleFieldDelimiter();
235
    }
236
237
    /**
238
     * Return's the multiple value delimiter character to use, default value is comma (|).
239
     *
240
     * @return string The multiple value delimiter character
241
     */
242
    protected function getMultipleValueDelimiter()
243
    {
244
        return $this->getSubject()->getMultipleValueDelimiter();
245
    }
246
247
    /**
248
     * Queries whether or not the header with the passed name is available.
249
     *
250
     * @param string $name The header name to query
251
     *
252
     * @return boolean TRUE if the header is available, else FALSE
253
     */
254
    protected function hasHeader($name)
255
    {
256
        return $this->getSubject()->hasHeader($name);
257
    }
258
259
    /**
260
     * Return's the header value for the passed name.
261
     *
262
     * @param string $name The name of the header to return the value for
263
     *
264
     * @return mixed The header value
265
     * \InvalidArgumentException Is thrown, if the header with the passed name is NOT available
266
     */
267
    protected function getHeader($name)
268
    {
269
        return $this->getSubject()->getHeader($name);
0 ignored issues
show
Bug introduced by
The method getHeader() does not exist on TechDivision\Import\Subjects\SubjectInterface. Did you maybe mean getHeaderMappings()?

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...
270
    }
271
272
    /**
273
     * Add's the header with the passed name and position, if not NULL.
274
     *
275
     * @param string $name The header name to add
276
     *
277
     * @return integer The new headers position
278
     */
279
    protected function addHeader($name)
280
    {
281
        return $this->getSubject()->addHeader($name);
282
    }
283
284
    /**
285
     * Return's the ID of the product that has been created recently.
286
     *
287
     * @return string The entity Id
288
     */
289
    protected function getLastEntityId()
290
    {
291
        return $this->getSubject()->getLastEntityId();
0 ignored issues
show
Bug introduced by
The method getLastEntityId() does not seem to exist on object<TechDivision\Impo...jects\SubjectInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
292
    }
293
294
    /**
295
     * Return's the source date format to use.
296
     *
297
     * @return string The source date format
298
     */
299
    protected function getSourceDateFormat()
300
    {
301
        return $this->getSubject()->getSourceDateFormat();
302
    }
303
304
    /**
305
     * Cast's the passed value based on the backend type information.
306
     *
307
     * @param string $backendType The backend type to cast to
308
     * @param mixed  $value       The value to be casted
309
     *
310
     * @return mixed The casted value
311
     */
312
    protected function castValueByBackendType($backendType, $value)
313
    {
314
        return $this->getSubject()->castValueByBackendType($backendType, $value);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface TechDivision\Import\Subjects\SubjectInterface as the method castValueByBackendType() does only exist in the following implementations of said interface: TechDivision\Import\Subjects\AbstractEavSubject.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
315
    }
316
317
    /**
318
     * Set's the store view code the create the product/attributes for.
319
     *
320
     * @param string $storeViewCode The store view code
321
     *
322
     * @return void
323
     */
324
    protected function setStoreViewCode($storeViewCode)
325
    {
326
        $this->getSubject()->setStoreViewCode($storeViewCode);
327
    }
328
329
    /**
330
     * Return's the store view code the create the product/attributes for.
331
     *
332
     * @param string|null $default The default value to return, if the store view code has not been set
333
     *
334
     * @return string The store view code
335
     */
336
    protected function getStoreViewCode($default = null)
337
    {
338
        return $this->getSubject()->getStoreViewCode($default);
339
    }
340
341
    /**
342
     * Prepare's the store view code in the subject.
343
     *
344
     * @return void
345
     */
346
    protected function prepareStoreViewCode()
347
    {
348
        $this->getSubject()->prepareStoreViewCode();
349
    }
350
351
    /**
352
     * Return's the store ID of the store with the passed store view code
353
     *
354
     * @param string $storeViewCode The store view code to return the store ID for
355
     *
356
     * @return integer The ID of the store with the passed ID
357
     * @throws \Exception Is thrown, if the store with the actual code is not available
358
     */
359
    protected function getStoreId($storeViewCode)
360
    {
361
        return $this->getSubject()->getStoreId($storeViewCode);
362
    }
363
364
    /**
365
     * Return's the store ID of the actual row, or of the default store
366
     * if no store view code is set in the CSV file.
367
     *
368
     * @param string|null $default The default store view code to use, if no store view code is set in the CSV file
369
     *
370
     * @return integer The ID of the actual store
371
     * @throws \Exception Is thrown, if the store with the actual code is not available
372
     */
373
    protected function getRowStoreId($default = null)
374
    {
375
        return $this->getSubject()->getRowStoreId($default);
376
    }
377
378
    /**
379
     * Tries to format the passed value to a valid date with format 'Y-m-d H:i:s'.
380
     * If the passed value is NOT a valid date, NULL will be returned.
381
     *
382
     * @param string|null $value The value to format
383
     *
384
     * @return string The formatted date
385
     */
386
    protected function formatDate($value)
387
    {
388
        return $this->getSubject()->formatDate($value);
389
    }
390
391
    /**
392
     * Extracts the elements of the passed value by exploding them
393
     * with the also passed delimiter.
394
     *
395
     * @param string      $value     The value to extract
396
     * @param string|null $delimiter The delimiter used to extrace the elements
397
     *
398
     * @return array The exploded values
399
     */
400
    protected function explode($value, $delimiter = null)
401
    {
402
        return $this->getSubject()->explode($value, $delimiter);
403
    }
404
405
    /**
406
     * Query whether or not a value for the column with the passed name exists.
407
     *
408
     * @param string $name The column name to query for a valid value
409
     *
410
     * @return boolean TRUE if the value is set, else FALSE
411
     */
412 View Code Duplication
    protected function hasValue($name)
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...
413
    {
414
415
        // query whether or not the header is available
416
        if ($this->hasHeader($name)) {
417
            // load the key for the row
418
            $headerValue = $this->getHeader($name);
419
420
            // query whether the rows column has a vaild value
421
            return (isset($this->row[$headerValue]) && $this->row[$headerValue] != '');
422
        }
423
424
        // return FALSE if not
425
        return false;
426
    }
427
428
    /**
429
     * Set the value in the passed column name.
430
     *
431
     * @param string $name  The column name to set the value for
432
     * @param mixed  $value The value to set
433
     *
434
     * @return void
435
     */
436
    protected function setValue($name, $value)
437
    {
438
        $this->row[$this->getHeader($name)] = $value;
439
    }
440
441
    /**
442
     * Resolve's the value with the passed colum name from the actual row. If a callback will
443
     * be passed, the callback will be invoked with the found value as parameter. If
444
     * the value is NULL or empty, the default value will be returned.
445
     *
446
     * @param string        $name     The name of the column to return the value for
447
     * @param mixed|null    $default  The default value, that has to be returned, if the row's value is empty
448
     * @param callable|null $callback The callback that has to be invoked on the value, e. g. to format it
449
     *
450
     * @return mixed|null The, almost formatted, value
451
     */
452 View Code Duplication
    protected function getValue($name, $default = null, callable $callback = 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...
453
    {
454
455
        // initialize the value
456
        $value = null;
457
458
        // query whether or not the header is available
459
        if ($this->hasHeader($name)) {
460
            // load the header value
461
            $headerValue = $this->getHeader($name);
462
            // query wheter or not, the value with the requested key is available
463
            if ((isset($this->row[$headerValue]) && $this->row[$headerValue] != '')) {
464
                $value = $this->row[$headerValue];
465
            }
466
        }
467
468
        // query whether or not, a callback has been passed
469
        if ($value != null && is_callable($callback)) {
470
            $value = call_user_func($callback, $value);
471
        }
472
473
        // query whether or not
474
        if ($value == null && $default !== null) {
475
            $value = $default;
476
        }
477
478
        // return the value
479
        return $value;
480
    }
481
482
    /**
483
     * Return's the Magento configuration value.
484
     *
485
     * @param string  $path    The Magento path of the requested configuration value
486
     * @param mixed   $default The default value that has to be returned, if the requested configuration value is not set
487
     * @param string  $scope   The scope the configuration value has been set
488
     * @param integer $scopeId The scope ID the configuration value has been set
489
     *
490
     * @return mixed The configuration value
491
     * @throws \Exception Is thrown, if nor a value can be found or a default value has been passed
492
     */
493
    protected function getCoreConfigData($path, $default = null, $scope = ScopeKeys::SCOPE_DEFAULT, $scopeId = 0)
494
    {
495
        return $this->getSubject()->getCoreConfigData($path, $default, $scope, $scopeId);
496
    }
497
498
    /**
499
     * Initialize's and return's a new entity with the status 'create'.
500
     *
501
     * @param array $attr The attributes to merge into the new entity
502
     *
503
     * @return array The initialized entity
504
     */
505
    protected function initializeEntity(array $attr = array())
506
    {
507
        return array_merge(array(EntityStatus::MEMBER_NAME => EntityStatus::STATUS_CREATE), $attr);
508
    }
509
510
    /**
511
     * Merge's and return's the entity with the passed attributes and set's the
512
     * status to 'update'.
513
     *
514
     * @param array $entity The entity to merge the attributes into
515
     * @param array $attr   The attributes to be merged
516
     *
517
     * @return array The merged entity
518
     */
519
    protected function mergeEntity(array $entity, array $attr)
520
    {
521
        return array_merge($entity, $attr, array(EntityStatus::MEMBER_NAME => EntityStatus::STATUS_UPDATE));
522
    }
523
}
524