Completed
Push — master ( 0891d0...500833 )
by Paweł
48:22 queued 28:23
created

ProductExampleFactory::configureOptions()   B

Complexity

Conditions 4
Paths 1

Size

Total Lines 71
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 71
rs 8.7238
c 0
b 0
f 0
cc 4
eloc 43
nc 1
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Bundle\CoreBundle\Fixture\Factory;
13
14
use Sylius\Bundle\CoreBundle\Fixture\OptionsResolver\LazyOption;
15
use Sylius\Component\Core\Formatter\StringInflector;
16
use Sylius\Component\Core\Model\ChannelInterface;
17
use Sylius\Component\Core\Model\ChannelPricingInterface;
18
use Sylius\Component\Core\Model\ImageInterface;
19
use Sylius\Component\Core\Model\ProductInterface;
20
use Sylius\Component\Core\Model\ProductVariantInterface;
21
use Sylius\Component\Core\Model\TaxonInterface;
22
use Sylius\Component\Core\Uploader\ImageUploaderInterface;
23
use Sylius\Component\Locale\Model\LocaleInterface;
24
use Sylius\Component\Product\Generator\ProductVariantGeneratorInterface;
25
use Sylius\Component\Product\Generator\SlugGeneratorInterface;
26
use Sylius\Component\Product\Model\ProductAttributeInterface;
27
use Sylius\Component\Product\Model\ProductAttributeValueInterface;
28
use Sylius\Component\Resource\Factory\FactoryInterface;
29
use Sylius\Component\Resource\Repository\RepositoryInterface;
30
use Symfony\Component\HttpFoundation\File\UploadedFile;
31
use Symfony\Component\OptionsResolver\Options;
32
use Symfony\Component\OptionsResolver\OptionsResolver;
33
use Webmozart\Assert\Assert;
34
35
/**
36
 * @author Kamil Kokot <[email protected]>
37
 */
