Completed
Push — master ( 7d844f...319af7 )
by Kamil
17s
created

AddressExampleFactory::getProvinceCode()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 5
nc 3
nop 2
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 Doctrine\Common\Collections\Collection;
15
use Sylius\Bundle\CoreBundle\Fixture\OptionsResolver\LazyOption;
16
use Sylius\Component\Addressing\Model\Country;
17
use Sylius\Component\Addressing\Model\ProvinceInterface;
18
use Sylius\Component\Core\Model\AddressInterface;
19
use Sylius\Component\Core\Model\CustomerInterface;
20
use Sylius\Component\Resource\Factory\FactoryInterface;
21
use Sylius\Component\Resource\Repository\RepositoryInterface;
22
use Symfony\Component\OptionsResolver\Options;
23
use Symfony\Component\OptionsResolver\OptionsResolver;
24
use Webmozart\Assert\Assert;
25
26
/**
27
 * @author Jan Góralski <[email protected]>
28
 */
29
class AddressExampleFactory extends AbstractExampleFactory
30
{
31
    /**
32
     * @var FactoryInterface
33
     */
34
    private $addressFactory;
35
36
    /**
37
     * @var RepositoryInterface
38
     */
39
    private $countryRepository;
40
41
    /**
42
     * @var RepositoryInterface
43
     */
44
    private $customerRepository;
45
46
    /**
47
     * @var \Faker\Generator
48
     */
49
    private $faker;
50
51
    /**
52
     * @var OptionsResolver
53
     */
54
    private $optionsResolver;
55
56
    /**
57
     * @param FactoryInterface $addressFactory
58
     * @param RepositoryInterface $countryRepository
59
     * @param RepositoryInterface $customerRepository
60
     */
61
    public function __construct(
62
        FactoryInterface $addressFactory,
63
        RepositoryInterface $countryRepository,
64
        RepositoryInterface $customerRepository
65
    ) {
66
        $this->addressFactory = $addressFactory;
67
        $this->countryRepository = $countryRepository;
68
        $this->customerRepository = $customerRepository;
69
70
        $this->faker = \Faker\Factory::create();
71
        $this->optionsResolver = new OptionsResolver();
72
73
        $this->configureOptions($this->optionsResolver);
74
    }
75
76
    /**
77
     * {@inheritdoc}
78
     */
79
    protected function configureOptions(OptionsResolver $resolver)
80
    {
81
        $resolver
82
            ->setDefault('first_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...
83
                return $this->faker->firstName;
84
            })
85
            ->setDefault('last_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...
86
                return $this->faker->lastName;
87
            })
88
            ->setDefault('phone_number', 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...
89
                return mt_rand(1, 100) > 50 ? $this->faker->phoneNumber : null;
90
            })
91
            ->setDefault('company', 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...
92
                return mt_rand(1, 100) > 50 ? $this->faker->company : null;
93
            })
94
            ->setDefault('street', 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...
95
                return $this->faker->streetAddress;
96
            })
97
            ->setDefault('city', 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...
98
                return $this->faker->city;
99
            })
100
            ->setDefault('postcode', 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...
101
                return $this->faker->postcode;
102
            })
103
            ->setDefault('country_code', 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...
104
                $countries = $this->countryRepository->findAll();
105
                shuffle($countries);
106
107
                return array_pop($countries)->getCode();
108
            })
109
            ->setAllowedTypes('country_code', ['string'])
110
            ->setDefault('province_name', null)
111
            ->setAllowedTypes('province_name', ['null', 'string'])
112
            ->setDefault('province_code', null)
113
            ->setAllowedTypes('province_code', ['null', 'string'])
114
            ->setDefault('customer', LazyOption::randomOne($this->customerRepository))
115
            ->setAllowedTypes('customer', ['string', CustomerInterface::class, 'null'])
116
            ->setNormalizer('customer', LazyOption::findOneBy($this->customerRepository, 'email'))
