Completed
Push — 16.x ( 3844cc...bd15cd )
by
unknown
11:39 queued 09:54
created

AttributeObserverTrait   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 511
Duplicated Lines 3.33 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 85.85%

Importance

Changes 0
Metric Value
wmc 34
lcom 1
cbo 1
dl 17
loc 511
ccs 91
cts 106
cp 0.8585
rs 9.68
c 0
b 0
f 0

27 Methods

Rating   Name   Duplication   Size   Complexity  
A getAttributeCode() 0 4 1
A getAttributeValue() 0 4 1
A getPrimaryKeyValue() 0 4 1
B clearRow() 17 30 8
D process() 0 155 17
A prepareAttributes() 0 30 2
A initializeAttribute() 0 4 1
A getCallbacksByType() 0 4 1
A getBackendTypes() 0 4 1
A getAttributes() 0 4 1
getAttributesByPrimaryKeyAndStoreId() 0 1 ?
getSystemLogger() 0 1 ?
getPrimaryKey() 0 1 ?
getPrimaryKeyMemberName() 0 1 ?
getPrimaryKeyColumnName() 0 1 ?
storeViewHasBeenProcessed() 0 1 ?
persistVarcharAttribute() 0 1 ?
persistIntAttribute() 0 1 ?
persistDecimalAttribute() 0 1 ?
persistDatetimeAttribute() 0 1 ?
persistTextAttribute() 0 1 ?
deleteDatetimeAttribute() 0 1 ?
deleteDecimalAttribute() 0 1 ?
deleteIntAttribute() 0 1 ?
deleteTextAttribute() 0 1 ?
deleteVarcharAttribute() 0 1 ?
hasChanges() 0 1 ?

How to fix   Duplicated Code   

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:

1
<?php
2
3
/**
4
 * TechDivision\Import\Observers\AttributeObserverTrait
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\LoggerKeys;
24
use TechDivision\Import\Utils\MemberNames;
25
use TechDivision\Import\Utils\EntityStatus;
26
use TechDivision\Import\Utils\StoreViewCodes;
27
use TechDivision\Import\Utils\BackendTypeKeys;
28
use TechDivision\Import\Utils\ConfigurationKeys;
29
30
/**
31
 * Observer that creates/updates the EAV attributes.
32
 *
33
 * @author    Tim Wagner <[email protected]>
34
 * @copyright 2016 TechDivision GmbH <[email protected]>
35
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
36
 * @link      https://github.com/techdivision/import
37
 * @link      http://www.techdivision.com
38
 */