38
class ProductExampleFactory extends AbstractExampleFactory implements ExampleFactoryInterface
39
{
40
    /**
41
     * @var FactoryInterface
42
     */
43
    private $productFactory;
44
45
    /**
46
     * @var FactoryInterface
47
     */
48
    private $productVariantFactory;
49
50
    /**
51
     * @var FactoryInterface
52
     */
53
    private $channelPricingFactory;
54
55
    /**
56
     * @var FactoryInterface
57
     */
58
    private $productTaxonFactory;
59
60
    /**
61
     * @var ProductVariantGeneratorInterface
62
     */
63
    private $variantGenerator;
64
65
    /**
66
     * @var FactoryInterface
67
     */
68
    private $productAttributeValueFactory;
69
70
    /**
71
     * @var FactoryInterface
72
     */
73
    private $productImageFactory;
74
75
    /**
76
     * @var ImageUploaderInterface
77
     */
78
    private $imageUploader;
79
80
    /**
81
     * @var SlugGeneratorInterface
82
     */
83
    private $slugGenerator;
84
85
    /**
86
     * @var RepositoryInterface
87
     */
88
    private $taxonRepository;
89
90
    /**
91
     * @var RepositoryInterface
92
     */
93
    private $productAttributeRepository;
94
95
    /**
96
     * @var RepositoryInterface
97
     */
98
    private $productOptionRepository;
99
100
    /**
101
     * @var RepositoryInterface
102
     */
103
    private $channelRepository;
104
105
    /**
106
     * @var RepositoryInterface
107
     */
108
    private $localeRepository;
109
110
    /**
111
     * @var \Faker\Generator
112
     */
113
    private $faker;
114
115
    /**
116
     * @var OptionsResolver
117
     */
118
    private $optionsResolver;
119
120
    /**
121
     * @param FactoryInterface $productFactory
122
     * @param FactoryInterface $productVariantFactory
123
     * @param FactoryInterface $channelPricing
124
     * @param ProductVariantGeneratorInterface $variantGenerator
125
     * @param FactoryInterface $productAttributeValueFactory
126
     * @param FactoryInterface $productImageFactory
127
     * @param FactoryInterface $productTaxonFactory
128
     * @param ImageUploaderInterface $imageUploader
129
     * @param SlugGeneratorInterface $slugGenerator
130
     * @param RepositoryInterface $taxonRepository
131
     * @param RepositoryInterface $productAttributeRepository
132
     * @param RepositoryInterface $productOptionRepository
133
     * @param RepositoryInterface $channelRepository
134
     * @param RepositoryInterface $localeRepository
135
     */
136
    public function __construct(
137
        FactoryInterface $productFactory,
138
        FactoryInterface $productVariantFactory,
139
        FactoryInterface $channelPricing,
140
        ProductVariantGeneratorInterface $variantGenerator,
141
        FactoryInterface $productAttributeValueFactory,
142
        FactoryInterface $productImageFactory,
143
        FactoryInterface $productTaxonFactory,
144
        ImageUploaderInterface $imageUploader,
145
        SlugGeneratorInterface $slugGenerator,
146
        RepositoryInterface $taxonRepository,
147
        RepositoryInterface $productAttributeRepository,
148
        RepositoryInterface $productOptionRepository,
149
        RepositoryInterface $channelRepository,
150
        RepositoryInterface $localeRepository
151
    ) {
152
        $this->productFactory = $productFactory;
153
        $this->productVariantFactory = $productVariantFactory;
154
        $this->channelPricingFactory = $channelPricing;
155
        $this->variantGenerator = $variantGenerator;
156
        $this->productAttributeValueFactory = $productAttributeValueFactory;
157
        $this->productImageFactory = $productImageFactory;
158
        $this->productTaxonFactory = $productTaxonFactory;
159
        $this->imageUploader = $imageUploader;
160
        $this->slugGenerator = $slugGenerator;
161
        $this->taxonRepository = $taxonRepository;
162
        $this->productAttributeRepository = $productAttributeRepository;
163
        $this->productOptionRepository = $productOptionRepository;
164
        $this->channelRepository = $channelRepository;
165
        $this->localeRepository = $localeRepository;
166
167
        $this->faker = \Faker\Factory::create();
168
        $this->optionsResolver = new OptionsResolver();
169
170
        $this->configureOptions($this->optionsResolver);
171
    }
172
173
    /**
174
     * {@inheritdoc}
175
     */
176
    public function create(array $options = [])
177
    {
178
        $options = $this->optionsResolver->resolve($options);
179
180
        /** @var ProductInterface $product */
181
        $product = $this->productFactory->createNew();
182
        $product->setVariantSelectionMethod($options['variant_selection_method']);
183
        $product->setCode($options['code']);
184
        $product->setEnabled($options['enabled']);
185
        $product->setMainTaxon($options['main_taxon']);
186
        $product->setCreatedAt($this->faker->dateTimeBetween('-1 week', 'now'));
187
188
        $this->createTranslations($product, $options);
189
        $this->createRelations($product, $options);
190
        $this->createVariants($product, $options);
191
        $this->createImages($product, $options);
192
        $this->createProductTaxons($product, $options);
193
194
        return $product;
195
    }
196
197
    /**
198
     * {@inheritdoc}
199
     */
200
    protected function configureOptions(OptionsResolver $resolver)
201
    {
202
        $resolver
203
            ->setDefault('name', function (Options $options) {
0 ignored issues
show
Unused Code introduced by
The parameter $options 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...
204
                return $this->faker->words(3, true);
205
            })
206
207
            ->setDefault('code', function (Options $options) {
208
                return StringInflector::nameToCode($options['name']);
209
            })
210
211
            ->setDefault('enabled', function (Options $options) {
0 ignored issues
show
Unused Code introduced by
The parameter $options 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...
212
                return $this->faker->boolean(90);
213
            })
214
            ->setAllowedTypes('enabled', 'bool')
215
216
            ->setDefault('short_description', function (Options $options) {
0 ignored issues
show
Unused Code introduced by
The parameter $options 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...
217
                return $this->faker->paragraph;
218
            })
219
220
            ->setDefault('description', function (Options $options) {
0 ignored issues
show
Unused Code introduced by
The parameter $options 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...
221
                return $this->faker->paragraphs(3, true);
222
            })
223
224
            ->setDefault('main_taxon', LazyOption::randomOne($this->taxonRepository))
225
            ->setAllowedTypes('main_taxon', ['null', 'string', TaxonInterface::class])
226
            ->setNormalizer('main_taxon', LazyOption::findOneBy($this->taxonRepository, 'code'))
227
228
            ->setDefault('taxons', LazyOption::randomOnes($this->taxonRepository, 3))
229
            ->setAllowedTypes('taxons', 'array')
230
            ->setNormalizer('taxons', LazyOption::findBy($this->taxonRepository, 'code'))
231
232
            ->setDefault('channels', LazyOption::randomOnes($this->channelRepository, 3))
233
            ->setAllowedTypes('channels', 'array')
234
            ->setNormalizer('channels', LazyOption::findBy($this->channelRepository, 'code'))
235
236
            ->setDefault('variant_selection_method', ProductInterface::VARIANT_SELECTION_MATCH)
237
            ->setAllowedValues('variant_selection_method', [ProductInterface::VARIANT_SELECTION_MATCH, ProductInterface::VARIANT_SELECTION_CHOICE])
238
239
            ->setDefault('product_attributes', [])
240
            ->setAllowedTypes('product_attributes', 'array')
241
            ->setNormalizer('product_attributes', function (Options $options, array $productAttributes) {
242
                $productAttributesValues = [];
243
                foreach ($productAttributes as $code => $value) {
244
                    foreach ($this->getLocales() as $localeCode) {
245
                        /** @var ProductAttributeInterface $productAttribute */
246
                        $productAttribute = $this->productAttributeRepository->findOneBy(['code' => $code]);
247
248
                        Assert::notNull($productAttribute);
249
250
                        /** @var ProductAttributeValueInterface $productAttributeValue */
251
                        $productAttributeValue = $this->productAttributeValueFactory->createNew();
252
                        $productAttributeValue->setAttribute($productAttribute);
253
                        $productAttributeValue->setValue($value ?: $this->getRandomValueForProductAttribute($productAttribute));
254
                        $productAttributeValue->setLocaleCode($localeCode);
255
256
                        $productAttributesValues[] = $productAttributeValue;
257
                    }
258
                }
259
260
                return $productAttributesValues;
261
            })
262
263
            ->setDefault('product_options', [])
264
            ->setAllowedTypes('product_options', 'array')
265
            ->setNormalizer('product_options', LazyOption::findBy($this->productOptionRepository, 'code'))
266
267
            ->setDefault('images', [])
268
            ->setAllowedTypes('images', 'array')
269
        ;
270
    }
271
272
    /**
273
     * @param ProductInterface $product
274
     * @param array $options
275
     */
276
    private function createTranslations(ProductInterface $product, array $options)
277
    {
278
        foreach ($this->getLocales() as $localeCode) {
279
            $product->setCurrentLocale($localeCode);
280
            $product->setFallbackLocale($localeCode);
281
282
            $product->setName($options['name']);
283
            $product->setSlug($this->slugGenerator->generate($options['name']));
284
            $product->setShortDescription($options['short_description']);
285
            $product->setDescription($options['description']);
286
        }
287
    }
288
289
    /**
290
     * @param ProductInterface $product
291
     * @param array $options
292
     */
293
    private function createRelations(ProductInterface $product, array $options)
294
    {
295
        foreach ($options['channels'] as $channel) {
296
            $product->addChannel($channel);
297
        }
298
299
        foreach ($options['product_options'] as $option) {
300
            $product->addOption($option);
301
        }
302
303
        foreach ($options['product_attributes'] as $attribute) {
304
            $product->addAttribute($attribute);
305
        }
306
    }
307
308
    /**
309
     * @param ProductInterface $product
310
     * @param array $options
311
     */
312
    private function createVariants(ProductInterface $product, array $options)
313
    {
314
        try {
315
            $this->variantGenerator->generate($product);
316
        } catch (\InvalidArgumentException $exception) {
317
            /** @var ProductVariantInterface $productVariant */
318
            $productVariant = $this->productVariantFactory->createNew();
319
320
            $product->addVariant($productVariant);
321
        }
322
323
        $i = 0;
324
        /** @var ProductVariantInterface $productVariant */
325
        foreach ($product->getVariants() as $productVariant) {
326
            $productVariant->setName($this->faker->word);
327
            $productVariant->setAvailableOn($this->faker->dateTimeThisYear);
328
            $productVariant->setCode(sprintf('%s-variant-%d', $options['code'], $i));
329
            $productVariant->setOnHand($this->faker->randomNumber(1));
330
331
            foreach ($this->channelRepository->findAll() as $channel) {
332
                $this->createChannelPricings($productVariant, $channel);
333
            }
334
335
            ++$i;
336
        }
337
    }
338
339
    /**
340
     * @param ProductVariantInterface $productVariant
341
     * @param ChannelInterface $channel
342
     */
343
    private function createChannelPricings(ProductVariantInterface $productVariant, ChannelInterface $channel)
344
    {
345
        /** @var ChannelPricingInterface $channelPricing */
346
        $channelPricing = $this->channelPricingFactory->createNew();
347
        $channelPricing->setChannel($channel);
348
        $channelPricing->setPrice($this->faker->randomNumber(3));
349
350
        $productVariant->addChannelPricing($channelPricing);
351
    }
352
353
    /**
354
     * @param ProductInterface $product
355
     * @param array $options
356
     */
357
    private function createImages(ProductInterface $product, array $options)
358
    {
359
        foreach ($options['images'] as $imageCode => $imagePath) {
360
            /** @var ImageInterface $productImage */
361
            $productImage = $this->productImageFactory->createNew();
362
            $productImage->setCode($imageCode);
363
            $productImage->setFile(new UploadedFile($imagePath, basename($imagePath)));
364
365
            $this->imageUploader->upload($productImage);
366
367
            $product->addImage($productImage);
368
        }
369
    }
370
371
    /**
372
     * @param ProductInterface $product
373
     * @param array $options
374
     */
375
    private function createProductTaxons(ProductInterface $product, array $options)
376
    {
377
        foreach ($options['taxons'] as $taxon) {
378
            $productTaxon = $this->productTaxonFactory->createNew();
379
            $productTaxon->setProduct($product);
380
            $productTaxon->setTaxon($taxon);
381
382
            $product->addProductTaxon($productTaxon);
383
        }
384
    }
385
386
    /**
387
     * @return \Generator
388
     */
389
    private function getLocales()
390
    {
391
        /** @var LocaleInterface[] $locales */
392
        $locales = $this->localeRepository->findAll();
393
        foreach ($locales as $locale) {
394
            yield $locale->getCode();
395
        }
396
    }
397
398
    /**
399
     * @param ProductAttributeInterface $productAttribute
400
     *
401
     * @return mixed
402
     */
403
    private function getRandomValueForProductAttribute(ProductAttributeInterface $productAttribute)
404
    {
405
        switch ($productAttribute->getStorageType()) {
406
            case ProductAttributeValueInterface::STORAGE_BOOLEAN:
407
                return $this->faker->boolean;
408
            case ProductAttributeValueInterface::STORAGE_INTEGER:
409
                return $this->faker->numberBetween(0, 10000);
410
            case ProductAttributeValueInterface::STORAGE_FLOAT:
411
                return $this->faker->randomFloat(4, 0, 10000);
412
            case ProductAttributeValueInterface::STORAGE_TEXT:
413
                return $this->faker->sentence;
414
            case ProductAttributeValueInterface::STORAGE_DATE:
415
            case ProductAttributeValueInterface::STORAGE_DATETIME:
416
                return $this->faker->dateTimeThisCentury;
417
            default:
418
                throw new \BadMethodCallException();
419
        }
420
    }
421
}
422