Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
ObsoleteCodeTest.php
Go to the documentation of this file.
1 <?php
11 namespace Magento\Test\Legacy;
12 
17 
21 class ObsoleteCodeTest extends \PHPUnit\Framework\TestCase
22 {
28  protected static $_classes = [];
29 
30  protected static $_constants = [];
31 
32  protected static $_methods = [];
33 
34  protected static $_attributes = [];
35 
36  protected static $_namespaces = [];
37 
38  protected static $_paths = [];
39 
45  public static function setUpBeforeClass()
46  {
47  $errors = [];
48  self::_populateList(self::$_classes, $errors, 'obsolete_classes*.php', false);
49  self::_populateList(self::$_constants, $errors, 'obsolete_constants*.php');
50  self::_populateList(self::$_methods, $errors, 'obsolete_methods*.php');
51  self::_populateList(self::$_paths, $errors, 'obsolete_paths*.php', false);
52  self::_populateList(self::$_namespaces, $errors, 'obsolete_namespaces*.php', false);
53  self::_populateList(self::$_attributes, $errors, 'obsolete_properties*.php');
54  if ($errors) {
55  $message = 'Duplicate patterns identified in list declarations:' . PHP_EOL . PHP_EOL;
56  foreach ($errors as $file => $list) {
57  $message .= $file . PHP_EOL;
58  foreach ($list as $key) {
59  $message .= " {$key}" . PHP_EOL;
60  }
61  $message .= PHP_EOL;
62  }
63  throw new \Exception($message);
64  }
65  }
66 
77  protected static function _populateList(array &$list, array &$errors, $filePattern, $hasScope = true)
78  {
79  foreach (glob(__DIR__ . '/_files/' . $filePattern) as $file) {
80  $readList = include $file;
81  foreach ($readList as $row) {
82  list($item, $scope, $replacement, $isDeprecated) = self::_padRow($row, $hasScope);
83  $key = "{$item}|{$scope}";
84  if (isset($list[$key])) {
85  $errors[$file][] = $key;
86  } else {
87  $list[$key] = [$item, $scope, $replacement, $isDeprecated];
88  }
89  }
90  }
91  }
92 
100  protected static function _padRow($row, $hasScope)
101  {
102  if ($hasScope) {
103  return array_pad($row, 4, '');
104  }
105  list($item, $replacement) = array_pad($row, 2, '');
106  return [$item, '', $replacement, ''];
107  }
108 
109  public function testPhpFiles()
110  {
111  $invoker = new AggregateInvoker($this);
112  $changedFiles = ChangedFiles::getPhpFiles(__DIR__ . '/../_files/changed_files*');
113  $blacklistFiles = $this->getBlacklistFiles();
114  foreach ($blacklistFiles as $blacklistFile) {
115  unset($changedFiles[$blacklistFile]);
116  }
117  $invoker(
118  function ($file) {
119  $content = file_get_contents($file);
122  $this->_testObsoleteMethods($content, $file);
123  $this->_testGetChildSpecialCase($content, $file);
130  },
132  );
133  }
134 
135  public function testClassFiles()
136  {
137  $invoker = new AggregateInvoker($this);
138  $invoker(
139  function ($file) {
140  $this->_testObsoletePaths($file);
141  },
142  Files::init()->getPhpFiles()
143  );
144  }
145 
146  public function testTemplateMageCalls()
147  {
148  $invoker = new AggregateInvoker($this);
149  $invoker(
150  function ($file) {
151  $content = file_get_contents($file);
152  $this->_assertNotRegExp(
153  '/\bMage::(\w+?)\(/iS',
154  $content,
155  "Static Method of 'Mage' class is obsolete."
156  );
157  },
158  Files::init()->getPhpFiles(
162  )
163  );
164  }
165 
166  public function testXmlFiles()
167  {
168  $invoker = new AggregateInvoker($this);
169  $invoker(
170  function ($file) {
171  $content = file_get_contents($file);
172  $this->_testObsoleteClasses($content, $file);
174  $this->_testObsoletePaths($file);
175  },
176  Files::init()->getXmlFiles()
177  );
178  }
179 
180  public function testJsFiles()
181  {
182  $invoker = new AggregateInvoker($this);
183  $invoker(
184  function ($file) {
185  $content = file_get_contents($file);
187  },
188  Files::init()->getJsFiles()
189  );
190  }
191 
197  protected function _testObsoleteClasses($content)
198  {
199  /* avoid collision between obsolete class name and valid namespace and package tag */
200  $content = preg_replace('/namespace[^;]+;/', '', $content);
201  $content = preg_replace('/\@package\s[a-zA-Z0-9\\\_]+/', '', $content);
202  foreach (self::$_classes as $row) {
203  list($class, , $replacement) = $row;
204  $this->_assertNotRegExp(
205  '/[^a-z\d_]' . preg_quote($class, '/') . '[^a-z\d_\\\\]/iS',
206  $content,
207  $this->_suggestReplacement(sprintf("Class '%s' is obsolete.", $class), $replacement)
208  );
209  }
210  }
211 
217  protected function _testObsoleteNamespaces($content)
218  {
219  foreach (self::$_namespaces as $row) {
220  list($namespace, , $replacement) = $row;
221  $this->_assertNotRegExp(
222  '/namespace\s+' . preg_quote($namespace, '/') . ';/S',
223  $content,
224  $this->_suggestReplacement(sprintf("Namespace '%s' is obsolete.", $namespace), $replacement)
225  );
226  $this->_assertNotRegExp(
227  '/[^a-zA-Z\d_]' . preg_quote($namespace . '\\', '/') . '/S',
228  $content,
229  $this->_suggestReplacement(sprintf("Namespace '%s' is obsolete.", $namespace), $replacement)
230  );
231  }
232  }
233 
247  protected function _testObsoleteMethods($content, $file)
248  {
249  foreach (self::$_methods as $row) {
250  list($method, $class, $replacement, $isDeprecated) = $row;
251  $quotedMethod = preg_quote($method, '/');
252  if ($class) {
253  $message = $this->_suggestReplacement(
254  "Method '{$class}::{$method}()' is obsolete in file '{$file}'.",
256  );
257  // without opening parentheses to match static callbacks notation
258  $this->_assertNotRegExp(
259  '/' . preg_quote($class, '/') . '::\s*' . $quotedMethod . '[^a-z\d_]/iS',
260  $content,
261  $message
262  );
264  if (!$isDeprecated) {
265  $this->_assertNotRegExp('/function\s*' . $quotedMethod . '\s*\(/iS', $content, $message);
266  }
267  $this->_assertNotRegExp('/this->' . $quotedMethod . '\s*\(/iS', $content, $message);
268  $this->_assertNotRegExp(
269  '/(self|static|parent)::\s*' . $quotedMethod . '\s*\(/iS',
270  $content,
271  $message
272  );
273  }
274  } else {
275  $message = $this->_suggestReplacement(
276  "Function or method '{$method}()' is obsolete in file '{$file}'.",
278  );
279  $this->_assertNotRegExp(
280  '/(?<!public|protected|private|static)\s+function\s*' . $quotedMethod . '\s*\(/iS',
281  $content,
282  $message
283  );
284  $this->_assertNotRegExp(
285  '/(?<![a-z\d_:]|->|function\s)' . $quotedMethod . '\s*\(/iS',
286  $content,
287  $message
288  );
289  }
290  }
291  }
292 
301  protected function _testObsoletePaths($file)
302  {
303  foreach (self::$_paths as $row) {
304  list($obsoletePath, , $replacementPath) = $row;
305  $relativePath = str_replace(BP, '', $file);
306  $message = $this->_suggestReplacement(
307  "Path '{$obsoletePath}' is obsolete.",
308  $replacementPath
309  );
310  $this->assertStringStartsNotWith($obsoletePath . '/', $relativePath, $message);
311  $this->assertStringStartsNotWith($obsoletePath . '.', $relativePath, $message);
312  $this->assertStringStartsNotWith($obsoletePath . 'Factory.', $relativePath, $message);
313  $this->assertStringStartsNotWith($obsoletePath . 'Interface.', $relativePath, $message);
314  $this->assertStringStartsNotWith($obsoletePath . 'Test.', $relativePath, $message);
315  }
316  }
317 
327  protected function _testGetChildSpecialCase($content, $file)
328  {
330  foreach ($componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $modulePath) {
331  if (0 === strpos($file, $modulePath)) {
332  $this->_assertNotRegexp(
333  '/[^a-z\d_]getChild\s*\(/iS',
334  $content,
335  'Block method getChild() is obsolete. ' .
336  'Replacement suggestion: \Magento\Framework\View\Element\AbstractBlock::getChildBlock()'
337  );
338  }
339  }
340  }
341 
348  {
349  $this->_assertNotRegexp(
350  '/getOptions\(\)\s*->get(Base|App|Code|Design|Etc|Lib|Locale|Js|Media' .
351  '|Var|Tmp|Cache|Log|Session|Upload|Export)?Dir\(/S',
352  $content,
353  'The class \Magento\Core\Model\Config\Options is obsolete. '
354  . 'Replacement suggestion: \Magento\Framework\Filesystem'
355  );
356  }
357 
362  {
363  $this->_assertNotRegExp(
364  '/[^a-z\d_]getTypeInstance\s*\(\s*[^\)]+/iS',
365  $content,
366  'Backwards-incompatible change: method getTypeInstance() is not supposed to be invoked with any arguments.'
367  );
368  $this->_assertNotRegExp(
369  '/\->getUsedProductIds\(([^\)]+,\s*[^\)]+)?\)/',
370  $content,
371  'Backwards-incompatible change: method getUsedProductIds($product)' .
372  ' must be invoked with one and only one argument - product model object'
373  );
374 
375  $this->_assertNotRegExp(
376  '#->_setActiveMenu\([\'"]([\w\d/_]+)[\'"]\)#Ui',
377  $content,
378  'Backwards-incompatible change: method _setActiveMenu()' .
379  ' must be invoked with menu item identifier than xpath for menu item'
380  );
381  }
382 
386  protected function _testObsoleteProperties($content)
387  {
388  foreach (self::$_attributes as $row) {
390  if ($class) {
392  continue;
393  }
394  $fullyQualified = "{$class}::\${$attribute}";
395  } else {
396  $fullyQualified = $attribute;
397  }
398  $this->_assertNotRegExp(
399  '/[^a-z\d_]' . preg_quote($attribute, '/') . '[^a-z\d_]/iS',
400  $content,
401  $this->_suggestReplacement(sprintf("Class attribute '%s' is obsolete.", $fullyQualified), $replacement)
402  );
403  }
404  }
405 
409  protected function _testObsoleteActions($content)
410  {
411  $suggestion = 'Resizing images upon the client request is obsolete, use server-side resizing instead';
412  $this->_assertNotRegExp(
413  '#[^a-z\d_/]catalog/product/image[^a-z\d_/]#iS',
414  $content,
415  "Action 'catalog/product/image' is obsolete. {$suggestion}"
416  );
417  }
418 
430  protected function _testObsoleteConstants($content)
431  {
432  foreach (self::$_constants as $row) {
433  list($constant, $class, $replacement) = $row;
434  if ($class) {
435  $class = ltrim($class, '\\');
436  $this->_checkConstantWithFullClasspath($constant, $class, $replacement, $content);
437  $this->_checkConstantWithClasspath($constant, $class, $replacement, $content);
438  } else {
439  $regex = '\b' . preg_quote($constant, '/') . '\b';
440  $this->_checkExistenceOfObsoleteConstants($regex, '', $content, $constant, $replacement, $class);
441  }
442  }
443  }
444 
453  private function buildRegExFromObsoleteConstant($classPartialPath, $content, $constant)
454  {
455  $regex = preg_quote("{$classPartialPath}::{$constant}");
456  if ($this->_isClassOrInterface($content, $classPartialPath)) {
457  $regex .= '|' . $this->_getClassConstantDefinitionRegExp($constant)
458  . '|' . preg_quote("self::{$constant}", '/')
459  . '|' . preg_quote("static::{$constant}", '/');
460  } elseif ($this->_isDirectDescendant($content, $classPartialPath)) {
461  $regex .= '|' . preg_quote("parent::{$constant}", '/');
462  if (!$this->_isClassConstantDefined($content, $constant)) {
463  $regex .= '|' . preg_quote("self::{$constant}", '/') . '|' . preg_quote("static::{$constant}", '/');
464  }
465  }
466  return $regex;
467  }
468 
478  private function _checkConstantWithFullClasspath($constant, $class, $replacement, $content)
479  {
480  $constantRegex = preg_quote($constant, '/');
481  $classRegex = preg_quote($class);
482  $this->_checkExistenceOfObsoleteConstants(
483  $constantRegex,
484  $classRegex,
485  $content,
486  "{$class}::{$constant}",
487  $replacement,
488  $class
489  );
490  }
491 
500  private function _checkConstantWithClasspath($constant, $class, $replacement, $content)
501  {
502  $classPathParts = explode('\\', $class);
503  $classPartialPath = '';
504  for ($i = count($classPathParts) - 1; $i >= 0; $i--) {
505  if ($i === (count($classPathParts) - 1)) {
506  $classPartialPath = $classPathParts[$i] . $classPartialPath;
507  } else {
508  $classPartialPath = $classPathParts[$i] . '\\' . $classPartialPath;
509  }
510  $constantRegex = $this->buildRegExFromObsoleteConstant($classPartialPath, $content, $constant);
511  $regexClassPartialPath = preg_replace('/' . preg_quote($classPartialPath) . '$/', '', $class);
512  $classRegex = preg_quote($regexClassPartialPath . $classPathParts[$i]);
513  if ($regexClassPartialPath !== '') {
514  $classRegex .= '|' . preg_quote(rtrim($regexClassPartialPath, '\\'));
515  }
516  // Checks condition when classpath is distributed over namespace and class definition
517  $classRegexNamespaceClass = '/namespace\s+' . preg_quote('\\') . '?(' . $classRegex . ')(\s|;)(\r?\n)+'
518  . 'class\s+' . preg_quote('\\') . '?(' . preg_quote(rtrim($classPartialPath, '\\')) . ')\s*/';
519  $matchNamespaceClass = preg_match($classRegexNamespaceClass, $content);
520  $constantRegexPartial = '/\b(?P<classWithConst>([a-zA-Z0-9_' . preg_quote('\\') . ']*))('
521  . preg_quote('::') . ')*' . '(' . preg_quote($constant, '/') . '\b)(\s*|;)/';
522  $matchConstantPartial = preg_match($constantRegexPartial, $content, $match);
523  if (($matchNamespaceClass === 1) && ($matchConstantPartial === 1) && ($match['classWithConst'] === '')) {
524  $this->assertSame(
525  0,
526  1,
527  $this->_suggestReplacement(sprintf("Constant '%s' is obsolete.", $constant), $replacement)
528  );
529  } else {
530  $this->_checkExistenceOfObsoleteConstants(
531  $constantRegex,
532  $classRegex,
533  $content,
534  "{$classPartialPath}::{$constant}",
535  $replacement,
536  $class
537  );
538  }
539  }
540  }
541 
552  private function _checkExistenceOfObsoleteConstants(
553  $constantRegex,
554  $classRegex,
555  $content,
556  $constant,
557  $replacement,
558  $class
559  ) {
560  $constantRegexFull = '/\b(?P<constPart>((?P<classWithConst>([a-zA-Z0-9_' . preg_quote('\\') . ']*))('
561  . preg_quote('::') . ')*' . '(' . $constantRegex . '\b)))(\s*|;)/';
562  $matchConstant = preg_match_all($constantRegexFull, $content, $matchConstantString);
563  $result = 0;
564  if ($matchConstant === 1) {
565  if ($classRegex !== '') {
566  $classRegexFull = '/(?P<useOrNamespace>(use|namespace))\s+(?P<classPath>(' . preg_quote('\\')
567  . '?(' . $classRegex . ')))(\s+as\s+(?P<classAlias>([\w\d_]+)))?(\s|;)/';
568  $matchClass = preg_match($classRegexFull, $content, $matchClassString);
569  if ($matchClass === 1) {
570  if ($matchClassString['classAlias']) {
571  $result = $this->_checkAliasUseNamespace(
572  $constantRegex,
573  $matchConstantString,
574  $matchClassString,
575  $class
576  );
577  } else {
578  $result = $this->_checkNoAliasUseNamespace($matchConstantString, $matchClassString, $class);
579  }
580  } else {
581  foreach ($matchConstantString['classWithConst'] as $constantMatch) {
582  if (trim($constantMatch, '\\') === $class) {
583  $result = 1;
584  break;
585  }
586  }
587  }
588  } else {
589  $result = 1;
590  }
591  }
592  $this->assertSame(
593  0,
594  $result,
595  $this->_suggestReplacement(sprintf("Constant '%s' is obsolete.", $constant), $replacement)
596  );
597  }
598 
608  private function _checkAliasUseNamespace(
609  $constantRegex,
610  $matchConstantString,
611  $matchClassString,
612  $class
613  ) {
614  $foundProperUse = false;
615  $foundAsComponent = false;
616  $asComponent = $matchClassString['classAlias'];
617  foreach ($matchConstantString['constPart'] as $constantMatch) {
618  $expectedOnlyConst = '/' . $asComponent . preg_quote('::') . $constantRegex . '/';
619  $expectedConstPartialClass = '/' . $asComponent . preg_quote('\\')
620  . $constantRegex . '/';
621  if ((preg_match($expectedOnlyConst, $constantMatch) === 1)
622  || (preg_match($expectedConstPartialClass, $constantMatch) === 1)) {
623  $foundAsComponent = true;
624  }
625  if (strpos($constantMatch, '::') !== false) {
626  $foundProperUse = $this->_checkCompletePathOfClass(
627  $constantMatch,
628  $matchClassString,
629  $class,
630  $foundAsComponent,
631  $asComponent
632  );
633  if ($foundProperUse) {
634  break;
635  }
636  }
637  }
638  if ($foundProperUse) {
639  return 1;
640  } else {
641  return 0;
642  }
643  }
644 
653  private function _checkNoAliasUseNamespace(
654  $matchConstantString,
655  $matchClassString,
656  $class
657  ) {
658  $foundProperUse = false;
659  foreach ($matchConstantString['constPart'] as $constantMatch) {
660  $foundProperUse = $this->_checkCompletePathOfClass(
661  $constantMatch,
662  $matchClassString,
663  $class
664  );
665  if ($foundProperUse) {
666  break;
667  }
668  }
669  if ($foundProperUse) {
670  return 1;
671  } else {
672  return 0;
673  }
674  }
675 
686  private function _checkCompletePathOfClass(
687  $constantMatch,
688  $matchClassString,
689  $class,
690  $foundAsComponent = false,
691  $asComponent = ''
692  ) {
693  $temp = explode('::', $constantMatch);
694  $pathWithConst = trim(ltrim(str_replace('\\\\', '\\', $temp[0]), '\\'));
695  if ($pathWithConst === $class) {
696  return true;
697  }
698  if ($foundAsComponent) {
699  $pathWithConst = ltrim(preg_replace('/^' . $asComponent . '/', '', $pathWithConst), '\\');
700  if ($pathWithConst === '') {
701  return true;
702  }
703  }
704  $pathWithConstParts = explode('\\', $pathWithConst);
705  $pathInUseNamespace = trim($matchClassString['classPath'], '\\');
706  $pathInUseNamespaceTruncated = trim(trim(
707  preg_replace(
708  '/' . preg_quote($pathWithConstParts[0]) . '$/',
709  '',
710  $pathInUseNamespace
711  ),
712  '\\'
713  ));
714  if ($this->_checkClasspathProperDivisionNoConstantPath(
715  $pathInUseNamespaceTruncated,
716  $pathInUseNamespace,
717  $matchClassString,
718  $class,
719  $foundAsComponent
720  )) {
721  return true;
722  } else {
723  return $this->_checkClasspathProperDivisionWithConstantPath(
724  $pathInUseNamespaceTruncated,
725  $pathInUseNamespace,
726  $pathWithConst,
727  $class,
728  $foundAsComponent
729  );
730  }
731  }
732 
743  private function _checkClasspathProperDivisionNoConstantPath(
744  $pathInUseNamespaceTruncated,
745  $pathInUseNamespace,
746  $matchClassString,
747  $class,
748  $foundAsComponent
749  ) {
750  if ($pathInUseNamespaceTruncated === $pathInUseNamespace && $pathInUseNamespaceTruncated !== $class
751  && ($foundAsComponent || (strpos($matchClassString['useOrNamespace'], 'namespace') !== false))) {
752  return true;
753  } else {
754  return false;
755  }
756  }
757 
768  private function _checkClasspathProperDivisionWithConstantPath(
769  $pathInUseNamespaceTruncated,
770  $pathInUseNamespace,
771  $pathWithConst,
772  $class,
773  $foundAsComponent
774  ) {
775  if ((($pathInUseNamespaceTruncated . '\\' . $pathWithConst === $class)
776  && ($pathInUseNamespaceTruncated !== $pathInUseNamespace) && !$foundAsComponent)
777  || (($pathInUseNamespaceTruncated === $class) && (strpos($pathWithConst, '\\') === false)
778  && $foundAsComponent)) {
779  return true;
780  } else {
781  return false;
782  }
783  }
784 
792  protected function _isClassConstantDefined($content, $constant)
793  {
794  return (bool)preg_match('/' . $this->_getClassConstantDefinitionRegExp($constant) . '/S', $content);
795  }
796 
803  protected function _getClassConstantDefinitionRegExp($constant)
804  {
805  return '\bconst\s+' . preg_quote($constant, '/') . '\b';
806  }
807 
812  {
813  $this->_assertNotRegExp(
814  '/[^a-z\d_]skipCalculate[^a-z\d_]/iS',
815  $content,
816  "Configuration property 'skipCalculate' is obsolete."
817  );
818  }
819 
827  protected function _isClassOrInterface($content, $name)
828  {
829  $name = preg_quote($name, '/');
830  return (bool)preg_match('/\b(?:class|interface)\s+' . $name . '\b[^{]*\{/iS', $content);
831  }
832 
840  protected function _isDirectDescendant($content, $name)
841  {
842  $name = preg_quote($name, '/');
843  return (bool)preg_match(
844  '/\s+extends\s+' . $name . '\b|\s+implements\s+[^{]*\b' . $name . '\b[^{^\\\\]*\{/iS',
845  $content
846  );
847  }
848 
856  private function _suggestReplacement($original, $suggestion)
857  {
858  if ($suggestion) {
859  return "{$original} Suggested replacement: {$suggestion}";
860  }
861  return $original;
862  }
863 
874  protected function _assertNotRegexp($regex, $content, $message)
875  {
876  $this->assertSame(0, preg_match($regex, $content), $message);
877  }
878 
879  public function testMageMethodsObsolete()
880  {
881  $ignored = $this->getBlacklistFiles(true);
882  $files = Files::init()->getPhpFiles(
887  );
888  $files = array_map('realpath', $files);
889  $files = array_diff($files, $ignored);
891 
892  $invoker = new AggregateInvoker($this);
893  $invoker(
899  function ($file) {
900  $this->_assertNotRegExp(
901  '/[^a-z\d_]Mage\s*::/i',
902  file_get_contents($file),
903  '"Mage" class methods are obsolete'
904  );
905  },
906  $files
907  );
908  }
909 
916  private function processPattern($appPath, $pattern)
917  {
918  $files = [];
919  $relativePathStart = strlen($appPath);
920 
921  $fileSet = glob($appPath . DIRECTORY_SEPARATOR . $pattern, GLOB_NOSORT);
922  foreach ($fileSet as $file) {
923  $files[] = ltrim(substr($file, $relativePathStart), '/');
924  }
925 
926  return $files;
927  }
928 
936  private function getBlacklistFiles($absolutePath = false)
937  {
938  $blackList = include __DIR__ . '/_files/blacklist/obsolete_mage.php';
939  $ignored = [];
940  $appPath = BP;
941  foreach ($blackList as $file) {
942  if ($absolutePath) {
943  $ignored = array_merge($ignored, glob($appPath . DIRECTORY_SEPARATOR . $file, GLOB_NOSORT));
944  } else {
945  $ignored = array_merge($ignored, $this->processPattern($appPath, $file));
946  }
947  }
948  return $ignored;
949  }
950 }
$componentRegistrar
Definition: bootstrap.php:23
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
static getPhpFiles($changedFilesList, $fileTypes=0)
$pattern
Definition: website.php:22
defined('TESTS_BP')||define('TESTS_BP' __DIR__
Definition: _bootstrap.php:60
_isClassConstantDefined($content, $constant)
static composeDataSets(array $files)
Definition: Files.php:161
$message
$replacement
Definition: website.php:23
$_option $_optionId $class
Definition: date.phtml:13
_assertNotRegexp($regex, $content, $message)
$method
Definition: info.phtml:13
static _populateList(array &$list, array &$errors, $filePattern, $hasScope=true)
const BP
Definition: autoload.php:14
$relativePath
Definition: get.php:35
$_attributes
$i
Definition: gallery.phtml:31
foreach($appDirs as $dir) $files
$errors
Definition: overview.phtml:9
if(!isset($_GET['name'])) $name
Definition: log.php:14