39
trait AttributeObserverTrait
40
{
41
42
    /**
43
     * The ID of the attribute to create the values for.
44
     *
45
     * @var integer
46
     */
47
    protected $attributeId;
48
49
    /**
50
     * The attribute code of the attribute to create the values for.
51
     *
52
     * @var string
53
     */
54
    protected $attributeCode;
55
56
    /**
57
     * The backend type of the attribute to create the values for.
58
     *
59
     * @var string
60
     */
61
    protected $backendType;
62
63
    /**
64
     * The attribute value to process.
65
     *
66
     * @var mixed
67
     */
68
    protected $attributeValue;
69
70
    /**
71
     * The array with the column keys that has to be cleaned up when their values are empty.
72
     *
73
     * @var array
74
     * @deprecated Will be removed up from version 17.0.0
75
     */
76
    protected $cleanUpEmptyColumnKeys;
77
78
    /**
79
     * The entity's existing attribues.
80
     *
81
     * @var array
82
     */
83
    protected $attributes;
84
85
    /**
86
     * The attribute code that has to be processed.
87
     *
88
     * @return string The attribute code
89
     */
90 1
    public function getAttributeCode()
91
    {
92 1
        return $this->attributeCode;
93
    }
94
95
    /**
96
     * The attribute value that has to be processed.
97
     *
98
     * @return string The attribute value
99
     */
100 1
    public function getAttributeValue()
101
    {
102 1
        return $this->attributeValue;
103
    }
104
105
    /**
106
     * Remove all the empty values from the row and return the cleared row.
107
     *
108
     * @return array The cleared row
109
     * @todo Move initialization of $this->cleanUpEmptyColumnKeys to createObserver() method and implement ObserverFactoryInterface
110
     */
111 7
    protected function clearRow()
112
    {
113
114
        // initialize the array with the column keys that has to be cleaned-up
115 7
        $this->cleanUpEmptyColumnKeys = array();
0 ignored issues
show
Deprecated Code introduced by
The property TechDivision\Import\Obse...$cleanUpEmptyColumnKeys has been deprecated with message: Will be removed up from version 17.0.0

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
116
117
        // query whether or not column names that has to be cleaned up have been configured
118 7 View Code Duplication
        if ($this->getSubject()->getConfiguration()->hasParam(ConfigurationKeys::CLEAN_UP_EMPTY_COLUMNS)) {
0 ignored issues
show
Bug introduced by
It seems like getSubject() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
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...
119
            // if yes, load the column names
120
            $cleanUpEmptyColumns = $this->getSubject()->getCleanUpColumns();
0 ignored issues
show
Bug introduced by
It seems like getSubject() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
121
122
            // translate the column names into column keys
123
            foreach ($cleanUpEmptyColumns as $cleanUpEmptyColumn) {
124
                if ($this->hasHeader($cleanUpEmptyColumn)) {
0 ignored issues
show
Bug introduced by
It seems like hasHeader() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
125
                    $this->cleanUpEmptyColumnKeys[] = $this->getHeader($cleanUpEmptyColumn);
0 ignored issues
show
Bug introduced by
It seems like getHeader() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
Deprecated Code introduced by
The property TechDivision\Import\Obse...$cleanUpEmptyColumnKeys has been deprecated with message: Will be removed up from version 17.0.0

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
126
                }
127
            }
128
        }
129
130
        // remove all the empty values from the row, expected the columns has to be cleaned-up
131 7 View Code Duplication
        foreach ($this->row as $key => $value) {
0 ignored issues
show
Bug introduced by
The property row does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
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...
132
            // query whether or not the value is empty AND the column has NOT to be cleaned-up
133 7
            if (($value === null || $value === '') && in_array($key, $this->cleanUpEmptyColumnKeys) === false) {
0 ignored issues
show
Deprecated Code introduced by
The property TechDivision\Import\Obse...$cleanUpEmptyColumnKeys has been deprecated with message: Will be removed up from version 17.0.0

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
134 7
                unset($this->row[$key]);
135
            }
136
        }
137
138
        // finally return the clean row
139 7
        return $this->row;
140
    }
141
142
    /**
143
     * Returns the value(s) of the primary key column(s). As the primary key column can
144
     * also consist of two columns, the return value can be an array also.
145
     *
146
     * @return mixed The primary key value(s)
147
     */
148 7
    protected function getPrimaryKeyValue()
149
    {
150 7
        return $this->getValue($this->getPrimaryKeyColumnName());
0 ignored issues
show
Bug introduced by
It seems like getValue() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
151
    }
152
153
    /**
154
     * Process the observer's business logic.
155
     *
156
     * @return void
157
     */
158 7
    protected function process()
159
    {
160
161
        // initialize the store view code
162 7
        $this->prepareStoreViewCode();
0 ignored issues
show
Bug introduced by
It seems like prepareStoreViewCode() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
163
164
        // load the store ID, use the admin store if NO store view code has been set
165 7
        $storeId = $this->getRowStoreId(StoreViewCodes::ADMIN);
0 ignored issues
show
Bug introduced by
It seems like getRowStoreId() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
166
167
        // load the entity's existing attributes
168 7
        $this->getAttributesByPrimaryKeyAndStoreId($this->getPrimaryKey(), $storeId);
169
170
        // load the store view - if no store view has been set, we assume the admin
171
        // store view, which will contain the default (fallback) attribute values
172 7
        $storeViewCode = $this->getSubject()->getStoreViewCode(StoreViewCodes::ADMIN);
0 ignored issues
show
Bug introduced by
It seems like getSubject() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
173
174
        // query whether or not the row has already been processed
175 7
        if ($this->storeViewHasBeenProcessed($pk = $this->getPrimaryKeyValue(), $storeViewCode)) {
176
            // log a message
177
            $this->getSystemLogger()->warning(
178
                $this->appendExceptionSuffix(
0 ignored issues
show
Bug introduced by
It seems like appendExceptionSuffix() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
179
                    sprintf(
180
                        'Attributes for "%s" "%s" + store view code "%s" has already been processed',
181
                        $this->getPrimaryKeyColumnName(),
182
                        $pk,
183
                        $storeViewCode
184
                    )
185
                )
186
            );
187
188
            // return immediately
189
            return;
190
        }
191
192
        // load the attributes by the found attribute set and the backend types
193 7
        $attributes = $this->getAttributes();
194 7
        $backendTypes = $this->getBackendTypes();
195
196
        // load the header keys
197 7
        $headers = array_flip($this->getHeaders());
0 ignored issues
show
Bug introduced by
It seems like getHeaders() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
198
199
        // remove all the empty values from the row
200 7
        $row = $this->clearRow();
201
202
        // iterate over the attributes and append them to the row
203 7
        foreach ($row as $key => $attributeValue) {
204
            // query whether or not attribute with the found code exists
205 6
            if (!isset($attributes[$attributeCode = $headers[$key]])) {
206
                // log a message in debug mode
207 1
                if ($this->isDebugMode()) {
0 ignored issues
show
Bug introduced by
It seems like isDebugMode() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
208 1
                    $this->getSystemLogger()->debug(
209 1
                        $this->appendExceptionSuffix(
0 ignored issues
show
Bug introduced by
It seems like appendExceptionSuffix() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
210 1
                            sprintf(
211 1
                                'Can\'t find attribute with attribute code "%s"',
212 1
                                $attributeCode
213
                            )
214
                        )
215
                    );
216
                }
217
218
                // stop processing
219 1
                continue;
220
            } else {
221
                // log a message in debug mode
222 5
                if ($this->isDebugMode()) {
0 ignored issues
show
Bug introduced by
It seems like isDebugMode() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
223
                // log a message in debug mode
224 2
                    $this->getSystemLogger()->debug(
225 2
                        $this->appendExceptionSuffix(
0 ignored issues
show
Bug introduced by
It seems like appendExceptionSuffix() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
226 2
                            sprintf(
227 2
                                'Found attribute with attribute code "%s"',
228 2
                                $attributeCode
229
                            )
230
                        )
231
                    );
232
                }
233
            }
234
235
            // if yes, load the attribute by its code
236 5
            $attribute = $attributes[$attributeCode];
237
238
            // load the backend type => to find the apropriate entity
239 5
            $backendType = $attribute[MemberNames::BACKEND_TYPE];
240 5
            if ($backendType === null) {
241
                // log a message in debug mode
242 1
                $this->getSystemLogger()->warning(
243 1
                    $this->appendExceptionSuffix(
0 ignored issues
show
Bug introduced by
It seems like appendExceptionSuffix() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
244 1
                        sprintf(
245 1
                            'Found EMTPY backend type for attribute "%s"',
246 1
                            $attributeCode
247
                        )
248
                    )
249
                );
250
                // stop processing
251 1
                continue;
252
            }
253
254
            // do nothing on static backend type
255 4
            if ($backendType === BackendTypeKeys::BACKEND_TYPE_STATIC) {
256 1
                continue;
257
            }
258
259
            // do nothing in non-default stores with global attributes
260 3
            if (isset($attribute[MemberNames::IS_GLOBAL]) &&
261 3
                $attribute[MemberNames::IS_GLOBAL] == 1 &&
262 3
                $storeId !== 0) {
263
                continue;
264
            }
265
266
            // query whether or not we've found a supported backend type
267 3
            if (isset($backendTypes[$backendType])) {
268
                // initialize attribute ID/code and backend type
269 2
                $this->attributeId = $attribute[MemberNames::ATTRIBUTE_ID];
270 2
                $this->attributeCode = $attributeCode;
271 2
                $this->backendType = $backendType;
272
273
                // initialize the persist method for the found backend type
274 2
                list ($persistMethod, , $deleteMethod) = $backendTypes[$backendType];
275
276
                // set the attribute value
277 2
                $this->attributeValue = $attributeValue;
278
279
                // prepare the attribute vale and query whether or not it has to be persisted
280 2
                if ($this->hasChanges($value = $this->initializeAttribute($this->prepareAttributes()))) {
0 ignored issues
show
Bug introduced by
It seems like $this->prepareAttributes() targeting TechDivision\Import\Obse...it::prepareAttributes() can also be of type null; however, TechDivision\Import\Obse...::initializeAttribute() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
281
                    // query whether or not the entity's value has to be persisted or deleted. if the value is
282
                    // an empty string and the status is UPDATE, then the value exists and has to be deleted
283
                    // We need to user $attributeValue instead of $value[MemberNames::VALUE] in cases where
284
                    // value was casted by attribute type. E.g. special_price = 0 if value is empty string in CSV
285 2
                    if ($attributeValue === '' && $value[EntityStatus::MEMBER_NAME] === EntityStatus::STATUS_UPDATE) {
286
                        $this->$deleteMethod(array(MemberNames::VALUE_ID => $value[MemberNames::VALUE_ID]));
287 2
                    } elseif ($attributeValue !== '' && $value[MemberNames::VALUE] !== null) {
288 1
                        $this->$persistMethod($value);
289
                    } else {
290
                        // log a debug message, because this should never happen
291 2
                        $this->getSubject()->getSystemLogger()->debug(sprintf('Found empty value for attribute "%s"', $attributeCode));
0 ignored issues
show
Bug introduced by
It seems like getSubject() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
292
                    }
293
                } else {
294
                    $this->getSubject()->getSystemLogger()->debug(sprintf('Skip to persist value for attribute "%s"', $attributeCode));
0 ignored issues
show
Bug introduced by
It seems like getSubject() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
295
                }
296
297
                // continue with the next value
298 2
                continue;
299
            }
300
301
            // log the debug message
302 1
            $this->getSystemLogger()->debug(
303 1
                $this->getSubject()->appendExceptionSuffix(
0 ignored issues
show
Bug introduced by
It seems like getSubject() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
304 1
                    sprintf(
305 1
                        'Found invalid backend type %s for attribute "%s"',
306 1
                        $backendType,
307 1
                        $attributeCode
308
                    )
309
                )
310
            );
311
        }
312 7
    }
313
314
    /**
315
     * Prepare the attributes of the entity that has to be persisted.
316
     *
317
     * @return array|null The prepared attributes
318
     */
319 2
    protected function prepareAttributes()
320
    {
321
322
        // laod the callbacks for the actual attribute code
323 2
        $callbacks = $this->getCallbacksByType($this->attributeCode);
324
325
        // invoke the pre-cast callbacks
326 2
        foreach ($callbacks as $callback) {
327 1
            $this->attributeValue = $callback->handle($this);
328
        }
329
330
        // load the ID of the product that has been created recently
331 2
        $lastEntityId = $this->getPrimaryKey();
332
333
        // load the store ID, use the admin store if NO store view code has been set
334 2
        $storeId = $this->getRowStoreId(StoreViewCodes::ADMIN);
0 ignored issues
show
Bug introduced by
It seems like getRowStoreId() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
335
336
        // cast the value based on the backend type
337 2
        $castedValue = $this->castValueByBackendType($this->backendType, $this->attributeValue);
0 ignored issues
show
Bug introduced by
It seems like castValueByBackendType() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
338
339
        // prepare the attribute values
340 2
        return $this->initializeEntity(
0 ignored issues
show
Bug introduced by
It seems like initializeEntity() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
341
            array(
342 2
               $this->getPrimaryKeyMemberName() => $lastEntityId,
343 2
                MemberNames::ATTRIBUTE_ID       => $this->attributeId,
344 2
                MemberNames::STORE_ID           => $storeId,
345 2
                MemberNames::VALUE              => $castedValue
346
            )
347
        );
348
    }
349
350
    /**
351
     * Initialize the category product with the passed attributes and returns an instance.
352
     *
353
     * @param array $attr The category product attributes
354
     *
355
     * @return array The initialized category product
356
     */
357 2
    protected function initializeAttribute(array $attr)
358
    {
359 2
        return $attr;
360
    }
361
362
    /**
363
     * Return's the array with callbacks for the passed type.
364
     *
365
     * @param string $type The type of the callbacks to return
366
     *
367
     * @return array The callbacks
368
     */
369 2
    protected function getCallbacksByType($type)
370
    {
371 2
        return $this->getSubject()->getCallbacksByType($type);
0 ignored issues
show
Bug introduced by
It seems like getSubject() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
372
    }
373
374
    /**
375
     * Return's mapping for the supported backend types (for the product entity) => persist methods.
376
     *
377
     * @return array The mapping for the supported backend types
378
     */
379 7
    protected function getBackendTypes()
380
    {
381 7
        return $this->getSubject()->getBackendTypes();
0 ignored issues
show
Bug introduced by
It seems like getSubject() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
382
    }
383
384
    /**
385
     * Return's the attributes for the attribute set of the product that has to be created.
386
     *
387
     * @return array The attributes
388
     * @throws \Exception
389
     */
390 7
    protected function getAttributes()
391
    {
392 7
        return $this->getSubject()->getAttributes();
0 ignored issues
show
Bug introduced by
It seems like getSubject() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
393
    }
394
395
    /**
396
     * Intializes the existing attributes for the entity with the passed primary key.
397
     *
398
     * @param string  $pk      The primary key of the entity to load the attributes for
399
     * @param integer $storeId The ID of the store view to load the attributes for
400
     *
401
     * @return array The entity attributes
402
     */
403
    abstract protected function getAttributesByPrimaryKeyAndStoreId($pk, $storeId);
404
405
    /**
406
     * Return's the logger with the passed name, by default the system logger.
407
     *
408
     * @param string $name The name of the requested system logger
409
     *
410
     * @return \Psr\Log\LoggerInterface The logger instance
411
     * @throws \Exception Is thrown, if the requested logger is NOT available
412
     */
413
    abstract protected function getSystemLogger($name = LoggerKeys::SYSTEM);
414
415
    /**
416
     * Return's the PK to create the product => attribute relation.
417
     *
418
     * @return integer The PK to create the relation with
419
     */
420
    abstract protected function getPrimaryKey();
421
422
    /**
423
     * Return's the PK column name to create the product => attribute relation.
424
     *
425
     * @return string The PK column name
426
     */
427
    abstract protected function getPrimaryKeyMemberName();
428
429
    /**
430
     * Return's the column name that contains the primary key.
431
     *
432
     * @return string the column name that contains the primary key
433
     */
434
    abstract protected function getPrimaryKeyColumnName();
435
436
    /**
437
     * Queries whether or not the passed PK and store view code has already been processed.
438
     *
439
     * @param string $pk            The PK to check been processed
440
     * @param string $storeViewCode The store view code to check been processed
441
     *
442
     * @return boolean TRUE if the PK and store view code has been processed, else FALSE
443
     */
444
    abstract protected function storeViewHasBeenProcessed($pk, $storeViewCode);
445
446
    /**
447
     * Persist's the passed varchar attribute.
448
     *
449
     * @param array $attribute The attribute to persist
450
     *
451
     * @return void
452
     */
453
    abstract protected function persistVarcharAttribute($attribute);
454
455
    /**
456
     * Persist's the passed integer attribute.
457
     *
458
     * @param array $attribute The attribute to persist
459
     *
460
     * @return void
461
     */
462
    abstract protected function persistIntAttribute($attribute);
463
464
    /**
465
     * Persist's the passed decimal attribute.
466
     *
467
     * @param array $attribute The attribute to persist
468
     *
469
     * @return void
470
     */
471
    abstract protected function persistDecimalAttribute($attribute);
472
473
    /**
474
     * Persist's the passed datetime attribute.
475
     *
476
     * @param array $attribute The attribute to persist
477
     *
478
     * @return void
479
     */
480
    abstract protected function persistDatetimeAttribute($attribute);
481
482
    /**
483
     * Persist's the passed text attribute.
484
     *
485
     * @param array $attribute The attribute to persist
486
     *
487
     * @return void
488
     */
489
    abstract protected function persistTextAttribute($attribute);
490
491
    /**
492
     * Delete's the datetime attribute with the passed value ID.
493
     *
494
     * @param array       $row  The attributes of the entity to delete
495
     * @param string|null $name The name of the prepared statement that has to be executed
496
     *
497
     * @return void
498
     */
499
    abstract protected function deleteDatetimeAttribute(array $row, $name = null);
500
501
    /**
502
     * Delete's the decimal attribute with the passed value ID.
503
     *
504
     * @param array       $row  The attributes of the entity to delete
505
     * @param string|null $name The name of the prepared statement that has to be executed
506
     *
507
     * @return void
508
     */
509
    abstract protected function deleteDecimalAttribute(array $row, $name = null);
510
511
    /**
512
     * Delete's the integer attribute with the passed value ID.
513
     *
514
     * @param array       $row  The attributes of the entity to delete
515
     * @param string|null $name The name of the prepared statement that has to be executed
516
     *
517
     * @return void
518
     */
519
    abstract protected function deleteIntAttribute(array $row, $name = null);
520
521
    /**
522
     * Delete's the text attribute with the passed value ID.
523
     *
524
     * @param array       $row  The attributes of the entity to delete
525
     * @param string|null $name The name of the prepared statement that has to be executed
526
     *
527
     * @return void
528
     */
529
    abstract protected function deleteTextAttribute(array $row, $name = null);
530
531
    /**
532
     * Delete's the varchar attribute with the passed value ID.
533
     *
534
     * @param array       $row  The attributes of the entity to delete
535
     * @param string|null $name The name of the prepared statement that has to be executed
536
     *
537
     * @return void
538
     */
539
    abstract protected function deleteVarcharAttribute(array $row, $name = null);
540
541
    /**
542
     * Query whether or not the entity has to be processed.
543
     *
544
     * @param array $entity The entity to query for
545
     *
546
     * @return boolean TRUE if the entity has to be processed, else FALSE
547
     */
548
    abstract protected function hasChanges(array $entity);
549
}
550