Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
CssUrls.php
Go to the documentation of this file.
1 <?php
7 
17 
24 class CssUrls implements ProcessorInterface
25 {
31  private $staticDir;
32 
38  private $minification;
39 
45  private $options = [];
46 
53  public function __construct(Filesystem $filesystem, Minification $minification)
54  {
55  $this->staticDir = $filesystem->getDirectoryWrite(DirectoryList::STATIC_VIEW);
56  $this->minification = $minification;
57  }
58 
62  public function process(Package $package, array $options)
63  {
64  $this->options = $options;
65  if ($this->options[DeployStaticOptions::NO_CSS] === true) {
66  return false;
67  }
68  $urlMap = [];
70  foreach (array_keys($package->getMap()) as $fileId) {
71  $filePath = str_replace(\Magento\Framework\View\Asset\Repository::FILE_ID_SEPARATOR, '/', $fileId);
72  if (strtolower(pathinfo($fileId, PATHINFO_EXTENSION)) == 'css') {
73  $urlMap = $this->parseCss(
74  $urlMap,
75  $filePath,
76  $package->getPath(),
77  $this->staticDir->readFile(
78  $this->minification->addMinifiedSign($package->getPath() . '/' . $filePath)
79  ),
80  $package
81  );
82  }
83  }
84  $this->updateCssUrls($urlMap);
85  return true;
86  }
87 
99  private function parseCss(array $urlMap, $cssFilePath, $packagePath, $cssContent, Package $package)
100  {
101  $cssFilePath = $this->minification->addMinifiedSign($cssFilePath);
102 
103  $cssFileBasePath = pathinfo($cssFilePath, PATHINFO_DIRNAME);
104  $urls = $this->getCssUrls($cssContent);
105  foreach ($urls as $url) {
106  if ($this->isExternalUrl($url)) {
107  $urlMap[$url][] = [
108  'filePath' => $this->minification->addMinifiedSign($packagePath . '/' . $cssFilePath),
109  'replace' => $this->getValidExternalUrl($url, $package)
110  ];
111  continue;
112  }
113  $filePath = $this->getNormalizedFilePath($packagePath . '/' . $cssFileBasePath . '/' . $url);
114  if ($this->staticDir->isReadable($this->minification->addMinifiedSign($filePath))) {
115  continue;
116  }
117  $lookupFileId = $this->getNormalizedFilePath($cssFileBasePath . '/' . $url);
119  $matchedFile = $this->getFileFromParent($lookupFileId, $package);
120  if ($matchedFile) {
121  $urlMap[$url][] = [
122  'filePath' => $this->minification->addMinifiedSign($packagePath . '/' . $cssFilePath),
123  'replace' => '../../../../' // base path is always of four chunks size
124  . str_repeat('../', count(explode('/', $cssFileBasePath)))
125  . $this->minification->addMinifiedSign($matchedFile->getDeployedFilePath())
126  ];
127  }
128  }
129  return $urlMap;
130  }
131 
138  private function updateCssUrls(array $urlMap)
139  {
140  foreach ($urlMap as $ref => $targetFiles) {
141  foreach ($targetFiles as $matchedFileData) {
142  $filePath = $matchedFileData['filePath'];
143  $oldCss = $this->staticDir->readFile($filePath);
144  $newCss = str_replace($ref, $matchedFileData['replace'], $oldCss);
145  if ($oldCss !== $newCss) {
146  $this->staticDir->writeFile($filePath, $newCss);
147  }
148  }
149  }
150  }
151 
158  private function getCssUrls($cssContent)
159  {
160  $urls = [];
161  preg_match_all(CssResolver::REGEX_CSS_RELATIVE_URLS, $cssContent, $matches);
162  if (!empty($matches[0]) && !empty($matches[1])) {
163  $urls = array_combine($matches[0], $matches[1]);
164  }
165  return $urls;
166  }
167 
174  private function getNormalizedFilePath($url)
175  {
176  $urlParts = explode('/', $url);
177  $result = [];
178  if (preg_match('/{{.*}}/', $url)) {
179  foreach (array_reverse($urlParts) as $index => $part) {
180  if (!preg_match('/^{{.*}}$/', $part)) {
181  $result[] = $part;
182  } else {
183  break;
184  }
185  }
186  return implode('/', array_reverse($result));
187  }
188  $prevIndex = 0;
189  foreach ($urlParts as $index => $part) {
190  if ($part == '..') {
191  unset($urlParts[$index]);
192  unset($urlParts[$prevIndex]);
193  --$prevIndex;
194  } else {
195  $prevIndex = $index;
196  }
197  }
198  return implode('/', $urlParts);
199  }
200 
208  private function getValidExternalUrl($url, Package $package)
209  {
210  $url = $this->minification->removeMinifiedSign($url);
211  $filePath = $this->getNormalizedFilePath($url);
212  if (!$this->isFileExistsInPackage($filePath, $package)) {
214  $matchedFile = $this->getFileFromParent($filePath, $package);
215  $package = $matchedFile->getPackage();
216  }
217  return preg_replace(
218  '/(?<=}})(.*)(?=\/{{)/',
219  $package->getArea() . '/' . $package->getTheme(),
220  $this->minification->addMinifiedSign($url)
221  );
222  }
223 
231  private function getFileFromParent($fileName, Package $currentPackage)
232  {
234  foreach (array_reverse($currentPackage->getParentPackages()) as $package) {
235  foreach ($package->getFiles() as $file) {
236  if ($file->getDeployedFileName() === $fileName) {
237  return $file;
238  }
239  }
240  }
241  return null;
242  }
243 
250  private function isExternalUrl($url)
251  {
252  return preg_match('/{{.*}}/', $url);
253  }
254 
262  private function isFileExistsInPackage($filePath, Package $package)
263  {
265  foreach ($package->getFiles() as $file) {
266  if ($file->getDeployedFileName() === $filePath) {
267  return true;
268  }
269  }
270  return false;
271  }
272 }
Definition: CssUrls.php:6
$fileName
Definition: translate.phtml:15
__construct(Filesystem $filesystem, Minification $minification)
Definition: CssUrls.php:53
process(Package $package, array $options)
Definition: CssUrls.php:24
$filesystem
$index
Definition: list.phtml:44