Passed
Push — trunk ( aa92c3...83ea4e )
by Christian
11:27 queued 13s
created

ChangeCustomerProfileRoute::change()   C

Complexity

Conditions 11
Paths 192

Size

Total Lines 62
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 35
c 0
b 0
f 0
nc 192
nop 3
dl 0
loc 62
rs 6.55

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php declare(strict_types=1);
2
3
namespace Shopware\Core\Checkout\Customer\SalesChannel;
4
5
use Shopware\Core\Checkout\Customer\Aggregate\CustomerAddress\CustomerAddressEntity;
6
use Shopware\Core\Checkout\Customer\CustomerDefinition;
7
use Shopware\Core\Checkout\Customer\CustomerEntity;
8
use Shopware\Core\Checkout\Customer\CustomerEvents;
9
use Shopware\Core\Checkout\Customer\Validation\Constraint\CustomerVatIdentification;
10
use Shopware\Core\Framework\Context;
11
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
12
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
13
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
14
use Shopware\Core\Framework\Event\DataMappingEvent;
15
use Shopware\Core\Framework\Log\Package;
16
use Shopware\Core\Framework\Plugin\Exception\DecorationPatternException;
17
use Shopware\Core\Framework\Validation\BuildValidationEvent;
18
use Shopware\Core\Framework\Validation\DataBag\DataBag;
19
use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
20
use Shopware\Core\Framework\Validation\DataValidationDefinition;
21
use Shopware\Core\Framework\Validation\DataValidationFactoryInterface;
22
use Shopware\Core\Framework\Validation\DataValidator;
23
use Shopware\Core\System\SalesChannel\SalesChannelContext;
24
use Shopware\Core\System\SalesChannel\StoreApiCustomFieldMapper;
25
use Shopware\Core\System\SalesChannel\SuccessResponse;
26
use Shopware\Core\System\Salutation\SalutationDefinition;
27
use Symfony\Component\Routing\Annotation\Route;
28
use Symfony\Component\Validator\Constraint;
29
use Symfony\Component\Validator\Constraints\NotBlank;
30
use Symfony\Component\Validator\Constraints\Type;
31
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
32
33
#[Route(defaults: ['_routeScope' => ['store-api'], '_contextTokenRequired' => true])]
34
#[Package('customer-order')]
35
class ChangeCustomerProfileRoute extends AbstractChangeCustomerProfileRoute
36
{
37
    /**
38
     * @internal
39
     */
40
    public function __construct(
41
        private readonly EntityRepository $customerRepository,
42
        private readonly EventDispatcherInterface $eventDispatcher,
43
        private readonly DataValidator $validator,
44
        private readonly DataValidationFactoryInterface $customerProfileValidationFactory,
45
        private readonly StoreApiCustomFieldMapper $storeApiCustomFieldMapper,
46
        private readonly EntityRepository $salutationRepository,
47
    ) {
48
    }
49
50
    public function getDecorated(): AbstractChangeCustomerProfileRoute
51
    {
52
        throw new DecorationPatternException(self::class);
53
    }
54
55
    #[Route(path: '/store-api/account/change-profile', name: 'store-api.account.change-profile', methods: ['POST'], defaults: ['_loginRequired' => true, '_loginRequiredAllowGuest' => true])]
56
    public function change(RequestDataBag $data, SalesChannelContext $context, CustomerEntity $customer): SuccessResponse
57
    {
58
        $validation = $this->customerProfileValidationFactory->update($context);
59
60
        if ($data->has('accountType') && empty($data->get('accountType'))) {
61
            $data->remove('accountType');
62
        }
63
64
        if ($data->get('accountType') === CustomerEntity::ACCOUNT_TYPE_BUSINESS) {
65
            $validation->add('company', new NotBlank());
66
            $billingAddress = $customer->getDefaultBillingAddress();
67
            if ($billingAddress) {
68
                $this->addVatIdsValidation($validation, $billingAddress);
69
            }
70
        } else {
71
            $data->set('company', '');
72
            $data->set('vatIds', null);
73
        }
74
75
        /** @var ?RequestDataBag $vatIds */
76
        $vatIds = $data->get('vatIds');
77
        if ($vatIds) {
78
            $vatIds = \array_filter($vatIds->all());
79
            $data->set('vatIds', empty($vatIds) ? null : $vatIds);
80
        }
81
82
        if (!$data->get('salutationId')) {
83
            $data->set('salutationId', $this->getDefaultSalutationId($context));
84
        }
85
86
        $this->dispatchValidationEvent($validation, $data, $context->getContext());
87
88
        $this->validator->validate($data->all(), $validation);
89
90
        $customerData = $data->only('firstName', 'lastName', 'salutationId', 'title', 'company', 'accountType');
91
92
        if ($vatIds) {
93
            $customerData['vatIds'] = $data->get('vatIds');
94
        }
95
96
        if ($birthday = $this->getBirthday($data)) {
97
            $customerData['birthday'] = $birthday;
98
        }
99
100
        if ($data->get('customFields') instanceof RequestDataBag) {
101
            $customerData['customFields'] = $this->storeApiCustomFieldMapper->map(
102
                CustomerDefinition::ENTITY_NAME,
103
                $data->get('customFields')
104
            );
105
        }
106
107
        $mappingEvent = new DataMappingEvent($data, $customerData, $context->getContext());
108
        $this->eventDispatcher->dispatch($mappingEvent, CustomerEvents::MAPPING_CUSTOMER_PROFILE_SAVE);
109
110
        $customerData = $mappingEvent->getOutput();
111
112
        $customerData['id'] = $customer->getId();
113
114
        $this->customerRepository->update([$customerData], $context->getContext());
115
116
        return new SuccessResponse();
117
    }
118
119
    private function dispatchValidationEvent(DataValidationDefinition $definition, DataBag $data, Context $context): void
120
    {
121
        $validationEvent = new BuildValidationEvent($definition, $data, $context);
122
        $this->eventDispatcher->dispatch($validationEvent, $validationEvent->getName());
123
    }
124
125
    private function addVatIdsValidation(DataValidationDefinition $validation, CustomerAddressEntity $address): void
126
    {
127
        /** @var Constraint[] $constraints */
128
        $constraints = [
129
            new Type('array'),
130
            new CustomerVatIdentification(
131
                ['countryId' => $address->getCountryId()]
132
            ),
133
        ];
134
        if ($address->getCountry() && $address->getCountry()->getVatIdRequired()) {
135
            $constraints[] = new NotBlank();
136
        }
137
138
        $validation->add('vatIds', ...$constraints);
139
    }
140
141
    private function getBirthday(DataBag $data): ?\DateTimeInterface
142
    {
143
        $birthdayDay = $data->get('birthdayDay');
144
        $birthdayMonth = $data->get('birthdayMonth');
145
        $birthdayYear = $data->get('birthdayYear');
146
147
        if (!$birthdayDay || !$birthdayMonth || !$birthdayYear) {
148
            return null;
149
        }
150
        \assert(\is_numeric($birthdayDay));
151
        \assert(\is_numeric($birthdayMonth));
152
        \assert(\is_numeric($birthdayYear));
153
154
        return new \DateTime(sprintf(
155
            '%s-%s-%s',
156
            $birthdayYear,
157
            $birthdayMonth,
158
            $birthdayDay
159
        ));
160
    }
161
162
    private function getDefaultSalutationId(SalesChannelContext $context): string
163
    {
164
        $criteria = new Criteria();
165
        $criteria->setLimit(1);
166
        $criteria->addFilter(
167
            new EqualsFilter('salutationKey', SalutationDefinition::NOT_SPECIFIED)
168
        );
169
170
        /** @var array<string> $ids */
171
        $ids = $this->salutationRepository->searchIds($criteria, $context->getContext())->getIds();
172
173
        return $ids[0] ?? '';
174
    }
175
}
176