1<?php 2/** 3 * Copyright since 2007 PrestaShop SA and Contributors 4 * PrestaShop is an International Registered Trademark & Property of PrestaShop SA 5 * 6 * NOTICE OF LICENSE 7 * 8 * This source file is subject to the Open Software License (OSL 3.0) 9 * that is bundled with this package in the file LICENSE.md. 10 * It is also available through the world-wide-web at this URL: 11 * https://opensource.org/licenses/OSL-3.0 12 * If you did not receive a copy of the license and are unable to 13 * obtain it through the world-wide-web, please send an email 14 * to license@prestashop.com so we can send you a copy immediately. 15 * 16 * DISCLAIMER 17 * 18 * Do not edit or add to this file if you wish to upgrade PrestaShop to newer 19 * versions in the future. If you wish to customize PrestaShop for your 20 * needs please refer to https://devdocs.prestashop.com/ for more information. 21 * 22 * @author PrestaShop SA and Contributors <contact@prestashop.com> 23 * @copyright Since 2007 PrestaShop SA and Contributors 24 * @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) 25 */ 26 27namespace PrestaShopBundle\Controller\Admin\Configure\ShopParameters; 28 29use Exception; 30use PrestaShop\PrestaShop\Core\Domain\Meta\Exception\MetaConstraintException; 31use PrestaShop\PrestaShop\Core\Domain\Meta\Exception\MetaNotFoundException; 32use PrestaShop\PrestaShop\Core\Domain\ShowcaseCard\Query\GetShowcaseCardIsClosed; 33use PrestaShop\PrestaShop\Core\Domain\ShowcaseCard\ValueObject\ShowcaseCard; 34use PrestaShop\PrestaShop\Core\Form\FormHandlerInterface; 35use PrestaShop\PrestaShop\Core\Form\IdentifiableObject\Builder\FormBuilderInterface; 36use PrestaShop\PrestaShop\Core\Form\IdentifiableObject\Handler; 37use PrestaShop\PrestaShop\Core\Search\Filters\MetaFilters; 38use PrestaShopBundle\Controller\Admin\FrameworkBundleAdminController; 39use PrestaShopBundle\Security\Annotation\AdminSecurity; 40use PrestaShopBundle\Security\Annotation\DemoRestricted; 41use Symfony\Component\Form\FormInterface; 42use Symfony\Component\HttpFoundation\RedirectResponse; 43use Symfony\Component\HttpFoundation\Request; 44use Symfony\Component\HttpFoundation\Response; 45 46/** 47 * Class MetaController is responsible for page display and all actions used in Configure -> Shop parameters -> 48 * Traffic & Seo -> Seo & Urls tab. 49 */ 50class MetaController extends FrameworkBundleAdminController 51{ 52 /** 53 * Shows index Meta page. 54 * 55 * @AdminSecurity("is_granted('read', request.get('_legacy_controller'))") 56 * 57 * @param MetaFilters $filters 58 * @param Request $request 59 * 60 * @return Response 61 */ 62 public function indexAction(MetaFilters $filters, Request $request) 63 { 64 $setUpUrlsForm = $this->getSetUpUrlsFormHandler()->getForm(); 65 $shopUrlsForm = $this->getShopUrlsFormHandler()->getForm(); 66 $seoOptionsForm = $this->getSeoOptionsFormHandler()->getForm(); 67 $isRewriteSettingEnabled = $this->get('prestashop.adapter.legacy.configuration')->getBoolean('PS_REWRITING_SETTINGS'); 68 69 $urlSchemaForm = null; 70 if ($isRewriteSettingEnabled) { 71 $urlSchemaForm = $this->getUrlSchemaFormHandler()->getForm(); 72 } 73 74 return $this->renderForm($request, $filters, $setUpUrlsForm, $shopUrlsForm, $seoOptionsForm, $urlSchemaForm); 75 } 76 77 /** 78 * @deprecated since 1.7.8 and will be removed in next major. Use CommonController:searchGridAction instead 79 * 80 * Used for applying filtering actions. 81 * 82 * @AdminSecurity("is_granted('read', request.get('_legacy_controller'))") 83 * @DemoRestricted(redirectRoute="admin_metas_index") 84 * 85 * @param Request $request 86 * 87 * @return RedirectResponse 88 */ 89 public function searchAction(Request $request) 90 { 91 $definitionFactory = $this->get('prestashop.core.grid.definition.factory.meta'); 92 $definitionFactory = $definitionFactory->getDefinition(); 93 94 $gridFilterFormFactory = $this->get('prestashop.core.grid.filter.form_factory'); 95 $searchParametersForm = $gridFilterFormFactory->create($definitionFactory); 96 $searchParametersForm->handleRequest($request); 97 98 $filters = []; 99 if ($searchParametersForm->isSubmitted()) { 100 $filters = $searchParametersForm->getData(); 101 } 102 103 return $this->redirectToRoute('admin_metas_index', ['filters' => $filters]); 104 } 105 106 /** 107 * Points to the form where new record of meta list can be created. 108 * 109 * @AdminSecurity("is_granted('create', request.get('_legacy_controller'))", message="You do not have permission to add this.") 110 * 111 * @param Request $request 112 * 113 * @return Response 114 */ 115 public function createAction(Request $request) 116 { 117 $data = []; 118 $metaForm = $this->getMetaFormBuilder()->getForm($data); 119 $metaForm->handleRequest($request); 120 121 try { 122 $result = $this->getMetaFormHandler()->handle($metaForm); 123 124 if (null !== $result->getIdentifiableObjectId()) { 125 $this->addFlash('success', $this->trans('Successful creation.', 'Admin.Notifications.Success')); 126 127 return $this->redirectToRoute('admin_metas_index'); 128 } 129 } catch (Exception $exception) { 130 $this->addFlash('error', $this->handleException($exception)); 131 } 132 133 return $this->render('@PrestaShop/Admin/Configure/ShopParameters/TrafficSeo/Meta/create.html.twig', [ 134 'meta_form' => $metaForm->createView(), 135 'multistoreInfoTip' => $this->trans( 136 'Note that this feature is available in all shops context only. It will be added to all your stores.', 137 'Admin.Notifications.Info' 138 ), 139 'multistoreIsUsed' => $this->get('prestashop.adapter.multistore_feature')->isUsed(), 140 ] 141 ); 142 } 143 144 /** 145 * Redirects to page where list record can be edited. 146 * 147 * @AdminSecurity("is_granted('update', request.get('_legacy_controller'))", message="You do not have permission to edit this.") 148 * 149 * @param int $metaId 150 * @param Request $request 151 * 152 * @return Response 153 */ 154 public function editAction($metaId, Request $request) 155 { 156 try { 157 $metaForm = $this->getMetaFormBuilder()->getFormFor($metaId); 158 $metaForm->handleRequest($request); 159 160 $result = $this->getMetaFormHandler()->handleFor($metaId, $metaForm); 161 162 if ($result->isSubmitted() && $result->isValid()) { 163 $this->addFlash('success', $this->trans('Successful update.', 'Admin.Notifications.Success')); 164 165 return $this->redirectToRoute('admin_metas_index'); 166 } 167 } catch (Exception $e) { 168 $this->addFlash('error', $this->handleException($e)); 169 170 return $this->redirectToRoute('admin_metas_index'); 171 } 172 173 return $this->render('@PrestaShop/Admin/Configure/ShopParameters/TrafficSeo/Meta/edit.html.twig', [ 174 'meta_form' => $metaForm->createView(), 175 ] 176 ); 177 } 178 179 /** 180 * Removes single element from meta list. 181 * 182 * @AdminSecurity("is_granted('delete', request.get('_legacy_controller'))", message="You do not have permission to delete this.") 183 * @DemoRestricted(redirectRoute="admin_metas_index") 184 * 185 * @param int $metaId 186 * 187 * @return RedirectResponse 188 */ 189 public function deleteAction($metaId) 190 { 191 $metaEraser = $this->get('prestashop.adapter.meta.meta_eraser'); 192 $errors = $metaEraser->erase([$metaId]); 193 194 if (!empty($errors)) { 195 $this->flashErrors($errors); 196 } else { 197 $this->addFlash( 198 'success', 199 $this->trans('Successful deletion.', 'Admin.Notifications.Success') 200 ); 201 } 202 203 return $this->redirectToRoute('admin_metas_index'); 204 } 205 206 /** 207 * Removes multiple records from meta list. 208 * 209 * @AdminSecurity("is_granted('delete', request.get('_legacy_controller'))", message="You do not have permission to delete this.") 210 * @DemoRestricted(redirectRoute="admin_metas_index") 211 * 212 * @param Request $request 213 * 214 * @return RedirectResponse 215 */ 216 public function deleteBulkAction(Request $request) 217 { 218 $metaToDelete = $request->request->get('meta_bulk'); 219 220 $metaEraser = $this->get('prestashop.adapter.meta.meta_eraser'); 221 $errors = $metaEraser->erase($metaToDelete); 222 223 if (!empty($errors)) { 224 $this->flashErrors($errors); 225 } else { 226 $this->addFlash( 227 'success', 228 $this->trans('The selection has been successfully deleted.', 'Admin.Notifications.Success') 229 ); 230 } 231 232 return $this->redirectToRoute('admin_metas_index'); 233 } 234 235 /** 236 * @AdminSecurity("is_granted('update', request.get('_legacy_controller'))", message="You do not have permission to edit this.") 237 * @DemoRestricted(redirectRoute="admin_metas_index") 238 * 239 * @param MetaFilters $filters 240 * @param Request $request 241 * 242 * @return Response|RedirectResponse 243 */ 244 public function processSetUpUrlsFormAction(MetaFilters $filters, Request $request) 245 { 246 $formProcessResult = $this->processForm( 247 $request, 248 $this->getSetUpUrlsFormHandler(), 249 'SetUpUrls' 250 ); 251 252 if ($formProcessResult instanceof RedirectResponse) { 253 return $formProcessResult; 254 } 255 256 $shopUrlsForm = $this->getShopUrlsFormHandler()->getForm(); 257 $seoOptionsForm = $this->getSeoOptionsFormHandler()->getForm(); 258 $isRewriteSettingEnabled = $this->get('prestashop.adapter.legacy.configuration')->getBoolean('PS_REWRITING_SETTINGS'); 259 260 $urlSchemaForm = null; 261 if ($isRewriteSettingEnabled) { 262 $urlSchemaForm = $this->getUrlSchemaFormHandler()->getForm(); 263 } 264 265 return $this->renderForm($request, $filters, $formProcessResult, $shopUrlsForm, $seoOptionsForm, $urlSchemaForm); 266 } 267 268 /** 269 * @AdminSecurity("is_granted('update', request.get('_legacy_controller'))", message="You do not have permission to edit this.") 270 * @DemoRestricted(redirectRoute="admin_metas_index") 271 * 272 * @param MetaFilters $filters 273 * @param Request $request 274 * 275 * @return Response|RedirectResponse 276 */ 277 public function processShopUrlsFormAction(MetaFilters $filters, Request $request) 278 { 279 $formProcessResult = $this->processForm( 280 $request, 281 $this->getShopUrlsFormHandler(), 282 'ShopUrls' 283 ); 284 285 if ($formProcessResult instanceof RedirectResponse) { 286 return $formProcessResult; 287 } 288 289 $setUpUrlsForm = $this->getSetUpUrlsFormHandler()->getForm(); 290 $seoOptionsForm = $this->getSeoOptionsFormHandler()->getForm(); 291 $isRewriteSettingEnabled = $this->get('prestashop.adapter.legacy.configuration')->getBoolean('PS_REWRITING_SETTINGS'); 292 293 $urlSchemaForm = null; 294 if ($isRewriteSettingEnabled) { 295 $urlSchemaForm = $this->getUrlSchemaFormHandler()->getForm(); 296 } 297 298 return $this->renderForm($request, $filters, $setUpUrlsForm, $formProcessResult, $seoOptionsForm, $urlSchemaForm); 299 } 300 301 /** 302 * @AdminSecurity("is_granted('update', request.get('_legacy_controller'))", message="You do not have permission to edit this.") 303 * @DemoRestricted(redirectRoute="admin_metas_index") 304 * 305 * @param MetaFilters $filters 306 * @param Request $request 307 * 308 * @return Response|RedirectResponse 309 */ 310 public function processUrlSchemaFormAction(MetaFilters $filters, Request $request) 311 { 312 $formProcessResult = $this->processForm( 313 $request, 314 $this->getUrlSchemaFormHandler(), 315 'UrlSchema' 316 ); 317 318 if ($formProcessResult instanceof RedirectResponse) { 319 return $formProcessResult; 320 } 321 322 $setUpUrlsForm = $this->getSetUpUrlsFormHandler()->getForm(); 323 $shopUrlsForm = $this->getShopUrlsFormHandler()->getForm(); 324 $seoOptionsForm = $this->getSeoOptionsFormHandler()->getForm(); 325 326 return $this->renderForm($request, $filters, $setUpUrlsForm, $shopUrlsForm, $seoOptionsForm, $formProcessResult); 327 } 328 329 /** 330 * @AdminSecurity("is_granted('update', request.get('_legacy_controller'))", message="You do not have permission to edit this.") 331 * @DemoRestricted(redirectRoute="admin_metas_index") 332 * 333 * @param MetaFilters $filters 334 * @param Request $request 335 * 336 * @return Response|RedirectResponse 337 */ 338 public function processSeoOptionsFormAction(MetaFilters $filters, Request $request) 339 { 340 $formProcessResult = $this->processForm( 341 $request, 342 $this->getSeoOptionsFormHandler(), 343 'SeoOptions' 344 ); 345 346 if ($formProcessResult instanceof RedirectResponse) { 347 return $formProcessResult; 348 } 349 350 $setUpUrlsForm = $this->getSetUpUrlsFormHandler()->getForm(); 351 $shopUrlsForm = $this->getShopUrlsFormHandler()->getForm(); 352 $isRewriteSettingEnabled = $this->get('prestashop.adapter.legacy.configuration')->getBoolean('PS_REWRITING_SETTINGS'); 353 354 $urlSchemaForm = null; 355 if ($isRewriteSettingEnabled) { 356 $urlSchemaForm = $this->getUrlSchemaFormHandler()->getForm(); 357 } 358 359 return $this->renderForm($request, $filters, $setUpUrlsForm, $shopUrlsForm, $formProcessResult, $urlSchemaForm); 360 } 361 362 /** 363 * Generates robots.txt file for Front Office. 364 * 365 * @AdminSecurity("is_granted(['create', 'update', 'delete'], request.get('_legacy_controller'))") 366 * @DemoRestricted(redirectRoute="admin_metas_index") 367 * 368 * @return RedirectResponse 369 */ 370 public function generateRobotsFileAction() 371 { 372 $robotsTextFileGenerator = $this->get('prestashop.adapter.file.robots_text_file_generator'); 373 374 $rootDir = $this->get('prestashop.adapter.legacy.configuration')->get('_PS_ROOT_DIR_'); 375 376 if (!$robotsTextFileGenerator->generateFile()) { 377 $this->addFlash( 378 'error', 379 $this->trans( 380 'Cannot write into file: %filename%. Please check write permissions.', 381 'Admin.Notifications.Error', 382 [ 383 '%filename%' => $rootDir . '/robots.txt', 384 ] 385 ) 386 ); 387 388 return $this->redirectToRoute('admin_metas_index'); 389 } 390 391 $this->addFlash( 392 'success', 393 $this->trans('Successful update.', 'Admin.Notifications.Success') 394 ); 395 396 return $this->redirectToRoute('admin_metas_index'); 397 } 398 399 /** 400 * @param Request $request 401 * @param MetaFilters $filters 402 * @param FormInterface $setUpUrlsForm 403 * @param FormInterface $shopUrlsForm 404 * @param FormInterface $seoOptionsForm 405 * @param FormInterface|null $urlSchemaForm 406 * 407 * @return Response 408 */ 409 protected function renderForm( 410 Request $request, 411 MetaFilters $filters, 412 FormInterface $setUpUrlsForm, 413 FormInterface $shopUrlsForm, 414 FormInterface $seoOptionsForm, 415 ?FormInterface $urlSchemaForm = null 416 ): Response { 417 $seoUrlsGridFactory = $this->get('prestashop.core.grid.factory.meta'); 418 419 $context = $this->get('prestashop.adapter.shop.context'); 420 421 $isShopContext = $context->isShopContext(); 422 $isShopFeatureActive = $this->get('prestashop.adapter.multistore_feature')->isActive(); 423 424 $isGridDisplayed = !($isShopFeatureActive && !$isShopContext); 425 426 $presentedGrid = null; 427 if ($isGridDisplayed) { 428 $grid = $seoUrlsGridFactory->getGrid($filters); 429 430 $gridPresenter = $this->get('prestashop.core.grid.presenter.grid_presenter'); 431 $presentedGrid = $gridPresenter->present($grid); 432 } 433 434 $tools = $this->get('prestashop.adapter.tools'); 435 $urlFileChecker = $this->get('prestashop.core.util.url.url_file_checker'); 436 $hostingInformation = $this->get('prestashop.adapter.hosting_information'); 437 $defaultRoutesProvider = $this->get('prestashop.adapter.data_provider.default_route'); 438 $helperBlockLinkProvider = $this->get('prestashop.core.util.helper_card.documentation_link_provider'); 439 $metaDataProvider = $this->get('prestashop.adapter.meta.data_provider'); 440 441 $showcaseCardIsClosed = $this->getQueryBus()->handle( 442 new GetShowcaseCardIsClosed((int) $this->getContext()->employee->id, ShowcaseCard::SEO_URLS_CARD) 443 ); 444 445 $doesMainShopUrlExist = $this->get('prestashop.adapter.shop.shop_url')->doesMainShopUrlExist(); 446 447 return $this->render( 448 '@PrestaShop/Admin/Configure/ShopParameters/TrafficSeo/Meta/index.html.twig', 449 [ 450 'layoutHeaderToolbarBtn' => [ 451 'add' => [ 452 'href' => $this->generateUrl('admin_metas_create'), 453 'desc' => $this->trans('Add a new page', 'Admin.Shopparameters.Feature'), 454 'icon' => 'add_circle_outline', 455 ], 456 ], 457 'grid' => $presentedGrid, 458 'setUpUrlsForm' => $setUpUrlsForm->createView(), 459 'shopUrlsForm' => $shopUrlsForm->createView(), 460 'urlSchemaForm' => $urlSchemaForm !== null ? $urlSchemaForm->createView() : null, 461 'seoOptionsForm' => $seoOptionsForm->createView(), 462 'robotsForm' => $this->createFormBuilder()->getForm()->createView(), 463 'routeKeywords' => $defaultRoutesProvider->getKeywords(), 464 'isGridDisplayed' => $isGridDisplayed, 465 'isModRewriteActive' => $tools->isModRewriteActive(), 466 'isShopContext' => $isShopContext, 467 'isHtaccessFileValid' => $urlFileChecker->isHtaccessFileWritable(), 468 'isRobotsTextFileValid' => $urlFileChecker->isRobotsFileWritable(), 469 'isShopFeatureActive' => $isShopFeatureActive, 470 'isHostMode' => $hostingInformation->isHostMode(), 471 'doesMainShopUrlExist' => $doesMainShopUrlExist, 472 'enableSidebar' => true, 473 'help_link' => $this->generateSidebarLink($request->attributes->get('_legacy_controller')), 474 'helperDocLink' => $helperBlockLinkProvider->getLink('meta'), 475 'indexPageId' => $metaDataProvider->getIdByPage('index'), 476 'metaShowcaseCardName' => ShowcaseCard::SEO_URLS_CARD, 477 'showcaseCardIsClosed' => $showcaseCardIsClosed, 478 ] 479 ); 480 } 481 482 /** 483 * Process the Meta configuration form. 484 * 485 * @param Request $request 486 * @param FormHandlerInterface $formHandler 487 * @param string $hookName 488 * 489 * @return FormInterface|RedirectResponse 490 */ 491 protected function processForm(Request $request, FormHandlerInterface $formHandler, string $hookName) 492 { 493 $this->dispatchHook( 494 'actionAdminShopParametersMetaControllerPostProcess' . $hookName . 'Before', 495 ['controller' => $this] 496 ); 497 498 $this->dispatchHook('actionAdminAdminShopParametersMetaControllerPostProcessBefore', ['controller' => $this]); 499 500 $form = $formHandler->getForm(); 501 $form->handleRequest($request); 502 503 if ($form->isSubmitted() && $form->isValid()) { 504 $data = $form->getData(); 505 $saveErrors = $formHandler->save($data); 506 507 if (0 === count($saveErrors)) { 508 $this->addFlash('success', $this->trans('Update successful', 'Admin.Notifications.Success')); 509 510 return $this->redirectToRoute('admin_metas_index'); 511 } else { 512 $this->flashErrors($saveErrors); 513 } 514 } 515 516 return $form; 517 } 518 519 /** 520 * Gets form builder. 521 * 522 * @return FormBuilderInterface 523 */ 524 private function getMetaFormBuilder() 525 { 526 return $this->get('prestashop.core.form.builder.meta_form_builder'); 527 } 528 529 /** 530 * @return Handler\FormHandlerInterface 531 */ 532 private function getMetaFormHandler() 533 { 534 return $this->get('prestashop.core.form.identifiable_object.meta_form_handler'); 535 } 536 537 /** 538 * Handles exception by its type and status code or by its type only and returns error message. 539 * 540 * @param Exception $exception 541 * 542 * @return string 543 * 544 * @todo use FrameworkAdminBundleController::getErrorMessageForException() instead 545 */ 546 private function handleException(Exception $exception) 547 { 548 if (0 !== $exception->getCode()) { 549 return $this->getExceptionByClassAndErrorCode($exception); 550 } 551 552 return $this->getExceptionByType($exception); 553 } 554 555 /** 556 * Gets exception by class and error code. 557 * 558 * @param Exception $exception 559 * 560 * @return string 561 */ 562 private function getExceptionByClassAndErrorCode(Exception $exception) 563 { 564 $exceptionDictionary = [ 565 MetaConstraintException::class => [ 566 MetaConstraintException::INVALID_URL_REWRITE => $this->trans( 567 'The %s field is not valid', 568 'Admin.Notifications.Error', 569 [ 570 sprintf( 571 '"%s"', 572 $this->trans('Rewritten URL', 'Admin.Shopparameters.Feature') 573 ), 574 ] 575 ), 576 MetaConstraintException::INVALID_PAGE_NAME => $this->trans( 577 'The %s field is required.', 578 'Admin.Notifications.Error', 579 [ 580 sprintf( 581 '"%s"', 582 $this->trans('Page name', 'Admin.Shopparameters.Feature') 583 ), 584 ] 585 ), 586 MetaConstraintException::INVALID_PAGE_TITLE => $this->trans( 587 'The %s field is not valid', 588 'Admin.Notifications.Error', 589 [ 590 sprintf( 591 '"%s"', 592 $this->trans('Page title', 'Admin.Shopparameters.Feature') 593 ), 594 ] 595 ), 596 MetaConstraintException::INVALID_META_DESCRIPTION => $this->trans( 597 'The %s field is not valid', 598 'Admin.Notifications.Error', 599 [ 600 sprintf( 601 '"%s"', 602 $this->trans('Meta description', 'Admin.Global') 603 ), 604 ] 605 ), 606 MetaConstraintException::INVALID_META_KEYWORDS => $this->trans( 607 'The %s field is not valid', 608 'Admin.Notifications.Error', 609 [ 610 sprintf( 611 '"%s"', 612 $this->trans('Meta keywords', 'Admin.Global') 613 ), 614 ] 615 ), 616 ], 617 ]; 618 619 $exceptionClass = get_class($exception); 620 $exceptionCode = $exception->getCode(); 621 if (isset($exceptionDictionary[$exceptionClass][$exceptionCode])) { 622 return $exceptionDictionary[$exceptionClass][$exceptionCode]; 623 } 624 625 return $this->getFallbackErrorMessage($exceptionClass, $exceptionCode); 626 } 627 628 /** 629 * Gets exception by class type. 630 * 631 * @param Exception $exception 632 * 633 * @return string 634 */ 635 private function getExceptionByType(Exception $exception) 636 { 637 $exceptionDictionary = [ 638 MetaNotFoundException::class => $this->trans( 639 'The object cannot be loaded (or found)', 640 'Admin.Notifications.Error' 641 ), 642 ]; 643 644 $exceptionClass = get_class($exception); 645 if (isset($exceptionDictionary[$exceptionClass])) { 646 return $exceptionDictionary[$exceptionClass]; 647 } 648 649 return $this->getFallbackErrorMessage($exceptionClass, $exception->getCode()); 650 } 651 652 /** 653 * @return FormHandlerInterface 654 */ 655 protected function getSetUpUrlsFormHandler(): FormHandlerInterface 656 { 657 return $this->get('prestashop.admin.meta_settings.set_up_urls.form_handler'); 658 } 659 660 /** 661 * @return FormHandlerInterface 662 */ 663 protected function getShopUrlsFormHandler(): FormHandlerInterface 664 { 665 return $this->get('prestashop.admin.meta_settings.shop_urls.form_handler'); 666 } 667 668 /** 669 * @return FormHandlerInterface 670 */ 671 protected function getUrlSchemaFormHandler(): FormHandlerInterface 672 { 673 return $this->get('prestashop.admin.meta_settings.url_schema.form_handler'); 674 } 675 676 /** 677 * @return FormHandlerInterface 678 */ 679 protected function getSeoOptionsFormHandler(): FormHandlerInterface 680 { 681 return $this->get('prestashop.admin.meta_settings.seo_options.form_handler'); 682 } 683} 684