| Total Complexity | 44 |
| Total Lines | 371 |
| Duplicated Lines | 0 % |
| Changes | 0 | ||
Complex classes like AddressController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use AddressController, and based on these observations, apply Extract Interface, too.
| 1 | <?php declare(strict_types=1); |
||
| 46 | class AddressController extends StorefrontController |
||
| 47 | { |
||
| 48 | private const ADDRESS_TYPE_BILLING = 'billing'; |
||
| 49 | private const ADDRESS_TYPE_SHIPPING = 'shipping'; |
||
| 50 | |||
| 51 | private AccountService $accountService; |
||
| 52 | |||
| 53 | private AddressListingPageLoader $addressListingPageLoader; |
||
| 54 | |||
| 55 | private AddressDetailPageLoader $addressDetailPageLoader; |
||
| 56 | |||
| 57 | private AbstractListAddressRoute $listAddressRoute; |
||
| 58 | |||
| 59 | private AbstractUpsertAddressRoute $updateAddressRoute; |
||
| 60 | |||
| 61 | private AbstractDeleteAddressRoute $deleteAddressRoute; |
||
| 62 | |||
| 63 | private AbstractChangeCustomerProfileRoute $updateCustomerProfileRoute; |
||
| 64 | |||
| 65 | /** |
||
| 66 | * @internal |
||
| 67 | */ |
||
| 68 | public function __construct( |
||
| 69 | AddressListingPageLoader $addressListingPageLoader, |
||
| 70 | AddressDetailPageLoader $addressDetailPageLoader, |
||
| 71 | AccountService $accountService, |
||
| 72 | AbstractListAddressRoute $listAddressRoute, |
||
| 73 | AbstractUpsertAddressRoute $updateAddressRoute, |
||
| 74 | AbstractDeleteAddressRoute $deleteAddressRoute, |
||
| 75 | AbstractChangeCustomerProfileRoute $updateCustomerProfileRoute |
||
| 76 | ) { |
||
| 77 | $this->accountService = $accountService; |
||
| 78 | $this->addressListingPageLoader = $addressListingPageLoader; |
||
| 79 | $this->addressDetailPageLoader = $addressDetailPageLoader; |
||
| 80 | $this->listAddressRoute = $listAddressRoute; |
||
| 81 | $this->updateAddressRoute = $updateAddressRoute; |
||
| 82 | $this->deleteAddressRoute = $deleteAddressRoute; |
||
| 83 | $this->updateCustomerProfileRoute = $updateCustomerProfileRoute; |
||
| 84 | } |
||
| 85 | |||
| 86 | /** |
||
| 87 | * @Since("6.0.0.0") |
||
| 88 | * @Route("/account/address", name="frontend.account.address.page", options={"seo"="false"}, methods={"GET"}, defaults={"_loginRequired"=true}) |
||
| 89 | * @NoStore |
||
| 90 | */ |
||
| 91 | public function accountAddressOverview(Request $request, SalesChannelContext $context, CustomerEntity $customer): Response |
||
| 92 | { |
||
| 93 | $page = $this->addressListingPageLoader->load($request, $context, $customer); |
||
| 94 | |||
| 95 | $this->hook(new AddressListingPageLoadedHook($page, $context)); |
||
| 96 | |||
| 97 | return $this->renderStorefront('@Storefront/storefront/page/account/addressbook/index.html.twig', ['page' => $page]); |
||
| 98 | } |
||
| 99 | |||
| 100 | /** |
||
| 101 | * @Since("6.0.0.0") |
||
| 102 | * @Route("/account/address/create", name="frontend.account.address.create.page", options={"seo"="false"}, methods={"GET"}, defaults={"_loginRequired"=true}) |
||
| 103 | * @NoStore |
||
| 104 | */ |
||
| 105 | public function accountCreateAddress(Request $request, RequestDataBag $data, SalesChannelContext $context, CustomerEntity $customer): Response |
||
| 106 | { |
||
| 107 | $page = $this->addressDetailPageLoader->load($request, $context, $customer); |
||
| 108 | |||
| 109 | $this->hook(new AddressDetailPageLoadedHook($page, $context)); |
||
| 110 | |||
| 111 | return $this->renderStorefront('@Storefront/storefront/page/account/addressbook/create.html.twig', [ |
||
| 112 | 'page' => $page, |
||
| 113 | 'data' => $data, |
||
| 114 | ]); |
||
| 115 | } |
||
| 116 | |||
| 117 | /** |
||
| 118 | * @Since("6.0.0.0") |
||
| 119 | * @Route("/account/address/{addressId}", name="frontend.account.address.edit.page", options={"seo"="false"}, methods={"GET"}, defaults={"_loginRequired"=true}) |
||
| 120 | * @NoStore |
||
| 121 | */ |
||
| 122 | public function accountEditAddress(Request $request, SalesChannelContext $context, CustomerEntity $customer): Response |
||
| 123 | { |
||
| 124 | $page = $this->addressDetailPageLoader->load($request, $context, $customer); |
||
| 125 | |||
| 126 | $this->hook(new AddressDetailPageLoadedHook($page, $context)); |
||
| 127 | |||
| 128 | return $this->renderStorefront('@Storefront/storefront/page/account/addressbook/edit.html.twig', ['page' => $page]); |
||
| 129 | } |
||
| 130 | |||
| 131 | /** |
||
| 132 | * @Since("6.0.0.0") |
||
| 133 | * @Route("/account/address/default-{type}/{addressId}", name="frontend.account.address.set-default-address", methods={"POST"}, defaults={"_loginRequired"=true}) |
||
| 134 | */ |
||
| 135 | public function switchDefaultAddress(string $type, string $addressId, SalesChannelContext $context, CustomerEntity $customer): RedirectResponse |
||
| 157 | ); |
||
| 158 | } |
||
| 159 | |||
| 160 | /** |
||
| 161 | * @Since("6.0.0.0") |
||
| 162 | * @Route("/account/address/delete/{addressId}", name="frontend.account.address.delete", options={"seo"="false"}, methods={"POST"}, defaults={"_loginRequired"=true}) |
||
| 163 | */ |
||
| 164 | public function deleteAddress(string $addressId, SalesChannelContext $context, CustomerEntity $customer): Response |
||
| 179 | } |
||
| 180 | |||
| 181 | /** |
||
| 182 | * @Since("6.0.0.0") |
||
| 183 | * @Route("/account/address/create", name="frontend.account.address.create", options={"seo"="false"}, methods={"POST"}, defaults={"_loginRequired"=true}) |
||
| 184 | * @Route("/account/address/{addressId}", name="frontend.account.address.edit.save", options={"seo"="false"}, methods={"POST"}, defaults={"_loginRequired"=true}) |
||
| 185 | */ |
||
| 186 | public function saveAddress(RequestDataBag $data, SalesChannelContext $context, CustomerEntity $customer): Response |
||
| 211 | ); |
||
| 212 | } |
||
| 213 | |||
| 214 | /** |
||
| 215 | * @Since("6.0.0.0") |
||
| 216 | * @Route("/widgets/account/address-book", name="frontend.account.addressbook", options={"seo"=true}, methods={"POST"}, defaults={"XmlHttpRequest"=true, "_loginRequired"=true, "_loginRequiredAllowGuest"=true}) |
||
| 217 | */ |
||
| 218 | public function addressBook(Request $request, RequestDataBag $dataBag, SalesChannelContext $context, CustomerEntity $customer): Response |
||
| 219 | { |
||
| 220 | $viewData = new AddressEditorModalStruct(); |
||
| 221 | $params = []; |
||
| 222 | |||
| 223 | try { |
||
| 224 | $this->handleChangeableAddresses($viewData, $dataBag, $context, $customer); |
||
| 225 | $this->handleAddressCreation($viewData, $dataBag, $context, $customer); |
||
| 226 | $this->handleAddressSelection($viewData, $dataBag, $context, $customer); |
||
| 227 | |||
| 228 | $page = $this->addressListingPageLoader->load($request, $context, $customer); |
||
| 229 | |||
| 230 | $this->hook(new AddressBookWidgetLoadedHook($page, $context)); |
||
| 231 | |||
| 232 | $viewData->setPage($page); |
||
| 233 | if (Feature::isActive('FEATURE_NEXT_15957')) { |
||
| 234 | $this->handleCustomerVatIds($dataBag, $context, $customer); |
||
| 235 | } |
||
| 236 | } catch (ConstraintViolationException $formViolations) { |
||
| 237 | $params['formViolations'] = $formViolations; |
||
| 238 | $params['postedData'] = $dataBag->get('address'); |
||
| 239 | } catch (\Exception $exception) { |
||
| 240 | $viewData->setSuccess(false); |
||
| 241 | $viewData->setMessages([ |
||
| 242 | 'type' => self::DANGER, |
||
| 243 | 'text' => $this->trans('error.message-default'), |
||
| 244 | ]); |
||
| 245 | } |
||
| 246 | |||
| 247 | if ($request->get('redirectTo') || $request->get('forwardTo')) { |
||
| 248 | return $this->createActionResponse($request); |
||
| 249 | } |
||
| 250 | $params = array_merge($params, $viewData->getVars()); |
||
| 251 | |||
| 252 | $response = $this->renderStorefront( |
||
| 253 | '@Storefront/storefront/component/address/address-editor-modal.html.twig', |
||
| 254 | $params |
||
| 255 | ); |
||
| 256 | |||
| 257 | $response->headers->set('x-robots-tag', 'noindex'); |
||
| 258 | |||
| 259 | return $response; |
||
| 260 | } |
||
| 261 | |||
| 262 | private function handleAddressCreation( |
||
| 303 | } |
||
| 304 | |||
| 305 | private function handleChangeableAddresses( |
||
| 327 | } |
||
| 328 | |||
| 329 | /** |
||
| 330 | * @throws CustomerNotLoggedInException |
||
| 331 | * @throws InvalidUuidException |
||
| 332 | */ |
||
| 333 | private function handleAddressSelection( |
||
| 334 | AddressEditorModalStruct $viewData, |
||
| 335 | RequestDataBag $dataBag, |
||
| 336 | SalesChannelContext $context, |
||
| 337 | CustomerEntity $customer |
||
| 338 | ): void { |
||
| 339 | $selectedAddress = $dataBag->get('selectAddress'); |
||
| 340 | |||
| 341 | if ($selectedAddress === null) { |
||
| 342 | return; |
||
| 343 | } |
||
| 344 | |||
| 345 | $addressType = $selectedAddress->get('type'); |
||
| 346 | $addressId = $selectedAddress->get('id'); |
||
| 347 | |||
| 348 | if (!Uuid::isValid($addressId)) { |
||
| 349 | throw new InvalidUuidException($addressId); |
||
| 350 | } |
||
| 351 | |||
| 352 | $success = true; |
||
| 353 | |||
| 354 | try { |
||
| 355 | if ($addressType === self::ADDRESS_TYPE_SHIPPING) { |
||
| 356 | $address = $this->getById($addressId, $context, $customer); |
||
| 357 | $customer->setDefaultShippingAddress($address); |
||
| 358 | $this->accountService->setDefaultShippingAddress($addressId, $context, $customer); |
||
| 359 | } elseif ($addressType === self::ADDRESS_TYPE_BILLING) { |
||
| 360 | $address = $this->getById($addressId, $context, $customer); |
||
| 361 | $customer->setDefaultBillingAddress($address); |
||
| 362 | $this->accountService->setDefaultBillingAddress($addressId, $context, $customer); |
||
| 363 | } else { |
||
| 364 | $success = false; |
||
| 365 | } |
||
| 366 | } catch (AddressNotFoundException $exception) { |
||
| 367 | $success = false; |
||
| 368 | } |
||
| 369 | |||
| 370 | if ($success) { |
||
| 371 | $this->addFlash(self::SUCCESS, $this->trans('account.addressDefaultChanged')); |
||
| 372 | } else { |
||
| 373 | $this->addFlash(self::DANGER, $this->trans('account.addressDefaultNotChanged')); |
||
| 374 | } |
||
| 375 | |||
| 376 | $viewData->setSuccess($success); |
||
| 377 | } |
||
| 378 | |||
| 379 | private function getById(string $addressId, SalesChannelContext $context, CustomerEntity $customer): CustomerAddressEntity |
||
| 380 | { |
||
| 381 | if (!Uuid::isValid($addressId)) { |
||
| 382 | throw new InvalidUuidException($addressId); |
||
| 383 | } |
||
| 384 | |||
| 385 | $criteria = new Criteria(); |
||
| 386 | $criteria->addFilter(new EqualsFilter('id', $addressId)); |
||
| 387 | $criteria->addFilter(new EqualsFilter('customerId', $customer->getId())); |
||
| 388 | |||
| 389 | $address = $this->listAddressRoute->load($criteria, $context, $customer)->getAddressCollection()->get($addressId); |
||
| 390 | |||
| 391 | if (!$address) { |
||
| 392 | throw new AddressNotFoundException($addressId); |
||
| 393 | } |
||
| 394 | |||
| 395 | return $address; |
||
| 396 | } |
||
| 397 | |||
| 398 | private function handleCustomerVatIds(RequestDataBag $dataBag, SalesChannelContext $context, CustomerEntity $customer): void |
||
| 417 | } |
||
| 418 | } |
||
| 419 |