Files

271 lines
7.8 KiB
PHP
Executable File

<?php
/**
* @author Olegnax
* @package Olegnax_InfiniteScroll
* @copyright Copyright (c) 2019 Olegnax (http://olegnax.com/). All rights reserved.
* See COPYING.txt for license details.
*/
namespace Olegnax\InfiniteScroll\Plugin;
use Amasty\Label\Plugin\Catalog\Product\ListProduct;
use Exception;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\App\Request\Http;
use Magento\Framework\Controller\Result\RawFactory;
use Magento\Framework\DataObject\IdentityInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Registry;
use Magento\Framework\Serialize\Serializer\Json;
use Magento\Framework\Url\DecoderInterface;
use Magento\Framework\Url\Helper\Data as UrlHelper;
use Magento\Framework\View\LayoutInterface;
use Magento\PageCache\Model\Cache\Type;
use Olegnax\InfiniteScroll\Helper\Helper;
/**
* Description of Ajax
*
* @author Master
*/
class Ajax
{
const AJAX_ATTR = 'scrollAjax';
const BLOCK_PRODUCTS = 'category.products.list';
const BLOCK_PRODUCTS_SEARCH = 'search_result_list';
const REGEX_URLS = '@aHR0c(Dov|HM6)[A-Za-z0-9_-]+@u';
/**
* @var Helper
*/
protected $helper;
/**
* @var RawFactory
*/
protected $resultRaw;
/**
* @var Http
*/
protected $request;
/**
* @var Json
*/
protected $json;
/**
* @var DecoderInterface
*/
protected $urlDecoder;
/**
* @var UrlHelper
*/
protected $urlHelper;
/**
* @var LayoutInterface
*/
protected $layout;
/**
* @var Registry
*/
protected $registry;
/**
* Ajax constructor.
* @param Helper $helper
* @param RawFactory $resultRaw
* @param Http $request
* @param UrlHelper $urlHelper
* @param DecoderInterface $urlDecoder
* @param LayoutInterface $layout
* @param Registry $registry
* @param Json $json
*/
public function __construct(
Helper $helper,
RawFactory $resultRaw,
Http $request,
UrlHelper $urlHelper,
DecoderInterface $urlDecoder,
LayoutInterface $layout,
Registry $registry,
Json $json
) {
$this->helper = $helper;
$this->resultRaw = $resultRaw;
$this->request = $request;
$this->urlHelper = $urlHelper;
$this->urlDecoder = $urlDecoder;
$this->layout = $layout;
$this->registry = $registry;
$this->json = $json;
}
/**
* @param string $html
* @return string
*/
public function removeArgs($html)
{
$html = str_replace(['?' . static::AJAX_ATTR . '=1&amp;', '?' . static::AJAX_ATTR . '=1&'], '?', $html);
$html = str_replace([
'?' . static::AJAX_ATTR . '=1',
'&amp;' . static::AJAX_ATTR . '=1',
'&' . static::AJAX_ATTR . '=1',
], '', $html);
return $html;
}
public function removeEncodedArgsItem($match)
{
$code_string = $match[0];
$url = $this->urlDecoder->decode($code_string);
if (false !== $url) {
$newUrl = $this->urlHelper->removeRequestParam($url, static::AJAX_ATTR);
$newUrl = $this->removeEncodedArgs($newUrl);
if ($url != $newUrl) {
$code_string = $this->urlHelper->getEncodedUrl($newUrl);
}
}
return $code_string;
}
/**
* @param string $html
* @return string
*/
public function removeEncodedArgs($html)
{
$_html = preg_replace_callback(static::REGEX_URLS, [$this, 'removeEncodedArgsItem'], $html);
if ($_html) {
$html = $_html;
}
return $html;
}
/**
* @return bool
*/
protected function isAjax()
{
return $this->helper->isEnabled() &&
$this->request->isXmlHttpRequest() &&
$this->request->isAjax() &&
$this->request->getParam(static::AJAX_ATTR, '');
}
protected function getAjaxContent()
{
/** @var LayoutInterface $layout */
$layout = $this->layout;
$layout->getOutput(); // @todo temporary fix: magenta ignoring the product limit parameter per page, per page with ajax request
$blocks = $this->getLayoutBlock($layout);
$page = (int)$this->request->getParam('p', 1);
$firstNum = 0;
$lastNum = 0;
$productsCount = 0;
$isFirst = false;
$isLast = false;
if ($blocks['products']) {
$collection = $blocks['products']->getLoadedProductCollection();
$pageSize = $collection->getPageSize() * 1;
$firstNum = $pageSize * ($page - 1) + 1;
$lastNum = $pageSize * ($page - 1) + $collection->count();
$productsCount = $collection->getSize();
$isFirst = $firstNum <= 1;
$isLast = $lastNum >= $productsCount;
}
$html = [];
$cache_tags = [];
foreach ($blocks as $key => $block) {
$cache_tags = $this->addIdentities($block, $cache_tags);
$html[$key] = $block ? $block->toHtml() : '';
}
$response = compact('productsCount', 'page', 'pageSize', 'firstNum', 'lastNum', 'isFirst', 'isLast', 'html');
$response['html']['_before'] = '';
$response['html']['_after'] = '';
try {
$response = $this->prepareForPlugins($response, $blocks);
} catch ( Exception $exception){
// @todo do nothing or log
}
$response = $this->changeResponse($response, $cache_tags, $page);
return $response;
}
/**
* @param LayoutInterface $layout
* @return array
*/
protected function getLayoutBlock($layout)
{
return [
'products' => $layout->getBlock(self::BLOCK_PRODUCTS) ?: $layout->getBlock(self::BLOCK_PRODUCTS_SEARCH),
];
}
protected function addIdentities($block, array $data = [])
{
if ($block instanceof IdentityInterface) {
$data = array_merge($data, $block->getIdentities());
}
return $data;
}
/**
* @param array $response
* @param array $blocks
* @return array
* @throws LocalizedException
*/
protected function prepareForPlugins(array $response, array $blocks)
{
if (array_key_exists('products', $blocks) && class_exists('\Amasty\Label\Plugin\Catalog\Product\ListProduct')) {
/** @var ListProduct $amastyLabelListProduct */
$amastyLabelListProduct = ObjectManager::getInstance()->get('\Amasty\Label\Plugin\Catalog\Product\ListProduct');
$this->registry->register('amlabel_category_observer', false);
$blocks['products']->setIsAmLabelObserved(false);
$response['html']['_after'] .= $amastyLabelListProduct->afterToHtml($blocks['products'], '');
}
return $response;
}
protected function changeResponse($response, $cache_tags)
{
$cache_tags[] = Type::CACHE_TAG;
$cache_tags = array_unique($cache_tags);
$cache_tags = implode(',', $cache_tags);
$response['cache_tags'] = $cache_tags;
$response['html'] = array_map([$this, 'removeArgs'], $response['html']);
$response['html'] = array_map([$this, 'removeEncodedArgs'], $response['html']);
return $response;
}
protected function json(array $data)
{
$response = $this->resultRaw->create();
$response->setHeader('Content-type', 'application/json');
if (array_key_exists('cache_tags', $data)) {
if (!empty($data['cache_tags'])) {
$response->setHeader('X-Magento-Tags', $data['cache_tags']);
}
unset($data['cache_tags']);
}
$data = $this->json->serialize($data);
$response->setContents($data);
return $response;
}
}