| Current Path : /home/rtorresani/www/vendor/magento/module-deploy/Package/Processor/PreProcessor/ |
| Current File : //home/rtorresani/www/vendor/magento/module-deploy/Package/Processor/PreProcessor/Less.php |
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Deploy\Package\Processor\PreProcessor;
use Magento\Deploy\Console\DeployStaticOptions;
use Magento\Deploy\Package\Package;
use Magento\Deploy\Package\PackageFile;
use Magento\Deploy\Package\Processor\ProcessorInterface;
use Magento\Deploy\Service\DeployStaticFile;
use Magento\Framework\Css\PreProcessor\Instruction\Import;
use Magento\Framework\View\Asset\Minification;
use Magento\Framework\View\Asset\NotationResolver;
use Magento\Framework\View\Asset\PreProcessor\FileNameResolver;
use Magento\Framework\View\Asset\Repository;
/**
* Pre-processor for speeding up deployment of Less files
*
* LESS-to-CSS compilation should happen only when it is really needed. If in some package there is no LESS files
* overridden which used for generating some CSS file, then such CSS file can be copied from ancestor package as is
*/
class Less implements ProcessorInterface
{
/**
* Resolver allows to distinguish "root" LESS files from "imported" LESS files
*
* @var FileNameResolver
*/
private $fileNameResolver;
/**
* @var \Magento\Framework\View\Asset\NotationResolver\Module
*/
private $notationResolver;
/**
* @var DeployStaticFile
*/
private $deployStaticFile;
/**
* @var Minification
*/
private $minification;
/**
* Deployment procedure options
*
* @var array
*/
private $options = [];
/**
* @var array
*/
private $map = [];
/**
* @var array
*/
private $pFileCache = [];
/**
* Less constructor
*
* @param FileNameResolver $fileNameResolver
* @param NotationResolver\Module $notationResolver
* @param DeployStaticFile $deployStaticFile
* @param Minification $minification
*/
public function __construct(
FileNameResolver $fileNameResolver,
NotationResolver\Module $notationResolver,
DeployStaticFile $deployStaticFile,
Minification $minification
) {
$this->fileNameResolver = $fileNameResolver;
$this->notationResolver = $notationResolver;
$this->deployStaticFile = $deployStaticFile;
$this->minification = $minification;
}
/**
* @inheritdoc
*/
public function process(Package $package, array $options)
{
$this->options = $options;
if ($this->options[DeployStaticOptions::NO_CSS] === true) {
return false;
}
if ($package->getArea() !== Package::BASE_AREA && $package->getTheme() !== Package::BASE_THEME) {
$files = $package->getParentFiles('less');
foreach ($files as $file) {
$packageFile = $package->getFile($file->getFileId());
if ($packageFile && $packageFile->getOrigPackage() === $package) {
continue;
}
$deployFileName = $this->fileNameResolver->resolve($file->getFileName() ?? '');
if ($deployFileName !== $file->getFileName()) {
if ($this->hasOverrides($file, $package)) {
$file = clone $file;
$file->setArea($package->getArea());
$file->setTheme($package->getTheme());
$file->setLocale($package->getLocale());
$file->setPackage($package);
$package->addFileToMap($file);
}
}
}
}
return true;
}
/**
* Checks if there are LESS files in current package which used for generating given CSS file from parent package
*
* If true then such CSS file must be re-compiled for current package to use overridden LESS files
*
* @param PackageFile $parentFile
* @param Package $package
* @return bool
*/
private function hasOverrides(PackageFile $parentFile, Package $package)
{
$map = $this->buildMap(
$parentFile->getFilePath(),
$parentFile->getPackage()->getPath(),
$parentFile->getExtension()
);
/** @var PackageFile[] $currentPackageFiles */
$currentPackageFiles = array_merge($package->getFilesByType('less'), $package->getFilesByType('css'));
foreach ($currentPackageFiles as $file) {
$this->pFileCache = [];
if ($this->inParentFiles($file->getDeployedFileName(), $parentFile->getFileName(), $map)) {
return true;
}
}
return false;
}
/**
* Checks if there is a LESS file in current package which used for generating given CSS from parent package
*
* @param string $fileName
* @param string $parentFile
* @param array $map
* @return bool
*/
private function inParentFiles($fileName, $parentFile, $map)
{
if (isset($map[$parentFile])) {
if (in_array($fileName, $map[$parentFile])) {
return true;
} else {
foreach ($map[$parentFile] as $pFile) {
if (in_array($pFile, $this->pFileCache)) {
continue;
}
$this->pFileCache[] = $pFile;
if ($this->inParentFiles($fileName, $pFile, $map)) {
return true;
}
}
}
}
return false;
}
/**
* Build map of imported files
*
* @param string $filePath
* @param string $packagePath
* @param string $contentType
* @return array
*/
private function buildMap($filePath, $packagePath, $contentType)
{
$content = $this->deployStaticFile->readTmpFile($filePath, $packagePath);
$replaceCallback = function ($matchedContent) use ($filePath, $packagePath, $contentType) {
$matchedFileId = $matchedContent['path'] ?? '';
// phpcs:ignore Magento2.Functions.DiscouragedFunction
if (!pathinfo($matchedContent['path'], PATHINFO_EXTENSION)) {
$matchedFileId .= '.' . $contentType;
}
if (strpos($matchedFileId, Repository::FILE_ID_SEPARATOR) !== false) {
$basePath = $packagePath;
} else {
// phpcs:ignore Magento2.Functions.DiscouragedFunction
$basePath = pathinfo($filePath, PATHINFO_DIRNAME);
}
$resolvedPath = str_replace(Repository::FILE_ID_SEPARATOR, '/', $matchedFileId);
if (strpos($resolvedPath, '@{baseUrl}') === 0) {
$resolvedMapPath = str_replace('@{baseUrl}', '', $resolvedPath);
} else {
$resolvedMapPath = $this->normalizePath($basePath . '/' . $resolvedPath);
}
if (!isset($this->map[$filePath])) {
$this->map[$filePath] = [];
}
$this->map[$filePath][] = $resolvedMapPath;
$this->buildMap($resolvedMapPath, $packagePath, $contentType);
};
if ($content) {
preg_replace_callback(Import::REPLACE_PATTERN, $replaceCallback, $content);
}
return $this->map;
}
/**
* Return normalized path
*
* @param string $path
* @return string
*/
private function normalizePath($path)
{
if ($path === null || strpos($path, '/../') === false) {
return $path;
}
$pathParts = explode('/', $path);
$realPath = [];
foreach ($pathParts as $pathPart) {
if ($pathPart == '.') {
continue;
}
if ($pathPart == '..') {
array_pop($realPath);
continue;
}
$realPath[] = $pathPart;
}
return implode('/', $realPath);
}
}