Completed
Pull Request — master (#23)
by Claudio
09:06 queued 04:23
created

ProductController::getAttributeCodeBlacklist()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Flagbit\Bundle\ProductClonerBundle\Controller;
4
5
use Akeneo\Tool\Component\StorageUtils\Saver\SaverInterface;
6
use Akeneo\Tool\Component\StorageUtils\Updater\ObjectUpdaterInterface;
7
use Oro\Bundle\SecurityBundle\Annotation\AclAncestor;
8
use Akeneo\UserManagement\Bundle\Context\UserContext;
9
use Akeneo\Pim\Enrichment\Component\Product\Builder\ProductBuilderInterface;
10
use Akeneo\Pim\Enrichment\Component\Product\Comparator\Filter\FilterInterface;
11
use Akeneo\Pim\Enrichment\Component\Product\Localization\Localizer\AttributeConverterInterface;
12
use Akeneo\Pim\Enrichment\Component\Product\Model\ProductInterface;
13
use Akeneo\Pim\Structure\Component\Repository\AttributeRepositoryInterface;
14
use Akeneo\Pim\Enrichment\Component\Product\Repository\ProductRepositoryInterface;
15
use Akeneo\Pim\Enrichment\Component\Product\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
    /**
30
     * @var ObjectUpdaterInterface
31
     */
32
    private $productUpdater;
33
34
    /**
35
     * @var SaverInterface
36
     */
37
    private $productSaver;
38
39
    /**
40
     * @var NormalizerInterface
41
     */
42
    private $normalizer;
43
44
    /**
45
     * @var ValidatorInterface
46
     */
47
    private $validator;
48
49
    /**
50
     * @var UserContext
51
     */
52
    private $userContext;
53
54
    /**
55
     * @var ProductBuilderInterface
56
     */
57
    private $productBuilder;
58
59
    /**
60
     * @var AttributeConverterInterface
61
     */
62
    private $localizedConverter;
63
64
    /**
65
     * @var FilterInterface
66
     */
67
    private $emptyValuesFilter;
68
69
    /**
70
     * @var ConverterInterface
71
     */
72
    private $productValueConverter;
73
74
    /**
75
     * @var NormalizerInterface
76
     */
77
    private $constraintViolationNormalizer;
78
79
    /**
80
     * @var ProductBuilderInterface
81
     */
82
    private $variantProductBuilder;
83
84
    /**
85
     * @var AttributeRepositoryInterface
86
     */
87
    private $attributeRepository;
88
89
    /**
90
     * @var string[]
91
     */
92
    private $attributeCodeBlacklist;
93
94
    public function __construct(
95
        ProductRepositoryInterface $productRepository,
96
        AttributeRepositoryInterface $attributeRepository,
97
        ObjectUpdaterInterface $productUpdater,
98
        SaverInterface $productSaver,
99
        NormalizerInterface $normalizer,
100
        ValidatorInterface $validator,
101
        UserContext $userContext,
102
        ProductBuilderInterface $productBuilder,
103
        AttributeConverterInterface $localizedConverter,
104
        FilterInterface $emptyValuesFilter,
105
        ConverterInterface $productValueConverter,
106
        NormalizerInterface $constraintViolationNormalizer,
107
        ProductBuilderInterface $variantProductBuilder,
108
        array $attributeCodeBlacklist = []
109
    ) {
110
111
        $this->productRepository = $productRepository;
112
        $this->productUpdater = $productUpdater;
113
        $this->productSaver = $productSaver;
114
        $this->normalizer = $normalizer;
115
        $this->validator = $validator;
116
        $this->userContext = $userContext;
117
        $this->productBuilder = $productBuilder;
118
        $this->localizedConverter = $localizedConverter;
119
        $this->emptyValuesFilter = $emptyValuesFilter;
120
        $this->productValueConverter = $productValueConverter;
121
        $this->constraintViolationNormalizer = $constraintViolationNormalizer;
122
        $this->variantProductBuilder = $variantProductBuilder;
123
        $this->attributeRepository = $attributeRepository;
124
        $this->attributeCodeBlacklist = $attributeCodeBlacklist;
125
    }
126
127
    /**
128
     * @param Request $request
129
     *
130
     * @AclAncestor("pim_enrich_product_model_create")
131
     *
132
     * @return JsonResponse
133
     */
134
    public function cloneAction(Request $request) : JsonResponse
135
    {
136
        $data = json_decode($request->getContent(), true);
137
        try {
138
            // check 'code_to_clone' is provided otherwise HTTP bad request
139
            if (false === isset($data['code_to_clone'])) {
140
                $message = [['message' => 'Field "code_to_clone" is missing.']];
141
                return new JsonResponse(['values' => $message], Response::HTTP_BAD_REQUEST);
142
            }
143
            // check whether product to be cloned is found otherwise not found HTTP
144
            $product = $this->productRepository->findOneByIdentifier($data['code_to_clone']);
145
            if (null === $product) {
146
                $message = [['message' => sprintf(
147
                    'Product model with code %s could not be found.',
148
                    $data['code_to_clone']
149
                )]];
150
                return new JsonResponse(
151
                    ['values' => $message],
152
                    Response::HTTP_NOT_FOUND
153
                );
154
            }
155
            unset($data['code_to_clone']);
156
            if (isset($data['parent'])) {
157
                // TODO: remove this as soon as support of 2.1 is dropped
158
                $cloneProduct = $this->variantProductBuilder->createProduct();
159
            } else {
160
                // check 'code' is provided otherwise HTTP bad request
161
                if (false === isset($data['code'])) {
162
                    $message = [['message' => 'Failed "Code" is missing.']];
163
                    return new JsonResponse(['values' => $message], Response::HTTP_BAD_REQUEST);
164
                }
165
166
                $cloneProduct = $this->productBuilder->createProduct(
167
                    $data['code']
168
                );
169
                unset($data['code']);
170
            }
171
172
            // clone product using Akeneo normalizer
173
            $normalizedProduct = $this->normalizeProduct($product);
174
175
            $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 null 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

175
            $normalizedProduct = $this->removeIdentifierAttributeValue(/** @scrutinizer ignore-type */ $normalizedProduct);
Loading history...
176
            $this->productUpdater->update($cloneProduct, $normalizedProduct);
177
            if (!empty($data['values'])) {
178
                $this->updateProduct($cloneProduct, $data);
179
            }
180
            // validate product model clone and return violations if found
181
            $violations = $this->validator->validate($cloneProduct);
182
            if (count($violations) > 0) {
183
                $normalizedViolations = [];
184
                foreach ($violations as $violation) {
185
                    $violation = $this->constraintViolationNormalizer->normalize(
186
                        $violation,
187
                        'internal_api',
188
                        ['product' => $cloneProduct]
189
                    );
190
                    $normalizedViolations[] = $violation;
191
                }
192
193
                return new JsonResponse(['values' => $normalizedViolations], Response::HTTP_BAD_REQUEST);
194
            }
195
            $this->productSaver->save($cloneProduct);
196
            return new JsonResponse('Success.');
197
        } catch (\Exception $e) {
198
            return new JsonResponse(['values' => [['message' => 'Failed.']]], $e->getMessage());
0 ignored issues
show
Bug introduced by
$e->getMessage() of type string is incompatible with the type integer expected by parameter $status of Symfony\Component\HttpFo...Response::__construct(). ( Ignorable by Annotation )

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

198
            return new JsonResponse(['values' => [['message' => 'Failed.']]], /** @scrutinizer ignore-type */ $e->getMessage());
Loading history...
199
        }
200
    }
201
202
    private function removeIdentifierAttributeValue(array $data) : array
203
    {
204
        unset($data['identifier']);
205
        $identifierAttributeCode = $this->attributeRepository->getIdentifier()->getCode();
206
207
        if (isset($data['values'][$identifierAttributeCode])) {
208
            unset($data['values'][$identifierAttributeCode]);
209
        }
210
        return $data;
211
    }
212
213
    /**
214
     * Updates product with the provided request data
215
     *
216
     * @param ProductInterface $product
217
     * @param array            $data
218
     */
219
    private function updateProduct(ProductInterface $product, array $data)
220
    {
221
        $values = $this->productValueConverter->convert($data['values']);
222
223
        $values = $this->localizedConverter->convertToDefaultFormats($values, [
224
            'locale' => $this->userContext->getUiLocale()->getCode(),
225
        ]);
226
227
        $dataFiltered = $this->emptyValuesFilter->filter($product, ['values' => $values]);
228
229
        if (!empty($dataFiltered)) {
230
            $data = array_replace($data, $dataFiltered);
231
        } else {
232
            $data['values'] = [];
233
        }
234
235
        $this->productUpdater->update($product, $data);
236
    }
237
238
    /**
239
     * @return string[]
240
     */
241
    protected function getAttributeCodeBlacklist() : array
242
    {
243
        return $this->attributeCodeBlacklist;
244
    }
245
246
    protected function getNormalizer() : NormalizerInterface
247
    {
248
        return $this->normalizer;
249
    }
250
251
    protected function getAttributeRepository() : AttributeRepositoryInterface
252
    {
253
        return $this->attributeRepository;
254
    }
255
}
256