Last Updated on January 30, 2023

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

Avatar photo
Author

Founder and tech lead at Emizentech, Mr. Vivek has over ten years of experience in developing IT infrastructures and solutions. With his profound knowledge in eCommerce technologies like Shopware, Magento, and Shopify, Mr. Vivek has been assisting SMEs to enterprises across the globe by developing and maintaining their eCommerce applications. Technology innovation and trends insight come easy to Vivek with his thorough knowledge in the eCommerce domain. See him talking about ideas, trends, and technology in this blog. To know more about how Team Vivek can assist you in your eCommerce strategy? Connect team Vivek here.

whatsapp