Completed
Push — missing-product-variant-variab... ( 2e9a80...01bfdb )
by Kamil
22:39
created

OrderFixture   C

Complexity

Total Complexity 18

Size/Duplication

Total Lines 289
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 19

Importance

Changes 0
Metric Value
wmc 18
lcom 1
cbo 19
dl 0
loc 289
rs 6.875
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 33 1
B load() 0 36 3
A getName() 0 4 1
A configureOptionsNode() 0 7 1
A generateItems() 0 17 2
A address() 0 16 1
A selectShipping() 0 16 3
A selectPayment() 0 16 3
A completeCheckout() 0 8 2
A applyCheckoutStateTransition() 0 4 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
namespace Sylius\Bundle\CoreBundle\Fixture;
13
14
use Doctrine\Common\Persistence\ObjectManager;
15
use SM\Factory\FactoryInterface as StateMachineFactoryInterface;
16
use Sylius\Bundle\FixturesBundle\Fixture\AbstractFixture;
17
use Sylius\Component\Core\Checker\OrderPaymentMethodSelectionRequirementCheckerInterface;
18
use Sylius\Component\Core\Checker\OrderShippingMethodSelectionRequirementCheckerInterface;
19
use Sylius\Component\Core\Model\AddressInterface;
20
use Sylius\Component\Core\Model\OrderInterface;
21
use Sylius\Component\Core\OrderCheckoutTransitions;
22
use Sylius\Component\Core\Repository\PaymentMethodRepositoryInterface;
23
use Sylius\Component\Core\Repository\ShippingMethodRepositoryInterface;
24
use Sylius\Component\Order\Modifier\OrderItemQuantityModifierInterface;
25
use Sylius\Component\Resource\Factory\FactoryInterface;
26
use Sylius\Component\Resource\Repository\RepositoryInterface;
27
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
28
use Webmozart\Assert\Assert;
29
30
/**
31
 * @author Paweł Jędrzejewski <[email protected]>
32
 */
