Files

439 lines
13 KiB
PHP
Executable File

<?php
namespace Olegnax\Athlete2\Helper;
use Exception;
use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Framework\App\Helper\Context;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\App\State;
use Magento\Framework\Escaper;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\UrlInterface;
use Magento\Framework\View\Asset\Repository;
use Magento\Store\Model\ScopeInterface;
use Magento\Store\Model\StoreManagerInterface;
class LazyLoad extends AbstractHelper
{
const PLACEHOLDERE = 'athlete2/placeholder.png';
const PLACEHOLDER_TEMPLATE = '{dirname}/lazy-placeholders/{width}_{height}.{extension}';
const SVG_ENABLED = 'athlete2_settings/general/lazyload_svg';
const EXCLUDE = 'athlete2_settings/general/lazyload_exclude';
const RESIZED_PLACEHOLDER = 'athlete2_settings/general/lazyload_resized_placeholder';
const SIMPLE = 'athlete2_settings/general/lazyload_simple';
const PRELOADER_IMG = 'Olegnax_Core/images/preloader-img.svg';
protected $_lazyExcludeClass;
protected $isEnabled;
/**
* @var Helper
*/
protected $athleteHelper;
/**
* @var StoreManagerInterface
*/
protected $storeManager;
/**
* @var string
*/
protected $urlMedia;
/**
* @var Image
*/
protected $imageHelper;
/**
* @var false|string
*/
protected $placeholder;
/**
* @var string
*/
protected $placeholderDefault;
/**
* @var Escaper
*/
protected $escaper;
/**
* @var State
*/
protected $_appState;
/**
* LazyLoad constructor.
* @param Context $context
* @param Image $imageHelper
* @param StoreManagerInterface $storeManager
* @param Escaper $escaper
* @param Helper $helper
* @throws NoSuchEntityException
*/
public function __construct(
Context $context,
Image $imageHelper,
StoreManagerInterface $storeManager,
Escaper $escaper,
State $appState,
Helper $helper
) {
$this->athleteHelper = $helper;
$this->escaper = $escaper;
$this->imageHelper = $imageHelper;
$this->_appState = $appState;
$this->urlMedia = rtrim(preg_replace(
'@^http[s]*\:@i',
'',
$storeManager->getStore()->getBaseUrl(UrlInterface::URL_TYPE_MEDIA)
), "/");
parent::__construct($context);
}
/**
* @param string $html
* @return bool
*/
public function _filterImg($html = '')
{
if (preg_match('@(data-original=\"|data-ox-image)@i', $html)) {
return false;
}
$class = $this->getExcludeClass();
if (!empty($class) && preg_match('@class="([^"]+)"@i', $html, $matches)) {
$matches = array_filter(explode(' ', $matches[1]));
$intersect = array_intersect($class, $matches);
return empty($intersect);
}
return true;
}
/**
* @return array|mixed|string[]
*/
public function getExcludeClass()
{
if (empty($this->_lazyExcludeClass)) {
$class = $this->getConfig(static::EXCLUDE);
if (empty($class)) {
$class = ['rev-slidebg', 'lazy', 'owl-lazy', 'rs-lazyload'];
} elseif (preg_match_all('@\S+@', $class, $matches)) {
$class = array_filter($matches[0]);
$class[] = 'lazy';
$class[] = 'owl-lazy';
$class[] = 'rev-slidebg';
$class[] = 'rs-lazyload';
}
if (is_array($class) && !empty($class)) {
$this->_lazyExcludeClass = $class;
}
}
return $this->_lazyExcludeClass;
}
/**
* @param string $path
* @param string $storeCode
* @return mixed
*/
public function getConfig($path, $storeCode = null)
{
$value = $this->scopeConfig->getValue($path, ScopeInterface::SCOPE_STORE, $storeCode);
if (is_null($value)) {
$value = '';
}
return $value;
}
/**
* @param string $html
* @return string|string[]
*/
public function replaceImageToLazy($html = '')
{
if ($this->isEnabled() && preg_match_all('@<img[^<>]+src\="[^<>]+>@ims', $html, $matches)) {
$matches = array_filter($matches[0], [$this, '_filterImg']);
if (!empty($matches) && is_array($matches)) {
$_matches = [];
$resizedPlaceholder = '1' == $this->getConfig(static::RESIZED_PLACEHOLDER);
$simple = '1' == $this->getConfig(static::SIMPLE);
foreach ($matches as $htmlImg) {
$_matches[$htmlImg] = $this->modifyImg($htmlImg, $simple, $resizedPlaceholder);
}
if (!empty($_matches)) {
$search = array_keys($_matches);
$replace = array_values($_matches);
$html = str_replace($search, $replace, $html);
}
}
}
return $html;
}
/**
* @return bool
*/
public function isEnabled()
{
if (is_null($this->isEnabled)) {
$this->isEnabled = $this->athleteHelper->isLazyLoadEnabled();
}
return $this->isEnabled;
}
/**
* @param string $html
* @param bool $simple
* @param bool $resizedPlaceholder
* @return string
*/
protected function modifyImg($html, $simple = false, $resizedPlaceholder = false)
{
$encoded = false !== strpos((string)$html, '\"');
if ($encoded) {
$html = json_decode('"' . $html . '"');
}
if (!$simple) {
$placeholder = $this->getDefaultPlaceHolder();
if ($resizedPlaceholder) {
$size = [];
if (preg_match('@width="(\d+)"@im', $html, $matches)) {
$size[] = (int)$matches[1];
}
if (preg_match('@height="(\d+)"@im', $html, $matches)) {
$size[] = (int)$matches[1];
}
$size = array_filter($size);
if (2 != count($size) && preg_match('@src="([^"]+)"@im', $html, $matches)) {
$size = $this->getSizeImageFromUrl($matches[1]);
}
if (2 == count($size)) {
if ($this->isSvg()) {
$placeholder = $this->createPlaceholder($size);
} else {
try {
$image = $this->getPlaceholderHelper()->adaptiveResize($size)->getUrl();
$placeholder = $image;
} catch (Exception $e) {
if ( State::MODE_DEVELOPER == $this->_appState->getMode()) {
$this->_logger->error($e->getMessage());
}
}
}
if (!preg_match('@ height="@i', $html)) {
$html = preg_replace('@(src="[^\"]+")@im', '$1 height="' . $size[1] . '"', $html);
}
if (!preg_match('@ width="@i', $html)) {
$html = preg_replace('@(src="[^\"]+")@im', '$1 width="' . $size[0] . '"', $html);
}
}
}
$html = preg_replace('@src="([^\"]+)"@im', 'src="' . $placeholder . '" data-original="$1"', $html);
$html = preg_replace('@class=""@i', '', $html);
if (preg_match('@class="@i', $html)) {
$html = preg_replace('@class="([^\"]+)"@im', 'class="$1 lazy"', $html);
} else {
$html = preg_replace('@<img@im', '$0 class="lazy"', $html);
}
$pattern = '@\sloading\s*=\s*"lazy"@i';
if ( preg_match( $pattern, $html ) ) {
$html = preg_replace( $pattern, '', $html );
}
}
// if (!preg_match('@\sloading\s*=\s*"lazy"@i', $html) && !preg_match('@src="data@i', $html)) {
// $html = preg_replace('@<img@im', '$0 loading="lazy"', $html);
// }
$html = preg_replace('@ {2,}@', ' ', preg_replace('@[\r\n\t]+@', ' ', $html));
if ($encoded) {
$html = trim((string)json_encode($html), '"');
}
return $html;
}
/**
* @return string
*/
public function getDefaultPlaceHolder()
{
if ($this->isSvg()) {
$this->placeholderDefault = $this->createPlaceholder();
}
if (empty($this->placeholderDefault)) {
$this->placeholderDefault = $this->getViewFileUrl(static::PRELOADER_IMG);
}
return $this->placeholderDefault;
}
/**
* @return bool
*/
public function isSvg()
{
return (bool)$this->athleteHelper->getSystemValue(static::SVG_ENABLED);
}
/**
* @param int[] $size
* @return string
*/
public function createPlaceholder($size = [1, 1])
{
$html = 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ' . $size[0] . ' ' .
$size[1] . '" width="' . $size[0] . '" height="' . $size[1] . '"></svg>';
return $this->escaper->escapeHtmlAttr($html);
}
/**
* Retrieve url of a view file
*
* @param string $fileId
* @param array $params
* @return string
*/
public function getViewFileUrl($fileId, array $params = [])
{
try {
$params = array_merge(['_secure' => $this->_loadObject(RequestInterface::class)->isSecure()], $params);
return $this->_loadObject(Repository::class)->getUrlWithParams($fileId, $params);
} catch (LocalizedException $e) {
return $this->_getNotFoundUrl();
}
}
/**
* @param string $object
* @return mixed
*/
protected function _loadObject($object)
{
return ObjectManager::getInstance()->get($object);
}
/**
* Get 404 file not found url
*
* @param string $route
* @param array $params
* @return string
*/
protected function _getNotFoundUrl($route = '', $params = ['_direct' => 'core/index/notFound'])
{
return $this->getUrl($route, $params);
}
/**
* Generate url by route and parameters
*
* @param string $route
* @param array $params
* @return string
*/
public function getUrl($route = '', $params = [])
{
return $this->_loadObject(UrlInterface::class)->getUrl($route, $params);
}
/**
* @param string $path
* @return array|int[]
*/
protected function getSizeImageFromUrl($path)
{
if (!empty($path)) {
return $this->getSizeImage($this->getAbsoluteImagePath($path));
}
return [];
}
/**
* @param $path
* @return array|null
*/
protected function getSizeImage($path)
{
try {
$image = $this->imageHelper->init($path);
if (!$image->getOriginalWidth() || !$image->getOriginalHeight()) {
throw new Exception(__('Image not found: ' . $path));
}
return [$image->getOriginalWidth(), $image->getOriginalHeight()];
} catch (Exception $e) {
if ( State::MODE_DEVELOPER == $this->_appState->getMode()) {
$this->_logger->warning('Athlete Lazy Loader: The file does not exist or not accessible, skipping. Response: ' . $e->getMessage());
}
return [];
}
return [];
}
/**
* @param string $url
* @return string|string[]|null
*/
protected function getAbsoluteImagePath($url)
{
$url = (string)preg_replace(
'@^http[s]*\:@i',
'',
$url
);
if (false === strpos($url, $this->urlMedia)) {
$path = preg_replace('@^\/media@i', '', $url);
} else {
$path = str_replace($this->urlMedia, '', $url);
}
return $path;
}
/**
* @return Image
* @throws Exception
*/
protected function getPlaceholderHelper()
{
return $this->imageHelper->init(
static::PLACEHOLDERE,
[
'fileTemplate' => static::PLACEHOLDER_TEMPLATE,
'quality' => 1,
]
);
}
/**
* @param string $url
* @return string
*/
public function getPlaceHolder($url)
{
$size = $this->getSizeImageFromUrl($url);
if (!empty($size)) {
if ($this->isSvg()) {
return $this->createPlaceholder($size);
} else {
try {
$image = $this->getPlaceholderHelper()->adaptiveResize($size)->getUrl();
return $image;
} catch (Exception $e) {
if ( State::MODE_DEVELOPER == $this->_appState->getMode()) {
$this->_logger->error($e->getMessage());
}
}
}
}
return $this->getDefaultPlaceHolder();
}
}