Completed
Push — master ( 3c7667...799620 )
by Kamil
94:52 queued 57:43
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
declare(strict_types=1);
13
14
namespace Sylius\Bundle\CoreBundle\Fixture;
15
16
use Doctrine\Common\Persistence\ObjectManager;
17
use SM\Factory\FactoryInterface as StateMachineFactoryInterface;
18
use Sylius\Bundle\FixturesBundle\Fixture\AbstractFixture;
19
use Sylius\Component\Core\Checker\OrderPaymentMethodSelectionRequirementCheckerInterface;
20
use Sylius\Component\Core\Checker\OrderShippingMethodSelectionRequirementCheckerInterface;
21
use Sylius\Component\Core\Model\AddressInterface;
22
use Sylius\Component\Core\Model\OrderInterface;
23
use Sylius\Component\Core\OrderCheckoutTransitions;
24
use Sylius\Component\Core\Repository\PaymentMethodRepositoryInterface;
25
use Sylius\Component\Core\Repository\ShippingMethodRepositoryInterface;
26
use Sylius\Component\Order\Modifier\OrderItemQuantityModifierInterface;
27
use Sylius\Component\Resource\Factory\FactoryInterface;
28
use Sylius\Component\Resource\Repository\RepositoryInterface;
29
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
30
use Webmozart\Assert\Assert;
31
32
class OrderFixture extends AbstractFixture
33
{
34
    /**
35
     * @var FactoryInterface
36
     */
37
    private $orderFactory;
38
39
    /**
40
     * @var FactoryInterface
41
     */
42
    private $orderItemFactory;
43
44
    /**
45
     * @var OrderItemQuantityModifierInterface
46
     */
47
    private $orderItemQuantityModifier;
48
49
    /**
50
     * @var ObjectManager
51
     */
52
    private $orderManager;
53
54
    /**
55
     * @var RepositoryInterface
56
     */
57
    private $channelRepository;
58
59
    /**
60
     * @var RepositoryInterface
61
     */
62
    private $customerRepository;
63
64
    /**
65
     * @var RepositoryInterface
66
     */
67
    private $productRepository;
68
69
    /**
70
     * @var RepositoryInterface
71
     */
72
    private $countryRepository;
73
74
    /**
75
     * @var PaymentMethodRepositoryInterface
76
     */
77
    private $paymentMethodRepository;
78
79
    /**
80
     * @var ShippingMethodRepositoryInterface
81
     */
82
    private $shippingMethodRepository;
83
84
    /**
85
     * @var FactoryInterface
86
     */
87
    private $addressFactory;
88
89
    /**
90
     * @var StateMachineFactoryInterface
91
     */
92
    private $stateMachineFactory;
93
94
    /**
95
     * @var OrderShippingMethodSelectionRequirementCheckerInterface
96
     */
97
    private $orderShippingMethodSelectionRequirementChecker;
98
99
    /**
100
     * @var OrderPaymentMethodSelectionRequirementCheckerInterface
101
     */
102
    private $orderPaymentMethodSelectionRequirementChecker;
103
104
    /**
105
     * @var \Faker\Generator
106
     */
107
    private $faker;
108
109
    /**
110
     * @param FactoryInterface $orderFactory
111
     * @param FactoryInterface $orderItemFactory
112
     * @param OrderItemQuantityModifierInterface $orderItemQuantityModifier
113
     * @param ObjectManager $orderManager
114
     * @param RepositoryInterface $channelRepository
115
     * @param RepositoryInterface $customerRepository
116
     * @param RepositoryInterface $productRepository
117
     * @param RepositoryInterface $countryRepository
118
     * @param PaymentMethodRepositoryInterface $paymentMethodRepository
119
     * @param ShippingMethodRepositoryInterface $shippingMethodRepository
120
     * @param FactoryInterface $addressFactory
121
     * @param StateMachineFactoryInterface $stateMachineFactory
122
     * @param OrderShippingMethodSelectionRequirementCheckerInterface $orderShippingMethodSelectionRequirementChecker
123
     * @param OrderPaymentMethodSelectionRequirementCheckerInterface $orderPaymentMethodSelectionRequirementChecker
124
     */
125
    public function __construct(
126
        FactoryInterface $orderFactory,
127
        FactoryInterface $orderItemFactory,
128
        OrderItemQuantityModifierInterface $orderItemQuantityModifier,
129
        ObjectManager $orderManager,
130
        RepositoryInterface $channelRepository,
131
        RepositoryInterface $customerRepository,
132
        RepositoryInterface $productRepository,
133
        RepositoryInterface $countryRepository,
134
        PaymentMethodRepositoryInterface $paymentMethodRepository,
135
        ShippingMethodRepositoryInterface $shippingMethodRepository,
136
        FactoryInterface $addressFactory,
137
        StateMachineFactoryInterface $stateMachineFactory,
138
        OrderShippingMethodSelectionRequirementCheckerInterface $orderShippingMethodSelectionRequirementChecker,
139
        OrderPaymentMethodSelectionRequirementCheckerInterface $orderPaymentMethodSelectionRequirementChecker
140
    ) {
141
        $this->orderFactory = $orderFactory;
142
        $this->orderItemFactory = $orderItemFactory;
143
        $this->orderItemQuantityModifier = $orderItemQuantityModifier;
144
        $this->orderManager = $orderManager;
145
        $this->channelRepository = $channelRepository;
146
        $this->customerRepository = $customerRepository;
147
        $this->productRepository = $productRepository;
148
        $this->countryRepository = $countryRepository;
149
        $this->paymentMethodRepository = $paymentMethodRepository;
150
        $this->shippingMethodRepository = $shippingMethodRepository;
151
        $this->addressFactory = $addressFactory;
152
        $this->stateMachineFactory = $stateMachineFactory;
153
        $this->orderShippingMethodSelectionRequirementChecker = $orderShippingMethodSelectionRequirementChecker;
154
        $this->orderPaymentMethodSelectionRequirementChecker = $orderPaymentMethodSelectionRequirementChecker;
155
156
        $this->faker = \Faker\Factory::create();
157
    }
158
159
    /**
160
     * {@inheritdoc}
161
     */
162
    public function load(array $options): void
163
    {
164
        $channels = $this->channelRepository->findAll();
165
        $customers = $this->customerRepository->findAll();
166
        $countries = $this->countryRepository->findAll();
167
168
        for ($i = 0; $i < $options['amount']; ++$i) {
169
            $channel = $this->faker->randomElement($channels);
170
            $customer = $this->faker->randomElement($customers);
171
            $countryCode = $this->faker->randomElement($countries)->getCode();
172
173
            $currencyCode = $channel->getBaseCurrency()->getCode();
174
            $localeCode = $this->faker->randomElement($channel->getLocales()->toArray())->getCode();
175
176
            $order = $this->orderFactory->createNew();
177
            $order->setChannel($channel);
178
            $order->setCustomer($customer);
179
            $order->setCurrencyCode($currencyCode);
180
            $order->setLocaleCode($localeCode);
181
182
            $this->generateItems($order);
183
184
            $this->address($order, $countryCode);
185
            $this->selectShipping($order);
186
            $this->selectPayment($order);
187
            $this->completeCheckout($order);
188
189
            $this->orderManager->persist($order);
190
191
            if (0 === ($i % 50)) {
192
                $this->orderManager->flush();
193
            }
194
        }
195
196
        $this->orderManager->flush();
197
    }
198
199
    /**
200
     * {@inheritdoc}
201
     */
202
    public function getName(): string
203
    {
204
        return 'order';
205
    }
206
207
    /**
208
     * {@inheritdoc}
209
     */
210
    protected function configureOptionsNode(ArrayNodeDefinition $optionsNode): void
211
    {
212
        $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...
213
            ->children()
214
                ->integerNode('amount')->isRequired()->min(0)->end()
215
        ;
216
    }
217
218
    /**
219
     * @param OrderInterface $order
220
     */
221
    private function generateItems(OrderInterface $order): void
222
    {
223
        $numberOfItems = random_int(1, 5);
224
        $products = $this->productRepository->findAll();
225
226
        for ($i = 0; $i < $numberOfItems; ++$i) {
227
            $item = $this->orderItemFactory->createNew();
228
229
            $product = $this->faker->randomElement($products);
230
            $variant = $this->faker->randomElement($product->getVariants()->toArray());
231
232
            $item->setVariant($variant);
233
            $this->orderItemQuantityModifier->modify($item, random_int(1, 5));
234
235
            $order->addItem($item);
236
        }
237
    }
238
239
    /**
240
     * @param OrderInterface $order
241
     * @param string $countryCode
242
     */
243
    private function address(OrderInterface $order, string $countryCode): void
244
    {
245
        /** @var AddressInterface $address */
246
        $address = $this->addressFactory->createNew();
247
        $address->setFirstName($this->faker->firstName);
248
        $address->setLastName($this->faker->lastName);
249
        $address->setStreet($this->faker->streetName);
250
        $address->setCountryCode($countryCode);
251
        $address->setCity($this->faker->city);
252
        $address->setPostcode($this->faker->postcode);
253
254
        $order->setShippingAddress($address);
255
        $order->setBillingAddress(clone $address);
256
257
        $this->applyCheckoutStateTransition($order, OrderCheckoutTransitions::TRANSITION_ADDRESS);
258
    }
259
260
    /**
261
     * @param OrderInterface $order
262
     */
263
    private function selectShipping(OrderInterface $order): void
264
    {
265
        $shippingMethod = $this
266
            ->faker
267
            ->randomElement($this->shippingMethodRepository->findEnabledForChannel($order->getChannel()))
0 ignored issues
show
Documentation introduced by
$order->getChannel() is of type object<Sylius\Component\...\ChannelInterface>|null, but the function expects a object<Sylius\Component\...Model\ChannelInterface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
268
        ;
269
        Assert::notNull($shippingMethod, 'Shipping method should not be null.');
270
271
        foreach ($order->getShipments() as $shipment) {
272
            $shipment->setMethod($shippingMethod);
273
        }
274
275
        if ($this->orderShippingMethodSelectionRequirementChecker->isShippingMethodSelectionRequired($order)) {
276
            $this->applyCheckoutStateTransition($order, OrderCheckoutTransitions::TRANSITION_SELECT_SHIPPING);
277
        }
278
    }
279
280
    /**
281
     * @param OrderInterface $order
282
     */
283
    private function selectPayment(OrderInterface $order): void
284
    {
285
        $paymentMethod = $this
286
            ->faker
287
            ->randomElement($this->paymentMethodRepository->findEnabledForChannel($order->getChannel()))
0 ignored issues
show
Documentation introduced by
$order->getChannel() is of type object<Sylius\Component\...\ChannelInterface>|null, but the function expects a object<Sylius\Component\...Model\ChannelInterface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

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