33
class OrderFixture extends AbstractFixture
34
{
35
    /**
36
     * @var FactoryInterface
37
     */
38
    private $orderFactory;
39
40
    /**
41
     * @var FactoryInterface
42
     */
43
    private $orderItemFactory;
44
45
    /**
46
     * @var OrderItemQuantityModifierInterface
47
     */
48
    private $orderItemQuantityModifier;
49
50
    /**
51
     * @var ObjectManager
52
     */
53
    private $orderManager;
54
55
    /**
56
     * @var RepositoryInterface
57
     */
58
    private $channelRepository;
59
60
    /**
61
     * @var RepositoryInterface
62
     */
63
    private $customerRepository;
64
65
    /**
66
     * @var RepositoryInterface
67
     */
68
    private $productRepository;
69
70
    /**
71
     * @var RepositoryInterface
72
     */
73
    private $countryRepository;
74
75
    /**
76
     * @var PaymentMethodRepositoryInterface
77
     */
78
    private $paymentMethodRepository;
79
80
    /**
81
     * @var ShippingMethodRepositoryInterface
82
     */
83
    private $shippingMethodRepository;
84
85
    /**
86
     * @var FactoryInterface
87
     */
88
    private $addressFactory;
89
90
    /**
91
     * @var StateMachineFactoryInterface
92
     */
93
    private $stateMachineFactory;
94
95
    /**
96
     * @var OrderShippingMethodSelectionRequirementCheckerInterface
97
     */
98
    private $orderShippingMethodSelectionRequirementChecker;
99
100
    /**
101
     * @var OrderPaymentMethodSelectionRequirementCheckerInterface
102
     */
103
    private $orderPaymentMethodSelectionRequirementChecker;
104
105
    /**
106
     * @var \Faker\Generator
107
     */
108
    private $faker;
109
110
    /**
111
     * @param FactoryInterface $orderFactory
112
     * @param FactoryInterface $orderItemFactory
113
     * @param OrderItemQuantityModifierInterface $orderItemQuantityModifier
114
     * @param ObjectManager $orderManager
115
     * @param RepositoryInterface $channelRepository
116
     * @param RepositoryInterface $customerRepository
117
     * @param RepositoryInterface $productRepository
118
     * @param RepositoryInterface $countryRepository
119
     * @param PaymentMethodRepositoryInterface $paymentMethodRepository
120
     * @param ShippingMethodRepositoryInterface $shippingMethodRepository
121
     * @param FactoryInterface $addressFactory
122
     * @param StateMachineFactoryInterface $stateMachineFactory
123
     * @param OrderShippingMethodSelectionRequirementCheckerInterface $orderShippingMethodSelectionRequirementChecker
124
     * @param OrderPaymentMethodSelectionRequirementCheckerInterface $orderPaymentMethodSelectionRequirementChecker
125
     */
126
    public function __construct(
127
        FactoryInterface $orderFactory,
128
        FactoryInterface $orderItemFactory,
129
        OrderItemQuantityModifierInterface $orderItemQuantityModifier,
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $orderItemQuantityModifier exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
130
        ObjectManager $orderManager,
131
        RepositoryInterface $channelRepository,
132
        RepositoryInterface $customerRepository,
133
        RepositoryInterface $productRepository,
134
        RepositoryInterface $countryRepository,
135
        PaymentMethodRepositoryInterface $paymentMethodRepository,
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $paymentMethodRepository exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
136
        ShippingMethodRepositoryInterface $shippingMethodRepository,
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $shippingMethodRepository exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
137
        FactoryInterface $addressFactory,
138
        StateMachineFactoryInterface $stateMachineFactory,
139
        OrderShippingMethodSelectionRequirementCheckerInterface $orderShippingMethodSelectionRequirementChecker,
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $orderShippingMethodSelectionRequirementChecker exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
140
        OrderPaymentMethodSelectionRequirementCheckerInterface $orderPaymentMethodSelectionRequirementChecker
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $orderPaymentMethodSelectionRequirementChecker exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
141
    ) {
142
        $this->orderFactory = $orderFactory;
143
        $this->orderItemFactory = $orderItemFactory;
144
        $this->orderItemQuantityModifier = $orderItemQuantityModifier;
145
        $this->orderManager = $orderManager;
146
        $this->channelRepository = $channelRepository;
147
        $this->customerRepository = $customerRepository;
148
        $this->productRepository = $productRepository;
149
        $this->countryRepository = $countryRepository;
150
        $this->paymentMethodRepository = $paymentMethodRepository;
151
        $this->shippingMethodRepository = $shippingMethodRepository;
152
        $this->addressFactory = $addressFactory;
153
        $this->stateMachineFactory = $stateMachineFactory;
154
        $this->orderShippingMethodSelectionRequirementChecker = $orderShippingMethodSelectionRequirementChecker;
155
        $this->orderPaymentMethodSelectionRequirementChecker = $orderPaymentMethodSelectionRequirementChecker;
156
157
        $this->faker = \Faker\Factory::create();
158
    }
159
160
    /**
161
     * {@inheritdoc}
162
     */
163
    public function load(array $options)
164
    {
165
        $channels = $this->channelRepository->findAll();
166
        $customers = $this->customerRepository->findAll();
167
        $countries = $this->countryRepository->findAll();
168
169
        for ($i = 0; $i < $options['amount']; $i++) {
170
            $channel = $this->faker->randomElement($channels);
171
            $customer = $this->faker->randomElement($customers);
172
            $countryCode = $this->faker->randomElement($countries)->getCode();
173
174
            $currencyCode = $channel->getBaseCurrency()->getCode();
175
            $localeCode = $this->faker->randomElement($channel->getLocales()->toArray())->getCode();
176
177
            $order = $this->orderFactory->createNew();
178
            $order->setChannel($channel);
179
            $order->setCustomer($customer);
180
            $order->setCurrencyCode($currencyCode);
181
            $order->setLocaleCode($localeCode);
182
183
            $this->generateItems($order);
184
185
            $this->address($order, $countryCode);
186
            $this->selectShipping($order);
187
            $this->selectPayment($order);
188
            $this->completeCheckout($order);
189
190
            $this->orderManager->persist($order);
191
192
            if (0 === ($i % 50)) {
193
                $this->orderManager->flush();
194
            }
195
        }
196
197
        $this->orderManager->flush();
198
    }
199
200
    /**
201
     * {@inheritdoc}
202
     */
203
    public function getName()
204
    {
205
        return 'order';
206
    }
207
208
    /**
209
     * {@inheritdoc}
210
     */
211
    protected function configureOptionsNode(ArrayNodeDefinition $optionsNode)
212
    {
213
        $optionsNode
0 ignored issues
show
Unused Code introduced by
The call to the method Symfony\Component\Config...erNodeDefinition::end() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
214
            ->children()
215
                ->integerNode('amount')->isRequired()->min(0)->end()
216
        ;
217
    }
218
219
    /**
220
     * @param OrderInterface $order
221
     */
222
    private function generateItems(OrderInterface $order)
223
    {
224
        $numberOfItems = rand(1, 5);
225
        $products = $this->productRepository->findAll();
226
227
        for ($i = 0; $i < $numberOfItems; $i++) {
228
            $item = $this->orderItemFactory->createNew();
229
230
            $product = $this->faker->randomElement($products);
231
            $variant = $this->faker->randomElement($product->getVariants()->toArray());
232
233
            $item->setVariant($variant);
234
            $this->orderItemQuantityModifier->modify($item, rand(1, 5));
235
236
            $order->addItem($item);
237
        }
238
    }
239
240
    /**
241
     * @param OrderInterface $order
242
     * @param string $countryCode
243
     */
244
    private function address(OrderInterface $order, $countryCode)
245
    {
246
        /** @var AddressInterface $address */
247
        $address = $this->addressFactory->createNew();
248
        $address->setFirstname($this->faker->firstName);
249
        $address->setLastname($this->faker->lastName);
250
        $address->setStreet($this->faker->streetName);
251
        $address->setCountryCode($countryCode);
252
        $address->setCity($this->faker->city);
253
        $address->setPostcode($this->faker->postcode);
254
255
        $order->setShippingAddress($address);
256
        $order->setBillingAddress(clone $address);
257
258
        $this->applyCheckoutStateTransition($order, OrderCheckoutTransitions::TRANSITION_ADDRESS);
259
    }
260
261
    /**
262
     * @param OrderInterface $order
263
     */
264
    private function selectShipping(OrderInterface $order)
265
    {
266
        $shippingMethod = $this
267
            ->faker
268
            ->randomElement($this->shippingMethodRepository->findEnabledForChannel($order->getChannel()))
0 ignored issues
show
Compatibility introduced by
$order->getChannel() of type object<Sylius\Component\...Model\ChannelInterface> is not a sub-type of object<Sylius\Component\...Model\ChannelInterface>. It seems like you assume a child interface of the interface Sylius\Component\Channel\Model\ChannelInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
269
        ;
270
        Assert::notNull($shippingMethod, 'Shipping method should not be null.');
271
272
        foreach ($order->getShipments() as $shipment) {
273
            $shipment->setMethod($shippingMethod);
274
        }
275
276
        if ($this->orderShippingMethodSelectionRequirementChecker->isShippingMethodSelectionRequired($order)) {
277
            $this->applyCheckoutStateTransition($order, OrderCheckoutTransitions::TRANSITION_SELECT_SHIPPING);
278
        }
279
    }
280
281
    /**
282
     * @param OrderInterface $order
283
     */
284
    private function selectPayment(OrderInterface $order)
285
    {
286
        $paymentMethod = $this
287
            ->faker
288
            ->randomElement($this->paymentMethodRepository->findEnabledForChannel($order->getChannel()))
0 ignored issues
show
Compatibility introduced by
$order->getChannel() of type object<Sylius\Component\...Model\ChannelInterface> is not a sub-type of object<Sylius\Component\...Model\ChannelInterface>. It seems like you assume a child interface of the interface Sylius\Component\Channel\Model\ChannelInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
289
        ;
290
        Assert::notNull($paymentMethod, 'Payment method should not be null.');
291
292
        foreach ($order->getPayments() as $payment) {
293
            $payment->setMethod($paymentMethod);
294
        }
295
296
        if ($this->orderPaymentMethodSelectionRequirementChecker->isPaymentMethodSelectionRequired($order)) {
297
            $this->applyCheckoutStateTransition($order, OrderCheckoutTransitions::TRANSITION_SELECT_PAYMENT);
298
        }
299
    }
300
301
    /**
302
     * @param OrderInterface $order
303
     */
304
    private function completeCheckout(OrderInterface $order)
305
    {
306
        if ($this->faker->boolean(25)) {
307
            $order->setNotes($this->faker->sentence);
308
        }
309
310
        $this->applyCheckoutStateTransition($order, OrderCheckoutTransitions::TRANSITION_COMPLETE);
311
    }
312
313
    /**
314
     * @param OrderInterface $order
315
     * @param string $transition
316
     */
317
    private function applyCheckoutStateTransition(OrderInterface $order, $transition)
318
    {
319
        $this->stateMachineFactory->get($order, OrderCheckoutTransitions::GRAPH)->apply($transition);
320
    }
321
}
322