Completed
Push — master ( d81c19...f57266 )
by Kamil
20s
created

Fixture/Factory/AddressExampleFactory.php (6 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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 Doctrine\Common\Collections\Collection;
17
use Sylius\Bundle\CoreBundle\Fixture\OptionsResolver\LazyOption;
18
use Sylius\Component\Addressing\Model\Country;
19
use Sylius\Component\Addressing\Model\ProvinceInterface;
20
use Sylius\Component\Core\Model\AddressInterface;
21
use Sylius\Component\Core\Model\CustomerInterface;
22
use Sylius\Component\Resource\Factory\FactoryInterface;
23
use Sylius\Component\Resource\Repository\RepositoryInterface;
24
use Symfony\Component\OptionsResolver\Options;
25
use Symfony\Component\OptionsResolver\OptionsResolver;
26
use Webmozart\Assert\Assert;
27
28
class AddressExampleFactory extends AbstractExampleFactory
29
{
30
    /**
31
     * @var FactoryInterface
32
     */
33
    private $addressFactory;
34
35
    /**
36
     * @var RepositoryInterface
37
     */
38
    private $countryRepository;
39
40
    /**
41
     * @var RepositoryInterface
42
     */
43
    private $customerRepository;
44
45
    /**
46
     * @var \Faker\Generator
47
     */
48
    private $faker;
49
50
    /**
51
     * @var OptionsResolver
52
     */
53
    private $optionsResolver;
54
55
    /**
56
     * @param FactoryInterface $addressFactory
57
     * @param RepositoryInterface $countryRepository
58
     * @param RepositoryInterface $customerRepository
59
     */
60
    public function __construct(
61
        FactoryInterface $addressFactory,
62
        RepositoryInterface $countryRepository,
63
        RepositoryInterface $customerRepository
64
    ) {
65
        $this->addressFactory = $addressFactory;
66
        $this->countryRepository = $countryRepository;
67
        $this->customerRepository = $customerRepository;
68
69
        $this->faker = \Faker\Factory::create();
70
        $this->optionsResolver = new OptionsResolver();
71
72
        $this->configureOptions($this->optionsResolver);
73
    }
74
75
    /**
76
     * {@inheritdoc}
77
     */
78
    protected function configureOptions(OptionsResolver $resolver): void
79
    {
80
        $resolver
81
            ->setDefault('first_name', function (Options $options): string {
82
                return $this->faker->firstName;
83
            })
84
            ->setDefault('last_name', function (Options $options): string {
0 ignored issues
show
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...
85
                return $this->faker->lastName;
86
            })
87
            ->setDefault('phone_number', function (Options $options): ?string {
0 ignored issues
show
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...
88
                return random_int(1, 100) > 50 ? $this->faker->phoneNumber : null;
89
            })
90
            ->setDefault('company', function (Options $options): ?string {
91
                return random_int(1, 100) > 50 ? $this->faker->company : null;
92
            })
93
            ->setDefault('street', function (Options $options): string {
0 ignored issues
show
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...
94
                return $this->faker->streetAddress;
95
            })
96
            ->setDefault('city', function (Options $options): string {
0 ignored issues
show
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...
97
                return $this->faker->city;
98
            })
99
            ->setDefault('postcode', function (Options $options): string {
0 ignored issues
show
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...
100
                return $this->faker->postcode;
101
            })
102
            ->setDefault('country_code', function (Options $options): string {
0 ignored issues
show
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...
103
                $countries = $this->countryRepository->findAll();
104
                shuffle($countries);
105
106
                return array_pop($countries)->getCode();
107
            })
108
            ->setAllowedTypes('country_code', ['string'])
109
            ->setDefault('province_name', null)
110
            ->setAllowedTypes('province_name', ['null', 'string'])
111
            ->setDefault('province_code', null)
112
            ->setAllowedTypes('province_code', ['null', 'string'])
113
            ->setDefault('customer', LazyOption::randomOne($this->customerRepository))
114
            ->setAllowedTypes('customer', ['string', CustomerInterface::class, 'null'])
115
            ->setNormalizer('customer', LazyOption::findOneBy($this->customerRepository, 'email'))
116
        ;
117
    }
118
119
    /**
120
     * {@inheritdoc}
121
     */
122
    public function create(array $options = []): AddressInterface
123
    {
124
        $options = $this->optionsResolver->resolve($options);
125
126
        /** @var AddressInterface $address */
127
        $address = $this->addressFactory->createNew();
128
        $address->setFirstName($options['first_name']);
129
        $address->setLastName($options['last_name']);
130
        $address->setPhoneNumber($options['phone_number']);
131
        $address->setCompany($options['company']);
132
        $address->setStreet($options['street']);
133
        $address->setCity($options['city']);
134
        $address->setPostcode($options['postcode']);
135
136
        $this->assertCountryCodeIsValid($options['country_code']);
137
        $address->setCountryCode($options['country_code']);
138
139
        $this->resolveCountryProvince($options, $address);
140
141
        if (isset($options['customer'])) {
142
            $options['customer']->addAddress($address);
143
        }
144
145
        return $address;
146
    }
147
148
    /**
149
     * @param string $code
150
     *
151
     * @throws \InvalidArgumentException
152
     */
153
    private function assertCountryCodeIsValid(string $code): void
154
    {
155
        $country = $this->countryRepository->findOneBy(['code' => $code]);
156
        Assert::notNull($country);
157
    }
158
159
    /**
160
     * @param string $provinceCode
161
     * @param string $countryCode
162
     *
163
     * @throws \InvalidArgumentException
164
     */
165
    private function assertProvinceCodeIsValid(string $provinceCode, string $countryCode): void
166
    {
167
        $country = $this->countryRepository->findOneBy(['code' => $countryCode]);
168
169
        /** @var ProvinceInterface $province */
170
        foreach ($country->getProvinces() as $province) {
171
            if ($province->getCode() === $provinceCode) {
172
                return;
173
            }
174
        }
175
176
        throw new \InvalidArgumentException(sprintf('Provided province code is not valid for "%s"', $country->getName()));
177
    }
178
179
    /**
180
     * @param array $options
181
     * @param AddressInterface $address
182
     */
183
    private function provideProvince(array $options, AddressInterface $address): void
184
    {
185
        /** @var Country $country */
186
        $country = $this->countryRepository->findOneBy(['code' => $options['country_code']]);
187
188
        if ($country->hasProvinces()) {
189
            $address->setProvinceCode($this->getProvinceCode($country->getProvinces(), $options['province_name']));
190
191
            return;
192
        }
193
194
        $address->setProvinceName($options['province_name']);
195
    }
196
197
    /**
198
     * @param Collection $provinces
199
     * @param string $provinceName
200
     *
201
     * @return string
202
     *
203
     * @throws \InvalidArgumentException
204
     */
205
    private function getProvinceCode(Collection $provinces, string $provinceName): string
206
    {
207
        /** @var ProvinceInterface $province */
208
        foreach ($provinces as $province) {
209
            if ($province->getName() === $provinceName) {
210
                return $province->getCode();
211
            }
212
        }
213
214
        throw new \InvalidArgumentException(sprintf('Country has defined provinces, but %s is not one of them', $provinceName));
215
    }
216
217
    /**
218
     * @param array $options
219
     * @param AddressInterface $address
220
     */
221
    private function resolveCountryProvince(array $options, AddressInterface $address): void
222
    {
223
        if (null !== $options['province_code']) {
224
            $this->assertProvinceCodeIsValid($options['province_code'], $options['country_code']);
225
            $address->setProvinceCode($options['province_code']);
226
227
            return;
228
        }
229
230
        if (null !== $options['province_name']) {
231
            $this->provideProvince($options, $address);
232
        }
233
    }
234
}
235