First, we create a controller in our custom plugin:
There are two ways to use repository in controller:
- 1. Using container of current controller
- 2. By sending the repository from services.xml file.
/custom/plugins/PluginName/src/Controller
<?php declare(strict_types=1);
namespace PluginName\Controller;
use Shopware\Core\Content\Cms\Exception\PageNotFoundException;
use Shopware\Core\Content\Cms\SalesChannel\SalesChannelCmsPageLoaderInterface;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\Routing\Annotation\RouteScope;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Storefront\Controller\StorefrontController;
use Shopware\Storefront\Framework\Cache\Annotation\HttpCache;
use Shopware\Storefront\Page\Navigation\NavigationPage;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
/**
* @RouteScope(scopes={"storefront"})
*/
class ProductController extends StorefrontController
{
private $productCategoryRepository;
/**
* @var EntityRepositoryInterface
*/
private $productRepository;
public function __construct(EntityRepositoryInterface $productRepository)
{
$this->productRepository= $productRepository;
}
/**
* @HttpCache()
* @Route("/products", name="frontend.products.detail", methods={"GET"})
*/
public function detailAction(Request $request, SalesChannelContext $context, Context $con): Response
{
$criteria1 = new Criteria();
$criteria1->addAssociations(['media', 'properties', 'properties.group', 'unit', 'tax']);
// using reference of repository sent from services.xml
$products = $this->productRepository->search($criteria1, $con)->getEntities();
$productIds;
foreach($products as $key => $p){
foreach($p as $k => $pr){
$productIds[] = $pr;
}
}
// using current class reference controller
$this->productPriceRepository = $this->container->get('product_price.repository');
$criteria2 = new Criteria();
$productPrice = $this->productPriceRepository->search($criteria2, $con);
return $this->renderStorefront('@Storefront/storefront/page/content/index.html.twig', [
'products' => $products,
'productPrice' => $productPrice,
]);
}
}
Then you need to create routes.xml file:
/custom/plugins/PluginName/src/Resources/config/routes.xml
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/routing
http://symfony.com/schema/routing/routing-1.0.xsd">
<import resource="../../Controller" type="annotation" />
</routes>
Then Next you need to create services.xml
/custom/plugins/PluginName/src/Resources/config/services.xml
<?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="PluginName\Controller\ProductController" public="true">
<argument type="service" id="product.repository"/>
<call method="setContainer">
<argument type="service" id="service_container"/>
</call>
</service>
</services>
</container>
Here I am creating two pages to show the product data on html.twig file
custom/plugins/PluginName/src/Resources/views/storefront/page/content/index.html.twig
{% sw_extends '@Storefront/storefront/page/content/index.html.twig' %}
{% block base_main_inner %}
<div class="container-main">
{% block page_content %}
{% block cms_content %}
<div class="cms-page">
{% block page_content_blocks %}
{% sw_include "@Storefront/storefront/page/content/product_detail.html.twig" %}
{% endblock %}
</div>
{% endblock %}
{% endblock %}
</div>
{% endblock %}
custom/plugins/PluginName/src/Resources/views/storefront/page/content/product_detail.html.twig
This code will show the Product detail on the page I have only 3 products you can show more products according to your need:
<div class="cms-block product-listing-part pos-1 cms-block-product-three-column section-products" style="">
<div class="cms-block-container" style="padding: 20px 20px 20px 20px;">
<div class="cms-block-container-row row cms-row ">
{% set i = 0 %}
{% for product in products %}
{% if i <= 2 %}
{% set i = (i+1) %}
<div class="col-md-4 card-col" data-cms-element-id="d3c7873569b844239e5756f6a89c1f7f">
<div class="cms-element-product-box">
<div class="card product-box box-minimal">
<div class="card-body">
<div class="product-badges"></div>
<meta itemprop="brand" content="">
<meta itemprop="mpn" content="SW10011">
<div class="product-image-wrapper">
<a href="{{ seoUrl('frontend.detail.page', {'productId': product.id}) }}" title="AIX Rosé Copy" class="product-image-link is-standard" "="">
{% for element in product.media.elements %}
{% if element.id == product.coverId %}
<img src="{{element.media.url}}" class="product-image is-standard" alt="{{product.translated.name}}" title="{{product.translated.name}}">
{%endif%}
{% endfor %}
</a>
</div>
<div class="product-info">
<span class="product-subtext">
{% set comma = null %}{% for element in product.properties.elements %}{{(comma ~ ' ' ~ element.translated.name)|trim|trans}}{% set comma=','%}{% endfor %}
</span>
<a href="{{ seoUrl('frontend.detail.page', {'productId': product.id}) }}" class="product-name" title="{{product.translated.name}}">{{product.translated.name}}</a>
<div class="product-price-info">
<div class="product-price-wrapper">
<span class="product-price">
{% set listPrice = 0 %}
{% for element in product.cheapestPrice.price.elements %}
{% if element.listPrice != null %}
{{element.listPrice.net|currency}}{{ "general.star"|trans|sw_sanitize }}
{% set listPrice = element.listPrice.net %}
{%endif%}
{% endfor %}
</span>
</div>
<br>
<p class="product-price-unit">
<span class="price-unit-content">
{{product.purchaseUnit}} {{product.unit.translated.name}}
{# for element in product.cheapestPriceContainer.value #}
{#element.default.purchase_unit#}
{# endfor #}
</span>
<span class="price-unit-reference">
{% set pricePerUnit = (((listPrice/product.purchaseUnit)*product.referenceUnit)|number_format(2))*1 %}
({{pricePerUnit|currency }} {{ "general.star"|trans|sw_sanitize }} / {{product.referenceUnit}} {{product.unit.translated.name}})
</span>
<br>
{% set taxText = "general.grossTaxInformation"|trans|sw_sanitize %}
{% if taxText == null or taxText == ''%}
{% set taxText = "general.netTaxInformation"|trans|sw_sanitize %}
{% endif %}
<span class="product-detail-tax">
{{taxText}}
</span>
</p>
</div>
<input type="hidden" name="product-name" value="{{product.translated.name}}">
<input type="hidden" name="product-id" value="{{product.id}}">
</div>
</div>
</div>
</div>
</div>
{% endif %}
{% endfor %}
</div>
</div>
</div>
emizentech