Completed
Pull Request — master (#23)
by Claudio
11:54 queued 04:36
created

ProductController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 31
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 14
c 1
b 0
f 0
dl 0
loc 31
rs 9.7998
cc 1
nc 1
nop 14

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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