<?php
/**
* Pimcore
*
* This source file is available under two different licenses:
* - GNU General Public License version 3 (GPLv3)
* - Pimcore Enterprise License (PEL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license http://www.pimcore.org/license GPLv3 and PEL
*/
namespace EcommerceShopBundle\Controller;
use EcommerceShopBundle\Model\Product\AbstractProduct;
use EcommerceShopBundle\Model\Product\ShopCategory;
use EcommerceShopBundle\Model\Product\ShopProduct;
use EcommerceShopBundle\Services\SegmentTrackingHelperService;
use EcommerceShopBundle\Website\LinkGenerator\ProductLinkGenerator;
use EcommerceShopBundle\Website\Navigation\BreadcrumbHelperService;
use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;
use Pimcore\Bundle\EcommerceFrameworkBundle\FilterService\Helper;
use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\ProductList\DefaultMysql;
use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\ProductList\ElasticSearch\AbstractElasticSearch;
use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\ProductList\ProductListInterface;
use Pimcore\Config;
use Pimcore\Model\DataObject\AbstractObject;
use Pimcore\Model\DataObject\Concrete;
use Pimcore\Model\DataObject\FilterDefinition;
use Pimcore\Templating\Helper\HeadTitle;
use Pimcore\Templating\Helper\Placeholder;
use Pimcore\Templating\Model\ViewModel;
use Pimcore\Translation\Translator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Zend\Paginator\Paginator;
use Pimcore\Localization;
use \Pimcore\Model\DataObject;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Pimcore\Model\Document;
use MembersBundle\Manager\RestrictionManager;
use MembersBundle\Security\RestrictionUri;
use Pimcore\Model\Asset;
class ProductController extends BaseController {
/**
* @param Request $request
* @param Factory $ecommerceFactory
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function indexAction(
Request $request,
SessionInterface $session,
Factory $ecommerceFactory
) {
$this->view->isShop = true;
// show price
$countryListing = new DataObject\ShopKonfiguration\Listing();
$showPrice = false;
foreach ($countryListing as $country) {
if (strtolower($country->getShortname()) == $session->get('country') || strtolower($country->getShortname()) == $request->get('country')) {
$showPrice = true;
}
}
$this->view->showPrice = $showPrice;
return $this->render('EcommerceShopBundle:index:index.html.twig', array_merge($this->view->getAllParameters()));
}
/**
* @Route("/shop/{path}{productname}~p{product}", name="shop-detail", defaults={"path"=""}, requirements={"path"=".*?", "productname"="[\w-]+", "product"="\d+"})
*
* @param Request $request
* @param HeadTitle $headTitleHelper
* @param BreadcrumbHelperService $breadcrumbHelperService
* @param Factory $ecommerceFactory
* @param SessionInterface $session
*
* @return \Symfony\Component\HttpFoundation\Response
*
* @throws \Exception
*/
public function detailAction(
Request $request,
HeadTitle $headTitleHelper,
BreadcrumbHelperService $breadcrumbHelperService,
SessionInterface $session,
Factory $ecommerceFactory,
RestrictionUri $restrictionUri,
\Pimcore\Config\Config $websiteConfig
) {
//Members RestrictionManager
if (!$this->editmode) {
$element = Document::getById($this->document->getId());
$restriction = $this->container->get(RestrictionManager::class)->getElementRestrictionStatus($element);
if ($restriction->getState() == 'members.restriction.logged_in') {
$isLoggedin = true;
} else {
$isLoggedin = false;
}
$this->view->isLoggedin = $isLoggedin;
$userRoles = [];
$user = $this->getUser();
if ($user) {
$userGroups = $user->getGroups()[0];
if ($userGroups) {
$userRoles = $user->getGroups()[0]->getRoles();
}
}
}
$this->view->user = $user;
$this->view->userRoles = $userRoles;
$this->view->isShop = true;
// show price
$countryListing = new DataObject\ShopKonfiguration\Listing();
$showPrice = false;
foreach ($countryListing as $country) {
if (strtolower($country->getShortname()) == $session->get('country') || strtolower($country->getShortname()) == $request->get('country')) {
$showPrice = true;
}
}
$this->view->showPrice = $showPrice;
$reveal = $request->get('reveal');
// clear or save country
if ($_REQUEST['country'] == 'null') {
$session->set("country", null);
} else if ($_REQUEST['country']) {
$session->set("country", $_REQUEST['country']);
}
// show or hide country popup
if ($session->get('country') !== null) {
$showCountryPopup = false;
} else {
$showCountryPopup = true;
}
$this->view->showCountryPopup = $showCountryPopup;
$countryNames = \Pimcore::getContainer()->get('pimcore.locale')->getDisplayRegions();
$arrCountries = [];
if ($countryNames) {
$i=0;
foreach ($countryNames as $key => $value) {
$i++;
$arrCountries[$i]['code'] = $key;
$arrCountries[$i]['name'] = $value;
}
}
$this->view->arrCountries = $arrCountries;
$product = Concrete::getById($request->get('product'));
if (!($product && ($product->isPublished() && ($product instanceof ShopProduct && $product->getObjectType() == ShopProduct::OBJECT_TYPE_ACTUAL_PRODUCT) || $this->verifyPreviewRequest($request, $product)))) {
throw new NotFoundHttpException('Product not found.');
}
$breadcrumbHelperService->enrichProductDetailPage($product);
$headTitleHelper($product->getOSName());
$paramBag = $this->view->getAllParameters();
$paramBag['product'] = $product;
$trackingManager = $ecommerceFactory->getTrackingManager();
$trackingManager->trackProductView($product);
// store current page for add-to-cart redirect
$currentUrl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
$session->set("add-to-cart-return", $currentUrl);
//$cleanCurrentUrl = strtok($currentUrl, '?');
//$paramBag['returnUrl'] = $cleanCurrentUrl;
$paramBag['isProductDetail'] = true;
$paramBag['isReveal'] = $reveal;
// filtered products
$filteredProducts = $session->get('filteredProducts');
$paramBag['filteredProducts'] = $filteredProducts;
// restricted asset
$key = substr($product->getSku(), strpos($product->getSku(), "-") + 1);
$operatingManualsFolder = $websiteConfig->get('operatingManualsFolder');
//$assetPath = $operatingManualsFolder . '/' . $key . '.pdf';
if ($product->getDownloadDoc()) {
$assetPathDownloadDoc = $operatingManualsFolder . '/' . $product->getDownloadDoc() . '.pdf';
$assetDownloadDoc = Asset::getByPath($assetPathDownloadDoc);
}
if ($product->getSku()) {
$assetPathIdent = $operatingManualsFolder . '/' . $key . '.pdf';
$assetIdent = Asset::getByPath($assetPathIdent);
}
if ($assetDownloadDoc || $assetIdent) {
$hasAsset = true;
} else {
$hasAsset = false;
}
// MembersBundle/Security
//$asset = Asset::getByPath($assetPath);
//$restrictedAsset = $restrictionUri->generateAssetUrl($asset, false, true);
//$restrictedAsset = $asset;
/* if ($asset) {
$hasAsset = true;
} else {
$hasAsset = false;
} */
// file icon
//$fileExtension = strtoupper(explode('.', substr(basename($asset), -5))[1]);
if ($assetDownloadDoc) {
$fileExtension = strtoupper(explode('.', substr(basename($assetDownloadDoc), -5))[1]);
} else if ($assetIdent) {
$fileExtension = strtoupper(explode('.', substr(basename($assetIdent), -5))[1]);
}
$this->view->hasAsset = $hasAsset;
//$this->view->restrictedAsset = $restrictedAsset;
$this->view->fileExtension = $fileExtension;
// download link
$downloadLink = $this->generateUrl('shop-download', ['productId' => base64_encode($product->getId())]);
$paramBag['hasAsset'] = $hasAsset;
//$paramBag['restrictedAsset'] = $restrictedAsset;
$paramBag['fileExtension'] = $fileExtension;
$paramBag['downloadLink'] = $downloadLink;
if ($product instanceof ShopProduct) {
return $this->render('EcommerceShopBundle:product:detail.html.twig', $paramBag);
}
}
/**
* @Route("/shop/{path}{categoryname}~c{category}", name="shop-category", defaults={"path"=""}, requirements={"path"=".*?", "categoryname"="[\w-]+", "category"="\d+"})
*
* @param Request $request
* @param HeadTitle $headTitleHelper
* @param BreadcrumbHelperService $breadcrumbHelperService
* @param Factory $ecommerceFactory
* @param SessionInterface $session
*
* @return array|\Symfony\Component\HttpFoundation\Response
*/
public function listingAction(
Request $request,
HeadTitle $headTitleHelper,
BreadcrumbHelperService $breadcrumbHelperService,
Factory $ecommerceFactory,
SessionInterface $session
) {
//Members RestrictionManager
if (!$this->editmode) {
$element = Document::getById($this->document->getId());
$restriction = $this->container->get(RestrictionManager::class)->getElementRestrictionStatus($element);
if ($restriction->getState() == 'members.restriction.logged_in') {
$isLoggedin = true;
} else {
$isLoggedin = false;
}
$this->view->isLoggedin = $isLoggedin;
$userRoles = [];
$user = $this->getUser();
if ($user) {
$userGroups = $user->getGroups()[0];
if ($userGroups) {
$userRoles = $user->getGroups()[0]->getRoles();
}
}
}
$this->view->user = $user;
$this->view->userRoles = $userRoles;
$this->view->isShop = true;
// ajax
$ajax = $request->get('ajax');
if ($ajax == 'true') {
$isAjax = true;
}
$viewModel = new ViewModel();
$params = array_merge($request->query->all(), $request->attributes->all());
// search text
$searchText = $request->get('title');
$viewModel->searchText = $searchText;
// needed to make sure category filter filters for active category
$params['parentCategoryIds'] = $params['category'] ?? null;
$category = ShopCategory::getById($params['category'] ?? null);
$viewModel->category = $category;
if ($category) {
$headTitleHelper($category->getName());
$breadcrumbHelperService->enrichCategoryPage($category);
}
$indexService = $ecommerceFactory->getIndexService();
$productListing = $indexService->getProductListForCurrentTenant();
$productListing->setOrder("ASC");
$productListing->setOrderKey('sku');
// search product title and sku
$term = strip_tags($request->get('title'));
$term = trim(preg_replace('/\s+/', ' ', $term));
if (!empty($term)) {
foreach (explode(' ', $term) as $t) {
$productListing->addQueryCondition($t);
}
}
$viewModel->productListing = $productListing;
// load current filter
if ($category) {
$filterDefinition = $category->getFilterdefinition();
$trackingManager = $ecommerceFactory->getTrackingManager();
$trackingManager->trackCategoryPageView($category->getName(), null);
}
if ($request->get('filterdefinition') instanceof FilterDefinition) {
$filterDefinition = $request->get('filterdefinition');
}
if (empty($filterDefinition)) {
$filterDefinition = Config::getWebsiteConfig()->get('fallbackFilterdefinition');
}
if (empty($filterDefinition)) {
echo 'Filter Definition fehlt';
die;
}
$filterService = $ecommerceFactory->getFilterService();
Helper::setupProductList($filterDefinition, $productListing, $params, $viewModel, $filterService, true);
$viewModel->filterService = $filterService;
$viewModel->filterDefinition = $filterDefinition;
// filtered products
$filteredProducts = [];
foreach ($productListing as $product) {
$filteredProducts[$product->getTitle()] = $product->getId();
}
$session->set("filteredProducts", $filteredProducts);
// pagination
$perPage = 12;
$paginator = new Paginator($productListing);
$paginator->setCurrentPageNumber($request->get('page'));
$paginator->setItemCountPerPage($perPage);
//$paginator->setPageRange(5);
$viewModel->results = $paginator;
$viewModel->paginationVariables = $paginator->getPages('Sliding');
// total
if ($productListing) {
$total = count($productListing);
}
$viewModel->total = $total;
$viewModel->perPage = $perPage;
$viewModel->isAjax = $isAjax;
// clear or save country
if ($_REQUEST['country'] == 'null') {
$session->set("country", null);
} else if ($_REQUEST['country']) {
$session->set("country", $_REQUEST['country']);
}
// show or hide country popup
if ($session->get('country') !== null) {
$showCountryPopup = false;
} else {
$showCountryPopup = true;
}
$viewModel->showCountryPopup = $showCountryPopup;
$countryNames = \Pimcore::getContainer()->get('pimcore.locale')->getDisplayRegions();
$arrCountries = [];
if ($countryNames) {
$i=0;
foreach ($countryNames as $key => $value) {
$i++;
$arrCountries[$i]['code'] = $key;
$arrCountries[$i]['name'] = $value;
}
}
$viewModel->arrCountries = $arrCountries;
// show price
$countryListing = new DataObject\ShopKonfiguration\Listing();
$showPrice = false;
foreach ($countryListing as $country) {
if (strtolower($country->getShortname()) == $session->get('country') || strtolower($country->getShortname()) == $request->get('country')) {
$showPrice = true;
}
}
$this->view->showPrice = $showPrice;
// store current page for add-to-cart redirect
$currentUrl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
//$session->set("add-to-cart-return", $currentUrl);
//$viewModel->returnUrl = $currentUrl;
if ($request->attributes->get('noLayout')) {
return $this->render('EcommerceShopBundle:product:listing_content.html.twig', array_merge($this->view->getAllParameters(), $viewModel->getAllParameters()));
}
return $viewModel->getAllParameters();
}
/**
* @param Request $request
* @param Factory $ecommerceFactory
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function productTeaserAction(
Request $request,
Factory $ecommerceFactory
) {
$paramsBag = [];
if ($request->get('type') == 'object') {
AbstractObject::setGetInheritedValues(true);
$product = AbstractProduct::getById($request->get('id'));
$paramsBag['product'] = $product;
// track product impression
$trackingManager = $ecommerceFactory->getTrackingManager();
$trackingManager->trackProductImpression($product, 'teaser');
return $this->render('EcommerceShopBundle:product:product_teaser.html.twig', $paramsBag);
}
throw new NotFoundHttpException('Product not found.');
}
/**
* @Route("/search", name="search")
*
* @param Request $request
* @param Factory $ecommerceFactory
* @param ProductLinkGenerator $productLinkGenerator
* @param Translator $translator
* @param BreadcrumbHelperService $breadcrumbHelperService
* @param HeadTitle $headTitleHelper
*
* @return array|\Symfony\Component\HttpFoundation\JsonResponse
*/
public function searchAction(
Request $request,
Factory $ecommerceFactory,
ProductLinkGenerator $productLinkGenerator,
Translator $translator,
BreadcrumbHelperService $breadcrumbHelperService,
HeadTitle $headTitleHelper
) {
$params = $request->query->all();
$viewModel = new ViewModel();
$this->view->isShop = true;
$viewModel->category = ShopCategory::getById($params['category'] ?? null);
$indexService = $ecommerceFactory->getIndexService();
$productListing = $indexService->getProductListForCurrentTenant();
$productListing->setVariantMode(ProductListInterface::VARIANT_MODE_VARIANTS_ONLY);
$term = strip_tags($request->get('term'));
if ($productListing instanceof AbstractElasticSearch) {
// simple elastic search query - uses multi-match query on all defined search_attributes
// $productListing->addQueryCondition($term);
// sample for a more specific elastic search query - not considers search_attributes but provides full flexibility
// this query weights cars more that accessries
$query = [
'function_score' => [
'query' => [
'multi_match' => [
"query" => $term,
"type" => "cross_fields",
"operator" => "and",
"fields" => [
"attributes.name^4",
"attributes.name.analyzed",
"attributes.name.analyzed_ngram",
"attributes.manufacturer_name^3",
"attributes.manufacturer_name.analyzed",
"attributes.manufacturer_name.analyzed_ngram",
"attributes.color",
"attributes.carClass"
]
]
],
'functions' => [
[
'filter' => ['match' => ['system.o_classId' => 'AP']],
'weight' => 1
],
[
'filter' => ['match' => ['system.o_classId' => 'CAR']],
'weight' => 2
]
],
'boost_mode' => 'multiply'
]
];
$productListing->addQueryCondition($query, 'searchTerm');
} else {
// default mysql search query condition - would also work for elastic search in that way
$term = trim(preg_replace('/\s+/', ' ', $term));
if (!empty($term)) {
foreach (explode(' ', $term) as $t) {
$productListing->addQueryCondition($t);
}
}
}
if ($params['autocomplete']) {
$resultset = [];
$productListing->setLimit(10);
foreach ($productListing as $product) {
$result['href'] = $productLinkGenerator->generateWithMockup($product, []);
$result['product'] = $product->getOSName();
$resultset[] = $result;
}
return $this->json($resultset);
}
$filterDefinition = $viewModel->filterDefinition = Config::getWebsiteConfig()->get('fallbackFilterdefinition');
// create and init filter service
$filterService = Factory::getInstance()->getFilterService();
Helper::setupProductList($filterDefinition, $productListing, $params, $viewModel, $filterService, true);
$viewModel->filterService = $filterService;
$viewModel->products = $productListing;
// init pagination
$paginator = new Paginator($productListing);
$paginator->setCurrentPageNumber($request->get('page'));
$paginator->setItemCountPerPage(18);
$paginator->setPageRange(5);
$viewModel->results = $paginator;
$viewModel->paginationVariables = $paginator->getPages('Sliding');
$trackingManager = $ecommerceFactory->getTrackingManager();
foreach ($paginator as $product) {
$trackingManager->trackProductImpression($product, 'search-results');
}
// breadcrumbs
/** @var Placeholder $placeholder */
$placeholder = $this->get('pimcore.templating.view_helper.placeholder');
$placeholder('addBreadcrumb')->append([
'parentId' => $this->document->getId(),
'id' => 'search-result',
'label' => $translator->trans('shop.search-result', [$term])
]);
$viewModel->language = $request->getLocale();
$viewModel->term = $term;
$breadcrumbHelperService->enrichGenericDynamicPage($translator->trans('shop.search-result', [$term]));
$headTitleHelper($translator->trans('shop.search-result', [$term]));
return $viewModel->getAllParameters();
}
}