Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Files.php
Go to the documentation of this file.
1 <?php
7 
14 
21 class Files
22 {
26  const INCLUDE_APP_CODE = 1;
27 
31  const INCLUDE_TESTS = 2;
32 
36  const INCLUDE_DEV_TOOLS = 4;
37 
41  const INCLUDE_TEMPLATES = 8;
42 
46  const INCLUDE_LIBS = 16;
47 
51  const INCLUDE_PUB_CODE = 32;
52 
56  const INCLUDE_NON_CLASSES = 64;
57 
61  const INCLUDE_SETUP = 128;
62 
66  const AS_DATA_SET = 1024;
67 
72 
76  protected static $_instance = null;
77 
81  protected static $_cache = [];
82 
86  private $dirSearch;
87 
91  private $themePackageList;
92 
96  private $serializer;
97 
101  private $regexIteratorFactory;
102 
112  public function __construct(
114  DirSearch $dirSearch,
115  ThemePackageList $themePackageList,
116  Json $serializer = null,
117  RegexIteratorFactory $regexIteratorFactory = null
118  ) {
119  $this->componentRegistrar = $componentRegistrar;
120  $this->dirSearch = $dirSearch;
121  $this->themePackageList = $themePackageList;
122  $this->serializer = $serializer ?: ObjectManager::getInstance()
123  ->get(Json::class);
124  $this->regexIteratorFactory = $regexIteratorFactory ?: ObjectManager::getInstance()
125  ->get(RegexIteratorFactory::class);
126  }
127 
136  public static function setInstance(Files $instance = null)
137  {
138  self::$_instance = $instance;
139  }
140 
147  public static function init()
148  {
149  if (!self::$_instance) {
150  throw new \Exception('Instance is not set yet.');
151  }
152  return self::$_instance;
153  }
154 
161  public static function composeDataSets(array $files)
162  {
163  $result = [];
164  foreach ($files as $file) {
165  $key = str_replace(BP . '/', '', $file);
166  $result[$key] = [$file];
167  }
168  return $result;
169  }
170 
176  private function getModuleTestDirsRegex()
177  {
178  $moduleTestDirs = [];
179  foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleDir) {
180  $moduleTestDirs[] = str_replace('\\', '/', '#' . $moduleDir . '/Test#');
181  }
182  return $moduleTestDirs;
183  }
184 
190  public function getPathToSource()
191  {
192  return BP;
193  }
194 
201  public function getPhpFiles($flags = 0)
202  {
203  // Sets default value
204  if ($flags === 0) {
205  $flags = self::INCLUDE_APP_CODE
206  | self::INCLUDE_TESTS
207  | self::INCLUDE_DEV_TOOLS
208  | self::INCLUDE_LIBS
210  }
211  $key = __METHOD__ . BP . $flags;
212  if (!isset(self::$_cache[$key])) {
213  $files = array_merge(
214  $this->getAppCodeFiles($flags),
215  $this->getTestFiles($flags),
216  $this->getDevToolsFiles($flags),
217  $this->getTemplateFiles($flags),
218  $this->getLibraryFiles($flags),
219  $this->getPubFiles($flags),
220  $this->getSetupPhpFiles($flags)
221  );
222  self::$_cache[$key] = $files;
223  }
224  if ($flags & self::AS_DATA_SET) {
225  return self::composeDataSets(self::$_cache[$key]);
226  }
227  return self::$_cache[$key];
228  }
229 
236  private function getTemplateFiles($flags)
237  {
238  if ($flags & self::INCLUDE_TEMPLATES) {
239  return $this->getPhtmlFiles(false, false);
240  }
241  return [];
242  }
243 
250  private function getLibraryFiles($flags)
251  {
252  if ($flags & self::INCLUDE_LIBS) {
253  $libraryExcludeDirs = [];
254  foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::LIBRARY) as $libraryDir) {
255  $libraryExcludeDirs[] = str_replace('\\', '/', '#' . $libraryDir . '/Test#');
256  $libraryExcludeDirs[] = str_replace('\\', '/', '#' . $libraryDir) . '/[\\w]+/Test#';
257  if (!($flags & self::INCLUDE_NON_CLASSES)) {
258  $libraryExcludeDirs[] = str_replace('\\', '/', '#' . $libraryDir . '/registration#');
259  }
260  }
261  return $this->getFilesSubset(
262  $this->componentRegistrar->getPaths(ComponentRegistrar::LIBRARY),
263  '*.php',
264  $libraryExcludeDirs
265  );
266  }
267  return [];
268  }
269 
276  private function getPubFiles($flags)
277  {
278  if ($flags & self::INCLUDE_PUB_CODE) {
279  return array_merge(
280  Glob::glob(BP . '/*.php', Glob::GLOB_NOSORT),
281  Glob::glob(BP . '/pub/*.php', Glob::GLOB_NOSORT)
282  );
283  }
284  return [];
285  }
286 
293  private function getDevToolsFiles($flags)
294  {
295  if ($flags & self::INCLUDE_DEV_TOOLS) {
296  return $this->getFilesSubset([BP . '/dev/tools/Magento'], '*.php', []);
297  }
298  return [];
299  }
300 
307  private function getAppCodeFiles($flags)
308  {
309  if ($flags & self::INCLUDE_APP_CODE) {
310  $excludePaths = [];
311  $paths = $this->componentRegistrar->getPaths(ComponentRegistrar::MODULE);
312  if ($flags & self::INCLUDE_NON_CLASSES) {
313  $paths[] = BP . '/app';
314  } else {
315  foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleDir) {
316  $excludePaths[] = str_replace('\\', '/', '#' . $moduleDir . '/registration.php#');
317  $excludePaths[] = str_replace('\\', '/', '#' . $moduleDir . '/cli_commands.php#');
318  }
319  }
320  return $this->getFilesSubset(
321  $paths,
322  '*.php',
323  array_merge($this->getModuleTestDirsRegex(), $excludePaths)
324  );
325  }
326  return [];
327  }
328 
335  private function getTestFiles($flags)
336  {
337  if ($flags & self::INCLUDE_TESTS) {
338  $testDirs = [
339  BP . '/dev/tests',
340  BP . '/setup/src/Magento/Setup/Test',
341  ];
342  $moduleTestDir = [];
343  foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleDir) {
344  $moduleTestDir[] = $moduleDir . '/Test';
345  }
346  $libraryTestDirs = [];
347  foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::LIBRARY) as $libraryDir) {
348  $libraryTestDirs[] = $libraryDir . '/Test';
349  $libraryTestDirs[] = $libraryDir . '/*/Test';
350  }
351  $testDirs = array_merge($testDirs, $moduleTestDir, $libraryTestDirs);
352  return self::getFiles($testDirs, '*.php');
353  }
354  return [];
355  }
356 
362  public function getXmlFiles()
363  {
364  return array_merge(
365  $this->getMainConfigFiles(),
366  $this->getLayoutFiles(),
367  $this->getPageLayoutFiles(),
368  $this->getConfigFiles(),
369  $this->getDiConfigs(true),
370  $this->getLayoutConfigFiles(),
371  $this->getPageTypeFiles()
372  );
373  }
374 
381  public function getMainConfigFiles($asDataSet = true)
382  {
383  $cacheKey = __METHOD__ . '|' . implode('|', [$asDataSet]);
384  if (!isset(self::$_cache[$cacheKey])) {
385  $configXmlPaths = [];
386  foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleDir) {
387  $configXmlPaths[] = $moduleDir . '/etc/config.xml';
388  // Module DB-specific configs, e.g. config.mysql4.xml
389  $configXmlPaths[] = $moduleDir . '/etc/config.*.xml';
390  }
391  $globPaths = [BP . '/app/etc/config.xml', BP . '/app/etc/*/config.xml'];
392  $configXmlPaths = array_merge($globPaths, $configXmlPaths);
393  $files = [];
394  foreach ($configXmlPaths as $xmlPath) {
395  $files = array_merge($files, glob($xmlPath, GLOB_NOSORT));
396  }
397  self::$_cache[$cacheKey] = $files;
398  }
399  if ($asDataSet) {
400  return self::composeDataSets(self::$_cache[$cacheKey]);
401  }
402  return self::$_cache[$cacheKey];
403  }
404 
414  public function getConfigFiles(
415  $fileNamePattern = '*.xml',
416  $excludedFileNames = ['wsdl.xml', 'wsdl2.xml', 'wsi.xml'],
417  $asDataSet = true
418  ) {
419  $cacheKey = __METHOD__ . '|' . $this->serializer->serialize([$fileNamePattern, $excludedFileNames, $asDataSet]);
420  if (!isset(self::$_cache[$cacheKey])) {
421  $files = $this->dirSearch->collectFiles(ComponentRegistrar::MODULE, "/etc/{$fileNamePattern}");
422  $files = array_filter(
423  $files,
424  function ($file) use ($excludedFileNames) {
425  return !in_array(basename($file), $excludedFileNames);
426  }
427  );
428  self::$_cache[$cacheKey] = $files;
429  }
430  if ($asDataSet) {
431  return self::composeDataSets(self::$_cache[$cacheKey]);
432  }
433  return self::$_cache[$cacheKey];
434  }
435 
436  // @codingStandardsIgnoreEnd
437 
446  public function getXmlCatalogFiles(
447  $fileNamePattern = '*.xsd',
448  $excludedFileNames = [],
449  $asDataSet = true
450  ) {
451  $cacheKey = __METHOD__ . '|' . $this->serializer->serialize([$fileNamePattern, $excludedFileNames, $asDataSet]);
452  if (!isset(self::$_cache[$cacheKey])) {
453  $files = $this->getFilesSubset(
454  $this->componentRegistrar->getPaths(ComponentRegistrar::MODULE),
455  $fileNamePattern,
456  []
457  );
458  $libraryExcludeDirs = [];
459  foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::LIBRARY) as $libraryDir) {
460  $libraryExcludeDirs[] = str_replace('\\', '/', '#' . $libraryDir . '/Test#');
461  $libraryExcludeDirs[] = str_replace('\\', '/', '#' . $libraryDir) . '/[\\w]+/Test#';
462  }
463  $files = array_merge(
464  $files,
465  $this->getFilesSubset(
466  $this->componentRegistrar->getPaths(ComponentRegistrar::LIBRARY),
467  $fileNamePattern,
468  $libraryExcludeDirs
469  )
470  );
471  $files = array_merge(
472  $files,
473  $this->getFilesSubset(
474  $this->componentRegistrar->getPaths(ComponentRegistrar::THEME),
475  $fileNamePattern,
476  []
477  )
478  );
479  $files = array_merge(
480  $files,
481  $this->getFilesSubset(
482  $this->componentRegistrar->getPaths(ComponentRegistrar::SETUP),
483  $fileNamePattern,
484  []
485  )
486  );
487  $files = array_filter(
488  $files,
489  function ($file) use ($excludedFileNames) {
490  return !in_array(basename($file), $excludedFileNames);
491  }
492  );
493  self::$_cache[$cacheKey] = $files;
494  }
495  if ($asDataSet) {
496  return self::composeDataSets(self::$_cache[$cacheKey]);
497  }
498  return self::$_cache[$cacheKey];
499  }
500 
508  public function getLayoutConfigFiles($fileNamePattern = '*.xml', $asDataSet = true)
509  {
510  $cacheKey = __METHOD__ . '|' . implode('|', [$fileNamePattern, $asDataSet]);
511  if (!isset(self::$_cache[$cacheKey])) {
512  self::$_cache[$cacheKey] = $this->dirSearch->collectFiles(
514  "/etc/{$fileNamePattern}"
515  );
516  }
517  if ($asDataSet) {
518  return self::composeDataSets(self::$_cache[$cacheKey]);
519  }
520  return self::$_cache[$cacheKey];
521  }
522 
541  public function getLayoutFiles($incomingParams = [], $asDataSet = true)
542  {
543  return $this->getLayoutXmlFiles('layout', $incomingParams, $asDataSet);
544  }
545 
564  public function getPageLayoutFiles($incomingParams = [], $asDataSet = true)
565  {
566  return $this->getLayoutXmlFiles('page_layout', $incomingParams, $asDataSet);
567  }
568 
587  public function getUiComponentXmlFiles($incomingParams = [], $asDataSet = true)
588  {
589  return $this->getLayoutXmlFiles('ui_component', $incomingParams, $asDataSet);
590  }
591 
598  protected function getLayoutXmlFiles($location, $incomingParams = [], $asDataSet = true)
599  {
600  $params = [
601  'namespace' => '*',
602  'module' => '*',
603  'area' => '*',
604  'theme_path' => '*/*',
605  'include_code' => true,
606  'include_design' => true,
607  'with_metainfo' => false
608  ];
609  foreach (array_keys($params) as $key) {
610  if (isset($incomingParams[$key])) {
611  $params[$key] = $incomingParams[$key];
612  }
613  }
614  $cacheKey = md5($location . '|' . implode('|', $params));
615 
616  if (!isset(self::$_cache[__METHOD__][$cacheKey])) {
617  $files = [];
618  if ($params['include_code']) {
619  $files = array_merge($files, $this->collectModuleLayoutFiles($params, $location));
620  }
621  if ($params['include_design']) {
622  $files = array_merge($files, $this->collectThemeLayoutFiles($params, $location));
623  }
624 
625  self::$_cache[__METHOD__][$cacheKey] = $files;
626  }
627 
628  if ($asDataSet) {
629  return self::composeDataSets(self::$_cache[__METHOD__][$cacheKey]);
630  }
631  return self::$_cache[__METHOD__][$cacheKey];
632  }
633 
641  private function collectModuleLayoutFiles(array $params, $location)
642  {
643  $files = [];
644  $area = $params['area'];
645  $requiredModuleName = $params['namespace'] . '_' . $params['module'];
646  foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleName => $moduleDir) {
647  if ($requiredModuleName == '*_*' || $moduleName == $requiredModuleName) {
648  $moduleFiles = [];
650  [$moduleDir . "/view/{$area}/{$location}"],
651  '*.xml',
652  $moduleFiles
653  );
654  if ($params['with_metainfo']) {
655  foreach ($moduleFiles as $moduleFile) {
656  $modulePath = str_replace(DIRECTORY_SEPARATOR, '/', preg_quote($moduleDir, '#'));
657  $regex = '#^' . $modulePath . '/view/(?P<area>[a-z]+)/layout/(?P<path>.+)$#i';
658  if (preg_match($regex, $moduleFile, $matches)) {
659  $files[] = [
660  $matches['area'],
661  '',
662  $moduleName,
663  $matches['path'],
664  $moduleFile,
665  ];
666  } else {
667  throw new \UnexpectedValueException("Could not parse modular layout file '$moduleFile'");
668  }
669  }
670  } else {
671  $files = array_merge($files, $moduleFiles);
672  }
673  }
674  }
675  return $files;
676  }
677 
685  private function collectThemeLayoutFiles(array $params, $location)
686  {
687  $files = [];
688  $area = $params['area'];
689  $requiredModuleName = $params['namespace'] . '_' . $params['module'];
690  $themePath = $params['theme_path'];
691  foreach ($this->themePackageList->getThemes() as $theme) {
692  $currentThemePath = str_replace(DIRECTORY_SEPARATOR, '/', $theme->getPath());
693  $currentThemeCode = $theme->getVendor() . '/' . $theme->getName();
694  if (($area == '*' || $theme->getArea() === $area)
695  && ($themePath == '*' || $themePath == '*/*' || $themePath == $currentThemeCode)
696  ) {
697  $themeFiles = [];
699  [$currentThemePath . "/{$requiredModuleName}/{$location}"],
700  '*.xml',
701  $themeFiles
702  );
703 
704  if ($params['with_metainfo']) {
705  $files = array_merge($this->parseThemeFiles($themeFiles, $currentThemePath, $theme));
706  } else {
707  $files = array_merge($files, $themeFiles);
708  }
709  }
710  }
711  return $files;
712  }
713 
720  private function parseThemeFiles($themeFiles, $currentThemePath, $theme)
721  {
722  $files = [];
723  $regex = '#^' . $currentThemePath
724  . '/(?P<module>[a-z\d]+_[a-z\d]+)/layout/(override/((base/)|(theme/[a-z\d_]+/[a-z\d_]+/)))?'
725  . '(?P<path>.+)$#i';
726  foreach ($themeFiles as $themeFile) {
727  if (preg_match($regex, $themeFile, $matches)) {
728  $files[] = [
729  $theme->getArea(),
730  $theme->getVendor() . '/' . $theme->getName(),
731  $matches['module'],
732  $matches['path'],
733  $themeFile,
734  ];
735  } else {
736  throw new \UnexpectedValueException("Could not parse theme layout file '$themeFile'");
737  }
738  }
739  return $files;
740  }
741 
757  public function getPageTypeFiles($incomingParams = [], $asDataSet = true)
758  {
759  $params = ['namespace' => '*', 'module' => '*', 'area' => '*'];
760  foreach (array_keys($params) as $key) {
761  if (isset($incomingParams[$key])) {
762  $params[$key] = $incomingParams[$key];
763  }
764  }
765  $cacheKey = md5(implode('|', $params));
766 
767  if (!isset(self::$_cache[__METHOD__][$cacheKey])) {
768  self::$_cache[__METHOD__][$cacheKey] = self::getFiles(
769  $this->getEtcAreaPaths($params['namespace'], $params['module'], $params['area']),
770  'page_types.xml'
771  );
772  }
773 
774  if ($asDataSet) {
775  return self::composeDataSets(self::$_cache[__METHOD__][$cacheKey]);
776  }
777  return self::$_cache[__METHOD__][$cacheKey];
778  }
779 
788  private function getEtcAreaPaths($namespace, $module, $area)
789  {
790  $etcAreaPaths = [];
791  foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleName => $moduleDir) {
792  $keyInfo = explode('_', $moduleName);
793  if ($keyInfo[0] == $namespace || $namespace == '*') {
794  if ($keyInfo[1] == $module || $module == '*') {
795  $etcAreaPaths[] = $moduleDir . "/etc/{$area}";
796  }
797  }
798  }
799  return $etcAreaPaths;
800  }
801 
811  public function getJsFiles($area = '*', $themePath = '*/*', $namespace = '*', $module = '*')
812  {
813  $key = $area . $themePath . $namespace . $module . __METHOD__ . BP;
814  if (isset(self::$_cache[$key])) {
815  return self::$_cache[$key];
816  }
817  $moduleWebPaths = [];
818  foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleName => $moduleDir) {
819  $keyInfo = explode('_', $moduleName);
820  if ($keyInfo[0] == $namespace || $namespace == '*') {
821  if ($keyInfo[1] == $module || $module == '*') {
822  $moduleWebPaths[] = $moduleDir . "/view/{$area}/web";
823  }
824  }
825  }
826  $themePaths = $this->getThemePaths($area, $namespace . '_' . $module, '/web');
828  array_merge(
829  [
830  BP . "/lib/web/{mage,varien}"
831  ],
832  $themePaths,
833  $moduleWebPaths
834  ),
835  '*.js'
836  );
838  self::$_cache[$key] = $result;
839  return $result;
840  }
841 
848  private function getThemePaths($area, $module, $subFolder)
849  {
850  $themePaths = [];
851  foreach ($this->themePackageList->getThemes() as $theme) {
852  if ($area == '*' || $theme->getArea() === $area) {
853  $themePaths[] = $theme->getPath() . $subFolder;
854  $themePaths[] = $theme->getPath() . "/{$module}" . $subFolder;
855  }
856  }
857  return $themePaths;
858  }
859 
869  public function getStaticHtmlFiles($area = '*', $themePath = '*/*', $namespace = '*', $module = '*')
870  {
871  $key = $area . $themePath . $namespace . $module . __METHOD__;
872  if (isset(self::$_cache[$key])) {
873  return self::$_cache[$key];
874  }
875  $moduleTemplatePaths = [];
876  foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleName => $moduleDir) {
877  $keyInfo = explode('_', $moduleName);
878  if ($keyInfo[0] == $namespace || $namespace == '*') {
879  if ($keyInfo[1] == $module || $module == '*') {
880  $moduleTemplatePaths[] = $moduleDir . "/view/{$area}/web/template";
881  $moduleTemplatePaths[] = $moduleDir . "/view/{$area}/web/templates";
882  }
883  }
884  }
885  $themePaths = $this->getThemePaths($area, $namespace . '_' . $module, '/web/template');
887  array_merge(
888  $themePaths,
889  $moduleTemplatePaths
890  ),
891  '*.html'
892  );
894  self::$_cache[$key] = $result;
895  return $result;
896  }
897 
904  public function getStaticPreProcessingFiles($filePattern = '*')
905  {
906  $key = __METHOD__ . '|' . $filePattern;
907  if (isset(self::$_cache[$key])) {
908  return self::$_cache[$key];
909  }
910  $area = '*';
911  $locale = '*';
912  $result = [];
913  $moduleWebPath = [];
914  $moduleLocalePath = [];
915  foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleDir) {
916  $moduleWebPath[] = $moduleDir . "/view/{$area}/web";
917  $moduleLocalePath[] = $moduleDir . "/view/{$area}/web/i18n/{$locale}";
918  }
919 
920  $this->_accumulateFilesByPatterns($moduleWebPath, $filePattern, $result, '_parseModuleStatic');
921  $this->_accumulateFilesByPatterns($moduleLocalePath, $filePattern, $result, '_parseModuleLocaleStatic');
922  $this->accumulateThemeStaticFiles($area, $locale, $filePattern, $result);
923  self::$_cache[$key] = $result;
924  return $result;
925  }
926 
936  private function accumulateThemeStaticFiles($area, $locale, $filePattern, &$result)
937  {
938  foreach ($this->themePackageList->getThemes() as $themePackage) {
939  $themeArea = $themePackage->getArea();
940  if ($area == '*' || $area == $themeArea) {
941  $files = [];
942  $themePath = str_replace(DIRECTORY_SEPARATOR, '/', $themePackage->getPath());
943  $paths = [
944  $themePath . "/web",
945  $themePath . "/*_*/web",
946  $themePath . "/web/i18n/{$locale}",
947  $themePath . "/*_*/web/i18n/{$locale}"
948  ];
949  $this->_accumulateFilesByPatterns($paths, $filePattern, $files);
950  $regex = '#^' . $themePath .
951  '/((?P<module>[a-z\d]+_[a-z\d]+)/)?web/(i18n/(?P<locale>[a-z_]+)/)?(?P<path>.+)$#i';
952  foreach ($files as $file) {
953  if (preg_match($regex, $file, $matches)) {
954  $result[] = [
955  $themeArea,
956  $themePackage->getVendor() . '/' . $themePackage->getName(),
957  $matches['locale'],
958  $matches['module'],
959  $matches['path'],
960  $file,
961  ];
962  } else {
963  throw new \UnexpectedValueException("Could not parse theme static file '$file'");
964  }
965  }
966 
967  if (!$files) {
968  $result[] = [
969  $themeArea,
970  $themePackage->getVendor() . '/' . $themePackage->getName(),
971  null,
972  null,
973  null,
974  null
975  ];
976  }
977  }
978  }
979  }
980 
986  public function getStaticLibraryFiles()
987  {
988  $result = [];
989  $this->_accumulateFilesByPatterns([BP . "/lib/web"], '*', $result, '_parseLibStatic');
990  return $result;
991  }
992 
1000  protected function _parseLibStatic($file, $path)
1001  {
1002  preg_match('/^' . preg_quote("{$path}/lib/web/", '/') . '(.+)$/i', $file, $matches);
1003  return $matches[1];
1004  }
1005 
1015  protected function _accumulateFilesByPatterns(array $patterns, $filePattern, array &$result, $subroutine = false)
1016  {
1017  $path = str_replace(DIRECTORY_SEPARATOR, '/', BP);
1018  foreach (self::getFiles($patterns, $filePattern) as $file) {
1019  $file = str_replace(DIRECTORY_SEPARATOR, '/', $file);
1020  if ($subroutine) {
1021  $result[] = $this->$subroutine($file, $path);
1022  } else {
1023  $result[] = $file;
1024  }
1025  }
1026  }
1027 
1034  protected function _parseModuleStatic($file)
1035  {
1036  foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleName => $modulePath) {
1037  if (preg_match(
1038  '/^' . preg_quote("{$modulePath}/", '/') . 'view\/([a-z]+)\/web\/(.+)$/i',
1039  $file,
1040  $matches
1041  ) === 1
1042  ) {
1043  list(, $area, $filePath) = $matches;
1044  return [$area, '', '', $moduleName, $filePath, $file];
1045  }
1046  }
1047  return [];
1048  }
1049 
1056  protected function _parseModuleLocaleStatic($file)
1057  {
1058  foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleName => $modulePath) {
1059  $appCode = preg_quote("{$modulePath}/", '/');
1060  if (preg_match('/^' . $appCode . 'view\/([a-z]+)\/web\/i18n\/([a-z_]+)\/(.+)$/i', $file, $matches) === 1) {
1061  list(, $area, $locale, $filePath) = $matches;
1062  return [$area, '', $locale, $moduleName, $filePath, $file];
1063  }
1064  }
1065  return [];
1066  }
1067 
1074  public function getJsFilesForArea($area)
1075  {
1076  $key = __METHOD__ . BP . $area;
1077  if (isset(self::$_cache[$key])) {
1078  return self::$_cache[$key];
1079  }
1080  $viewAreaPaths = [];
1081  foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleDir) {
1082  $viewAreaPaths[] = $moduleDir . "/view/{$area}";
1083  }
1084  $themePaths = [];
1085  foreach ($this->themePackageList->getThemes() as $theme) {
1086  if ($area == '*' || $theme->getArea() === $area) {
1087  $themePaths[] = $theme->getPath();
1088  }
1089  }
1090  $paths = [
1091  BP . "/lib/web/varien"
1092  ];
1093  $paths = array_merge($paths, $viewAreaPaths, $themePaths);
1094  $files = self::getFiles($paths, '*.js');
1095 
1096  if ($area == 'adminhtml') {
1097  $adminhtmlPaths = [BP . "/lib/web/mage/{adminhtml,backend}"];
1098  $files = array_merge($files, self::getFiles($adminhtmlPaths, '*.js'));
1099  } else {
1100  $frontendPaths = [BP . "/lib/web/mage"];
1101  /* current structure of /lib/web/mage directory contains frontend javascript in the root,
1102  backend javascript in subdirectories. That's why script shouldn't go recursive throught subdirectories
1103  to get js files for frontend */
1104  $files = array_merge($files, self::getFiles($frontendPaths, '*.js', false));
1105  }
1106 
1107  self::$_cache[$key] = $files;
1108  return $files;
1109  }
1110 
1118  public function getPhtmlFiles($withMetaInfo = false, $asDataSet = true)
1119  {
1120  $key = __METHOD__ . (int)$withMetaInfo;
1121  if (!isset(self::$_cache[$key])) {
1122  $result = [];
1123  $this->accumulateModuleTemplateFiles($withMetaInfo, $result);
1124  $this->accumulateThemeTemplateFiles($withMetaInfo, $result);
1125  self::$_cache[$key] = $result;
1126  }
1127  if ($asDataSet) {
1128  return self::composeDataSets(self::$_cache[$key]);
1129  }
1130  return self::$_cache[$key];
1131  }
1132 
1142  public function getDbSchemaFiles(
1143  $fileNamePattern = 'db_schema.xml',
1144  $excludedFileNames = [],
1145  $asDataSet = true
1146  ) {
1147  $cacheKey = __METHOD__ . '|' . $this->serializer->serialize([$fileNamePattern, $excludedFileNames, $asDataSet]);
1148  if (!isset(self::$_cache[$cacheKey])) {
1149  $files = $this->dirSearch->collectFiles(ComponentRegistrar::MODULE, "/etc/{$fileNamePattern}");
1150  $files = array_filter(
1151  $files,
1152  function ($file) use ($excludedFileNames) {
1153  return !in_array(basename($file), $excludedFileNames);
1154  }
1155  );
1156  self::$_cache[$cacheKey] = $files;
1157  }
1158  if ($asDataSet) {
1159  return self::composeDataSets(self::$_cache[$cacheKey]);
1160  }
1161  return self::$_cache[$cacheKey];
1162  }
1163 
1171  private function accumulateThemeTemplateFiles($withMetaInfo, array &$result)
1172  {
1173  foreach ($this->themePackageList->getThemes() as $theme) {
1174  $files = [];
1176  [$theme->getPath() . '/*_*/templates'],
1177  '*.phtml',
1178  $files
1179  );
1180  if ($withMetaInfo) {
1181  $regex = '#^' . str_replace(DIRECTORY_SEPARATOR, '/', $theme->getPath())
1182  . '/(?P<module>[a-z\d]+_[a-z\d]+)/templates/(?P<path>.+)$#i';
1183  foreach ($files as $file) {
1184  if (preg_match($regex, $file, $matches)) {
1185  $result[] = [
1186  $theme->getArea(),
1187  $theme->getVendor() . '/' . $theme->getName(),
1188  $matches['module'],
1189  $matches['path'],
1190  $file,
1191  ];
1192  } else {
1193  echo $regex . " - " . $file . "\n";
1194  throw new \UnexpectedValueException("Could not parse theme template file '$file'");
1195  }
1196  }
1197  } else {
1198  $result = array_merge($result, $files);
1199  }
1200  }
1201  }
1202 
1210  private function accumulateModuleTemplateFiles($withMetaInfo, array &$result)
1211  {
1212  foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleName => $moduleDir) {
1213  $files = [];
1215  [$moduleDir . "/view/*/templates"],
1216  '*.phtml',
1217  $files
1218  );
1219  if ($withMetaInfo) {
1220  $modulePath = str_replace(DIRECTORY_SEPARATOR, '/', preg_quote($moduleDir, '#'));
1221  $regex = '#^' . $modulePath . '/view/(?P<area>[a-z]+)/templates/(?P<path>.+)$#i';
1222  foreach ($files as $file) {
1223  if (preg_match($regex, $file, $matches)) {
1224  $result[] = [
1225  $matches['area'],
1226  '',
1227  $moduleName,
1228  $matches['path'],
1229  $file,
1230  ];
1231  } else {
1232  throw new \UnexpectedValueException("Could not parse module template file '$file'");
1233  }
1234  }
1235  } else {
1236  $result = array_merge($result, $files);
1237  }
1238  }
1239  }
1240 
1246  public function getEmailTemplates()
1247  {
1248  $key = __METHOD__;
1249  if (isset(self::$_cache[$key])) {
1250  return self::$_cache[$key];
1251  }
1252  $moduleEmailPaths = [];
1253  foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleDir) {
1254  $moduleEmailPaths[] = $moduleDir . "/view/email";
1255  }
1256  $files = self::getFiles($moduleEmailPaths, '*.html');
1258  self::$_cache[$key] = $result;
1259  return $result;
1260  }
1261 
1268  public function getAllFiles()
1269  {
1270  $key = __METHOD__ . BP;
1271  if (isset(self::$_cache[$key])) {
1272  return self::$_cache[$key];
1273  }
1274 
1275  $paths = array_merge(
1276  [BP . '/app', BP . '/dev', BP . '/lib', BP . '/pub'],
1277  $this->componentRegistrar->getPaths(ComponentRegistrar::LANGUAGE),
1278  $this->componentRegistrar->getPaths(ComponentRegistrar::THEME),
1279  $this->getPaths()
1280  );
1281  $subFiles = self::getFiles($paths, '*');
1282 
1283  $rootFiles = glob(BP . '/*', GLOB_NOSORT);
1284  $rootFiles = array_filter(
1285  $rootFiles,
1286  function ($file) {
1287  return is_file($file);
1288  }
1289  );
1290 
1291  $result = array_merge($rootFiles, $subFiles);
1293 
1294  self::$_cache[$key] = $result;
1295  return $result;
1296  }
1297 
1306  public static function getFiles(array $dirPatterns, $fileNamePattern, $recursive = true)
1307  {
1308  $result = [];
1309  foreach ($dirPatterns as $oneDirPattern) {
1310  $oneDirPattern = str_replace('\\', '/', $oneDirPattern);
1311  $entriesInDir = Glob::glob("{$oneDirPattern}/{$fileNamePattern}", Glob::GLOB_NOSORT | Glob::GLOB_BRACE);
1312  $subDirs = Glob::glob("{$oneDirPattern}/*", Glob::GLOB_ONLYDIR | Glob::GLOB_NOSORT | Glob::GLOB_BRACE);
1313  $filesInDir = array_diff($entriesInDir, $subDirs);
1314 
1315  if ($recursive) {
1316  $filesInSubDir = self::getFiles($subDirs, $fileNamePattern);
1317  $result = array_merge($result, $filesInDir, $filesInSubDir);
1318  }
1319  }
1320  return $result;
1321  }
1322 
1329  public function getDiConfigs($asDataSet = false)
1330  {
1331  $primaryConfigs = Glob::glob(BP . '/app/etc/{di.xml,*/di.xml}', Glob::GLOB_BRACE);
1332  $moduleConfigs = [];
1333  foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleDir) {
1334  $moduleConfigs = array_merge(
1335  $moduleConfigs,
1336  Glob::glob($moduleDir . '/etc/{di,*/di}.xml', Glob::GLOB_BRACE)
1337  );
1338  }
1339  $configs = array_merge($primaryConfigs, $moduleConfigs);
1340 
1341  if ($asDataSet) {
1342  $output = [];
1343  foreach ($configs as $file) {
1344  $output[$file] = [$file];
1345  }
1346 
1347  return $output;
1348  }
1349  return $configs;
1350  }
1351 
1357  private function getPaths()
1358  {
1359  $directories = [];
1360  foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $fullModuleDir) {
1361  $directories[] = $fullModuleDir;
1362  }
1363  foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::LIBRARY) as $libraryDir) {
1364  $directories[] = $libraryDir;
1365  }
1366  return $directories;
1367  }
1368 
1377  public function classFileExists($class, &$path = '')
1378  {
1379  if ($class[0] == '\\') {
1380  $class = substr($class, 1);
1381  }
1382  $classParts = explode('\\', $class);
1383  $className = array_pop($classParts);
1384  $namespace = implode('\\', $classParts);
1385  $path = implode('/', explode('\\', $class)) . '.php';
1386  $directories = [
1387  '/dev/tools',
1388  '/dev/tests/api-functional/framework',
1389  '/dev/tests/setup-integration/framework',
1390  '/dev/tests/integration/framework',
1391  '/dev/tests/integration/framework/tests/unit/testsuite',
1392  '/dev/tests/integration/testsuite',
1393  '/dev/tests/integration/testsuite/Magento/Test/Integrity',
1394  '/dev/tests/static/framework',
1395  '/dev/tests/static/testsuite',
1396  '/dev/tests/functional/tests/app',
1397  '/dev/tests/functional/lib',
1398  '/dev/tests/functional/vendor/magento/mtf',
1399  '/setup/src'
1400  ];
1401  foreach ($directories as $key => $dir) {
1402  $directories[$key] = BP . $dir;
1403  }
1404 
1405  $directories = array_merge($directories, $this->getPaths());
1406 
1407  foreach ($directories as $dir) {
1408  $fullPath = $dir . '/' . $path;
1409  if ($this->classFileExistsCheckContent($fullPath, $namespace, $className)) {
1410  return true;
1411  }
1412  $classParts = explode('/', $path, 3);
1413  if (count($classParts) >= 3) {
1414  // Check if it's PSR-4 class with trimmed vendor and package name parts
1415  $trimmedFullPath = $dir . '/' . $classParts[2];
1416  if ($this->classFileExistsCheckContent($trimmedFullPath, $namespace, $className)) {
1417  return true;
1418  }
1419  }
1420  $classParts = explode('/', $path, 4);
1421  if (count($classParts) >= 4) {
1422  // Check if it's a library under framework directory
1423  $trimmedFullPath = $dir . '/' . $classParts[3];
1424  if ($this->classFileExistsCheckContent($trimmedFullPath, $namespace, $className)) {
1425  return true;
1426  }
1427  $trimmedFullPath = $dir . '/' . $classParts[2] . '/' . $classParts[3];
1428  if ($this->classFileExistsCheckContent($trimmedFullPath, $namespace, $className)) {
1429  return true;
1430  }
1431  }
1432  }
1433  return false;
1434  }
1435 
1444  private function classFileExistsCheckContent($fullPath, $namespace, $className)
1445  {
1452  if (realpath($fullPath) == str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $fullPath)
1453  || file_exists($fullPath)
1454  ) {
1455  $fileContent = file_get_contents($fullPath);
1456  if (strpos($fileContent, 'namespace ' . $namespace) !== false
1457  && (strpos($fileContent, 'class ' . $className) !== false
1458  || strpos($fileContent, 'interface ' . $className) !== false
1459  || strpos($fileContent, 'trait ' . $className) !== false)
1460  ) {
1461  return true;
1462  }
1463  }
1464  return false;
1465  }
1466 
1472  public function getNamespaces()
1473  {
1474  $key = __METHOD__;
1475  if (isset(self::$_cache[$key])) {
1476  return self::$_cache[$key];
1477  }
1478 
1479  $result = [];
1480  foreach (array_keys($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE)) as $moduleName) {
1481  $namespace = explode('_', $moduleName)[0];
1482  if (!in_array($namespace, $result) && $namespace !== 'Zend') {
1483  $result[] = $namespace;
1484  }
1485  }
1486  self::$_cache[$key] = $result;
1487  return $result;
1488  }
1489 
1496  public function getModuleFile($namespace, $module, $file)
1497  {
1498  return $this->componentRegistrar->getPath(ComponentRegistrar::MODULE, $namespace . '_' . $module) .
1499  '/' . $file;
1500  }
1501 
1509  public function getModulePhpFiles($module, $asDataSet = true)
1510  {
1511  $key = __METHOD__ . "/{$module}";
1512  if (!isset(self::$_cache[$key])) {
1514  [$this->componentRegistrar->getPath(ComponentRegistrar::MODULE, 'Magento_' . $module)],
1515  '*.php'
1516  );
1517  self::$_cache[$key] = $files;
1518  }
1519 
1520  if ($asDataSet) {
1521  return self::composeDataSets(self::$_cache[$key]);
1522  }
1523 
1524  return self::$_cache[$key];
1525  }
1526 
1534  public function getComposerFiles($componentType, $asDataSet = true)
1535  {
1536  $key = __METHOD__ . '|' . implode('|', [$componentType, $asDataSet]);
1537  if (!isset(self::$_cache[$key])) {
1538  $excludes = $componentType == ComponentRegistrar::MODULE ? $this->getModuleTestDirsRegex() : [];
1539  $files = $this->getFilesSubset(
1540  $this->componentRegistrar->getPaths($componentType),
1541  'composer.json',
1542  $excludes
1543  );
1544 
1545  self::$_cache[$key] = $files;
1546  }
1547 
1548  if ($asDataSet) {
1549  return self::composeDataSets(self::$_cache[$key]);
1550  }
1551 
1552  return self::$_cache[$key];
1553  }
1554 
1564  public function readLists($globPattern)
1565  {
1566  $patterns = [];
1567  foreach (glob($globPattern) as $list) {
1568  $patterns = array_merge($patterns, file($list, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES));
1569  }
1570 
1571  // Expand glob patterns
1572  $result = [];
1573  $incorrectPatterns = [];
1574  foreach ($patterns as $pattern) {
1575  if (0 === strpos($pattern, '#')) {
1576  continue;
1577  }
1578  $patternParts = explode(' ', $pattern);
1579  if (count($patternParts) == 3) {
1580  list($componentType, $componentName, $pathPattern) = $patternParts;
1581  $files = $this->getPathByComponentPattern($componentType, $componentName, $pathPattern);
1582  } elseif (count($patternParts) == 1) {
1587  $files = Glob::glob(BP . '/' . $pattern, Glob::GLOB_BRACE);
1588  } else {
1589  throw new \UnexpectedValueException(
1590  "Incorrect pattern record '$pattern'. Supported formats: "
1591  . "'<componentType> <componentName> <glob_pattern>' or '<glob_pattern>'"
1592  );
1593  }
1594  if (empty($files)) {
1595  $incorrectPatterns[] = $pattern;
1596  }
1597  $result = array_merge($result, $files);
1598  }
1599  if (!empty($incorrectPatterns)) {
1600  throw new \Exception("The following patterns didn't return any result:\n" . join("\n", $incorrectPatterns));
1601  }
1602  return $result;
1603  }
1604 
1613  private function getPathByComponentPattern($componentType, $componentName, $pathPattern)
1614  {
1615  $files = [];
1616  if ($componentType == '*') {
1617  $componentTypes = [
1622  ];
1623  } else {
1624  $componentTypes = [$componentType];
1625  }
1626  foreach ($componentTypes as $type) {
1627  if ($componentName == '*') {
1628  $files = array_merge($files, $this->dirSearch->collectFiles($type, $pathPattern));
1629  } else {
1630  $componentDir = $this->componentRegistrar->getPath($type, $componentName);
1631  if (!empty($componentDir)) {
1632  $files = array_merge($files, Glob::glob($componentDir . '/' . $pathPattern, Glob::GLOB_BRACE));
1633  }
1634  }
1635  }
1636  return $files;
1637  }
1638 
1645  public function isModuleExists($moduleName)
1646  {
1647  $key = __METHOD__ . "/{$moduleName}";
1648  if (!isset(self::$_cache[$key])) {
1649  self::$_cache[$key] = file_exists(
1650  $this->componentRegistrar->getPath(ComponentRegistrar::MODULE, $moduleName)
1651  );
1652  }
1653 
1654  return self::$_cache[$key];
1655  }
1656 
1665  protected function getFilesSubset(array $dirPatterns, $fileNamePattern, $excludes)
1666  {
1667  if (!is_array($excludes)) {
1668  $excludes = [$excludes];
1669  }
1670  $fileSet = self::getFiles($dirPatterns, $fileNamePattern);
1671  foreach ($excludes as $excludeRegex) {
1672  $fileSet = preg_grep($excludeRegex, $fileSet, PREG_GREP_INVERT);
1673  }
1674  return $fileSet;
1675  }
1676 
1683  private function getSetupPhpFiles($flags = null)
1684  {
1685  $files = [];
1686  $setupAppPath = BP . '/setup';
1687  if ($flags & self::INCLUDE_SETUP && file_exists($setupAppPath)) {
1688  $regexIterator = $this->regexIteratorFactory->create(
1689  $setupAppPath,
1690  '/.*php$/'
1691  );
1692  foreach ($regexIterator as $file) {
1693  $files[] = $file[0];
1694  }
1695  }
1696  return $files;
1697  }
1698 }
getFilesSubset(array $dirPatterns, $fileNamePattern, $excludes)
Definition: Files.php:1665
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
getPageLayoutFiles($incomingParams=[], $asDataSet=true)
Definition: Files.php:564
getMainConfigFiles($asDataSet=true)
Definition: Files.php:381
return false
Definition: gallery.phtml:36
$pathPattern
$pattern
Definition: website.php:22
static glob($pattern, $flags=0, $forceFallback=false)
Definition: Glob.php:24
static composeDataSets(array $files)
Definition: Files.php:161
getLayoutXmlFiles($location, $incomingParams=[], $asDataSet=true)
Definition: Files.php:598
getStaticPreProcessingFiles($filePattern=' *')
Definition: Files.php:904
getConfigFiles( $fileNamePattern=' *.xml', $excludedFileNames=['wsdl.xml', 'wsdl2.xml', 'wsi.xml'], $asDataSet=true)
Definition: Files.php:414
getPageTypeFiles($incomingParams=[], $asDataSet=true)
Definition: Files.php:757
getLayoutFiles($incomingParams=[], $asDataSet=true)
Definition: Files.php:541
$type
Definition: item.phtml:13
$themePackageList
Definition: bootstrap.php:88
_accumulateFilesByPatterns(array $patterns, $filePattern, array &$result, $subroutine=false)
Definition: Files.php:1015
$_option $_optionId $class
Definition: date.phtml:13
static setInstance(Files $instance=null)
Definition: Files.php:136
getLayoutConfigFiles($fileNamePattern=' *.xml', $asDataSet=true)
Definition: Files.php:508
$dirSearch
Definition: bootstrap.php:86
classFileExists($class, &$path='')
Definition: Files.php:1377
getJsFiles($area=' *', $themePath=' */*', $namespace=' *', $module=' *')
Definition: Files.php:811
__construct(ComponentRegistrar $componentRegistrar, DirSearch $dirSearch, ThemePackageList $themePackageList, Json $serializer=null, RegexIteratorFactory $regexIteratorFactory=null)
Definition: Files.php:112
getXmlCatalogFiles( $fileNamePattern=' *.xsd', $excludedFileNames=[], $asDataSet=true)
Definition: Files.php:446
static getFiles(array $dirPatterns, $fileNamePattern, $recursive=true)
Definition: Files.php:1306
$theme
getModulePhpFiles($module, $asDataSet=true)
Definition: Files.php:1509
getDiConfigs($asDataSet=false)
Definition: Files.php:1329
getPhtmlFiles($withMetaInfo=false, $asDataSet=true)
Definition: Files.php:1118
getStaticHtmlFiles($area=' *', $themePath=' */*', $namespace=' *', $module=' *')
Definition: Files.php:869
const BP
Definition: autoload.php:14
getComposerFiles($componentType, $asDataSet=true)
Definition: Files.php:1534
getDbSchemaFiles( $fileNamePattern='db_schema.xml', $excludedFileNames=[], $asDataSet=true)
Definition: Files.php:1142
$paths
Definition: _bootstrap.php:83
$params[\Magento\Store\Model\StoreManager::PARAM_RUN_CODE]
Definition: website.php:18
getUiComponentXmlFiles($incomingParams=[], $asDataSet=true)
Definition: Files.php:587
foreach($appDirs as $dir) $files
getModuleFile($namespace, $module, $file)
Definition: Files.php:1496
if($currentSelectedMethod==$_code) $className
Definition: form.phtml:31