Completed
Pull Request — master (#16)
by Tim
07:10
created

addAttributeCodeIdMapping()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
/**
4
 * TechDivision\Import\Attribute\Observers\CatalogAttributeObserver
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-attribute
18
 * @link      http://www.techdivision.com
19
 */
20
21
namespace TechDivision\Import\Attribute\Observers;
22
23
use TechDivision\Import\Attribute\Utils\ColumnKeys;
24
use TechDivision\Import\Attribute\Utils\MemberNames;
25
use TechDivision\Import\Attribute\Services\AttributeBunchProcessorInterface;
26
27
/**
28
 * Observer that create's the EAV catalog attribute itself.
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-attribute
34
 * @link      http://www.techdivision.com
35
 */
36
class CatalogAttributeObserver extends AbstractAttributeImportObserver
37
{
38
39
    /**
40
     * The attribute processor instance.
41
     *
42
     * @var \TechDivision\Import\Attribute\Services\AttributeBunchProcessorInterface
43
     */
44
    protected $attributeBunchProcessor;
45
46
    /**
47
     * Initializes the observer with the passed subject instance.
48
     *
49
     * @param \TechDivision\Import\Attribute\Services\AttributeBunchProcessorInterface $attributeBunchProcessor The attribute bunch processor instance
50
     */
51
    public function __construct(AttributeBunchProcessorInterface $attributeBunchProcessor)
52
    {
53
        $this->attributeBunchProcessor = $attributeBunchProcessor;
54
    }
55
56
    /**
57
     * Process the observer's business logic.
58
     *
59
     * @return void
60
     */
61
    protected function process()
62
    {
63
64
        // query whether or not, we've found a new attribute code => means we've found a new attribute
65
        if ($this->hasBeenProcessed($this->getValue(ColumnKeys::ATTRIBUTE_CODE))) {
66
            return;
67
        }
68
69
        // initialize and persist the EAV catalog attribute
70
        $this->persistCatalogAttribute($this->initializeAttribute($this->prepareAttributes()));
71
    }
72
73
    /**
74
     * Prepare the attributes of the entity that has to be persisted.
75
     *
76
     * @return array The prepared attributes
77
     */
78
    protected function prepareAttributes()
79
    {
80
81
        // load the recently created EAV attribute ID
82
        $attributeId = $this->getLastAttributeId();
83
84
        // load the data from the row
85
        $frontendInputRenderer = $this->getValue(ColumnKeys::FRONTEND_INPUT_RENDERER);
86
        $isGlobal = $this->getValue(ColumnKeys::IS_GLOBAL, 1);
87
        $isVisible = $this->getValue(ColumnKeys::IS_VISIBLE, 1);
88
        $isSearchable = $this->getValue(ColumnKeys::IS_SEARCHABLE, 0);
89
        $isFilterable = $this->getValue(ColumnKeys::IS_FILTERABLE, 0);
90
        $isComparable = $this->getValue(ColumnKeys::IS_COMPARABLE, 0);
91
        $isVisibleOnFront = $this->getValue(ColumnKeys::IS_VISIBLE_ON_FRONT, 0);
92
        $isHtmlAllowedOnFront = $this->getValue(ColumnKeys::IS_HTML_ALLOWED_ON_FRONT, 0);
93
        $isUsedForPriceRules = $this->getValue(ColumnKeys::IS_USED_FOR_PRICE_RULES, 0);
94
        $isFilterableInSearch = $this->getValue(ColumnKeys::IS_FILTERABLE_IN_SEARCH, 0);
95
        $usedInProductListing = $this->getValue(ColumnKeys::USED_IN_PRODUCT_LISTING, 0);
96
        $usedForSortBy = $this->getValue(ColumnKeys::USED_FOR_SORT_BY, 0);
97
        $applyTo = $this->getValue(ColumnKeys::APPLY_TO);
98
        $isVisibleInAdvancedSearch = $this->getValue(ColumnKeys::IS_VISIBLE_IN_ADVANCED_SEARCH, 0);
99
        $position = $this->getValue(ColumnKeys::POSITION, 0);
100
        $isWysiwygEnabled = $this->getValue(ColumnKeys::IS_WYSIWYG_ENABLED, 0);
101
        $isUsedForPromoRules = $this->getValue(ColumnKeys::IS_USED_FOR_PROMO_RULES, 0);
102
        $isRequiredInAdminStore = $this->getValue(ColumnKeys::IS_REQUIRED_IN_ADMIN_STORE, 0);
103
        $isUsedInGrid = $this->getValue(ColumnKeys::IS_USED_IN_GRID, 0);
104
        $isVisibleInGrid = $this->getValue(ColumnKeys::IS_VISIBLE_IN_GRID, 0);
105
        $isFilterableInGrid = $this->getValue(ColumnKeys::IS_FILTERABLE_IN_GRID, 0);
106
        $searchWeight = $this->getValue(ColumnKeys::SEARCH_WEIGHT, 1);
107
108
        // load and extract the additional data
109
        $additionalData = array();
110
        $explodedAdditionalData = $this->getValue(ColumnKeys::ADDITIONAL_DATA, array(), array($this, 'explode'));
111
        foreach ($explodedAdditionalData as $value) {
112
            list ($key, $val) = $this->explode($value, '=');
0 ignored issues
show
Deprecated Code introduced by
The method TechDivision\Import\Obse...ractObserver::explode() has been deprecated with message: Will be removed with version 1.0.0, use subject method instead

This method 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 method will be removed from the class and what other method or class to use instead.

Loading history...
113
            $additionalData[$key] = $val;
114
        }
115
116
        // return the prepared product
117
        return $this->initializeEntity(
118
            array(
119
                MemberNames::ATTRIBUTE_ID                  => $attributeId,
120
                MemberNames::FRONTEND_INPUT_RENDERER       => $frontendInputRenderer,
121
                MemberNames::IS_GLOBAL                     => $isGlobal,
122
                MemberNames::IS_VISIBLE                    => $isVisible,
123
                MemberNames::IS_SEARCHABLE                 => $isSearchable,
124
                MemberNames::IS_FILTERABLE                 => $isFilterable,
125
                MemberNames::IS_COMPARABLE                 => $isComparable,
126
                MemberNames::IS_VISIBLE_ON_FRONT           => $isVisibleOnFront,
127
                MemberNames::IS_HTML_ALLOWED_ON_FRONT      => $isHtmlAllowedOnFront,
128
                MemberNames::IS_USED_FOR_PRICE_RULES       => $isUsedForPriceRules,
129
                MemberNames::IS_FILTERABLE_IN_SEARCH       => $isFilterableInSearch,
130
                MemberNames::USED_IN_PRODUCT_LISTING       => $usedInProductListing,
131
                MemberNames::USED_FOR_SORT_BY              => $usedForSortBy,
132
                MemberNames::APPLY_TO                      => $applyTo,
133
                MemberNames::IS_VISIBLE_IN_ADVANCED_SEARCH => $isVisibleInAdvancedSearch,
134
                MemberNames::POSITION                      => $position,
135
                MemberNames::IS_WYSIWYG_ENABLED            => $isWysiwygEnabled,
136
                MemberNames::IS_USED_FOR_PROMO_RULES       => $isUsedForPromoRules,
137
                MemberNames::IS_REQUIRED_IN_ADMIN_STORE    => $isRequiredInAdminStore,
138
                MemberNames::IS_USED_IN_GRID               => $isUsedInGrid,
139
                MemberNames::IS_VISIBLE_IN_GRID            => $isVisibleInGrid,
140
                MemberNames::IS_FILTERABLE_IN_GRID         => $isFilterableInGrid,
141
                MemberNames::SEARCH_WEIGHT                 => $searchWeight,
142
                MemberNames::ADDITIONAL_DATA               => $additionalData
143
            )
144
        );
145
    }
146
147
    /**
148
     * Serialize the additional_data attribute of the passed array.
149
     *
150
     * @param array $attr The attribute with the data to serialize
151
     *
152
     * @return array The attribute with the serialized additional_data
153
     */
154
    protected function serializeAdditionalData(array $attr)
155
    {
156
157
        // serialize the additional data value if available
158
        if (is_array($attr[MemberNames::ADDITIONAL_DATA])) {
159
            $attr[MemberNames::ADDITIONAL_DATA] = serialize($attr[MemberNames::ADDITIONAL_DATA]);
160
        }
161
162
        // return the attribute
163
        return $attr;
164
    }
165
166
    /**
167
     * Initialize the attribute with the passed attributes and returns an instance.
168
     *
169
     * @param array $attr The attribute attributes
170
     *
171
     * @return array The initialized attribute
172
     */
173
    protected function initializeAttribute(array $attr)
174
    {
175
        return $this->serializeAdditionalData($attr);
176
    }
177
178
    /**
179
     * Return's the attribute bunch processor instance.
180
     *
181
     * @return \TechDivision\Import\Attribute\Services\AttributeBunchProcessorInterface The attribute bunch processor instance
182
     */
183
    protected function getAttributeBunchProcessor()
184
    {
185
        return $this->attributeBunchProcessor;
186
    }
187
188
    /**
189
     * Map's the passed attribute code to the attribute ID that has been created recently.
190
     *
191
     * @param string $attributeCode The attribute code that has to be mapped
192
     *
193
     * @return void
194
     */
195
    protected function addAttributeCodeIdMapping($attributeCode)
196
    {
197
        $this->getSubject()->addAttributeCodeIdMapping($attributeCode);
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 addAttributeCodeIdMapping() does only exist in the following implementations of said interface: TechDivision\Import\Attr...e\Subjects\BunchSubject.

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...
198
    }
199
200
    /**
201
     * Queries whether or not the attribute with the passed code has already been processed.
202
     *
203
     * @param string $attributeCode The attribute code to check
204
     *
205
     * @return boolean TRUE if the path has been processed, else FALSE
206
     */
207
    protected function hasBeenProcessed($attributeCode)
208
    {
209
        return $this->getSubject()->hasBeenProcessed($attributeCode);
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 hasBeenProcessed() does only exist in the following implementations of said interface: TechDivision\Import\Attr...e\Subjects\BunchSubject, TechDivision\Import\Attr...\Subjects\OptionSubject.

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...
210
    }
211
212
    /**
213
     * Return's the ID of the attribute that has been created recently.
214
     *
215
     * @return integer The attribute ID
216
     */
217
    protected function getLastAttributeId()
218
    {
219
        return $this->getSubject()->getLastAttributeId();
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 getLastAttributeId() does only exist in the following implementations of said interface: TechDivision\Import\Attr...e\Subjects\BunchSubject.

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...
220
    }
221
222
    /**
223
     * Persist the passed EAV catalog attribute.
224
     *
225
     * @param array $catalogAttribute The EAV catalog attribute to persist
226
     *
227
     * @return void
228
     */
229
    protected function persistCatalogAttribute(array $catalogAttribute)
230
    {
231
        return $this->getAttributeBunchProcessor()->persistCatalogAttribute($catalogAttribute);
232
    }
233
}
234