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

UpsertAddressRoute   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 124
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 64
c 0
b 0
f 0
dl 0
loc 124
rs 10
wmc 12

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 1
A getValidationDefinition() 0 18 4
A getDecorated() 0 3 1
B upsert() 0 59 5
A getDefaultSalutationId() 0 12 1
1
<?php declare(strict_types=1);
2
3
namespace Shopware\Core\Checkout\Customer\SalesChannel;
4
5
use Shopware\Core\Checkout\Customer\Aggregate\CustomerAddress\CustomerAddressDefinition;
6
use Shopware\Core\Checkout\Customer\Aggregate\CustomerAddress\CustomerAddressEntity;
7
use Shopware\Core\Checkout\Customer\CustomerEntity;
8
use Shopware\Core\Checkout\Customer\CustomerEvents;
9
use Shopware\Core\Checkout\Customer\Validation\Constraint\CustomerZipCode;
10
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
11
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
12
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
13
use Shopware\Core\Framework\Event\DataMappingEvent;
14
use Shopware\Core\Framework\Log\Package;
15
use Shopware\Core\Framework\Plugin\Exception\DecorationPatternException;
16
use Shopware\Core\Framework\Uuid\Uuid;
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\Salutation\SalutationDefinition;
26
use Shopware\Core\System\SystemConfig\SystemConfigService;
27
use Symfony\Component\Routing\Annotation\Route;
28
use Symfony\Component\Validator\Constraints\NotBlank;
29
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
30
31
#[Route(defaults: ['_routeScope' => ['store-api']])]
32
#[Package('customer-order')]
33
class UpsertAddressRoute extends AbstractUpsertAddressRoute
34
{
35
    use CustomerAddressValidationTrait;
36
37
    /**
38
     * @var EntityRepository
39
     */
40
    private $addressRepository;
41
42
    /**
43
     * @internal
44
     */
45
    public function __construct(
46
        EntityRepository $addressRepository,
47
        private readonly DataValidator $validator,
48
        private readonly EventDispatcherInterface $eventDispatcher,
49
        private readonly DataValidationFactoryInterface $addressValidationFactory,
50
        private readonly SystemConfigService $systemConfigService,
51
        private readonly StoreApiCustomFieldMapper $storeApiCustomFieldMapper,
52
        private readonly EntityRepository $salutationRepository,
53
    ) {
54
        $this->addressRepository = $addressRepository;
55
    }
56
57
    public function getDecorated(): AbstractUpsertAddressRoute
58
    {
59
        throw new DecorationPatternException(self::class);
60
    }
61
62
    #[Route(path: '/store-api/account/address', name: 'store-api.account.address.create', methods: ['POST'], defaults: ['addressId' => null, '_loginRequired' => true, '_loginRequiredAllowGuest' => true])]
63
    #[Route(path: '/store-api/account/address/{addressId}', name: 'store-api.account.address.update', methods: ['PATCH'], defaults: ['_loginRequired' => true, '_loginRequiredAllowGuest' => true])]
64
    public function upsert(?string $addressId, RequestDataBag $data, SalesChannelContext $context, CustomerEntity $customer): UpsertAddressRouteResponse
65
    {
66
        if (!$addressId) {
67
            $isCreate = true;
68
            $addressId = Uuid::randomHex();
69
        } else {
70
            $this->validateAddress($addressId, $context, $customer);
71
            $isCreate = false;
72
        }
73
74
        if (!$data->get('salutationId')) {
75
            $data->set('salutationId', $this->getDefaultSalutationId($context));
76
        }
77
78
        $accountType = $data->get('accountType', CustomerEntity::ACCOUNT_TYPE_PRIVATE);
79
        $definition = $this->getValidationDefinition($data, $accountType, $isCreate, $context);
80
        $this->validator->validate(array_merge(['id' => $addressId], $data->all()), $definition);
81
82
        $addressData = [
83
            'salutationId' => $data->get('salutationId'),
84
            'firstName' => $data->get('firstName'),
85
            'lastName' => $data->get('lastName'),
86
            'street' => $data->get('street'),
87
            'city' => $data->get('city'),
88
            'zipcode' => $data->get('zipcode'),
89
            'countryId' => $data->get('countryId'),
90
            'countryStateId' => $data->get('countryStateId') ?: null,
91
            'company' => $data->get('company'),
92
            'department' => $data->get('department'),
93
            'title' => $data->get('title'),
94
            'phoneNumber' => $data->get('phoneNumber'),
95
            'additionalAddressLine1' => $data->get('additionalAddressLine1'),
96
            'additionalAddressLine2' => $data->get('additionalAddressLine2'),
97
        ];
98
99
        if ($data->get('customFields') instanceof RequestDataBag) {
100
            $addressData['customFields'] = $this->storeApiCustomFieldMapper->map(
101
                CustomerAddressDefinition::ENTITY_NAME,
102
                $data->get('customFields')
103
            );
104
        }
105
106
        $mappingEvent = new DataMappingEvent($data, $addressData, $context->getContext());
107
        $this->eventDispatcher->dispatch($mappingEvent, CustomerEvents::MAPPING_ADDRESS_CREATE);
108
109
        $addressData = $mappingEvent->getOutput();
110
        $addressData['id'] = $addressId;
111
        $addressData['customerId'] = $customer->getId();
112
113
        $this->addressRepository->upsert([$addressData], $context->getContext());
114
115
        $criteria = new Criteria([$addressId]);
116
117
        /** @var CustomerAddressEntity $address */
118
        $address = $this->addressRepository->search($criteria, $context->getContext())->first();
119
120
        return new UpsertAddressRouteResponse($address);
121
    }
122
123
    private function getValidationDefinition(DataBag $data, string $accountType, bool $isCreate, SalesChannelContext $context): DataValidationDefinition
124
    {
125
        if ($isCreate) {
126
            $validation = $this->addressValidationFactory->create($context);
127
        } else {
128
            $validation = $this->addressValidationFactory->update($context);
129
        }
130
131
        if ($accountType === CustomerEntity::ACCOUNT_TYPE_BUSINESS && $this->systemConfigService->get('core.loginRegistration.showAccountTypeSelection')) {
132
            $validation->add('company', new NotBlank());
133
        }
134
135
        $validation->set('zipcode', new CustomerZipCode(['countryId' => $data->get('countryId')]));
136
137
        $validationEvent = new BuildValidationEvent($validation, $data, $context->getContext());
138
        $this->eventDispatcher->dispatch($validationEvent, $validationEvent->getName());
139
140
        return $validation;
141
    }
142
143
    private function getDefaultSalutationId(SalesChannelContext $context): string
144
    {
145
        $criteria = new Criteria();
146
        $criteria->setLimit(1);
147
        $criteria->addFilter(
148
            new EqualsFilter('salutationKey', SalutationDefinition::NOT_SPECIFIED)
149
        );
150
151
        /** @var array<string> $ids */
152
        $ids = $this->salutationRepository->searchIds($criteria, $context->getContext())->getIds();
153
154
        return $ids[0] ?? '';
155
    }
156
}
157