Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
ViewFileReferenceTest.php
Go to the documentation of this file.
1 <?php
21 namespace Magento\Test\Integrity;
22 
24 
28 class ViewFileReferenceTest extends \PHPUnit\Framework\TestCase
29 {
33  protected static $_fallbackRule;
34 
38  protected static $_viewFilesFallback;
39 
43  protected static $_filesFallback;
44 
48  protected static $_checkThemeLocales = [];
49 
53  protected static $_themeCollection;
54 
58  protected static $_componentRegistrar;
59 
60  public static function setUpBeforeClass()
61  {
63  $objectManager->configure(
64  ['preferences' => [\Magento\Theme\Model\Theme::class => \Magento\Theme\Model\Theme\Data::class]]
65  );
66 
67  self::$_componentRegistrar = $objectManager->get(\Magento\Framework\Component\ComponentRegistrar::class);
68 
70  $fallbackPool = $objectManager->get(\Magento\Framework\View\Design\Fallback\RulePool::class);
71  self::$_fallbackRule = $fallbackPool->getRule(
72  $fallbackPool::TYPE_STATIC_FILE
73  );
74 
75  self::$_viewFilesFallback = $objectManager->get(
76  \Magento\Framework\View\Design\FileResolution\Fallback\StaticFile::class
77  );
78  self::$_filesFallback = $objectManager->get(\Magento\Framework\View\Design\FileResolution\Fallback\File::class);
79 
80  // Themes to be checked
81  self::$_themeCollection = $objectManager->get(\Magento\Theme\Model\Theme\Collection::class);
82 
83  // Compose list of locales, needed to be checked for themes
84  self::$_checkThemeLocales = [];
85  foreach (self::$_themeCollection as $theme) {
86  $themeLocales = self::_getThemeLocales($theme);
87  $themeLocales[] = null;
88  // Default non-localized file will need to be checked as well
89  self::$_checkThemeLocales[$theme->getFullPath()] = $themeLocales;
90  }
91  }
92 
99  protected static function _getThemeLocales(\Magento\Framework\View\Design\ThemeInterface $theme)
100  {
101  $result = [];
102  $patternDir = self::_getLocalePatternDir($theme);
103  foreach (\ResourceBundle::getLocales('') as $locale) {
104  $dir = str_replace('<locale_placeholder>', $locale, $patternDir);
105  if (is_dir($dir)) {
106  $result[] = $locale;
107  }
108  }
109  return $result;
110  }
111 
119  protected static function _getLocalePatternDir(\Magento\Framework\View\Design\ThemeInterface $theme)
120  {
121  $localePlaceholder = '<locale_placeholder>';
122  $params = ['area' => $theme->getArea(), 'theme' => $theme, 'locale' => $localePlaceholder];
123  $patternDirs = self::$_fallbackRule->getPatternDirs($params);
124  $themePath = self::$_componentRegistrar->getPath(
125  \Magento\Framework\Component\ComponentRegistrar::THEME,
126  $theme->getFullPath()
127  );
128  foreach ($patternDirs as $patternDir) {
129  $patternPath = $patternDir . '/';
130  if ((strpos($patternPath, $themePath) !== false) // It is theme's directory
131  && (strpos($patternPath, $localePlaceholder) !== false) // It is localized directory
132  ) {
133  return $patternDir;
134  }
135  }
136  throw new \Exception('Unable to determine theme locale path');
137  }
138 
145  public function testModularFallback($modularCall, array $usages, $area)
146  {
147  list(, $file) = explode(\Magento\Framework\View\Asset\Repository::FILE_ID_SEPARATOR, $modularCall);
148 
149  $wrongResolutions = [];
150  foreach (self::$_themeCollection as $theme) {
151  if ($area && $theme->getArea() != $area) {
152  continue;
153  }
154 
155  $found = $this->_getFileResolutions($theme, $file);
156  $wrongResolutions = array_merge($wrongResolutions, $found);
157  }
158 
159  if ($wrongResolutions) {
160  // If file is found, then old functionality (find modular files in non-modular locations) is used
161  $message = sprintf(
162  "Found modular call:\n %s in\n %s\n which may resolve to non-modular location(s):\n %s",
163  $modularCall,
164  implode(', ', $usages),
165  implode(', ', $wrongResolutions)
166  );
167  $this->fail($message);
168  }
169  }
170 
178  protected function _getFileResolutions(\Magento\Framework\View\Design\ThemeInterface $theme, $file)
179  {
180  $found = [];
181  $fileResolved = self::$_filesFallback->getFile($theme->getArea(), $theme, $file);
182  if (file_exists($fileResolved)) {
183  $found[$fileResolved] = $fileResolved;
184  }
185 
186  foreach (self::$_checkThemeLocales[$theme->getFullPath()] as $locale) {
187  $fileResolved = self::$_viewFilesFallback->getFile($theme->getArea(), $theme, $locale, $file);
188  if (file_exists($fileResolved)) {
189  $found[$fileResolved] = $fileResolved;
190  }
191  }
192  return $found;
193  }
194 
198  public static function modularFallbackDataProvider()
199  {
200  $result = [];
201  foreach (self::_getFilesToProcess() as $file) {
202  $file = (string)$file;
203 
204  $modulePattern = '[A-Z][a-z]+_[A-Z][a-z]+';
205  $filePattern = '[[:alnum:]_/-]+\\.[[:alnum:]_./-]+';
206  $pattern = '#' . $modulePattern
207  . preg_quote(\Magento\Framework\View\Asset\Repository::FILE_ID_SEPARATOR)
208  . $filePattern . '#S';
209  if (!preg_match_all($pattern, file_get_contents($file), $matches)) {
210  continue;
211  }
212 
213  $area = self::_getArea($file);
214 
215  foreach ($matches[0] as $modularCall) {
216  $dataSetKey = $modularCall . ' @ ' . ($area ?: 'any area');
217 
218  if (!isset($result[$dataSetKey])) {
219  $result[$dataSetKey] = ['modularCall' => $modularCall, 'usages' => [], 'area' => $area];
220  }
221  $result[$dataSetKey]['usages'][$file] = $file;
222  }
223  }
224  return $result;
225  }
226 
232  protected static function _getFilesToProcess()
233  {
234  $result = [];
235  $componentRegistrar = new \Magento\Framework\Component\ComponentRegistrar();
236  $dirs = array_merge(
239  );
240  foreach ($dirs as $dir) {
241  $iterator = new \RecursiveIteratorIterator(
242  new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS)
243  );
244  $result = array_merge($result, iterator_to_array($iterator));
245  }
246 
247  return $result;
248  }
249 
258  protected static function _getArea($file)
259  {
260  $file = str_replace('\\', '/', $file);
261  $areaPatterns = [];
262  $componentRegistrar = new ComponentRegistrar();
263  foreach ($componentRegistrar->getPaths(ComponentRegistrar::THEME) as $themeDir) {
264  $areaPatterns[] = '#' . $themeDir . '/([^/]+)/#S';
265  }
266  foreach ($componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleDir) {
267  $areaPatterns[] = '#' . $moduleDir . '/view/([^/]+)/#S';
268  }
269  foreach ($areaPatterns as $pattern) {
270  if (preg_match($pattern, $file, $matches)) {
271  return $matches[1];
272  }
273  }
274  return null;
275  }
276 }
$componentRegistrar
Definition: bootstrap.php:23
$objectManager
Definition: bootstrap.php:17
$pattern
Definition: website.php:22
$message
$theme
$params[\Magento\Store\Model\StoreManager::PARAM_RUN_CODE]
Definition: website.php:18