Completed
Push — 19.x ( 3864f1...239dba )
by Tim
01:40
created

EntityAttributeObserver::getLastAttributeId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 4
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
/**
4
 * TechDivision\Import\Attribute\Observers\EntityAttributeObserver
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 entity 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 EntityAttributeObserver 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
        // load the last attribute ID
70
        $this->attributeId = $this->getLastAttributeId();
0 ignored issues
show
Bug introduced by
The property attributeId 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...
71
72
        // map the entity type code to the ID
73
        $entityType = $this->getEntityType($this->entityTypeCode = $this->getValue(ColumnKeys::ENTITY_TYPE_CODE));
0 ignored issues
show
Bug introduced by
The property entityTypeCode 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...
74
        $this->entityTypeId = $entityType[MemberNames::ENTITY_TYPE_ID];
0 ignored issues
show
Bug introduced by
The property entityTypeId 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...
75
76
        // load the sort order for the attribute
77
        $this->sortOrder = $this->getValue(ColumnKeys::SORT_ORDER, 0);
0 ignored issues
show
Bug introduced by
The property sortOrder 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...
78
79
        // explode the attribute set + group names
80
        $attributeSetNames = $this->getValue(ColumnKeys::ATTRIBUTE_SET_NAME, array(), array($this, 'explode'));
81
        $attributeGroupNames = $this->getValue(ColumnKeys::ATTRIBUTE_GROUP_NAME, array(), array($this, 'explode'));
82
83
        // make sure we've the same number of attribute sets/gropus
84
        if (sizeof($attributeSetNames) !== sizeof($attributeGroupNames)) {
85
            throw new \Exception(sprintf('Size of attribute names doesn\'t match size of attribute groups'));
86
        }
87
88
        // iterate over the attribute names and create the attribute entities therefore
89
        foreach ($attributeSetNames as $key => $attributeSetName) {
90
            // load the attribute set ID
91
            $attributeSet = $this->getAttributeSetByAttributeSetNameAndEntityTypeCode($attributeSetName, $this->entityTypeCode);
92
93
            // initialize the values to create the attribute entity
94
            $this->attributeSetId = $attributeSet[MemberNames::ATTRIBUTE_SET_ID];
0 ignored issues
show
Bug introduced by
The property attributeSetId 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...
95
            $this->attributeSetName = $attributeSetName;
0 ignored issues
show
Bug introduced by
The property attributeSetName 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...
96
            $this->attributeGroupName = $attributeGroupNames[$key];
0 ignored issues
show
Bug introduced by
The property attributeGroupName 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...
97
98
            // prepare the EAV entity attribue values
99
            $entityAttribute = $this->initializeAttribute($this->prepareAttributes());
100
101
            // insert the EAV entity attribute
102
            $this->persistEntityAttribute($entityAttribute);
103
        }
104
    }
105
106
    /**
107
     * Prepare the attributes of the entity that has to be persisted.
108
     *
109
     * @return array The prepared attributes
110
     */
111
    protected function prepareAttributes()
112
    {
113
114
        // load the attribute group ID
115
        $attributeGroup = $this->getAttributeGroupByEntityTypeCodeAndAttributeSetNameAndAttributeGroupName(
116
            $this->entityTypeCode,
117
            $this->attributeSetName,
118
            $this->attributeGroupName
119
        );
120
121
        // load the attribute group ID
122
        $attributeGroupId = $attributeGroup[MemberNames::ATTRIBUTE_GROUP_ID];
123
124
        // return the prepared product
125
        return $this->initializeEntity(
126
            array(
127
                MemberNames::ATTRIBUTE_ID       => $this->attributeId,
128
                MemberNames::ENTITY_TYPE_ID     => $this->entityTypeId,
129
                MemberNames::ATTRIBUTE_SET_ID   => $this->attributeSetId,
130
                MemberNames::SORT_ORDER         => $this->sortOrder,
131
                MemberNames::ATTRIBUTE_GROUP_ID => $attributeGroupId
132
            )
133
        );
134
    }
