Completed
Push — master ( fb754a...2a3626 )
by Antonio
03:49
created

ProductController   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 192
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 14
eloc 75
dl 0
loc 192
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A removeIdentifierAttributeValue() 0 9 2
A updateProduct() 0 17 2
A getNormalizer() 0 3 1
A __construct() 0 29 1
B cloneAction() 0 55 7
A getAttributeRepository() 0 3 1
1
<?php
2
3
namespace Flagbit\Bundle\ProductClonerBundle\Controller;
4
5
use Akeneo\Component\StorageUtils\Saver\SaverInterface;
6
use Akeneo\Component\StorageUtils\Updater\ObjectUpdaterInterface;
7
use Oro\Bundle\SecurityBundle\Annotation\AclAncestor;
8
use Pim\Bundle\UserBundle\Context\UserContext;
9
use Pim\Component\Catalog\Builder\ProductBuilderInterface;
10
use Pim\Component\Catalog\Comparator\Filter\FilterInterface;
11
use Pim\Component\Catalog\Localization\Localizer\AttributeConverterInterface;
12
use Pim\Component\Catalog\Model\ProductInterface;
13
use Pim\Component\Catalog\Repository\AttributeRepositoryInterface;
14
use Pim\Component\Catalog\Repository\ProductRepositoryInterface;
15
use Pim\Component\Enrich\Converter\ConverterInterface;
16
use Symfony\Component\HttpFoundation\JsonResponse;
17
use Symfony\Component\HttpFoundation\Request;
18
use Symfony\Component\HttpFoundation\Response;
19
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
20
use Symfony\Component\Validator\Validator\ValidatorInterface;
21
22
class ProductController extends AbstractController
23
{
24
    /**
25
     * @var ProductRepositoryInterface
26
     */
27
    private $productRepository;
28
    /**
29
     * @var ObjectUpdaterInterface
30
     */
31
    private $productUpdater;
32
    /**
33
     * @var SaverInterface
34
     */
35
    private $productSaver;
36
    /**
37
     * @var NormalizerInterface
38
     */
39
    private $normalizer;
40
    /**
41
     * @var ValidatorInterface
42
     */
43
    private $validator;
44
    /**
45
     * @var UserContext
46
     */
47
    private $userContext;
48
    /**
49
     * @var ProductBuilderInterface
50
     */
51
    private $productBuilder;
52
    /**
53
     * @var AttributeConverterInterface
54
     */
55
    private $localizedConverter;
56
    /**
57
     * @var FilterInterface
58
     */
59
    private $emptyValuesFilter;
60
    /**
61
     * @var ConverterInterface
62
     */
63
    private $productValueConverter;
64
    /**
65
     * @var NormalizerInterface
66
     */
67
    private $constraintViolationNormalizer;
68
    /**
69
     * @var ProductBuilderInterface
70
     */
71
    private $variantProductBuilder;
72
    /**
73
     * @var AttributeRepositoryInterface
74
     */
75
    private $attributeRepository;
76
77
    public function __construct(
78
        ProductRepositoryInterface $productRepository,
79
        AttributeRepositoryInterface $attributeRepository,
80
        ObjectUpdaterInterface $productUpdater,
81
        SaverInterface $productSaver,
82
        NormalizerInterface $normalizer,
83
        ValidatorInterface $validator,
84
        UserContext $userContext,
85
        ProductBuilderInterface $productBuilder,
86
        AttributeConverterInterface $localizedConverter,
87
        FilterInterface $emptyValuesFilter,
88
        ConverterInterface $productValueConverter,
89
        NormalizerInterface $constraintViolationNormalizer,
90
        ProductBuilderInterface $variantProductBuilder
91
    ) {
92
93
        $this->productRepository = $productRepository;
94
        $this->productUpdater = $productUpdater;
95
        $this->productSaver = $productSaver;
96
        $this->normalizer = $normalizer;
97
        $this->validator = $validator;
98
        $this->userContext = $userContext;
99
        $this->productBuilder = $productBuilder;
100
        $this->localizedConverter = $localizedConverter;
101
        $this->emptyValuesFilter = $emptyValuesFilter;
102
        $this->productValueConverter = $productValueConverter;
103
        $this->constraintViolationNormalizer = $constraintViolationNormalizer;
104
        $this->variantProductBuilder = $variantProductBuilder;
105
        $this->attributeRepository = $attributeRepository;
106
    }
107
    /**
108
     * @param Request $request
109
     *
110
     * @AclAncestor("pim_enrich_product_model_create")
111
     *
112
     * @return JsonResponse
113
     */
114
    public function cloneAction(Request $request) : JsonResponse
115
    {
116
        $data = json_decode($request->getContent(), true);
117
118
        // check 'code_to_clone' is provided otherwise HTTP bad request
119
        if (false === isset($data['code_to_clone'])) {
120
            return new JsonResponse('Field "code_to_clone" is missing.', Response::HTTP_BAD_REQUEST);
121
        }
122
123
        // check whether product to be cloned is found otherwise not found HTTP
124
        $product = $this->productRepository->findOneByIdentifier($data['code_to_clone']);
125
        if (null === $product) {
126
            return new JsonResponse(
127
                sprintf('Product model with code %s could not be found.', $data['code_to_clone']),
128
                Response::HTTP_NOT_FOUND
129
            );
130
        }
131
        unset($data['code_to_clone']);
132
        if (isset($data['parent'])) {
133
            // TODO: remove this as soon as support of 2.1 is dropped
134
            $cloneProduct = $this->variantProductBuilder->createProduct();
135
        } else {
136
            $cloneProduct = $this->productBuilder->createProduct(
137
                $data['code']
138
            );
139
            unset($data['code']);
140
        }
141
142
        // clone product using Akeneo normalizer
143
        $normalizedProduct = $this->normalizeProduct($product);
144
145
        $normalizedProduct = $this->removeIdentifierAttributeValue($normalizedProduct);
0 ignored issues
show
Bug introduced by
It seems like $normalizedProduct can also be of type boolean and double and integer and string; however, parameter $data of Flagbit\Bundle\ProductCl...ntifierAttributeValue() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

145
        $normalizedProduct = $this->removeIdentifierAttributeValue(/** @scrutinizer ignore-type */ $normalizedProduct);
Loading history...
146
        $this->productUpdater->update($cloneProduct, $normalizedProduct);
147
        if (!empty($data['values'])) {
148
            $this->updateProduct($cloneProduct, $data);
149
        }
150
        // validate product model clone and return violations if found
151
        $violations = $this->validator->validate($cloneProduct);
152
        if (count($violations) > 0) {
153
            $normalizedViolations = [];
154
            foreach ($violations as $violation) {
155
                $violation = $this->constraintViolationNormalizer->normalize(
156
                    $violation,
157
                    'internal_api',
158
                    ['product' => $cloneProduct]
159
                );
160
                $normalizedViolations[] = $violation;
161
            }
162
163
            return new JsonResponse(['values' => $normalizedViolations], Response::HTTP_BAD_REQUEST);
164
        }
165
166
        $this->productSaver->save($cloneProduct);
167
168
        return new JsonResponse();
169
    }
170
171
    private function removeIdentifierAttributeValue(array $data): array
172
    {
173
        unset($data['identifier']);
174
        $identifierAttributeCode = $this->attributeRepository->getIdentifier()->getCode();
175
176
        if (isset($data['values'][$identifierAttributeCode])) {
177
            unset($data['values'][$identifierAttributeCode]);
178
        }
179
        return $data;
180
    }
181
    /**
182
     * Updates product with the provided request data
183
     *
184
     * @param ProductInterface $product
185
     * @param array            $data
186
     */
187
    private function updateProduct(ProductInterface $product, array $data)
188
    {
189
        $values = $this->productValueConverter->convert($data['values']);
190
191
        $values = $this->localizedConverter->convertToDefaultFormats($values, [
192
            'locale' => $this->userContext->getUiLocale()->getCode()
193
        ]);
194
195
        $dataFiltered = $this->emptyValuesFilter->filter($product, ['values' => $values]);
196
197
        if (!empty($dataFiltered)) {
198
            $data = array_replace($data, $dataFiltered);
199
        } else {
200
            $data['values'] = [];
201
        }
202
203
        $this->productUpdater->update($product, $data);
204
    }
205
206
    protected function getNormalizer(): NormalizerInterface
207
    {
208
        return $this->normalizer;
209
    }
210
211
    protected function getAttributeRepository(): AttributeRepositoryInterface
212
    {
213
        return $this->attributeRepository;
214
    }
215
}
216