Enquiry Now

In Shopware 6, the controller is responsible for handling incoming requests, and it’s the linchpin of Shopware 6 routing implementation.

When you are working on the custom modules in Shopware 6, it’s very crucial to override core module files instead of making changes to it right away. Overriding the controller in Shopware 6 provides the flexibility to change the core functionality according your Shopware 6 module development requirements.

By following the steps given below you can override the core controller of Shopware 6 easily.

Firstly,create a basic plugin in shopware using command:- ./bin/console plugin:create Emizentech

Then create a plugin controller at this location:-Emizentech/src/Storefront/Controller/ProductController.php
and this following code:

<?php declare(strict_types=1);

namespace Emizentech\Storefront\Controller;

use Shopware\Storefront\Controller\StorefrontController;
use Shopware\Core\Content\Product\Exception\ProductNotFoundException;
use Shopware\Core\Content\Product\SalesChannel\Review\AbstractProductReviewSaveRoute;
use Shopware\Core\Content\Seo\SeoUrlPlaceholderHandlerInterface;
use Shopware\Core\Framework\Routing\Annotation\RouteScope;
use Shopware\Core\Framework\Routing\Annotation\Since;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Storefront\Framework\Cache\Annotation\HttpCache;
use Shopware\Storefront\Framework\Routing\RequestTransformer;
use Shopware\Storefront\Page\Product\Configurator\ProductCombinationFinder;
use Shopware\Storefront\Page\Product\ProductPageLoader;
use Shopware\Storefront\Page\Product\QuickView\MinimalQuickViewPageLoader;
use Shopware\Storefront\Page\Product\Review\ProductReviewLoader;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener;
use Symfony\Component\Routing\Annotation\Route;

/**
 * @RouteScope(scopes={"storefront"})
 */
class ProductController extends StorefrontController
{
    /**
     * @var ProductPageLoader
     */
    private $productPageLoader;

    /**
     * @var ProductCombinationFinder
     */
    private $combinationFinder;

    /**
     * @var MinimalQuickViewPageLoader
     */
    private $minimalQuickViewPageLoader;

    /**
     * @var SeoUrlPlaceholderHandlerInterface
     */
    private $seoUrlPlaceholderHandler;

    /**
     * @var ProductReviewLoader
     */
    private $productReviewLoader;

    /**
     * @var SystemConfigService
     */
    private $systemConfigService;

    private AbstractProductReviewSaveRoute $productReviewSaveRoute;

    public function __construct(
        ProductPageLoader $productPageLoader,
        ProductCombinationFinder $combinationFinder,
        MinimalQuickViewPageLoader $minimalQuickViewPageLoader,
        AbstractProductReviewSaveRoute $productReviewSaveRoute,
        SeoUrlPlaceholderHandlerInterface $seoUrlPlaceholderHandler,
        ProductReviewLoader $productReviewLoader,
        SystemConfigService $systemConfigService
    ) {
        $this->productPageLoader = $productPageLoader;
        $this->combinationFinder = $combinationFinder;
        $this->minimalQuickViewPageLoader = $minimalQuickViewPageLoader;
        $this->seoUrlPlaceholderHandler = $seoUrlPlaceholderHandler;
        $this->productReviewLoader = $productReviewLoader;
        $this->systemConfigService = $systemConfigService;
        $this->productReviewSaveRoute = $productReviewSaveRoute;
    }

  /**
     * @Since("6.0.0.0")
     * @HttpCache()
     * @Route("/detail/{productId}/switch", name="frontend.detail.switch", methods={"GET"}, defaults={"XmlHttpRequest": true})
     */
    public function switch(string $productId, Request $request, SalesChannelContext $salesChannelContext): JsonResponse
    {
        $switchedOption = $request->query->get('switched');

        $options = $request->query->get('options');
        $newOptions = $options !== null ? json_decode($options, true) : [];

        try {
            $redirect = $this->combinationFinder->find($productId, $switchedOption, $newOptions, $salesChannelContext);

            $productId = $redirect->getVariantId();
        } catch (ProductNotFoundException $productNotFoundException) {
            //nth
        }

        $host = $request->attributes->get(RequestTransformer::SALES_CHANNEL_ABSOLUTE_BASE_URL)
            . $request->attributes->get(RequestTransformer::SALES_CHANNEL_BASE_URL);

        $url = $this->seoUrlPlaceholderHandler->replace(
            $this->seoUrlPlaceholderHandler->generate(
                'frontend.detail.page',
                ['productId' => $productId]
            ),
            $host,
            $salesChannelContext
        );

        $response = new JsonResponse(['url' => $url,'productId' => $productId]);
        $response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, '1');

        return $response;
    }
}

This class will override the vender Productcontroller class and method “switch” .

Next, we need to register our controller in the DI-container and make it public,
for doing that create a new file in your plugin at location:- Emizentech/src/Resources/config/services.xml
and add the following code :-

<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services" 
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

    <services>
        <service id="Emizentech\Storefront\Controller\ProductController" public="true">
            <argument type="service" id="Shopware\Storefront\Page\Product\ProductPageLoader"/>
            <argument type="service" id="Shopware\Storefront\Page\Product\Configurator\ProductCombinationFinder"/>
            <argument type="service" id="Shopware\Storefront\Page\Product\QuickView\MinimalQuickViewPageLoader"/>
            <argument type="service" id="Shopware\Core\Content\Product\SalesChannel\Review\ProductReviewSaveRoute"/>
            <argument type="service" id="Shopware\Core\Content\Seo\SeoUrlPlaceholderHandlerInterface"/>
            <argument type="service" id="Shopware\Storefront\Page\Product\Review\ProductReviewLoader"/>
            <argument type="service" id="Shopware\Core\System\SystemConfig\SystemConfigService" />
            <call method="setContainer">
                <argument type="service" id="service_container"/>
            </call>
        </service>
    </services>
</container>

Please also note the call tag, which is necessary in order to set the DI container to the controller.

Once we‘ve registered our new controller, we have to tell Shopware how we want it to search for new routes in our plugin. This is done with a routes.xml file at :Emizentech/src/Resources/config/ location and add the following code:-

<routes xmlns="http://symfony.com/schema/routing"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/routing
        https://symfony.com/schema/routing/routing-1.0.xsd">

    <import resource="../../Storefront/Controller/**/*ProductController.php" type="annotation" />
</routes>

That’s it now the switch method of product controller is overridden and also we can also make a new controller with this process

Get in Touch

Vivek Khatri
Author

Founder and tech lead at Emizentech, Mr. Vivek has years of experience in developing IT infrastructure and solutions. With profound knowledge of eCommerce technologies like Shopify, Shopware, and Magento, and a capable team delivering full-fledged eCommerce development services, Mr. Vivek has helped SMEs and enterprises worldwide. His deep knowledge of the eCommerce domain enables him to identify technology innovations and trends, which are also the focus of his blogs. To learn more about how Team Vivek can assist you with your eCommerce strategy, connect with us here.

whatsapp