ProductNormalizer   A
last analyzed

Complexity

Total Complexity 28

Size/Duplication

Total Lines 281
Duplicated Lines 15.3 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 9
Bugs 1 Features 3
Metric Value
wmc 28
c 9
b 1
f 3
lcom 1
cbo 6
dl 43
loc 281
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 1
A getFormattedRootCategory() 0 12 3
A normalize() 0 15 1
B getDefaultDrupalProduct() 0 35 4
A computeProductGroup() 0 15 4
B computeProductAssociation() 26 35 6
A computeProductCategory() 0 12 3
B computeProductValues() 17 60 5
A supportsNormalization() 0 4 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
namespace Actualys\Bundle\DrupalCommerceConnectorBundle\Normalizer;
4
5
use Actualys\Bundle\DrupalCommerceConnectorBundle\Normalizer\Exception\NormalizeException;
6
use Pim\Bundle\CatalogBundle\Entity\Category;
7
use Pim\Bundle\CatalogBundle\Model\Product;
8
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
9
use Actualys\Bundle\DrupalCommerceConnectorBundle\Guesser\NormalizerGuesser;
10
use Pim\Bundle\CatalogBundle\Manager\ChannelManager;
11
use Pim\Bundle\CatalogBundle\Model\ProductInterface;
12
use Pim\Bundle\CatalogBundle\Entity\Channel;
13
use Pim\Bundle\CatalogBundle\Entity\Repository\CategoryRepository;
14
use Pim\Bundle\CatalogBundle\Entity\Repository\GroupRepository;
15
use Pim\Bundle\CatalogBundle\Entity\Group;
16
use Pim\Bundle\CatalogBundle\Manager\ProductManager;
17
18
class ProductNormalizer implements NormalizerInterface
19
{
20
    /**
21
     * @var NormalizerGuesser $normalizerGuesser
22
     */
23
    protected $normalizerGuesser;
24
25
26
    /** @var CategoryRepository $categoryRepository */
27
    protected $categoryRepository;
28
29
    /** @var ChannelManager $channelManager */
30
    protected $channelManager;
31
32
    /** @var ProductManager $channelManager */
33
    protected $productManager;
34
35
    /** @var Array $rootCategories */
36
    protected $rootCategories;
37
38
    /** @var Array $formattedRootCategories */
39
    private $formattedRootCategories;
40
41
    /**
42
     * @param ChannelManager    $channelManager
43
     * @param NormalizerGuesser $normalizerGuesser
44
     */
45
    public function __construct(
46
      ChannelManager $channelManager,
47
      NormalizerGuesser $normalizerGuesser,
48
      CategoryRepository $categoryRepository,
49
      ProductManager $productManager
50
    ) {
51
        $this->channelManager     = $channelManager;
52
        $this->productManager     = $channelManager;
0 ignored issues
show
Documentation Bug introduced by
It seems like $channelManager of type object<Pim\Bundle\Catalo...Manager\ChannelManager> is incompatible with the declared type object<Pim\Bundle\Catalo...Manager\ProductManager> of property $productManager.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
53
        $this->normalizerGuesser  = $normalizerGuesser;
54
        $this->categoryRepository = $categoryRepository;
55
        $this->productManager     = $productManager;
56
    }
57
58
    /**
59
     * Returns formatted root categories
60
     *
61
     *
62
     * @return array
63
     */
64
    protected function getFormattedRootCategory($code)
65
    {
66
        if (empty($this->formattedRootCategories)) {
67
            $this->rootCategories = $this->categoryRepository->getRootNodes();
68
            foreach ($this->rootCategories as $rootCategory) {
69
                $this->formattedRootCategories[$rootCategory->getId(
70
                )] = $rootCategory->getCode();
71
            }
72
        };
73
74
        return $this->formattedRootCategories[$code];
75
    }
76
77
    /**
78
     * @param  object                                                $product
79
     * @param  null                                                  $format
80
     * @param  array                                                 $context
81
     * @return array|\Symfony\Component\Serializer\Normalizer\scalar
82
     * @throws NormalizeException
83
     */
84
    public function normalize($product, $format = null, array $context = [])
85
    {
86
        $drupalProduct = $this->getDefaultDrupalProduct($product);
87
        $this->computeProductCategory($product, $drupalProduct);
88
        $this->computeProductGroup($product, $drupalProduct);
89
        $this->computeProductAssociation($product, $drupalProduct);
90
        $this->computeProductValues(
91
          $product,
92
          $drupalProduct,
93
          $context['channel'],
94
          $context['configuration']
95
        );
96
97
        return $drupalProduct;
98
    }
99
100
    /**
101
     * @param  $product
102
     * @return array
103
     */
104
    public function getDefaultDrupalProduct(ProductInterface $product)
105
    {
106
        $labels           = [];
107
        $attributeAsLabel = $product->getFamily()->getAttributeAsLabel();
108
        $availableLocales = $attributeAsLabel->getAvailableLocales();
109
        if (!is_null($availableLocales)) {
110
            foreach ($availableLocales as $availableLocale) {
111
                $labels[$availableLocale->getCode()] = $product->getLabel(
112
                  $availableLocale->getCode()
113
                );
114
            }
115
        }
116
117
        // TODO: fix availableLocales doesn t must be NULL
118
        foreach ($attributeAsLabel->getTranslations() as $translation) {
119
            $labels[$translation->getLocale()] = $product->getLabel(
120
              $translation->getLocale()
121
            );
122
        }
123
124
        $defaultDrupalProduct = [
125
          'sku'        => $product->getReference(),
126
          'family'     => $product->getFamily()->getCode(),
127
          'created'    => $product->getCreated()->format('c'),
128
          'updated'    => $product->getUpdated()->format('c'),
129
          'status'     => $product->isEnabled(),
130
          'labels'     => $labels,
131
          'categories' => [],
132
          'groups' => [],
133
          'associations' => [],
134
          'values'     => [],
135
        ];
136
137
        return $defaultDrupalProduct;
138
    }
139
140
    /**
141
     * @param ProductInterface $product
142
     * @param array            $drupalProduct
143
     */
144
    protected function computeProductGroup(
145
      ProductInterface $product,
146
      array &$drupalProduct
147
    ) {
148
149
       /** @var Group $group */
150
       foreach ($product->getGroups() as $group) {
151
           $drupalProduct['groups'][$group->getType()->getCode()]['code'] = $group->getCode();
152
           foreach ($group->getProducts() as $productInGroup) {
153
               if ($product->getReference() != $productInGroup->getReference()) {
154
                   $drupalProduct['groups'][$group->getType()->getCode()]['products'][] = $product->getReference();
155
               }
156
           }
157
       }
158
    }
159
160
    /**
161
     * @param ProductInterface $product
162
     * @param array            $drupalProduct
163
     */
164
    protected function computeProductAssociation(
165
      ProductInterface $product,
166
      array &$drupalProduct
167
    ) {
168
169
        $identifierAttributeCode = $this->productManager->getIdentifierAttribute(
170
        )->getCode();
171
       /** @var Group $group */
172 View Code Duplication
       foreach ($product->getAssociations() as $association) {
0 ignored issues
show
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...
173
           $associationCode = $association->getAssociationType()->getCode();
174
175
           if ($association->getGroups()->count(
176
             ) > 0 || $association->getProducts()->count() > 0
177
           ) {
178
179
               /**@var Product $product * */
180
               $drupalProduct['associations'][$associationCode] = [
181
                 'type'     => null,
182
                 'groups'   => [],
183
                 'products' => [],
184
               ];
185
186
               $drupalProduct['associations'][$associationCode]['type'] = $associationCode;
187
               foreach ($association->getGroups() as $group) {
188
                   $drupalProduct['associations'][$associationCode]['groups'][] = $group->getCode(
189
                   );
190
               }
191
               foreach ($association->getProducts() as $product) {
192
                   $drupalProduct['associations'][$associationCode]['products'][] = $product->getValue(
193
                     $identifierAttributeCode
194
                   )->getData();
195
               }
196
           }
197
       }
198
    }
199
200
    /**
201
     * @param ProductInterface $product
202
     * @param array            $drupalProduct
203
     */
204
    protected function computeProductCategory(
205
      ProductInterface $product,
206
      array &$drupalProduct
207
    ) {
208
        /** @var Category $category */
209
        foreach ($product->getCategories() as $category) {
210
            if ($category->getLevel() > 0) {
211
                $drupalProduct['categories'][$this->getFormattedRootCategory($category->getRoot())][] =
212
                    $category->getCode();
213
            }
214
        }
215
    }
216
217
    /**
218
     * @param ProductInterface $product
219
     * @param array            $drupalProduct
220
     * @param Channel          $channel
221
     * @param array            $configuration
222
     *
223
     * @throws \Exception
224
     */
225
    protected function computeProductValues(
226
      ProductInterface $product,
227
      array &$drupalProduct,
228
      Channel $channel,
0 ignored issues
show
Unused Code introduced by
The parameter $channel is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
229
      $configuration
230
    ) {
231
232
        /** @var \Pim\Bundle\CatalogBundle\Model\ProductValue $value */
233
        foreach ($product->getValues() as $value) {
234
235
            /*
236
            // Skip out of scope values or not global ones.
237
            if ($value->getScope() != $channel->getCode() && $value->getScope(
238
              ) !== null
239
            ) {
240
                continue;
241
            }*/
242
243
            $field  = $value->getAttribute()->getCode();
244
            $type   = $value->getAttribute()->getAttributeType();
245
            $locale = $value->getLocale();
246
            if (is_null($locale)) {
247
                $locale = LANGUAGE_NONE;
248
            }
249
            $labelAttribute = $value->getEntity()
0 ignored issues
show
Unused Code introduced by
$labelAttribute is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
250
              ->getFamily()
251
              ->getAttributeAsLabel()
252
              ->getCode();
253
            
254
            if ($type == 'pim_catalog_identifier' /* || $field == $labelAttribute*/) {
255
                continue;
256
            }
257
258
            // Setup default locale.
259
            $context = [
260
              'locale'        => $locale,
261
              'scope'         => $value->getScope(),
262
              'defaultLocale' => 'fr_FR',
263
              'configuration' => $configuration,
264
            ];
265
266 View Code Duplication
            if ($normalizer = $this->normalizerGuesser->guessNormalizer(
0 ignored issues
show
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...
267
              $type,
268
              'product_value'
269
            )
270
            ) {
271
                $normalizer->normalize(
272
                  $drupalProduct,
273
                  $value,
274
                  $field,
275
                  $context
276
                );
277
            } else {
278
                throw new NormalizeException(
279
                  'Type field not supported: "'.$type.'".',
280
                  'Normalizing error'
281
                );
282
            }
283
        }
284
    }
285
286
    /**
287
     * Checks whether the given class is supported for normalization by this normalizer
288
     *
289
     * @param mixed  $data   Data to normalize.
290
     * @param string $format The format being (de-)serialized from or into.
291
     *
292
     * @return boolean
293
     */
294
    public function supportsNormalization($data, $format = null)
295
    {
296
        return $data instanceof Product;
297
    }
298
}
299