135
136
    /**
137
     * Initialize the attribute with the passed attributes and returns an instance.
138
     *
139
     * @param array $attr The attribute attributes
140
     *
141
     * @return array The initialized attribute
142
     */
143
    protected function initializeAttribute(array $attr)
144
    {
145
        return $attr;
146
    }
147
148
    /**
149
     * Return's the attribute bunch processor instance.
150
     *
151
     * @return \TechDivision\Import\Attribute\Services\AttributeBunchProcessorInterface The attribute bunch processor instance
152
     */
153
    protected function getAttributeBunchProcessor()
154
    {
155
        return $this->attributeBunchProcessor;
156
    }
157
158
    /**
159
     * Queries whether or not the attribute with the passed code has already been processed.
160
     *
161
     * @param string $attributeCode The attribute code to check
162
     *
163
     * @return boolean TRUE if the path has been processed, else FALSE
164
     */
165
    protected function hasBeenProcessed($attributeCode)
166
    {
167
        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...rs\AttributeSubjectImpl, 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...
168
    }
169
170
    /**
171
     * Return's the ID of the attribute that has been created recently.
172
     *
173
     * @return integer The attribute ID
174
     */
175
    protected function getLastAttributeId()
176
    {
177
        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...rs\AttributeSubjectImpl, 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...
178
    }
179
180
    /**
181
     * Return's the entity type for the passed code.
182
     *
183
     * @param string $entityTypeCode The entity type code
184
     *
185
     * @return array The requested entity type
186
     * @throws \Exception Is thrown, if the entity type with the passed code is not available
187
     */
188
    protected function getEntityType($entityTypeCode)
189
    {
190
        return $this->getSubject()->getEntityType($entityTypeCode);
0 ignored issues
show
Bug introduced by
The method getEntityType() does not exist on TechDivision\Import\Subjects\SubjectInterface. Did you maybe mean getEntityTypeCode()?

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...
191
    }
192
193
    /**
194
     * Return's the attribute set with the passed attribute set name.
195
     *
196
     * @param string $attributeSetName The name of the requested attribute set
197
     * @param string $entityTypeCode   The entity type code of the requested attribute set
198
     *
199
     * @return array The EAV attribute set
200
     * @throws \Exception Is thrown, if the attribute set with the passed name is not available
201
     */
202
    protected function getAttributeSetByAttributeSetNameAndEntityTypeCode($attributeSetName, $entityTypeCode)
203
    {
204
        return $this->getSubject()->getAttributeSetByAttributeSetNameAndEntityTypeCode($attributeSetName, $entityTypeCode);
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 getAttributeSetByAttribu...NameAndEntityTypeCode() 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...
205
    }
206
207
    /**
208
     * Return's the attribute group with the passed attribute set/group name.
209
     *
210
     * @param string $entityTypeCode     The entity type code of the requested attribute group
211
     * @param string $attributeSetName   The name of the requested attribute group's attribute set
212
     * @param string $attributeGroupName The name of the requested attribute group
213
     *
214
     * @return array The EAV attribute group
215
     * @throws \Exception Is thrown, if the attribute group with the passed attribute set/group name is not available
216
     */
217
    protected function getAttributeGroupByEntityTypeCodeAndAttributeSetNameAndAttributeGroupName($entityTypeCode, $attributeSetName, $attributeGroupName)
218
    {
219
        return $this->getSubject()->getAttributeGroupByEntityTypeCodeAndAttributeSetNameAndAttributeGroupName($entityTypeCode, $attributeSetName, $attributeGroupName);
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 getAttributeGroupByEntit...AndAttributeGroupName() 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 entity attribute.
224
     *
225
     * @param array $entityAttribute The entity attribute to persist
226
     *
227
     * @return void
228
     */
229
    protected function persistEntityAttribute(array $entityAttribute)
230
    {
231
        return $this->getAttributeBunchProcessor()->persistEntityAttribute($entityAttribute);
232
    }
233
}
234