117
        ;
118
    }
119
120
    /**
121
     * {@inheritdoc}
122
     */
123
    public function create(array $options = [])
124
    {
125
        $options = $this->optionsResolver->resolve($options);
126
127
        /** @var AddressInterface $address */
128
        $address = $this->addressFactory->createNew();
129
        $address->setFirstName($options['first_name']);
130
        $address->setLastName($options['last_name']);
131
        $address->setPhoneNumber($options['phone_number']);
132
        $address->setCompany($options['company']);
133
        $address->setStreet($options['street']);
134
        $address->setCity($options['city']);
135
        $address->setPostcode($options['postcode']);
136
137
        $this->assertCountryCodeIsValid($options['country_code']);
138
        $address->setCountryCode($options['country_code']);
139
140
        $this->resolveCountryProvince($options, $address);
141
142
        if (isset($options['customer'])) {
143
            $options['customer']->addAddress($address);
144
        }
145
146
        return $address;
147
    }
148
149
    /**
150
     * @param string $code
151
     */
152
    private function assertCountryCodeIsValid($code)
153
    {
154
        $country = $this->countryRepository->findOneBy(['code' => $code]);
155
        Assert::notNull($country);
156
    }
157
158
    /**
159
     * @param string $provinceCode
160
     * @param string $countryCode
161
     */
162
    private function assertProvinceCodeIsValid($provinceCode, $countryCode)
163
    {
164
        $country = $this->countryRepository->findOneBy(['code' => $countryCode]);
165
166
        /** @var ProvinceInterface $province */
167
        foreach ($country->getProvinces() as $province) {
168
            if ($province->getCode() === $provinceCode) {
169
                return;
170
            }
171
        }
172
        throw new \InvalidArgumentException('Provided province code is not valid for "%s"', $country->getName());
173
    }
174
175
    /**
176
     * @param array $options
177
     * @param AddressInterface $address
178
     *
179
     * @return string
180
     */
181
    private function provideProvince(array $options, AddressInterface $address)
182
    {
183
        /** @var Country $country */
184
        $country = $this->countryRepository->findOneBy(['code' => $options['country_code']]);
185
186
        if ($country->hasProvinces()) {
187
            $address->setProvinceCode($this->getProvinceCode($country->getProvinces(), $options['province_name']));
0 ignored issues
show
Bug introduced by
It seems like $country->getProvinces() targeting Sylius\Component\Address...Country::getProvinces() can also be of type array<integer,object<Syl...del\ProvinceInterface>>; however, Sylius\Bundle\CoreBundle...tory::getProvinceCode() does only seem to accept object<Doctrine\Common\Collections\Collection>, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
188
189
            return;
190
        }
191
192
        $address->setProvinceName($options['province_name']);
193
    }
194
195
    /**
196
     * @param Collection $provinces
197
     * @param string $provinceName
198
     *
199
     * @return string
200
     */
201
    private function getProvinceCode(Collection $provinces, $provinceName)
202
    {
203
        /** @var ProvinceInterface $province */
204
        foreach ($provinces as $province) {
205
            if ($province->getName() === $provinceName) {
206
                return $province->getCode();
207
            }
208
        }
209
210
        throw new \InvalidArgumentException(sprintf('Country has defined provinces, but %s is not one of them', $provinceName));
211
    }
212
213
    /**
214
     * @param array $options
215
     * @param AddressInterface $address
216
     */
217
    private function resolveCountryProvince(array $options, AddressInterface $address)
218
    {
219
        if (null !== $options['province_code']) {
220
            $this->assertProvinceCodeIsValid($options['province_code'], $options['country_code']);
221
            $address->setProvinceCode($options['province_code']);
222
223
            return;
224
        }
225
226
        if (null !== $options['province_name']){
227
            $this->provideProvince($options, $address);
228
        }
229
    }
230
}
231