Completed
Push — remove-availableon-availableun... ( a4afbd )
by Kamil
49:15 queued 24:06
created

Product::getAvailableVariants()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 1
eloc 3
nc 1
nop 0
1
<?php
2
3
/*
4
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Sylius\Component\Product\Model;
13
14
use Doctrine\Common\Collections\ArrayCollection;
15
use Doctrine\Common\Collections\Collection;
16
use Webmozart\Assert\Assert;
17
use Sylius\Component\Attribute\Model\AttributeValueInterface;
18
use Sylius\Component\Resource\Model\TimestampableTrait;
19
use Sylius\Component\Resource\Model\ToggleableTrait;
20
use Sylius\Component\Resource\Model\TranslatableTrait;
21
22
/**
23
 * @author Paweł Jędrzejewski <[email protected]>
24
 * @author Gonzalo Vilaseca <[email protected]>
25
 */
26
class Product implements ProductInterface
27
{
28
    use TimestampableTrait, ToggleableTrait;
29
    use TranslatableTrait {
30
        __construct as private initializeTranslationsCollection;
31
    }
32
33
    /**
34
     * @var mixed
35
     */
36
    protected $id;
37
38
    /**
39
     * @var string
40
     */
41
    protected $code;
42
43
    /**
44
     * @var Collection|AttributeValueInterface[]
45
     */
46
    protected $attributes;
47
48
    /**
49
     * @var Collection|ProductVariantInterface[]
50
     */
51
    protected $variants;
52
53
    /**
54
     * @var Collection|ProductOptionInterface[]
55
     */
56
    protected $options;
57
58
    /**
59
     * @var Collection|ProductAssociationInterface[]
60
     */
61
    protected $associations;
62
63
    public function __construct()
64
    {
65
        $this->initializeTranslationsCollection();
66
67
        $this->createdAt = new \DateTime();
68
        $this->attributes = new ArrayCollection();
69
        $this->associations = new ArrayCollection();
70
        $this->variants = new ArrayCollection();
71
        $this->options = new ArrayCollection();
72
    }
73
74
    /**
75
     * @return string
76
     */
77
    public function __toString()
78
    {
79
        return $this->getName();
80
    }
81
82
    /**
83
     * {@inheritdoc}
84
     */
85
    public function getId()
86
    {
87
        return $this->id;
88
    }
89
90
    /**
91
     * @return string
92
     */
93
    public function getCode()
94
    {
95
        return $this->code;
96
    }
97
98
    /**
99
     * @param string $code
100
     */
101
    public function setCode($code)
102
    {
103
        $this->code = $code;
104
    }
105
106
    /**
107
     * {@inheritdoc}
108
     */
109
    public function getName()
110
    {
111
        return $this->getTranslation()->getName();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Sylius\Component\Resourc...el\TranslationInterface as the method getName() does only exist in the following implementations of said interface: Sylius\Component\Attribu...el\AttributeTranslation, Sylius\Component\Core\Model\ProductTranslation, Sylius\Component\Payment...aymentMethodTranslation, Sylius\Component\Product...ociationTypeTranslation, Sylius\Component\Product...uctAttributeTranslation, Sylius\Component\Product...roductOptionTranslation, Sylius\Component\Product\Model\ProductTranslation, Sylius\Component\Product...oductVariantTranslation, Sylius\Component\Shippin...ippingMethodTranslation, Sylius\Component\Taxonomy\Model\TaxonTranslation.

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...
112
    }
113
114
    /**
115
     * {@inheritdoc}
116
     */
117
    public function setName($name)
118
    {
119
        $this->getTranslation()->setName($name);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Sylius\Component\Resourc...el\TranslationInterface as the method setName() does only exist in the following implementations of said interface: Sylius\Component\Attribu...el\AttributeTranslation, Sylius\Component\Core\Model\ProductTranslation, Sylius\Component\Payment...aymentMethodTranslation, Sylius\Component\Product...ociationTypeTranslation, Sylius\Component\Product...uctAttributeTranslation, Sylius\Component\Product...roductOptionTranslation, Sylius\Component\Product\Model\ProductTranslation, Sylius\Component\Product...oductVariantTranslation, Sylius\Component\Shippin...ippingMethodTranslation, Sylius\Component\Taxonomy\Model\TaxonTranslation.

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...
120
    }
121
122
    /**
123
     * {@inheritdoc}
124
     */
125
    public function getSlug()
126
    {
127
        return $this->getTranslation()->getSlug();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Sylius\Component\Resourc...el\TranslationInterface as the method getSlug() does only exist in the following implementations of said interface: Sylius\Component\Core\Model\ProductTranslation, Sylius\Component\Product\Model\ProductTranslation, Sylius\Component\Taxonomy\Model\TaxonTranslation.

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...
128
    }
129
130
    /**
131
     * {@inheritdoc}
132
     */
133
    public function setSlug($slug = null)
134
    {
135
        $this->getTranslation()->setSlug($slug);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Sylius\Component\Resourc...el\TranslationInterface as the method setSlug() does only exist in the following implementations of said interface: Sylius\Component\Core\Model\ProductTranslation, Sylius\Component\Product\Model\ProductTranslation, Sylius\Component\Taxonomy\Model\TaxonTranslation.

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...
136
    }
137
138
    /**
139
     * {@inheritdoc}
140
     */
141
    public function getDescription()
142
    {
143
        return $this->getTranslation()->getDescription();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Sylius\Component\Resourc...el\TranslationInterface as the method getDescription() does only exist in the following implementations of said interface: Sylius\Component\Core\Model\ProductTranslation, Sylius\Component\Payment...aymentMethodTranslation, Sylius\Component\Product\Model\ProductTranslation, Sylius\Component\Shippin...ippingMethodTranslation, Sylius\Component\Taxonomy\Model\TaxonTranslation.

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...
144
    }
145
146
    /**
147
     * {@inheritdoc}
148
     */
149
    public function setDescription($description)
150
    {
151
        $this->getTranslation()->setDescription($description);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Sylius\Component\Resourc...el\TranslationInterface as the method setDescription() does only exist in the following implementations of said interface: Sylius\Component\Core\Model\ProductTranslation, Sylius\Component\Payment...aymentMethodTranslation, Sylius\Component\Product\Model\ProductTranslation, Sylius\Component\Shippin...ippingMethodTranslation, Sylius\Component\Taxonomy\Model\TaxonTranslation.

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...
152
    }
153
154
    /**
155
     * {@inheritdoc}
156
     */
157
    public function getMetaKeywords()
158
    {
159
        return $this->getTranslation()->getMetaKeywords();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Sylius\Component\Resourc...el\TranslationInterface as the method getMetaKeywords() does only exist in the following implementations of said interface: Sylius\Component\Core\Model\ProductTranslation, Sylius\Component\Product\Model\ProductTranslation.

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...
160
    }
161
162
    /**
163
     * {@inheritdoc}
164
     */
165
    public function setMetaKeywords($metaKeywords)
166
    {
167
        $this->getTranslation()->setMetaKeywords($metaKeywords);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Sylius\Component\Resourc...el\TranslationInterface as the method setMetaKeywords() does only exist in the following implementations of said interface: Sylius\Component\Core\Model\ProductTranslation, Sylius\Component\Product\Model\ProductTranslation.

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
     * {@inheritdoc}
172
     */
173
    public function getMetaDescription()
174
    {
175
        return $this->getTranslation()->getMetaDescription();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Sylius\Component\Resourc...el\TranslationInterface as the method getMetaDescription() does only exist in the following implementations of said interface: Sylius\Component\Core\Model\ProductTranslation, Sylius\Component\Product\Model\ProductTranslation.

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...
176
    }
177
178
    /**
179
     * {@inheritdoc}
180
     */
181
    public function setMetaDescription($metaDescription)
182
    {
183
        $this->getTranslation()->setMetaDescription($metaDescription);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Sylius\Component\Resourc...el\TranslationInterface as the method setMetaDescription() does only exist in the following implementations of said interface: Sylius\Component\Core\Model\ProductTranslation, Sylius\Component\Product\Model\ProductTranslation.

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...
184
    }
185
186
    /**
187
     * {@inheritdoc}
188
     */
189
    public function getAttributes()
190
    {
191
        return $this->attributes;
192
    }
193
194
    /**
195
     * {@inheritdoc}
196
     */
197
    public function getAttributesByLocale($localeCode, $fallbackLocaleCode)
198
    {
199
        $attributes = $this->attributes->filter(
200
            function (ProductAttributeValueInterface $attribute) use ($fallbackLocaleCode) {
201
                return $attribute->getLocaleCode() === $fallbackLocaleCode;
202
            }
203
        );
204
205
        $attributesWithFallback = [];
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $attributesWithFallback exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
206
        foreach ($attributes as $attribute) {
207
            $attributesWithFallback[] = $this->getAttributeInDifferentLocale($attribute, $localeCode);
208
        }
209
210
        return $attributesWithFallback;
211
    }
212
213
    /**
214
     * {@inheritdoc}
215
     */
216
    public function addAttribute(AttributeValueInterface $attribute)
217
    {
218
        Assert::isInstanceOf(
219
            $attribute,
220
            ProductAttributeValueInterface::class,
221
            'Attribute objects added to a Product object have to implement ProductAttributeValueInterface'
222
        );
223
224
        if (!$this->hasAttribute($attribute)) {
225
            $attribute->setProduct($this);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Sylius\Component\Attribu...AttributeValueInterface as the method setProduct() does only exist in the following implementations of said interface: Sylius\Component\Product...l\ProductAttributeValue.

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...
226
            $this->attributes->add($attribute);
227
        }
228
    }
229
230
    /**
231
     * {@inheritdoc}
232
     */
233
    public function removeAttribute(AttributeValueInterface $attribute)
234
    {
235
        Assert::isInstanceOf(
236
            $attribute,
237
            ProductAttributeValueInterface::class,
238
            'Attribute objects removed from a Product object have to implement ProductAttributeValueInterface'
239
        );
240
241
        if ($this->hasAttribute($attribute)) {
242
            $this->attributes->removeElement($attribute);
243
            $attribute->setProduct(null);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Sylius\Component\Attribu...AttributeValueInterface as the method setProduct() does only exist in the following implementations of said interface: Sylius\Component\Product...l\ProductAttributeValue.

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...
244
        }
245
    }
246
247
    /**
248
     * {@inheritdoc}
249
     */
250
    public function hasAttribute(AttributeValueInterface $attribute)
251
    {
252
        return $this->attributes->contains($attribute);
253
    }
254
255
    /**
256
     * {@inheritdoc}
257
     */
258
    public function hasAttributeByCodeAndLocale($attributeCode, $localeCode = null)
259
    {
260
        $localeCode = $localeCode ?: $this->getTranslation()->getLocale();
261
262
        foreach ($this->attributes as $attribute) {
263
            if ($attribute->getAttribute()->getCode() === $attributeCode
264
                && $attribute->getLocaleCode() === $localeCode) {
265
                return true;
266
            }
267
        }
268
269
        return false;
270
    }
271
272
    /**
273
     * {@inheritdoc}
274
     */
275
    public function getAttributeByCodeAndLocale($attributeCode, $localeCode = null)
276
    {
277
        if (null === $localeCode) {
278
            $localeCode = $this->getTranslation()->getLocale();
279
        }
280
281
        foreach ($this->attributes as $attribute) {
282
            if ($attribute->getAttribute()->getCode() === $attributeCode &&
283
                $attribute->getLocaleCode() === $localeCode) {
284
                return $attribute;
285
            }
286
        }
287
288
        return null;
289
    }
290
291
    /**
292
     * {@inheritdoc}
293
     */
294
    public function hasVariants()
295
    {
296
        return !$this->getVariants()->isEmpty();
297
    }
298
299
    /**
300
     * {@inheritdoc}
301
     */
302
    public function getVariants()
303
    {
304
        return $this->variants;
305
    }
306
307
    /**
308
     * {@inheritdoc}
309
     */
310
    public function addVariant(ProductVariantInterface $variant)
311
    {
312
        if (!$this->hasVariant($variant)) {
313
            $variant->setProduct($this);
314
            $this->variants->add($variant);
315
        }
316
    }
317
318
    /**
319
     * {@inheritdoc}
320
     */
321
    public function removeVariant(ProductVariantInterface $variant)
322
    {
323
        if ($this->hasVariant($variant)) {
324
            $variant->setProduct(null);
325
            $this->variants->removeElement($variant);
326
        }
327
    }
328
329
    /**
330
     * {@inheritdoc}
331
     */
332
    public function hasVariant(ProductVariantInterface $variant)
333
    {
334
        return $this->variants->contains($variant);
335
    }
336
337
    /**
338
     * {@inheritdoc}
339
     */
340
    public function hasOptions()
341
    {
342
        return !$this->options->isEmpty();
343
    }
344
345
    /**
346
     * {@inheritdoc}
347
     */
348
    public function getOptions()
349
    {
350
        return $this->options;
351
    }
352
353
    /**
354
     * {@inheritdoc}
355
     */
356
    public function addOption(ProductOptionInterface $option)
357
    {
358
        if (!$this->hasOption($option)) {
359
            $this->options->add($option);
360
        }
361
    }
362
363
    /**
364
     * {@inheritdoc}
365
     */
366
    public function removeOption(ProductOptionInterface $option)
367
    {
368
        if ($this->hasOption($option)) {
369
            $this->options->removeElement($option);
370
        }
371
    }
372
373
    /**
374
     * {@inheritdoc}
375
     */
376
    public function hasOption(ProductOptionInterface $option)
377
    {
378
        return $this->options->contains($option);
379
    }
380
381
    /**
382
     * {@inheritdoc}
383
     */
384
    public function getAssociations()
385
    {
386
        return $this->associations;
387
    }
388
389
    /**
390
     * {@inheritdoc}
391
     */
392
    public function addAssociation(ProductAssociationInterface $association)
393
    {
394
        if (!$this->hasAssociation($association)) {
395
            $this->associations->add($association);
396
            $association->setOwner($this);
397
        }
398
    }
399
400
    /**
401
     * {@inheritdoc}
402
     */
403
    public function removeAssociation(ProductAssociationInterface $association)
404
    {
405
        if ($this->hasAssociation($association)) {
406
            $association->setOwner(null);
407
            $this->associations->removeElement($association);
408
        }
409
    }
410
411
    /**
412
     * {@inheritdoc}
413
     */
414
    public function hasAssociation(ProductAssociationInterface $association)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
415
    {
416
        return $this->associations->contains($association);
417
    }
418
419
    /**
420
     * {@inheritdoc}
421
     */
422
    public function isSimple()
423
    {
424
        return 1 === $this->variants->count() && !$this->hasOptions();
425
    }
426
427
    /**
428
     * {@inheritdoc}
429
     */
430
    public function isConfigurable()
431
    {
432
        return !$this->isSimple();
433
    }
434
435
    /**
436
     * {@inheritdoc}
437
     */
438
    protected function createTranslation()
439
    {
440
        return new ProductTranslation();
441
    }
442
443
    /**
444
     * {@inheritdoc}
445
     */
446
    private function getAttributeInDifferentLocale(ProductAttributeValueInterface $attributeValue, $localeCode)
447
    {
448
        if (!$this->hasAttributeByCodeAndLocale($attributeValue->getCode(), $localeCode)) {
449
            return $attributeValue;
450
        }
451
452
        $attributeValueInDifferentLocale = $this->getAttributeByCodeAndLocale($attributeValue->getCode(), $localeCode);
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $attributeValueInDifferentLocale exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
453
        if ('' === $attributeValueInDifferentLocale->getValue()
454
            || null === $attributeValueInDifferentLocale->getValue()) {
455
            return $attributeValue;
456
        }
457
458
        return $attributeValueInDifferentLocale;
459
    }
460
}
461