Completed
Push — master ( b4619a...ab6ee6 )
by Kamil
12:06 queued 06:35
created

PromotionExampleFactory::getCouponNormalizer()   B

Complexity

Conditions 6
Paths 1

Size

Total Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 30
rs 8.8177
c 0
b 0
f 0
cc 6
nc 1
nop 1
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
declare(strict_types=1);
13
14
namespace Sylius\Bundle\CoreBundle\Fixture\Factory;
15
16
use Sylius\Bundle\CoreBundle\Fixture\OptionsResolver\LazyOption;
17
use Sylius\Component\Channel\Repository\ChannelRepositoryInterface;
18
use Sylius\Component\Core\Formatter\StringInflector;
19
use Sylius\Component\Core\Model\PromotionCouponInterface;
20
use Sylius\Component\Core\Model\PromotionInterface;
21
use Sylius\Component\Promotion\Model\PromotionActionInterface;
22
use Sylius\Component\Promotion\Model\PromotionRuleInterface;
23
use Sylius\Component\Resource\Factory\FactoryInterface;
24
use Symfony\Component\OptionsResolver\Exception\InvalidArgumentException;
25
use Symfony\Component\OptionsResolver\Options;
26
use Symfony\Component\OptionsResolver\OptionsResolver;
27
28
class PromotionExampleFactory extends AbstractExampleFactory implements ExampleFactoryInterface
29
{
30
    /** @var FactoryInterface */
31
    private $promotionFactory;
32
33
    /** @var ExampleFactoryInterface */
34
    private $promotionRuleExampleFactory;
35
36
    /** @var ExampleFactoryInterface */
37
    private $promotionActionExampleFactory;
38
39
    /** @var ChannelRepositoryInterface */
40
    private $channelRepository;
41
42
    /** @var FactoryInterface|null */
43
    private $couponFactory;
44
45
    /** @var \Faker\Generator */
46
    private $faker;
47
48
    /** @var OptionsResolver */
49
    private $optionsResolver;
50
51
    public function __construct(
52
        FactoryInterface $promotionFactory,
53
        ExampleFactoryInterface $promotionRuleExampleFactory,
54
        ExampleFactoryInterface $promotionActionExampleFactory,
55
        ChannelRepositoryInterface $channelRepository,
56
        ?FactoryInterface $couponFactory = null
57
    ) {
58
        $this->promotionFactory = $promotionFactory;
59
        $this->promotionRuleExampleFactory = $promotionRuleExampleFactory;
60
        $this->promotionActionExampleFactory = $promotionActionExampleFactory;
61
        $this->channelRepository = $channelRepository;
62
        $this->couponFactory = $couponFactory;
63
64
        $this->faker = \Faker\Factory::create();
65
        $this->optionsResolver = new OptionsResolver();
66
67
        $this->configureOptions($this->optionsResolver);
68
69
        if ($this->couponFactory === null) {
70
            @trigger_error(sprintf('Not passing a $couponFactory to %s constructor is deprecated since Sylius 1.8 and will be removed in Sylius 2.0.', self::class), \E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
71
        }
72
    }
73
74
    /**
75
     * {@inheritdoc}
76
     */
77
    public function create(array $options = []): PromotionInterface
78
    {
79
        $options = $this->optionsResolver->resolve($options);
80
81
        /** @var PromotionInterface $promotion */
82
        $promotion = $this->promotionFactory->createNew();
83
        $promotion->setCode($options['code']);
84
        $promotion->setName($options['name']);
85
        $promotion->setDescription($options['description']);
86
        $promotion->setCouponBased($options['coupon_based']);
87
        $promotion->setUsageLimit($options['usage_limit']);
88
        $promotion->setExclusive($options['exclusive']);
89
        $promotion->setPriority((int) $options['priority']);
90
91
        if (isset($options['starts_at'])) {
92
            $promotion->setStartsAt(new \DateTime($options['starts_at']));
93
        }
94
95
        if (isset($options['ends_at'])) {
96
            $promotion->setEndsAt(new \DateTime($options['ends_at']));
97
        }
98
99
        foreach ($options['channels'] as $channel) {
100
            $promotion->addChannel($channel);
101
        }
102
103
        foreach ($options['rules'] as $rule) {
104
            /** @var PromotionRuleInterface $promotionRule */
105
            $promotionRule = $this->promotionRuleExampleFactory->create($rule);
106
            $promotion->addRule($promotionRule);
107
        }
108
109
        foreach ($options['actions'] as $action) {
110
            /** @var PromotionActionInterface $promotionAction */
111
            $promotionAction = $this->promotionActionExampleFactory->create($action);
112
            $promotion->addAction($promotionAction);
113
        }
114
115
        foreach ($options['coupons'] as $coupon) {
116
            $promotion->addCoupon($coupon);
117
        }
118
119
        return $promotion;
120
    }
121
122
    /**
123
     * {@inheritdoc}
124
     */
125
    protected function configureOptions(OptionsResolver $resolver): void
126
    {
127
        $resolver
128
            ->setDefault('code', function (Options $options): string {
129
                return StringInflector::nameToCode($options['name']);
130
            })
131
            ->setDefault('name', $this->faker->words(3, true))
132
            ->setDefault('description', $this->faker->sentence())
133
            ->setDefault('usage_limit', null)
134
            ->setDefault('coupon_based', false)
135
            ->setDefault('exclusive', $this->faker->boolean(25))
136
            ->setDefault('priority', 0)
137
            ->setDefault('starts_at', null)
138
            ->setAllowedTypes('starts_at', ['null', 'string'])
139
            ->setDefault('ends_at', null)
140
            ->setAllowedTypes('ends_at', ['null', 'string'])
141
            ->setDefault('channels', LazyOption::all($this->channelRepository))
142
            ->setAllowedTypes('channels', 'array')
143
            ->setNormalizer('channels', LazyOption::findBy($this->channelRepository, 'code'))
144
            ->setDefined('rules')
145
            ->setNormalizer('rules', function (Options $options, array $rules): array {
146
                if (empty($rules)) {
147
                    return [[]];
148
                }
149
150
                return $rules;
151
            })
152
            ->setDefined('actions')
153
            ->setNormalizer('actions', function (Options $options, array $actions): array {
154
                if (empty($actions)) {
155
                    return [[]];
156
                }
157
158
                return $actions;
159
            })
160
161
            ->setDefault('coupons', [])
162
            ->setAllowedTypes('coupons', 'array')
163
            ->setNormalizer('coupons', self::getCouponNormalizer($this->couponFactory))
164
        ;
165
    }
166
167
    private static function getCouponNormalizer (?FactoryInterface $couponFactory): \Closure
168
    {
169
        return function (Options $options, array $couponDefinitions) use ($couponFactory): array {
170
            if (null === $couponFactory) {
171
                throw new \RuntimeException('You must configure a $couponFactory');
172
            }
173
174
            if (!$options['coupon_based'] && count($couponDefinitions) > 0) {
175
                throw new InvalidArgumentException('Cannot define coupons for promotion that is not coupon based');
176
            }
177
178
            $coupons = [];
179
            foreach ($couponDefinitions as $couponDefinition) {
180
                /** @var PromotionCouponInterface $coupon */
181
                $coupon = $couponFactory->createNew();
182
                $coupon->setCode($couponDefinition['code']);
183
                $coupon->setPerCustomerUsageLimit($couponDefinition['per_customer_usage_limit']);
184
                $coupon->setReusableFromCancelledOrders($couponDefinition['reusable_from_cancelled_orders']);
185
                $coupon->setUsageLimit($couponDefinition['usage_limit']);
186
187
                if (null !== $couponDefinition['expires_at']) {
188
                    $coupon->setExpiresAt(new \DateTime($couponDefinition['expires_at']));
189
                }
190
191
                $coupons[] = $coupon;
192
            }
193
194
            return $coupons;
195
        };
196
    }
197
}
198