From 43c898f52c52bf1388f467fb06e9894a468069a8 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Tue, 21 Mar 2017 15:28:14 -0500 Subject: [PATCH 01/61] Updated the class scanner so it calls SplFileInfo::realpath() only once in a loop instead of several times. This can have a significant performance impact on large codebases.or slow filesystems. --- .../Setup/Module/Di/Code/Reader/ClassesScanner.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 04336639a3a43..5cb1d98262213 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -58,19 +58,20 @@ public function getList($path) if ($fileItem->isDir() || $fileItem->getExtension() !== 'php') { continue; } + $fileItemPath = $fileItem->getRealPath(); foreach ($this->excludePatterns as $excludePatterns) { - if ($this->isExclude($fileItem, $excludePatterns)) { + if ($this->isExclude($fileItemPath, $excludePatterns)) { continue 2; } } - $fileScanner = new FileScanner($fileItem->getRealPath()); + $fileScanner = new FileScanner($fileItemPath); $classNames = $fileScanner->getClassNames(); foreach ($classNames as $className) { if (empty($className)) { continue; } if (!class_exists($className)) { - require_once $fileItem->getRealPath(); + require_once $fileItemPath; } $classes[] = $className; } @@ -81,17 +82,17 @@ public function getList($path) /** * Find out if file should be excluded * - * @param \SplFileInfo $fileItem + * @param string $fileItem * @param string $patterns * @return bool */ - private function isExclude(\SplFileInfo $fileItem, $patterns) + private function isExclude($fileItemPath, $patterns) { if (!is_array($patterns)) { $patterns = (array)$patterns; } foreach ($patterns as $pattern) { - if (preg_match($pattern, str_replace('\\', '/', $fileItem->getRealPath()))) { + if (preg_match($pattern, str_replace('\\', '/', $fileItemPath))) { return true; } } From acc587ffd3ffd75e096d73d55b101f38ed3e33c0 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Tue, 21 Mar 2017 16:55:25 -0500 Subject: [PATCH 02/61] Updated the class scanner to reduce cyclomatic complexity. --- .../Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index d11536f52bf4c..cc72b32e681d7 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -52,6 +52,12 @@ public function getList($path) \RecursiveIteratorIterator::SELF_FIRST ); + $classes = $this->extract($recursiveIterator); + return $classes; + } + + private function extract($recursiveIterator) + { $classes = []; foreach ($recursiveIterator as $fileItem) { /** @var $fileItem \SplFileInfo */ From b127afa5ca0a94c1b6da3bf40c244086cf13c844 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Tue, 21 Mar 2017 17:37:59 -0500 Subject: [PATCH 03/61] Stupid cyclomatic complexity tests for stupid missing function doc comments --- .../Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index cc72b32e681d7..9e97729022688 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -56,6 +56,13 @@ public function getList($path) return $classes; } + /** + * Extracts all the classes from the recursive iterator + * + * @param $recursiveIterator + * @return array + */ + private function extract($recursiveIterator) { $classes = []; From 1f5de9d9da70864c5c7db948de4a903314c32b48 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Tue, 21 Mar 2017 20:48:06 -0500 Subject: [PATCH 04/61] Fixed some PHPDoc mixups --- .../Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 9e97729022688..5f63e72fc2997 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -59,11 +59,11 @@ public function getList($path) /** * Extracts all the classes from the recursive iterator * - * @param $recursiveIterator + * @param \RecursiveIteratorIterator $recursiveIterator * @return array */ - private function extract($recursiveIterator) + private function extract(\RecursiveIteratorIterator $recursiveIterator) { $classes = []; foreach ($recursiveIterator as $fileItem) { @@ -95,7 +95,7 @@ private function extract($recursiveIterator) /** * Find out if file should be excluded * - * @param string $fileItem + * @param string $fileItemPath * @param string $patterns * @return bool */ From 60a289b1f0cc1e60b2996493b59439ad78615d12 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Tue, 21 Mar 2017 15:28:14 -0500 Subject: [PATCH 05/61] Updated the class scanner so it calls SplFileInfo::realpath() only once in a loop instead of several times. This can have a significant performance impact on large codebases.or slow filesystems. --- .../Module/Di/Code/Reader/ClassesScanner.php | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 5f63e72fc2997..5cb1d98262213 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -1,6 +1,6 @@ extract($recursiveIterator); - return $classes; - } - - /** - * Extracts all the classes from the recursive iterator - * - * @param \RecursiveIteratorIterator $recursiveIterator - * @return array - */ - - private function extract(\RecursiveIteratorIterator $recursiveIterator) - { $classes = []; foreach ($recursiveIterator as $fileItem) { /** @var $fileItem \SplFileInfo */ @@ -95,7 +82,7 @@ private function extract(\RecursiveIteratorIterator $recursiveIterator) /** * Find out if file should be excluded * - * @param string $fileItemPath + * @param string $fileItem * @param string $patterns * @return bool */ From 06865dc0ce07f1e3753c7daacc63d13b74efef5d Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Tue, 21 Mar 2017 16:55:25 -0500 Subject: [PATCH 06/61] Updated the class scanner to reduce cyclomatic complexity. --- .../Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 5cb1d98262213..f7cf057e31c7f 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -52,6 +52,12 @@ public function getList($path) \RecursiveIteratorIterator::SELF_FIRST ); + $classes = $this->extract($recursiveIterator); + return $classes; + } + + private function extract($recursiveIterator) + { $classes = []; foreach ($recursiveIterator as $fileItem) { /** @var $fileItem \SplFileInfo */ From 98828dc285a7fe37a8f6d4e78ab0dd1c6d582506 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Tue, 21 Mar 2017 17:37:59 -0500 Subject: [PATCH 07/61] Stupid cyclomatic complexity tests for stupid missing function doc comments --- .../Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index f7cf057e31c7f..eeed41a11610d 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -56,6 +56,13 @@ public function getList($path) return $classes; } + /** + * Extracts all the classes from the recursive iterator + * + * @param $recursiveIterator + * @return array + */ + private function extract($recursiveIterator) { $classes = []; From 0c86dcd9626240ed8bc572ebabbb693e06d9983e Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Tue, 21 Mar 2017 20:48:06 -0500 Subject: [PATCH 08/61] Fixed some PHPDoc mixups --- .../Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index eeed41a11610d..a38c9db9eef5f 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -59,11 +59,11 @@ public function getList($path) /** * Extracts all the classes from the recursive iterator * - * @param $recursiveIterator + * @param \RecursiveIteratorIterator $recursiveIterator * @return array */ - private function extract($recursiveIterator) + private function extract(\RecursiveIteratorIterator $recursiveIterator) { $classes = []; foreach ($recursiveIterator as $fileItem) { @@ -95,7 +95,7 @@ private function extract($recursiveIterator) /** * Find out if file should be excluded * - * @param string $fileItem + * @param string $fileItemPath * @param string $patterns * @return bool */ From 60be23675150780bc4f66eb4595e741e019c462a Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Thu, 23 Mar 2017 16:50:48 -0500 Subject: [PATCH 09/61] Added a FileClassScanner which uses the tokenizer to extract only the class names. It's like FileScanner except it only cares about namespaces and classes. --- .../Module/Di/Code/Reader/ClassesScanner.php | 12 +- .../Di/Code/Reader/FileClassScanner.php | 90 ++++++++++ .../Di/Code/Reader/InvalidFileException.php | 5 + .../Di/Code/Reader/FileClassScannerTest.php | 159 ++++++++++++++++++ 4 files changed, 257 insertions(+), 9 deletions(-) create mode 100644 setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php create mode 100644 setup/src/Magento/Setup/Module/Di/Code/Reader/InvalidFileException.php create mode 100644 setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index a38c9db9eef5f..6529199e417aa 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -77,16 +77,10 @@ private function extract(\RecursiveIteratorIterator $recursiveIterator) continue 2; } } - $fileScanner = new FileScanner($fileItemPath); + $fileScanner = new FileClassScanner($fileItemPath); $classNames = $fileScanner->getClassNames(); - foreach ($classNames as $className) { - if (empty($className)) { - continue; - } - if (!class_exists($className)) { - require_once $fileItemPath; - } - $classes[] = $className; + if ($classNames) { + $classes = array_merge($classes, $classNames); } } return $classes; diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php new file mode 100644 index 0000000000000..de9ac920c7ffd --- /dev/null +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -0,0 +1,90 @@ +filename = $filename; + } + + public function getFileContents() + { + return file_get_contents($this->filename); + } + + protected function extract() + { + $classes = []; + $tokens = token_get_all($this->getFileContents()); + $namespace = ''; + $class = ''; + $triggerClass = false; + $triggerNamespace = false; + $paramNestingLevel = $currentParamNestingLevel = 0; + foreach ($tokens as $key => $token) { + if (!is_array($token)) { + if ($token == '{') { + $paramNestingLevel++; + } else if ($token == '}') { + $paramNestingLevel--; + } + } + if ($triggerNamespace) { + if (is_array($token)) { + $namespace .= $token[1]; + } else { + $currentParamNestingLevel = $paramNestingLevel; + $triggerNamespace = false; + $namespace .= '\\'; + continue; + } + } else if ($triggerClass && $token[0] == T_STRING) { + $triggerClass = false; + $class = $token[1]; + } + if ($token[0] == T_NAMESPACE) { + $triggerNamespace = true; + } else if ($token[0] == T_CLASS && $currentParamNestingLevel == $paramNestingLevel) { + $triggerClass = true; + } + if ($class != '' && $currentParamNestingLevel == $paramNestingLevel) { + $namespace = trim($namespace); + $fqClassName = $namespace . trim($class); + $classes[] = $fqClassName; + $class = ''; + continue; + } + } + return $classes; + } + + public function getClassNames() + { + if ($this->classNames === false) { + $this->classNames = $this->extract(); + } + return $this->classNames; + } + + +} diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/InvalidFileException.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/InvalidFileException.php new file mode 100644 index 0000000000000..84d8c3f553f35 --- /dev/null +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/InvalidFileException.php @@ -0,0 +1,5 @@ +setExpectedException(InvalidFileException::class); + new FileClassScanner(false); + } + + public function testEmptyArrayForFileWithoutNamespaceOrClass() + { + $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ + 'getFileContents' + ])->getMock(); + $scanner->expects(self::once())->method('getFileContents')->willReturn(<<getClassNames(); + self::assertCount(0, $result); + } + + public function testGetClassName() + { + $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ + 'getFileContents' + ])->getMock(); + $scanner->expects(self::once())->method('getFileContents')->willReturn(<<getClassNames(); + + self::assertCount(1, $result); + self::assertContains('ThisIsATest', $result); + } + + public function testGetClassNameAndSingleNamespace() + { + $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ + 'getFileContents' + ])->getMock(); + $scanner->expects(self::once())->method('getFileContents')->willReturn(<<getClassNames(); + + self::assertCount(1, $result); + self::assertContains('NS\ThisIsMyTest', $result); + } + + public function testGetClassNameAndMultiNamespace() + { + $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ + 'getFileContents' + ])->getMock(); + $scanner->expects(self::once())->method('getFileContents')->willReturn(<<getClassNames(); + + self::assertCount(1, $result); + self::assertContains('This\Is\My\Namespace\ThisIsMyTest', $result); + } + public function testGetMultipleClassesInMultiNamespace() + { + $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ + 'getFileContents' + ])->getMock(); + $scanner->expects(self::once())->method('getFileContents')->willReturn(<<getClassNames(); + + self::assertCount(2, $result); + self::assertContains('This\Is\My\Namespace\ThisIsMyTest', $result); + self::assertContains('This\Is\My\Namespace\ThisIsAnotherTest', $result); + } + + +} From 3a80af3cf7bf117b5ea92d6c3a02317140fac00c Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Thu, 23 Mar 2017 18:37:01 -0500 Subject: [PATCH 10/61] Fixed an issue with the FileClassScanner not liking one case when the word "class" was in a class. This change will now only return the Namespace\Class up until the first {. Given that there should only be one class per file this should have no effect beyond reducing the potential for problems. --- .../Di/Code/Reader/FileClassScanner.php | 10 ++--- .../Di/Code/Reader/FileClassScannerTest.php | 37 +++---------------- 2 files changed, 8 insertions(+), 39 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index de9ac920c7ffd..ff564a8f5277e 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -12,6 +12,7 @@ class FileClassScanner protected $filename; protected $classNames = false; + protected $tokens; public function __construct( $filename ) { @@ -42,12 +43,8 @@ protected function extract() $triggerNamespace = false; $paramNestingLevel = $currentParamNestingLevel = 0; foreach ($tokens as $key => $token) { - if (!is_array($token)) { - if ($token == '{') { - $paramNestingLevel++; - } else if ($token == '}') { - $paramNestingLevel--; - } + if ($token == '{') { + return $classes; } if ($triggerNamespace) { if (is_array($token)) { @@ -86,5 +83,4 @@ public function getClassNames() return $this->classNames; } - } diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php index ecefbf5f0468d..3fb5470407d98 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php @@ -117,42 +117,15 @@ public function test() self::assertCount(1, $result); self::assertContains('This\Is\My\Namespace\ThisIsMyTest', $result); } - public function testGetMultipleClassesInMultiNamespace() - { - $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ - 'getFileContents' - ])->getMock(); - $scanner->expects(self::once())->method('getFileContents')->willReturn(<<getClassNames(); - self::assertCount(2, $result); - self::assertContains('This\Is\My\Namespace\ThisIsMyTest', $result); - self::assertContains('This\Is\My\Namespace\ThisIsAnotherTest', $result); + self::assertCount(1, $result); } From 4aa7ce061b258f649e5b7c516bb49fbdade55af7 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Thu, 23 Mar 2017 18:52:53 -0500 Subject: [PATCH 11/61] This includes a cache for class results because the individual class structures are scanned five times over the course of compilation. /var/generation is excluded. --- .../Module/Di/Code/Reader/ClassesScanner.php | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 6529199e417aa..3deb0edb30af9 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -5,8 +5,8 @@ */ namespace Magento\Setup\Module\Di\Code\Reader; +use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Exception\FileSystemException; -use Magento\Setup\Module\Di\Code\Reader\FileScanner; class ClassesScanner implements ClassesScannerInterface { @@ -16,11 +16,25 @@ class ClassesScanner implements ClassesScannerInterface protected $excludePatterns = []; /** + * @var array + */ + + protected $fileResults = []; + + /** + * @var DirectoryList + */ + + protected $directoryList; + + /** + * @param DirectoryList $directoryList * @param array $excludePatterns */ - public function __construct(array $excludePatterns = []) + public function __construct(DirectoryList $directoryList, array $excludePatterns = []) { $this->excludePatterns = $excludePatterns; + $this->directoryList = $directoryList; } /** @@ -43,7 +57,14 @@ public function addExcludePatterns(array $excludePatterns) */ public function getList($path) { + $generation = $this->directoryList->getPath(DirectoryList::GENERATION); $realPath = realpath($path); + $isGeneration = strpos($realPath, $generation) !== false; + if (!$isGeneration) { + if (isset($this->fileResults[$realPath])) { + return $this->fileResults[$realPath]; + } + } if (!(bool)$realPath) { throw new FileSystemException(new \Magento\Framework\Phrase('Invalid path: %1', [$path])); } @@ -53,6 +74,9 @@ public function getList($path) ); $classes = $this->extract($recursiveIterator); + if (!$isGeneration) { + $this->fileResults[$realPath] = $classes; + } return $classes; } @@ -79,9 +103,18 @@ private function extract(\RecursiveIteratorIterator $recursiveIterator) } $fileScanner = new FileClassScanner($fileItemPath); $classNames = $fileScanner->getClassNames(); + $classExists = false; if ($classNames) { + foreach ($classNames as $className) { + if (class_exists($className)) { + $classExists = true; + } + } $classes = array_merge($classes, $classNames); } + if (!$classExists) { + require_once $fileItemPath; + } } return $classes; } From 55a765fd6b6ddfce19dd2d5201bbfd4093383483 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Thu, 23 Mar 2017 19:08:11 -0500 Subject: [PATCH 12/61] Fixed some mess detection issues. Removed the DirectoryList dependency so other unit tests wouldn't break. It just checks to see if /generation/ is in the filename, --- .../Module/Di/Code/Reader/ClassesScanner.php | 14 +---- .../Di/Code/Reader/FileClassScanner.php | 60 +++++++++++++++---- .../Di/Code/Reader/InvalidFileException.php | 5 +- .../Di/Code/Reader/FileClassScannerTest.php | 14 +++-- 4 files changed, 64 insertions(+), 29 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 3deb0edb30af9..1bc99cf92ee56 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -22,19 +22,11 @@ class ClassesScanner implements ClassesScannerInterface protected $fileResults = []; /** - * @var DirectoryList - */ - - protected $directoryList; - - /** - * @param DirectoryList $directoryList * @param array $excludePatterns */ - public function __construct(DirectoryList $directoryList, array $excludePatterns = []) + public function __construct(array $excludePatterns = []) { $this->excludePatterns = $excludePatterns; - $this->directoryList = $directoryList; } /** @@ -57,9 +49,9 @@ public function addExcludePatterns(array $excludePatterns) */ public function getList($path) { - $generation = $this->directoryList->getPath(DirectoryList::GENERATION); + $realPath = realpath($path); - $isGeneration = strpos($realPath, $generation) !== false; + $isGeneration = strpos($realPath, DIRECTORY_SEPARATOR . 'generation' . DIRECTORY_SEPARATOR) !== false; if (!$isGeneration) { if (isset($this->fileResults[$realPath])) { return $this->fileResults[$realPath]; diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index ff564a8f5277e..ef5dd428ac766 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -9,10 +9,26 @@ class FileClassScanner { + /** + * The filename of the file to introspect + * + * @var string + */ protected $filename; + + /** + * The list of classes found in the file. + * + * @var bool + */ + protected $classNames = false; - protected $tokens; + + /** + * Constructor for the file class scanner. Requires the filename + * @param $filename + */ public function __construct( $filename ) { @@ -28,11 +44,24 @@ public function __construct( $filename ) $this->filename = $filename; } + /** + * Retrieves the contents of a file. Mostly here for Mock injection + * + * @return string + */ + public function getFileContents() { return file_get_contents($this->filename); } + /** + * Extracts the fully qualified class name from a file. It only searches for the first match and stops looking + * as soon as it enters the class definition itself. + * + * @return array + */ + protected function extract() { $classes = []; @@ -41,40 +70,49 @@ protected function extract() $class = ''; $triggerClass = false; $triggerNamespace = false; - $paramNestingLevel = $currentParamNestingLevel = 0; foreach ($tokens as $key => $token) { - if ($token == '{') { - return $classes; - } + + // The namespace keyword was found in the last loop if ($triggerNamespace) { if (is_array($token)) { $namespace .= $token[1]; } else { - $currentParamNestingLevel = $paramNestingLevel; $triggerNamespace = false; $namespace .= '\\'; continue; } + // The class keyword was found in the last loop } else if ($triggerClass && $token[0] == T_STRING) { $triggerClass = false; $class = $token[1]; } + + // Current loop contains the namespace keyword. Between this and the semicolon is the namespace if ($token[0] == T_NAMESPACE) { $triggerNamespace = true; - } else if ($token[0] == T_CLASS && $currentParamNestingLevel == $paramNestingLevel) { + // Current loop contains the class keyword. Next loop will have the class name itself. + } else if ($token[0] == T_CLASS ) { $triggerClass = true; } - if ($class != '' && $currentParamNestingLevel == $paramNestingLevel) { + + // We have a class name, let's concatenate and store it! + if ($class != '' ) { $namespace = trim($namespace); $fqClassName = $namespace . trim($class); $classes[] = $fqClassName; - $class = ''; - continue; + return $classes; } } - return $classes; + return []; } + /** + * Retrieves the first class found in a class file. The return value is in an array format so it retains the + * same usage as the FileScanner. + * + * @return array + */ + public function getClassNames() { if ($this->classNames === false) { diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/InvalidFileException.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/InvalidFileException.php index 84d8c3f553f35..049381f907d13 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/InvalidFileException.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/InvalidFileException.php @@ -2,4 +2,7 @@ namespace Magento\Setup\Module\Di\Code\Reader; -class InvalidFileException extends \InvalidArgumentException {} +class InvalidFileException extends \InvalidArgumentException +{ + +} diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php index 3fb5470407d98..d1642d539ac80 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php @@ -9,7 +9,6 @@ use Magento\Setup\Module\Di\Code\Reader\FileClassScanner; use Magento\Setup\Module\Di\Code\Reader\InvalidFileException; -use Magento\Setup\Test\Unit\Module\Di\Compiler\Config\Chain\PreferencesResolvingTest; class FileClassScannerTest extends \PHPUnit_Framework_TestCase { @@ -25,7 +24,8 @@ public function testEmptyArrayForFileWithoutNamespaceOrClass() $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ 'getFileContents' ])->getMock(); - $scanner->expects(self::once())->method('getFileContents')->willReturn(<<expects(self::once())->method('getFileContents')->willReturn( +<<getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ 'getFileContents' ])->getMock(); - $scanner->expects(self::once())->method('getFileContents')->willReturn(<<expects(self::once())->method('getFileContents')->willReturn( +<<getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ 'getFileContents' ])->getMock(); - $scanner->expects(self::once())->method('getFileContents')->willReturn(<<expects(self::once())->method('getFileContents')->willReturn( +<<getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ 'getFileContents' ])->getMock(); - $scanner->expects(self::once())->method('getFileContents')->willReturn(<<expects(self::once())->method('getFileContents')->willReturn( +<< Date: Thu, 23 Mar 2017 20:04:45 -0500 Subject: [PATCH 13/61] Fixed mess detection issues --- .../Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php index d1642d539ac80..eda436b087d3d 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php @@ -122,7 +122,9 @@ public function test() public function testTheWeirdExceptionCaseThatHappens() { - $filename = __DIR__ . '/../../../../../../../../../../app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/AbstractEav.php'; + $filename = __DIR__ + . '/../../../../../../../../../..' + . '/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/AbstractEav.php'; $filename = realpath($filename); $scanner = new FileClassScanner($filename); $result = $scanner->getClassNames(); @@ -130,5 +132,4 @@ public function testTheWeirdExceptionCaseThatHappens() self::assertCount(1, $result); } - } From bf87fdb8fb2fd81b8175249c7818916556b0e155 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Thu, 23 Mar 2017 20:06:40 -0500 Subject: [PATCH 14/61] Fixed mess detection issues --- .../Setup/Module/Di/Code/Reader/FileClassScanner.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index ef5dd428ac766..bce9cbc6d3369 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -27,10 +27,11 @@ class FileClassScanner /** * Constructor for the file class scanner. Requires the filename - * @param $filename + * + * @param string $filename */ - public function __construct( $filename ) + public function __construct($filename) { $filename = realpath($filename); if (!file_exists($filename) || !\is_file($filename)) { @@ -91,12 +92,12 @@ protected function extract() if ($token[0] == T_NAMESPACE) { $triggerNamespace = true; // Current loop contains the class keyword. Next loop will have the class name itself. - } else if ($token[0] == T_CLASS ) { + } else if ($token[0] == T_CLASS) { $triggerClass = true; } // We have a class name, let's concatenate and store it! - if ($class != '' ) { + if ($class != '') { $namespace = trim($namespace); $fqClassName = $namespace . trim($class); $classes[] = $fqClassName; From dd3f4b5cf7f41fa6a76e69074ab3f5bd2a24a581 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Thu, 23 Mar 2017 21:25:09 -0500 Subject: [PATCH 15/61] Another run at MD and Cyc. Complexity. --- .../Module/Di/Code/Reader/FileClassScanner.php | 17 ++++++++++------- .../Di/Code/Reader/FileClassScannerTest.php | 1 - 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index bce9cbc6d3369..74d0f07f317f1 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -71,7 +71,7 @@ protected function extract() $class = ''; $triggerClass = false; $triggerNamespace = false; - foreach ($tokens as $key => $token) { + foreach ($tokens as $token) { // The namespace keyword was found in the last loop if ($triggerNamespace) { @@ -88,12 +88,15 @@ protected function extract() $class = $token[1]; } - // Current loop contains the namespace keyword. Between this and the semicolon is the namespace - if ($token[0] == T_NAMESPACE) { - $triggerNamespace = true; - // Current loop contains the class keyword. Next loop will have the class name itself. - } else if ($token[0] == T_CLASS) { - $triggerClass = true; + switch ($token[0]) { + case T_NAMESPACE: + // Current loop contains the namespace keyword. Between this and the semicolon is the namespace + $triggerNamespace = true; + break; + case T_CLASS: + // Current loop contains the class keyword. Next loop will have the class name itself. + $triggerClass = true; + break; } // We have a class name, let's concatenate and store it! diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php index eda436b087d3d..dcc100149d96c 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php @@ -131,5 +131,4 @@ public function testTheWeirdExceptionCaseThatHappens() self::assertCount(1, $result); } - } From a8abd1b2d03268be7b6d8d77b59304aaf38b6514 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Fri, 24 Mar 2017 07:44:55 -0500 Subject: [PATCH 16/61] Updated for complexity and an else expression Codacy didn't like --- .../Module/Di/Code/Reader/ClassesScanner.php | 28 +++++++++++-------- .../Di/Code/Reader/FileClassScanner.php | 8 +++--- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 1bc99cf92ee56..9a008d40fa619 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -95,22 +95,26 @@ private function extract(\RecursiveIteratorIterator $recursiveIterator) } $fileScanner = new FileClassScanner($fileItemPath); $classNames = $fileScanner->getClassNames(); - $classExists = false; - if ($classNames) { - foreach ($classNames as $className) { - if (class_exists($className)) { - $classExists = true; - } - } - $classes = array_merge($classes, $classNames); - } - if (!$classExists) { - require_once $fileItemPath; - } + $this->includeClasses($classNames, $fileItemPath); + $classes = array_merge($classes, $classNames); + } return $classes; } + protected function includeClasses(array $classNames, $fileItemPath) + { + $classExists = false; + foreach ($classNames as $className) { + if (class_exists($className)) { + $classExists = true; + } + } + if (!$classExists) { + require_once $fileItemPath; + } + } + /** * Find out if file should be excluded * diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index 74d0f07f317f1..cd9e56c0728f6 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -75,14 +75,14 @@ protected function extract() // The namespace keyword was found in the last loop if ($triggerNamespace) { - if (is_array($token)) { - $namespace .= $token[1]; - } else { + if (!is_array($token)) { $triggerNamespace = false; $namespace .= '\\'; continue; } - // The class keyword was found in the last loop + $namespace .= $token[1]; + + // The class keyword was found in the last loop } else if ($triggerClass && $token[0] == T_STRING) { $triggerClass = false; $class = $token[1]; From c593ef638f1c1b15dfec95ab2c765301f0707a2a Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Fri, 24 Mar 2017 07:45:53 -0500 Subject: [PATCH 17/61] Updated for a code style issue --- .../src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php | 1 - 1 file changed, 1 deletion(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index cd9e56c0728f6..ca4360fee0d50 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -124,5 +124,4 @@ public function getClassNames() } return $this->classNames; } - } From ac8299880d43600531c80ff9f74c87206ce23295 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Fri, 24 Mar 2017 12:15:25 -0500 Subject: [PATCH 18/61] Updated for code review responses, handle namespaces better, and handle some token edge cases --- .../Module/Di/Code/Reader/ClassesScanner.php | 47 +++++-- .../Di/Code/Reader/FileClassScanner.php | 61 +++++++-- .../Di/Code/Reader/ClassesScannerTest.php | 22 +++- .../Di/Code/Reader/FileClassScannerTest.php | 118 +++++++++++++++++- .../Module/Di/_files/var/generation/.keep | 0 5 files changed, 227 insertions(+), 21 deletions(-) create mode 100644 setup/src/Magento/Setup/Test/Unit/Module/Di/_files/var/generation/.keep diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 9a008d40fa619..ecb6ec46fba2f 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -6,6 +6,7 @@ namespace Magento\Setup\Module\Di\Code\Reader; use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Exception\FileSystemException; class ClassesScanner implements ClassesScannerInterface @@ -21,12 +22,29 @@ class ClassesScanner implements ClassesScannerInterface protected $fileResults = []; + /** + * @var string + */ + + protected $generationDirectory; + /** * @param array $excludePatterns */ - public function __construct(array $excludePatterns = []) + public function __construct(array $excludePatterns = [], $generationDirectory = false) { $this->excludePatterns = $excludePatterns; + $this->generationDirectory = $generationDirectory; + } + + public function getGenerationDirectory() + { + if ($this->generationDirectory === false) { + $directoryList = ObjectManager::getInstance()->get(DirectoryList::class); + /* @var $directoryList DirectoryList */ + $this->generationDirectory = $directoryList->getPath(DirectoryList::GENERATION); + } + return $this->generationDirectory; } /** @@ -40,6 +58,19 @@ public function addExcludePatterns(array $excludePatterns) $this->excludePatterns = array_merge($this->excludePatterns, $excludePatterns); } + /** + * Determines if the path provided is in the var/generation folder + * + * @param $path + * @return bool + */ + + public function isGeneration($path) + { + $generation = $this->getGenerationDirectory(); + return strpos($path, $generation) === 0; + } + /** * Retrieves list of classes for given path * @@ -51,7 +82,9 @@ public function getList($path) { $realPath = realpath($path); - $isGeneration = strpos($realPath, DIRECTORY_SEPARATOR . 'generation' . DIRECTORY_SEPARATOR) !== false; + $isGeneration = $this->isGeneration($realPath); + + // Generation folders should not have their results cached since they may actually change during compile if (!$isGeneration) { if (isset($this->fileResults[$realPath])) { return $this->fileResults[$realPath]; @@ -97,22 +130,18 @@ private function extract(\RecursiveIteratorIterator $recursiveIterator) $classNames = $fileScanner->getClassNames(); $this->includeClasses($classNames, $fileItemPath); $classes = array_merge($classes, $classNames); - } return $classes; } protected function includeClasses(array $classNames, $fileItemPath) { - $classExists = false; foreach ($classNames as $className) { - if (class_exists($className)) { - $classExists = true; + if (!class_exists($className)) { + require_once $fileItemPath; + return; } } - if (!$classExists) { - require_once $fileItemPath; - } } /** diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index ca4360fee0d50..2313ebe28b7ac 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -25,6 +25,12 @@ class FileClassScanner protected $classNames = false; + /** + * @var array + */ + + protected $tokens; + /** * Constructor for the file class scanner. Requires the filename * @@ -65,17 +71,27 @@ public function getFileContents() protected function extract() { + $allowedOpenBraces = [T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES, T_STRING_VARNAME]; $classes = []; - $tokens = token_get_all($this->getFileContents()); $namespace = ''; $class = ''; $triggerClass = false; $triggerNamespace = false; - foreach ($tokens as $token) { - + $braceLevel = 0; + $bracedNamespace = false; + + $this->tokens = token_get_all($this->getFileContents()); + foreach ($this->tokens as $index => $token) { + // Is either a literal brace or an interpolated brace + if ($token == '{' || (is_array($token) && in_array($token[0], $allowedOpenBraces))) { + $braceLevel++; + } else if ($token == '}') { + $braceLevel--; + } // The namespace keyword was found in the last loop if ($triggerNamespace) { - if (!is_array($token)) { + // A string ; or a discovered namespace that looks like "namespace name { }" + if (!is_array($token) || ($namespace && $token[0] == T_WHITESPACE)) { $triggerNamespace = false; $namespace .= '\\'; continue; @@ -92,10 +108,14 @@ protected function extract() case T_NAMESPACE: // Current loop contains the namespace keyword. Between this and the semicolon is the namespace $triggerNamespace = true; + $namespace = ''; + $bracedNamespace = $this->isBracedNamespace($index); break; case T_CLASS: // Current loop contains the class keyword. Next loop will have the class name itself. - $triggerClass = true; + if ($braceLevel == 0 || ($bracedNamespace && $braceLevel == 1)) { + $triggerClass = true; + } break; } @@ -104,10 +124,37 @@ protected function extract() $namespace = trim($namespace); $fqClassName = $namespace . trim($class); $classes[] = $fqClassName; - return $classes; + $class = ''; + } + } + return $classes;; + } + + /** + * Looks forward from the current index to determine if the namespace is nested in {} or terminated with ; + * + * @param $index + * @return bool + */ + + protected function isBracedNamespace($index) + { + $len = count($this->tokens); + while ($index++ < $len) { + if (!is_array($this->tokens[$index])) { + if ($this->tokens[$index] == ';') { + return false; + } else if ($this->tokens[$index] == '{') { + return true; + } + continue; + } + + if (!in_array($this->tokens[$index][0], [T_WHITESPACE, T_STRING, T_NS_SEPARATOR])) { + throw new InvalidFileException('Namespace not defined properly'); } } - return []; + throw new InvalidFileException('Could not find namespace termination'); } /** diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php index 89664d70c4a69..61e5527fb8d06 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php @@ -12,9 +12,18 @@ class ClassesScannerTest extends \PHPUnit_Framework_TestCase */ private $model; + /** + * the /var/generation directory realpath + * + * @var string + */ + + private $generation; + protected function setUp() { - $this->model = new \Magento\Setup\Module\Di\Code\Reader\ClassesScanner(); + $this->generation = realpath(__DIR__ . '/../../_files/var/generation'); + $this->model = new \Magento\Setup\Module\Di\Code\Reader\ClassesScanner([], $this->generation); } public function testGetList() @@ -24,4 +33,15 @@ public function testGetList() $this->assertTrue(is_array($actual)); $this->assertCount(5, $actual); } + + public function testIsGenerationIgnoresRegularPath() + { + self::assertFalse($this->model->isGeneration(__DIR__)); + } + + public function testIsGenerationNotesGenerationPath() + { + self::assertTrue($this->model->isGeneration($this->generation)); + } + } diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php index dcc100149d96c..bd65dbad1a16e 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php @@ -96,13 +96,13 @@ public function testGetClassNameAndMultiNamespace() <<getClassNames(); self::assertCount(1, $result); - self::assertContains('This\Is\My\Namespace\ThisIsMyTest', $result); + self::assertContains('This\Is\My\Ns\ThisIsMyTest', $result); } - public function testTheWeirdExceptionCaseThatHappens() + + public function testGetMultiClassNameAndMultiNamespace() + { + $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ + 'getFileContents' + ])->getMock(); + $scanner->expects(self::once())->method('getFileContents')->willReturn( +<<get(\This\Is\Another\Ns::class)->method(); + self:: class; + } + + public function test() + { + + } +} + +class ThisIsForBreaking { + +} + +PHP + ); + /* @var $scanner FileClassScanner */ + + $result = $scanner->getClassNames(); + + self::assertCount(2, $result); + self::assertContains('This\Is\My\Ns\ThisIsMyTest', $result); + self::assertContains('This\Is\My\Ns\ThisIsForBreaking', $result); + } + + public function testBracketedNamespacesAndClasses() + { + $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ + 'getFileContents' + ])->getMock(); + $scanner->expects(self::once())->method('getFileContents')->willReturn( +<<getClassNames(); + + self::assertCount(3, $result); + self::assertContains('This\Is\My\Ns\ThisIsMyTest', $result); + self::assertContains('This\Is\My\Ns\ThisIsForBreaking', $result); + self::assertContains('This\Is\Not\My\Ns\ThisIsNotMyTest', $result); + } + + public function testClassKeywordInMiddleOfFile() { $filename = __DIR__ . '/../../../../../../../../../..' @@ -131,4 +218,27 @@ public function testTheWeirdExceptionCaseThatHappens() self::assertCount(1, $result); } + + public function testInvalidPHPCodeThrowsExceptionWhenCannotDetermineBraceOrSemiColon() + { + $this->setExpectedException(InvalidFileException::class); + $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ + 'getFileContents' + ])->getMock(); + $scanner->expects(self::once())->method('getFileContents')->willReturn( + <<getClassNames(); + } } diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/var/generation/.keep b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/var/generation/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d From 70647be675c1f4e099f7685e73924abc4154cdc6 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Fri, 24 Mar 2017 12:16:30 -0500 Subject: [PATCH 19/61] Updated copyright date --- .../src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index ecb6ec46fba2f..44f0001eec721 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -1,6 +1,6 @@ Date: Fri, 24 Mar 2017 13:16:26 -0500 Subject: [PATCH 20/61] Merged a condition --- .../Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 44f0001eec721..eff71842bcc76 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -85,10 +85,8 @@ public function getList($path) $isGeneration = $this->isGeneration($realPath); // Generation folders should not have their results cached since they may actually change during compile - if (!$isGeneration) { - if (isset($this->fileResults[$realPath])) { - return $this->fileResults[$realPath]; - } + if (!$isGeneration && isset($this->fileResults[$realPath])) { + return $this->fileResults[$realPath]; } if (!(bool)$realPath) { throw new FileSystemException(new \Magento\Framework\Phrase('Invalid path: %1', [$path])); From b8703c4e93aaf91dacb1bb6153c1eb9f84be99c4 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Fri, 24 Mar 2017 13:28:12 -0500 Subject: [PATCH 21/61] Updated code and docs from code mess --- .../Setup/Module/Di/Code/Reader/ClassesScanner.php | 8 +++++--- .../Setup/Module/Di/Code/Reader/FileClassScanner.php | 6 +++--- .../Unit/Module/Di/Code/Reader/ClassesScannerTest.php | 1 - .../Unit/Module/Di/Code/Reader/FileClassScannerTest.php | 1 - 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index eff71842bcc76..c5c947efc8dac 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -30,8 +30,10 @@ class ClassesScanner implements ClassesScannerInterface /** * @param array $excludePatterns + * @param string $generationDirectory */ - public function __construct(array $excludePatterns = [], $generationDirectory = false) + + public function __construct(array $excludePatterns = [], $generationDirectory = null) { $this->excludePatterns = $excludePatterns; $this->generationDirectory = $generationDirectory; @@ -39,7 +41,7 @@ public function __construct(array $excludePatterns = [], $generationDirectory = public function getGenerationDirectory() { - if ($this->generationDirectory === false) { + if ($this->generationDirectory === null) { $directoryList = ObjectManager::getInstance()->get(DirectoryList::class); /* @var $directoryList DirectoryList */ $this->generationDirectory = $directoryList->getPath(DirectoryList::GENERATION); @@ -61,7 +63,7 @@ public function addExcludePatterns(array $excludePatterns) /** * Determines if the path provided is in the var/generation folder * - * @param $path + * @param string $path * @return bool */ diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index 2313ebe28b7ac..10d0e85a96d1c 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -82,7 +82,7 @@ protected function extract() $this->tokens = token_get_all($this->getFileContents()); foreach ($this->tokens as $index => $token) { - // Is either a literal brace or an interpolated brace + // Is either a literal brace or an interpolated brace with a variable if ($token == '{' || (is_array($token) && in_array($token[0], $allowedOpenBraces))) { $braceLevel++; } else if ($token == '}') { @@ -127,13 +127,13 @@ protected function extract() $class = ''; } } - return $classes;; + return $classes; } /** * Looks forward from the current index to determine if the namespace is nested in {} or terminated with ; * - * @param $index + * @param integer $index * @return bool */ diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php index 61e5527fb8d06..a8c25f7bfea1e 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php @@ -43,5 +43,4 @@ public function testIsGenerationNotesGenerationPath() { self::assertTrue($this->model->isGeneration($this->generation)); } - } diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php index bd65dbad1a16e..d2ba088b01e5e 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php @@ -120,7 +120,6 @@ public function test() self::assertContains('This\Is\My\Ns\ThisIsMyTest', $result); } - public function testGetMultiClassNameAndMultiNamespace() { $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ From ea907205c027037b1af67604f0281d72721d61fe Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Fri, 24 Mar 2017 16:52:48 -0500 Subject: [PATCH 22/61] Disabled CyclomaticComplexity check. This code is sometimes called multiple 10's of millions of times so micro-optimizations are the name of the game here. --- .../src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php | 1 + 1 file changed, 1 insertion(+) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index 10d0e85a96d1c..ae3608db9d335 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -66,6 +66,7 @@ public function getFileContents() * Extracts the fully qualified class name from a file. It only searches for the first match and stops looking * as soon as it enters the class definition itself. * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @return array */ From 5fc1ea5044823ec72292a8f7e13ebbcc9a9d2f8c Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Fri, 24 Mar 2017 16:53:49 -0500 Subject: [PATCH 23/61] Disabled CyclomaticComplexity check. This code is sometimes called multiple 10's of millions of times so micro-optimizations are the name of the game here. --- .../src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php | 1 + 1 file changed, 1 insertion(+) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index ae3608db9d335..12dcaa02d95ea 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -67,6 +67,7 @@ public function getFileContents() * as soon as it enters the class definition itself. * * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) * @return array */ From dc61477c712a9988afe522571cb12634d37af1ff Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Mon, 27 Mar 2017 08:31:01 -0500 Subject: [PATCH 24/61] Updated some MD and code review recommendations --- .../Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 6 ++++++ .../Setup/Module/Di/Code/Reader/FileClassScanner.php | 3 +++ 2 files changed, 9 insertions(+) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index c5c947efc8dac..d8144a7e511f9 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -39,6 +39,12 @@ public function __construct(array $excludePatterns = [], $generationDirectory = $this->generationDirectory = $generationDirectory; } + /** + * Retrieves the fully qualified path for var/generation. + * + * @return string + */ + public function getGenerationDirectory() { if ($this->generationDirectory === null) { diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index 12dcaa02d95ea..ce47a2f1d86c3 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -66,6 +66,9 @@ public function getFileContents() * Extracts the fully qualified class name from a file. It only searches for the first match and stops looking * as soon as it enters the class definition itself. * + * Warnings are suppressed for this method due to a micro-optimization that only really shows up when this logic + * is called several millions of times, which can happen quite easily with even moderately sized codebases. + * * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) * @return array From b1ba44603fc07cd8bdd860756858177ad41b5007 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Mon, 27 Mar 2017 09:29:27 -0500 Subject: [PATCH 25/61] Updated to follow @schmengler's recommendation --- .../Module/Di/Code/Reader/ClassesScanner.php | 23 ++++--------------- .../Di/Code/Reader/ClassesScannerTest.php | 8 ++++++- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index d8144a7e511f9..2713c1a31af3f 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -33,28 +33,16 @@ class ClassesScanner implements ClassesScannerInterface * @param string $generationDirectory */ - public function __construct(array $excludePatterns = [], $generationDirectory = null) + public function __construct(array $excludePatterns = [], DirectoryList $directoryList = null) { $this->excludePatterns = $excludePatterns; - $this->generationDirectory = $generationDirectory; - } - - /** - * Retrieves the fully qualified path for var/generation. - * - * @return string - */ - - public function getGenerationDirectory() - { - if ($this->generationDirectory === null) { + if (!$directoryList instanceof DirectoryList) { $directoryList = ObjectManager::getInstance()->get(DirectoryList::class); - /* @var $directoryList DirectoryList */ - $this->generationDirectory = $directoryList->getPath(DirectoryList::GENERATION); } - return $this->generationDirectory; + $this->generationDirectory = $directoryList->getPath(DirectoryList::GENERATION); } + /** * Adds exclude patterns * @@ -75,8 +63,7 @@ public function addExcludePatterns(array $excludePatterns) public function isGeneration($path) { - $generation = $this->getGenerationDirectory(); - return strpos($path, $generation) === 0; + return strpos($path, $this->generationDirectory) === 0; } /** diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php index a8c25f7bfea1e..b68178ef85b38 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php @@ -5,6 +5,8 @@ */ namespace Magento\Setup\Test\Unit\Module\Di\Code\Reader; +use Magento\Framework\App\Filesystem\DirectoryList; + class ClassesScannerTest extends \PHPUnit_Framework_TestCase { /** @@ -23,7 +25,11 @@ class ClassesScannerTest extends \PHPUnit_Framework_TestCase protected function setUp() { $this->generation = realpath(__DIR__ . '/../../_files/var/generation'); - $this->model = new \Magento\Setup\Module\Di\Code\Reader\ClassesScanner([], $this->generation); + $mock = $this->getMockBuilder(DirectoryList::class)->disableOriginalConstructor()->setMethods( + ['getPath'] + )->getMock(); + $mock->method('getPath')->willReturn($this->generation); + $this->model = new \Magento\Setup\Module\Di\Code\Reader\ClassesScanner([], $mock); } public function testGetList() From 7f9d3fe1c577e4828cf425344c3e9d63d1d1a357 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Mon, 27 Mar 2017 10:31:34 -0500 Subject: [PATCH 26/61] Updated based on recommendations --- .../Module/Di/Code/Reader/ClassesScanner.php | 18 +++--------------- .../Module/Di/Code/Reader/FileClassScanner.php | 6 +++--- .../Di/Code/Reader/ClassesScannerTest.php | 10 ---------- .../Di/Code/Reader/FileClassScannerTest.php | 14 +++++++------- 4 files changed, 13 insertions(+), 35 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 2713c1a31af3f..a28b8aeb9bdbe 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -20,13 +20,13 @@ class ClassesScanner implements ClassesScannerInterface * @var array */ - protected $fileResults = []; + private $fileResults = []; /** * @var string */ - protected $generationDirectory; + private $generationDirectory; /** * @param array $excludePatterns @@ -54,18 +54,6 @@ public function addExcludePatterns(array $excludePatterns) $this->excludePatterns = array_merge($this->excludePatterns, $excludePatterns); } - /** - * Determines if the path provided is in the var/generation folder - * - * @param string $path - * @return bool - */ - - public function isGeneration($path) - { - return strpos($path, $this->generationDirectory) === 0; - } - /** * Retrieves list of classes for given path * @@ -77,7 +65,7 @@ public function getList($path) { $realPath = realpath($path); - $isGeneration = $this->isGeneration($realPath); + $isGeneration = strpos($realPath, $this->generationDirectory) === 0; // Generation folders should not have their results cached since they may actually change during compile if (!$isGeneration && isset($this->fileResults[$realPath])) { diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index ce47a2f1d86c3..560d3ef63429f 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -15,7 +15,7 @@ class FileClassScanner * @var string */ - protected $filename; + private $filename; /** * The list of classes found in the file. @@ -23,13 +23,13 @@ class FileClassScanner * @var bool */ - protected $classNames = false; + private $classNames = false; /** * @var array */ - protected $tokens; + private $tokens; /** * Constructor for the file class scanner. Requires the filename diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php index b68178ef85b38..1448a757f669b 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php @@ -39,14 +39,4 @@ public function testGetList() $this->assertTrue(is_array($actual)); $this->assertCount(5, $actual); } - - public function testIsGenerationIgnoresRegularPath() - { - self::assertFalse($this->model->isGeneration(__DIR__)); - } - - public function testIsGenerationNotesGenerationPath() - { - self::assertTrue($this->model->isGeneration($this->generation)); - } } diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php index d2ba088b01e5e..66d7dc4a20a9c 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php @@ -35,7 +35,7 @@ public function testEmptyArrayForFileWithoutNamespaceOrClass() } PHP ); - /* @var $scanner FileClassScanner */ + /** @var $scanner FileClassScanner */ $result = $scanner->getClassNames(); self::assertCount(0, $result); @@ -55,7 +55,7 @@ class ThisIsATest { } PHP ); - /* @var $scanner FileClassScanner */ + /** @var $scanner FileClassScanner */ $result = $scanner->getClassNames(); @@ -79,7 +79,7 @@ class ThisIsMyTest { } PHP ); - /* @var $scanner FileClassScanner */ + /** @var $scanner FileClassScanner */ $result = $scanner->getClassNames(); @@ -112,7 +112,7 @@ public function test() } PHP ); - /* @var $scanner FileClassScanner */ + /** @var $scanner FileClassScanner */ $result = $scanner->getClassNames(); @@ -151,7 +151,7 @@ class ThisIsForBreaking { PHP ); - /* @var $scanner FileClassScanner */ + /** @var $scanner FileClassScanner */ $result = $scanner->getClassNames(); @@ -196,7 +196,7 @@ class ThisIsNotMyTest PHP ); - /* @var $scanner FileClassScanner */ + /** @var $scanner FileClassScanner */ $result = $scanner->getClassNames(); @@ -236,7 +236,7 @@ class ThisIsMyTest PHP ); - /* @var $scanner FileClassScanner */ + /** @var $scanner FileClassScanner */ $scanner->getClassNames(); } From 5df626c07fe0f540e08e2ecdbdc00d02fcd7468a Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Wed, 29 Mar 2017 08:40:02 -0500 Subject: [PATCH 27/61] Removed a line --- setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 1 - 1 file changed, 1 deletion(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index a28b8aeb9bdbe..c6450c22c7d59 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -42,7 +42,6 @@ public function __construct(array $excludePatterns = [], DirectoryList $director $this->generationDirectory = $directoryList->getPath(DirectoryList::GENERATION); } - /** * Adds exclude patterns * From f2f6b0a2376765e08b94fbb7074949d68d74871f Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Tue, 21 Mar 2017 15:28:14 -0500 Subject: [PATCH 28/61] Updated the class scanner so it calls SplFileInfo::realpath() only once in a loop instead of several times. This can have a significant performance impact on large codebases.or slow filesystems. --- .../Setup/Module/Di/Code/Reader/ClassesScanner.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 1528a48dd2b33..d11536f52bf4c 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -58,19 +58,20 @@ public function getList($path) if ($fileItem->isDir() || $fileItem->getExtension() !== 'php') { continue; } + $fileItemPath = $fileItem->getRealPath(); foreach ($this->excludePatterns as $excludePatterns) { - if ($this->isExclude($fileItem, $excludePatterns)) { + if ($this->isExclude($fileItemPath, $excludePatterns)) { continue 2; } } - $fileScanner = new FileScanner($fileItem->getRealPath()); + $fileScanner = new FileScanner($fileItemPath); $classNames = $fileScanner->getClassNames(); foreach ($classNames as $className) { if (empty($className)) { continue; } if (!class_exists($className)) { - require_once $fileItem->getRealPath(); + require_once $fileItemPath; } $classes[] = $className; } @@ -81,17 +82,17 @@ public function getList($path) /** * Find out if file should be excluded * - * @param \SplFileInfo $fileItem + * @param string $fileItem * @param string $patterns * @return bool */ - private function isExclude(\SplFileInfo $fileItem, $patterns) + private function isExclude($fileItemPath, $patterns) { if (!is_array($patterns)) { $patterns = (array)$patterns; } foreach ($patterns as $pattern) { - if (preg_match($pattern, str_replace('\\', '/', $fileItem->getRealPath()))) { + if (preg_match($pattern, str_replace('\\', '/', $fileItemPath))) { return true; } } From bc74883cf55f97f2e4c4e1959bd0d000fa2dd26e Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Tue, 21 Mar 2017 16:55:25 -0500 Subject: [PATCH 29/61] Updated the class scanner to reduce cyclomatic complexity. --- .../Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index d11536f52bf4c..cc72b32e681d7 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -52,6 +52,12 @@ public function getList($path) \RecursiveIteratorIterator::SELF_FIRST ); + $classes = $this->extract($recursiveIterator); + return $classes; + } + + private function extract($recursiveIterator) + { $classes = []; foreach ($recursiveIterator as $fileItem) { /** @var $fileItem \SplFileInfo */ From 1bafd4abb7e3e5f06f19835958f1118a879ce5f0 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Tue, 21 Mar 2017 17:37:59 -0500 Subject: [PATCH 30/61] Stupid cyclomatic complexity tests for stupid missing function doc comments --- .../Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index cc72b32e681d7..9e97729022688 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -56,6 +56,13 @@ public function getList($path) return $classes; } + /** + * Extracts all the classes from the recursive iterator + * + * @param $recursiveIterator + * @return array + */ + private function extract($recursiveIterator) { $classes = []; From be9b572a6f95f69e81aff1eb482afece80da164a Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Tue, 21 Mar 2017 20:48:06 -0500 Subject: [PATCH 31/61] Fixed some PHPDoc mixups --- .../Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 9e97729022688..5f63e72fc2997 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -59,11 +59,11 @@ public function getList($path) /** * Extracts all the classes from the recursive iterator * - * @param $recursiveIterator + * @param \RecursiveIteratorIterator $recursiveIterator * @return array */ - private function extract($recursiveIterator) + private function extract(\RecursiveIteratorIterator $recursiveIterator) { $classes = []; foreach ($recursiveIterator as $fileItem) { @@ -95,7 +95,7 @@ private function extract($recursiveIterator) /** * Find out if file should be excluded * - * @param string $fileItem + * @param string $fileItemPath * @param string $patterns * @return bool */ From 5ff09a7ac9cda625875ccf22b765d53931d4cb28 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Tue, 21 Mar 2017 15:28:14 -0500 Subject: [PATCH 32/61] Updated the class scanner so it calls SplFileInfo::realpath() only once in a loop instead of several times. This can have a significant performance impact on large codebases.or slow filesystems. --- .../Module/Di/Code/Reader/ClassesScanner.php | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 5f63e72fc2997..5cb1d98262213 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -1,6 +1,6 @@ extract($recursiveIterator); - return $classes; - } - - /** - * Extracts all the classes from the recursive iterator - * - * @param \RecursiveIteratorIterator $recursiveIterator - * @return array - */ - - private function extract(\RecursiveIteratorIterator $recursiveIterator) - { $classes = []; foreach ($recursiveIterator as $fileItem) { /** @var $fileItem \SplFileInfo */ @@ -95,7 +82,7 @@ private function extract(\RecursiveIteratorIterator $recursiveIterator) /** * Find out if file should be excluded * - * @param string $fileItemPath + * @param string $fileItem * @param string $patterns * @return bool */ From 28cec245360b0d5ce6c8ba6ba1807714a09729de Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Tue, 21 Mar 2017 16:55:25 -0500 Subject: [PATCH 33/61] Updated the class scanner to reduce cyclomatic complexity. --- .../Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 5cb1d98262213..f7cf057e31c7f 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -52,6 +52,12 @@ public function getList($path) \RecursiveIteratorIterator::SELF_FIRST ); + $classes = $this->extract($recursiveIterator); + return $classes; + } + + private function extract($recursiveIterator) + { $classes = []; foreach ($recursiveIterator as $fileItem) { /** @var $fileItem \SplFileInfo */ From 4b96b47b9eb4418e976214ecfb8cd94d0f79065d Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Tue, 21 Mar 2017 17:37:59 -0500 Subject: [PATCH 34/61] Stupid cyclomatic complexity tests for stupid missing function doc comments --- .../Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index f7cf057e31c7f..eeed41a11610d 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -56,6 +56,13 @@ public function getList($path) return $classes; } + /** + * Extracts all the classes from the recursive iterator + * + * @param $recursiveIterator + * @return array + */ + private function extract($recursiveIterator) { $classes = []; From f4c174f48cfad2ffcb018821b0cd2578d0ed1fff Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Tue, 21 Mar 2017 20:48:06 -0500 Subject: [PATCH 35/61] Fixed some PHPDoc mixups --- .../Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index eeed41a11610d..a38c9db9eef5f 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -59,11 +59,11 @@ public function getList($path) /** * Extracts all the classes from the recursive iterator * - * @param $recursiveIterator + * @param \RecursiveIteratorIterator $recursiveIterator * @return array */ - private function extract($recursiveIterator) + private function extract(\RecursiveIteratorIterator $recursiveIterator) { $classes = []; foreach ($recursiveIterator as $fileItem) { @@ -95,7 +95,7 @@ private function extract($recursiveIterator) /** * Find out if file should be excluded * - * @param string $fileItem + * @param string $fileItemPath * @param string $patterns * @return bool */ From 3375612ecdfcafd21885c22cebc45197bd742905 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Thu, 23 Mar 2017 16:50:48 -0500 Subject: [PATCH 36/61] Added a FileClassScanner which uses the tokenizer to extract only the class names. It's like FileScanner except it only cares about namespaces and classes. --- .../Module/Di/Code/Reader/ClassesScanner.php | 12 +- .../Di/Code/Reader/FileClassScanner.php | 90 ++++++++++ .../Di/Code/Reader/InvalidFileException.php | 5 + .../Di/Code/Reader/FileClassScannerTest.php | 159 ++++++++++++++++++ 4 files changed, 257 insertions(+), 9 deletions(-) create mode 100644 setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php create mode 100644 setup/src/Magento/Setup/Module/Di/Code/Reader/InvalidFileException.php create mode 100644 setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index a38c9db9eef5f..6529199e417aa 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -77,16 +77,10 @@ private function extract(\RecursiveIteratorIterator $recursiveIterator) continue 2; } } - $fileScanner = new FileScanner($fileItemPath); + $fileScanner = new FileClassScanner($fileItemPath); $classNames = $fileScanner->getClassNames(); - foreach ($classNames as $className) { - if (empty($className)) { - continue; - } - if (!class_exists($className)) { - require_once $fileItemPath; - } - $classes[] = $className; + if ($classNames) { + $classes = array_merge($classes, $classNames); } } return $classes; diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php new file mode 100644 index 0000000000000..de9ac920c7ffd --- /dev/null +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -0,0 +1,90 @@ +filename = $filename; + } + + public function getFileContents() + { + return file_get_contents($this->filename); + } + + protected function extract() + { + $classes = []; + $tokens = token_get_all($this->getFileContents()); + $namespace = ''; + $class = ''; + $triggerClass = false; + $triggerNamespace = false; + $paramNestingLevel = $currentParamNestingLevel = 0; + foreach ($tokens as $key => $token) { + if (!is_array($token)) { + if ($token == '{') { + $paramNestingLevel++; + } else if ($token == '}') { + $paramNestingLevel--; + } + } + if ($triggerNamespace) { + if (is_array($token)) { + $namespace .= $token[1]; + } else { + $currentParamNestingLevel = $paramNestingLevel; + $triggerNamespace = false; + $namespace .= '\\'; + continue; + } + } else if ($triggerClass && $token[0] == T_STRING) { + $triggerClass = false; + $class = $token[1]; + } + if ($token[0] == T_NAMESPACE) { + $triggerNamespace = true; + } else if ($token[0] == T_CLASS && $currentParamNestingLevel == $paramNestingLevel) { + $triggerClass = true; + } + if ($class != '' && $currentParamNestingLevel == $paramNestingLevel) { + $namespace = trim($namespace); + $fqClassName = $namespace . trim($class); + $classes[] = $fqClassName; + $class = ''; + continue; + } + } + return $classes; + } + + public function getClassNames() + { + if ($this->classNames === false) { + $this->classNames = $this->extract(); + } + return $this->classNames; + } + + +} diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/InvalidFileException.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/InvalidFileException.php new file mode 100644 index 0000000000000..84d8c3f553f35 --- /dev/null +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/InvalidFileException.php @@ -0,0 +1,5 @@ +setExpectedException(InvalidFileException::class); + new FileClassScanner(false); + } + + public function testEmptyArrayForFileWithoutNamespaceOrClass() + { + $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ + 'getFileContents' + ])->getMock(); + $scanner->expects(self::once())->method('getFileContents')->willReturn(<<getClassNames(); + self::assertCount(0, $result); + } + + public function testGetClassName() + { + $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ + 'getFileContents' + ])->getMock(); + $scanner->expects(self::once())->method('getFileContents')->willReturn(<<getClassNames(); + + self::assertCount(1, $result); + self::assertContains('ThisIsATest', $result); + } + + public function testGetClassNameAndSingleNamespace() + { + $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ + 'getFileContents' + ])->getMock(); + $scanner->expects(self::once())->method('getFileContents')->willReturn(<<getClassNames(); + + self::assertCount(1, $result); + self::assertContains('NS\ThisIsMyTest', $result); + } + + public function testGetClassNameAndMultiNamespace() + { + $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ + 'getFileContents' + ])->getMock(); + $scanner->expects(self::once())->method('getFileContents')->willReturn(<<getClassNames(); + + self::assertCount(1, $result); + self::assertContains('This\Is\My\Namespace\ThisIsMyTest', $result); + } + public function testGetMultipleClassesInMultiNamespace() + { + $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ + 'getFileContents' + ])->getMock(); + $scanner->expects(self::once())->method('getFileContents')->willReturn(<<getClassNames(); + + self::assertCount(2, $result); + self::assertContains('This\Is\My\Namespace\ThisIsMyTest', $result); + self::assertContains('This\Is\My\Namespace\ThisIsAnotherTest', $result); + } + + +} From 4e8d1d612a98cbe35e7782faba5c0609935a1c2a Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Thu, 23 Mar 2017 18:37:01 -0500 Subject: [PATCH 37/61] Fixed an issue with the FileClassScanner not liking one case when the word "class" was in a class. This change will now only return the Namespace\Class up until the first {. Given that there should only be one class per file this should have no effect beyond reducing the potential for problems. --- .../Di/Code/Reader/FileClassScanner.php | 10 ++--- .../Di/Code/Reader/FileClassScannerTest.php | 37 +++---------------- 2 files changed, 8 insertions(+), 39 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index de9ac920c7ffd..ff564a8f5277e 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -12,6 +12,7 @@ class FileClassScanner protected $filename; protected $classNames = false; + protected $tokens; public function __construct( $filename ) { @@ -42,12 +43,8 @@ protected function extract() $triggerNamespace = false; $paramNestingLevel = $currentParamNestingLevel = 0; foreach ($tokens as $key => $token) { - if (!is_array($token)) { - if ($token == '{') { - $paramNestingLevel++; - } else if ($token == '}') { - $paramNestingLevel--; - } + if ($token == '{') { + return $classes; } if ($triggerNamespace) { if (is_array($token)) { @@ -86,5 +83,4 @@ public function getClassNames() return $this->classNames; } - } diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php index ecefbf5f0468d..3fb5470407d98 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php @@ -117,42 +117,15 @@ public function test() self::assertCount(1, $result); self::assertContains('This\Is\My\Namespace\ThisIsMyTest', $result); } - public function testGetMultipleClassesInMultiNamespace() - { - $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ - 'getFileContents' - ])->getMock(); - $scanner->expects(self::once())->method('getFileContents')->willReturn(<<getClassNames(); - self::assertCount(2, $result); - self::assertContains('This\Is\My\Namespace\ThisIsMyTest', $result); - self::assertContains('This\Is\My\Namespace\ThisIsAnotherTest', $result); + self::assertCount(1, $result); } From 4ee5b06e126f4274b78fc083340e5fb6c2cc203b Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Thu, 23 Mar 2017 18:52:53 -0500 Subject: [PATCH 38/61] This includes a cache for class results because the individual class structures are scanned five times over the course of compilation. /var/generation is excluded. --- .../Module/Di/Code/Reader/ClassesScanner.php | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 6529199e417aa..3deb0edb30af9 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -5,8 +5,8 @@ */ namespace Magento\Setup\Module\Di\Code\Reader; +use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Exception\FileSystemException; -use Magento\Setup\Module\Di\Code\Reader\FileScanner; class ClassesScanner implements ClassesScannerInterface { @@ -16,11 +16,25 @@ class ClassesScanner implements ClassesScannerInterface protected $excludePatterns = []; /** + * @var array + */ + + protected $fileResults = []; + + /** + * @var DirectoryList + */ + + protected $directoryList; + + /** + * @param DirectoryList $directoryList * @param array $excludePatterns */ - public function __construct(array $excludePatterns = []) + public function __construct(DirectoryList $directoryList, array $excludePatterns = []) { $this->excludePatterns = $excludePatterns; + $this->directoryList = $directoryList; } /** @@ -43,7 +57,14 @@ public function addExcludePatterns(array $excludePatterns) */ public function getList($path) { + $generation = $this->directoryList->getPath(DirectoryList::GENERATION); $realPath = realpath($path); + $isGeneration = strpos($realPath, $generation) !== false; + if (!$isGeneration) { + if (isset($this->fileResults[$realPath])) { + return $this->fileResults[$realPath]; + } + } if (!(bool)$realPath) { throw new FileSystemException(new \Magento\Framework\Phrase('Invalid path: %1', [$path])); } @@ -53,6 +74,9 @@ public function getList($path) ); $classes = $this->extract($recursiveIterator); + if (!$isGeneration) { + $this->fileResults[$realPath] = $classes; + } return $classes; } @@ -79,9 +103,18 @@ private function extract(\RecursiveIteratorIterator $recursiveIterator) } $fileScanner = new FileClassScanner($fileItemPath); $classNames = $fileScanner->getClassNames(); + $classExists = false; if ($classNames) { + foreach ($classNames as $className) { + if (class_exists($className)) { + $classExists = true; + } + } $classes = array_merge($classes, $classNames); } + if (!$classExists) { + require_once $fileItemPath; + } } return $classes; } From aac32a01bb2c0bd08dcdc3f9047261286263f52e Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Thu, 23 Mar 2017 19:08:11 -0500 Subject: [PATCH 39/61] Fixed some mess detection issues. Removed the DirectoryList dependency so other unit tests wouldn't break. It just checks to see if /generation/ is in the filename, --- .../Module/Di/Code/Reader/ClassesScanner.php | 14 +---- .../Di/Code/Reader/FileClassScanner.php | 60 +++++++++++++++---- .../Di/Code/Reader/InvalidFileException.php | 5 +- .../Di/Code/Reader/FileClassScannerTest.php | 14 +++-- 4 files changed, 64 insertions(+), 29 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 3deb0edb30af9..1bc99cf92ee56 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -22,19 +22,11 @@ class ClassesScanner implements ClassesScannerInterface protected $fileResults = []; /** - * @var DirectoryList - */ - - protected $directoryList; - - /** - * @param DirectoryList $directoryList * @param array $excludePatterns */ - public function __construct(DirectoryList $directoryList, array $excludePatterns = []) + public function __construct(array $excludePatterns = []) { $this->excludePatterns = $excludePatterns; - $this->directoryList = $directoryList; } /** @@ -57,9 +49,9 @@ public function addExcludePatterns(array $excludePatterns) */ public function getList($path) { - $generation = $this->directoryList->getPath(DirectoryList::GENERATION); + $realPath = realpath($path); - $isGeneration = strpos($realPath, $generation) !== false; + $isGeneration = strpos($realPath, DIRECTORY_SEPARATOR . 'generation' . DIRECTORY_SEPARATOR) !== false; if (!$isGeneration) { if (isset($this->fileResults[$realPath])) { return $this->fileResults[$realPath]; diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index ff564a8f5277e..ef5dd428ac766 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -9,10 +9,26 @@ class FileClassScanner { + /** + * The filename of the file to introspect + * + * @var string + */ protected $filename; + + /** + * The list of classes found in the file. + * + * @var bool + */ + protected $classNames = false; - protected $tokens; + + /** + * Constructor for the file class scanner. Requires the filename + * @param $filename + */ public function __construct( $filename ) { @@ -28,11 +44,24 @@ public function __construct( $filename ) $this->filename = $filename; } + /** + * Retrieves the contents of a file. Mostly here for Mock injection + * + * @return string + */ + public function getFileContents() { return file_get_contents($this->filename); } + /** + * Extracts the fully qualified class name from a file. It only searches for the first match and stops looking + * as soon as it enters the class definition itself. + * + * @return array + */ + protected function extract() { $classes = []; @@ -41,40 +70,49 @@ protected function extract() $class = ''; $triggerClass = false; $triggerNamespace = false; - $paramNestingLevel = $currentParamNestingLevel = 0; foreach ($tokens as $key => $token) { - if ($token == '{') { - return $classes; - } + + // The namespace keyword was found in the last loop if ($triggerNamespace) { if (is_array($token)) { $namespace .= $token[1]; } else { - $currentParamNestingLevel = $paramNestingLevel; $triggerNamespace = false; $namespace .= '\\'; continue; } + // The class keyword was found in the last loop } else if ($triggerClass && $token[0] == T_STRING) { $triggerClass = false; $class = $token[1]; } + + // Current loop contains the namespace keyword. Between this and the semicolon is the namespace if ($token[0] == T_NAMESPACE) { $triggerNamespace = true; - } else if ($token[0] == T_CLASS && $currentParamNestingLevel == $paramNestingLevel) { + // Current loop contains the class keyword. Next loop will have the class name itself. + } else if ($token[0] == T_CLASS ) { $triggerClass = true; } - if ($class != '' && $currentParamNestingLevel == $paramNestingLevel) { + + // We have a class name, let's concatenate and store it! + if ($class != '' ) { $namespace = trim($namespace); $fqClassName = $namespace . trim($class); $classes[] = $fqClassName; - $class = ''; - continue; + return $classes; } } - return $classes; + return []; } + /** + * Retrieves the first class found in a class file. The return value is in an array format so it retains the + * same usage as the FileScanner. + * + * @return array + */ + public function getClassNames() { if ($this->classNames === false) { diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/InvalidFileException.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/InvalidFileException.php index 84d8c3f553f35..049381f907d13 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/InvalidFileException.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/InvalidFileException.php @@ -2,4 +2,7 @@ namespace Magento\Setup\Module\Di\Code\Reader; -class InvalidFileException extends \InvalidArgumentException {} +class InvalidFileException extends \InvalidArgumentException +{ + +} diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php index 3fb5470407d98..d1642d539ac80 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php @@ -9,7 +9,6 @@ use Magento\Setup\Module\Di\Code\Reader\FileClassScanner; use Magento\Setup\Module\Di\Code\Reader\InvalidFileException; -use Magento\Setup\Test\Unit\Module\Di\Compiler\Config\Chain\PreferencesResolvingTest; class FileClassScannerTest extends \PHPUnit_Framework_TestCase { @@ -25,7 +24,8 @@ public function testEmptyArrayForFileWithoutNamespaceOrClass() $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ 'getFileContents' ])->getMock(); - $scanner->expects(self::once())->method('getFileContents')->willReturn(<<expects(self::once())->method('getFileContents')->willReturn( +<<getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ 'getFileContents' ])->getMock(); - $scanner->expects(self::once())->method('getFileContents')->willReturn(<<expects(self::once())->method('getFileContents')->willReturn( +<<getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ 'getFileContents' ])->getMock(); - $scanner->expects(self::once())->method('getFileContents')->willReturn(<<expects(self::once())->method('getFileContents')->willReturn( +<<getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ 'getFileContents' ])->getMock(); - $scanner->expects(self::once())->method('getFileContents')->willReturn(<<expects(self::once())->method('getFileContents')->willReturn( +<< Date: Thu, 23 Mar 2017 20:04:45 -0500 Subject: [PATCH 40/61] Fixed mess detection issues --- .../Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php index d1642d539ac80..eda436b087d3d 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php @@ -122,7 +122,9 @@ public function test() public function testTheWeirdExceptionCaseThatHappens() { - $filename = __DIR__ . '/../../../../../../../../../../app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/AbstractEav.php'; + $filename = __DIR__ + . '/../../../../../../../../../..' + . '/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/AbstractEav.php'; $filename = realpath($filename); $scanner = new FileClassScanner($filename); $result = $scanner->getClassNames(); @@ -130,5 +132,4 @@ public function testTheWeirdExceptionCaseThatHappens() self::assertCount(1, $result); } - } From bb7f32a2060af83dce6ee0f4933b787fe6aab8be Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Thu, 23 Mar 2017 20:06:40 -0500 Subject: [PATCH 41/61] Fixed mess detection issues --- .../Setup/Module/Di/Code/Reader/FileClassScanner.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index ef5dd428ac766..bce9cbc6d3369 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -27,10 +27,11 @@ class FileClassScanner /** * Constructor for the file class scanner. Requires the filename - * @param $filename + * + * @param string $filename */ - public function __construct( $filename ) + public function __construct($filename) { $filename = realpath($filename); if (!file_exists($filename) || !\is_file($filename)) { @@ -91,12 +92,12 @@ protected function extract() if ($token[0] == T_NAMESPACE) { $triggerNamespace = true; // Current loop contains the class keyword. Next loop will have the class name itself. - } else if ($token[0] == T_CLASS ) { + } else if ($token[0] == T_CLASS) { $triggerClass = true; } // We have a class name, let's concatenate and store it! - if ($class != '' ) { + if ($class != '') { $namespace = trim($namespace); $fqClassName = $namespace . trim($class); $classes[] = $fqClassName; From 489838409d3c3d7b437ad4464a7ceb0873842bb6 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Thu, 23 Mar 2017 21:25:09 -0500 Subject: [PATCH 42/61] Another run at MD and Cyc. Complexity. --- .../Module/Di/Code/Reader/FileClassScanner.php | 17 ++++++++++------- .../Di/Code/Reader/FileClassScannerTest.php | 1 - 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index bce9cbc6d3369..74d0f07f317f1 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -71,7 +71,7 @@ protected function extract() $class = ''; $triggerClass = false; $triggerNamespace = false; - foreach ($tokens as $key => $token) { + foreach ($tokens as $token) { // The namespace keyword was found in the last loop if ($triggerNamespace) { @@ -88,12 +88,15 @@ protected function extract() $class = $token[1]; } - // Current loop contains the namespace keyword. Between this and the semicolon is the namespace - if ($token[0] == T_NAMESPACE) { - $triggerNamespace = true; - // Current loop contains the class keyword. Next loop will have the class name itself. - } else if ($token[0] == T_CLASS) { - $triggerClass = true; + switch ($token[0]) { + case T_NAMESPACE: + // Current loop contains the namespace keyword. Between this and the semicolon is the namespace + $triggerNamespace = true; + break; + case T_CLASS: + // Current loop contains the class keyword. Next loop will have the class name itself. + $triggerClass = true; + break; } // We have a class name, let's concatenate and store it! diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php index eda436b087d3d..dcc100149d96c 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php @@ -131,5 +131,4 @@ public function testTheWeirdExceptionCaseThatHappens() self::assertCount(1, $result); } - } From b8c142ae11a3a702e1e2ba495e09029cb2213250 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Fri, 24 Mar 2017 07:44:55 -0500 Subject: [PATCH 43/61] Updated for complexity and an else expression Codacy didn't like --- .../Module/Di/Code/Reader/ClassesScanner.php | 28 +++++++++++-------- .../Di/Code/Reader/FileClassScanner.php | 8 +++--- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 1bc99cf92ee56..9a008d40fa619 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -95,22 +95,26 @@ private function extract(\RecursiveIteratorIterator $recursiveIterator) } $fileScanner = new FileClassScanner($fileItemPath); $classNames = $fileScanner->getClassNames(); - $classExists = false; - if ($classNames) { - foreach ($classNames as $className) { - if (class_exists($className)) { - $classExists = true; - } - } - $classes = array_merge($classes, $classNames); - } - if (!$classExists) { - require_once $fileItemPath; - } + $this->includeClasses($classNames, $fileItemPath); + $classes = array_merge($classes, $classNames); + } return $classes; } + protected function includeClasses(array $classNames, $fileItemPath) + { + $classExists = false; + foreach ($classNames as $className) { + if (class_exists($className)) { + $classExists = true; + } + } + if (!$classExists) { + require_once $fileItemPath; + } + } + /** * Find out if file should be excluded * diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index 74d0f07f317f1..cd9e56c0728f6 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -75,14 +75,14 @@ protected function extract() // The namespace keyword was found in the last loop if ($triggerNamespace) { - if (is_array($token)) { - $namespace .= $token[1]; - } else { + if (!is_array($token)) { $triggerNamespace = false; $namespace .= '\\'; continue; } - // The class keyword was found in the last loop + $namespace .= $token[1]; + + // The class keyword was found in the last loop } else if ($triggerClass && $token[0] == T_STRING) { $triggerClass = false; $class = $token[1]; From cdcb7769d3d22843b8517c93b5c8e7479fbe070a Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Fri, 24 Mar 2017 07:45:53 -0500 Subject: [PATCH 44/61] Updated for a code style issue --- .../src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php | 1 - 1 file changed, 1 deletion(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index cd9e56c0728f6..ca4360fee0d50 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -124,5 +124,4 @@ public function getClassNames() } return $this->classNames; } - } From 09d5ff35b987a018531603107f311ed29b4202bb Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Fri, 24 Mar 2017 12:15:25 -0500 Subject: [PATCH 45/61] Updated for code review responses, handle namespaces better, and handle some token edge cases --- .../Module/Di/Code/Reader/ClassesScanner.php | 47 +++++-- .../Di/Code/Reader/FileClassScanner.php | 61 +++++++-- .../Di/Code/Reader/ClassesScannerTest.php | 22 +++- .../Di/Code/Reader/FileClassScannerTest.php | 118 +++++++++++++++++- .../Module/Di/_files/var/generation/.keep | 0 5 files changed, 227 insertions(+), 21 deletions(-) create mode 100644 setup/src/Magento/Setup/Test/Unit/Module/Di/_files/var/generation/.keep diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 9a008d40fa619..ecb6ec46fba2f 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -6,6 +6,7 @@ namespace Magento\Setup\Module\Di\Code\Reader; use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Exception\FileSystemException; class ClassesScanner implements ClassesScannerInterface @@ -21,12 +22,29 @@ class ClassesScanner implements ClassesScannerInterface protected $fileResults = []; + /** + * @var string + */ + + protected $generationDirectory; + /** * @param array $excludePatterns */ - public function __construct(array $excludePatterns = []) + public function __construct(array $excludePatterns = [], $generationDirectory = false) { $this->excludePatterns = $excludePatterns; + $this->generationDirectory = $generationDirectory; + } + + public function getGenerationDirectory() + { + if ($this->generationDirectory === false) { + $directoryList = ObjectManager::getInstance()->get(DirectoryList::class); + /* @var $directoryList DirectoryList */ + $this->generationDirectory = $directoryList->getPath(DirectoryList::GENERATION); + } + return $this->generationDirectory; } /** @@ -40,6 +58,19 @@ public function addExcludePatterns(array $excludePatterns) $this->excludePatterns = array_merge($this->excludePatterns, $excludePatterns); } + /** + * Determines if the path provided is in the var/generation folder + * + * @param $path + * @return bool + */ + + public function isGeneration($path) + { + $generation = $this->getGenerationDirectory(); + return strpos($path, $generation) === 0; + } + /** * Retrieves list of classes for given path * @@ -51,7 +82,9 @@ public function getList($path) { $realPath = realpath($path); - $isGeneration = strpos($realPath, DIRECTORY_SEPARATOR . 'generation' . DIRECTORY_SEPARATOR) !== false; + $isGeneration = $this->isGeneration($realPath); + + // Generation folders should not have their results cached since they may actually change during compile if (!$isGeneration) { if (isset($this->fileResults[$realPath])) { return $this->fileResults[$realPath]; @@ -97,22 +130,18 @@ private function extract(\RecursiveIteratorIterator $recursiveIterator) $classNames = $fileScanner->getClassNames(); $this->includeClasses($classNames, $fileItemPath); $classes = array_merge($classes, $classNames); - } return $classes; } protected function includeClasses(array $classNames, $fileItemPath) { - $classExists = false; foreach ($classNames as $className) { - if (class_exists($className)) { - $classExists = true; + if (!class_exists($className)) { + require_once $fileItemPath; + return; } } - if (!$classExists) { - require_once $fileItemPath; - } } /** diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index ca4360fee0d50..2313ebe28b7ac 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -25,6 +25,12 @@ class FileClassScanner protected $classNames = false; + /** + * @var array + */ + + protected $tokens; + /** * Constructor for the file class scanner. Requires the filename * @@ -65,17 +71,27 @@ public function getFileContents() protected function extract() { + $allowedOpenBraces = [T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES, T_STRING_VARNAME]; $classes = []; - $tokens = token_get_all($this->getFileContents()); $namespace = ''; $class = ''; $triggerClass = false; $triggerNamespace = false; - foreach ($tokens as $token) { - + $braceLevel = 0; + $bracedNamespace = false; + + $this->tokens = token_get_all($this->getFileContents()); + foreach ($this->tokens as $index => $token) { + // Is either a literal brace or an interpolated brace + if ($token == '{' || (is_array($token) && in_array($token[0], $allowedOpenBraces))) { + $braceLevel++; + } else if ($token == '}') { + $braceLevel--; + } // The namespace keyword was found in the last loop if ($triggerNamespace) { - if (!is_array($token)) { + // A string ; or a discovered namespace that looks like "namespace name { }" + if (!is_array($token) || ($namespace && $token[0] == T_WHITESPACE)) { $triggerNamespace = false; $namespace .= '\\'; continue; @@ -92,10 +108,14 @@ protected function extract() case T_NAMESPACE: // Current loop contains the namespace keyword. Between this and the semicolon is the namespace $triggerNamespace = true; + $namespace = ''; + $bracedNamespace = $this->isBracedNamespace($index); break; case T_CLASS: // Current loop contains the class keyword. Next loop will have the class name itself. - $triggerClass = true; + if ($braceLevel == 0 || ($bracedNamespace && $braceLevel == 1)) { + $triggerClass = true; + } break; } @@ -104,10 +124,37 @@ protected function extract() $namespace = trim($namespace); $fqClassName = $namespace . trim($class); $classes[] = $fqClassName; - return $classes; + $class = ''; + } + } + return $classes;; + } + + /** + * Looks forward from the current index to determine if the namespace is nested in {} or terminated with ; + * + * @param $index + * @return bool + */ + + protected function isBracedNamespace($index) + { + $len = count($this->tokens); + while ($index++ < $len) { + if (!is_array($this->tokens[$index])) { + if ($this->tokens[$index] == ';') { + return false; + } else if ($this->tokens[$index] == '{') { + return true; + } + continue; + } + + if (!in_array($this->tokens[$index][0], [T_WHITESPACE, T_STRING, T_NS_SEPARATOR])) { + throw new InvalidFileException('Namespace not defined properly'); } } - return []; + throw new InvalidFileException('Could not find namespace termination'); } /** diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php index 89664d70c4a69..61e5527fb8d06 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php @@ -12,9 +12,18 @@ class ClassesScannerTest extends \PHPUnit_Framework_TestCase */ private $model; + /** + * the /var/generation directory realpath + * + * @var string + */ + + private $generation; + protected function setUp() { - $this->model = new \Magento\Setup\Module\Di\Code\Reader\ClassesScanner(); + $this->generation = realpath(__DIR__ . '/../../_files/var/generation'); + $this->model = new \Magento\Setup\Module\Di\Code\Reader\ClassesScanner([], $this->generation); } public function testGetList() @@ -24,4 +33,15 @@ public function testGetList() $this->assertTrue(is_array($actual)); $this->assertCount(5, $actual); } + + public function testIsGenerationIgnoresRegularPath() + { + self::assertFalse($this->model->isGeneration(__DIR__)); + } + + public function testIsGenerationNotesGenerationPath() + { + self::assertTrue($this->model->isGeneration($this->generation)); + } + } diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php index dcc100149d96c..bd65dbad1a16e 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php @@ -96,13 +96,13 @@ public function testGetClassNameAndMultiNamespace() <<getClassNames(); self::assertCount(1, $result); - self::assertContains('This\Is\My\Namespace\ThisIsMyTest', $result); + self::assertContains('This\Is\My\Ns\ThisIsMyTest', $result); } - public function testTheWeirdExceptionCaseThatHappens() + + public function testGetMultiClassNameAndMultiNamespace() + { + $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ + 'getFileContents' + ])->getMock(); + $scanner->expects(self::once())->method('getFileContents')->willReturn( +<<get(\This\Is\Another\Ns::class)->method(); + self:: class; + } + + public function test() + { + + } +} + +class ThisIsForBreaking { + +} + +PHP + ); + /* @var $scanner FileClassScanner */ + + $result = $scanner->getClassNames(); + + self::assertCount(2, $result); + self::assertContains('This\Is\My\Ns\ThisIsMyTest', $result); + self::assertContains('This\Is\My\Ns\ThisIsForBreaking', $result); + } + + public function testBracketedNamespacesAndClasses() + { + $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ + 'getFileContents' + ])->getMock(); + $scanner->expects(self::once())->method('getFileContents')->willReturn( +<<getClassNames(); + + self::assertCount(3, $result); + self::assertContains('This\Is\My\Ns\ThisIsMyTest', $result); + self::assertContains('This\Is\My\Ns\ThisIsForBreaking', $result); + self::assertContains('This\Is\Not\My\Ns\ThisIsNotMyTest', $result); + } + + public function testClassKeywordInMiddleOfFile() { $filename = __DIR__ . '/../../../../../../../../../..' @@ -131,4 +218,27 @@ public function testTheWeirdExceptionCaseThatHappens() self::assertCount(1, $result); } + + public function testInvalidPHPCodeThrowsExceptionWhenCannotDetermineBraceOrSemiColon() + { + $this->setExpectedException(InvalidFileException::class); + $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ + 'getFileContents' + ])->getMock(); + $scanner->expects(self::once())->method('getFileContents')->willReturn( + <<getClassNames(); + } } diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/var/generation/.keep b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/var/generation/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d From f660cb24f2d99b7352e3e069937197092c07c544 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Fri, 24 Mar 2017 12:16:30 -0500 Subject: [PATCH 46/61] Updated copyright date --- .../src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index ecb6ec46fba2f..44f0001eec721 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -1,6 +1,6 @@ Date: Fri, 24 Mar 2017 13:16:26 -0500 Subject: [PATCH 47/61] Merged a condition --- .../Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 44f0001eec721..eff71842bcc76 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -85,10 +85,8 @@ public function getList($path) $isGeneration = $this->isGeneration($realPath); // Generation folders should not have their results cached since they may actually change during compile - if (!$isGeneration) { - if (isset($this->fileResults[$realPath])) { - return $this->fileResults[$realPath]; - } + if (!$isGeneration && isset($this->fileResults[$realPath])) { + return $this->fileResults[$realPath]; } if (!(bool)$realPath) { throw new FileSystemException(new \Magento\Framework\Phrase('Invalid path: %1', [$path])); From cf39bfd93debfef61564559743177439c1160a7a Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Fri, 24 Mar 2017 13:28:12 -0500 Subject: [PATCH 48/61] Updated code and docs from code mess --- .../Setup/Module/Di/Code/Reader/ClassesScanner.php | 8 +++++--- .../Setup/Module/Di/Code/Reader/FileClassScanner.php | 6 +++--- .../Unit/Module/Di/Code/Reader/ClassesScannerTest.php | 1 - .../Unit/Module/Di/Code/Reader/FileClassScannerTest.php | 1 - 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index eff71842bcc76..c5c947efc8dac 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -30,8 +30,10 @@ class ClassesScanner implements ClassesScannerInterface /** * @param array $excludePatterns + * @param string $generationDirectory */ - public function __construct(array $excludePatterns = [], $generationDirectory = false) + + public function __construct(array $excludePatterns = [], $generationDirectory = null) { $this->excludePatterns = $excludePatterns; $this->generationDirectory = $generationDirectory; @@ -39,7 +41,7 @@ public function __construct(array $excludePatterns = [], $generationDirectory = public function getGenerationDirectory() { - if ($this->generationDirectory === false) { + if ($this->generationDirectory === null) { $directoryList = ObjectManager::getInstance()->get(DirectoryList::class); /* @var $directoryList DirectoryList */ $this->generationDirectory = $directoryList->getPath(DirectoryList::GENERATION); @@ -61,7 +63,7 @@ public function addExcludePatterns(array $excludePatterns) /** * Determines if the path provided is in the var/generation folder * - * @param $path + * @param string $path * @return bool */ diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index 2313ebe28b7ac..10d0e85a96d1c 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -82,7 +82,7 @@ protected function extract() $this->tokens = token_get_all($this->getFileContents()); foreach ($this->tokens as $index => $token) { - // Is either a literal brace or an interpolated brace + // Is either a literal brace or an interpolated brace with a variable if ($token == '{' || (is_array($token) && in_array($token[0], $allowedOpenBraces))) { $braceLevel++; } else if ($token == '}') { @@ -127,13 +127,13 @@ protected function extract() $class = ''; } } - return $classes;; + return $classes; } /** * Looks forward from the current index to determine if the namespace is nested in {} or terminated with ; * - * @param $index + * @param integer $index * @return bool */ diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php index 61e5527fb8d06..a8c25f7bfea1e 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php @@ -43,5 +43,4 @@ public function testIsGenerationNotesGenerationPath() { self::assertTrue($this->model->isGeneration($this->generation)); } - } diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php index bd65dbad1a16e..d2ba088b01e5e 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php @@ -120,7 +120,6 @@ public function test() self::assertContains('This\Is\My\Ns\ThisIsMyTest', $result); } - public function testGetMultiClassNameAndMultiNamespace() { $scanner = $this->getMockBuilder(FileClassScanner::class)->disableOriginalConstructor()->setMethods([ From da396305df63c4dcdb3b71da952d57dfdd007f0a Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Fri, 24 Mar 2017 16:52:48 -0500 Subject: [PATCH 49/61] Disabled CyclomaticComplexity check. This code is sometimes called multiple 10's of millions of times so micro-optimizations are the name of the game here. --- .../src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php | 1 + 1 file changed, 1 insertion(+) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index 10d0e85a96d1c..ae3608db9d335 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -66,6 +66,7 @@ public function getFileContents() * Extracts the fully qualified class name from a file. It only searches for the first match and stops looking * as soon as it enters the class definition itself. * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @return array */ From 67f5346ace6f23977e71f49dd0c3898d3f42aebb Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Fri, 24 Mar 2017 16:53:49 -0500 Subject: [PATCH 50/61] Disabled CyclomaticComplexity check. This code is sometimes called multiple 10's of millions of times so micro-optimizations are the name of the game here. --- .../src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php | 1 + 1 file changed, 1 insertion(+) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index ae3608db9d335..12dcaa02d95ea 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -67,6 +67,7 @@ public function getFileContents() * as soon as it enters the class definition itself. * * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) * @return array */ From 727439a43408ce08d1ec66c375c91017018c4161 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Mon, 27 Mar 2017 08:31:01 -0500 Subject: [PATCH 51/61] Updated some MD and code review recommendations --- .../Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 6 ++++++ .../Setup/Module/Di/Code/Reader/FileClassScanner.php | 3 +++ 2 files changed, 9 insertions(+) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index c5c947efc8dac..d8144a7e511f9 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -39,6 +39,12 @@ public function __construct(array $excludePatterns = [], $generationDirectory = $this->generationDirectory = $generationDirectory; } + /** + * Retrieves the fully qualified path for var/generation. + * + * @return string + */ + public function getGenerationDirectory() { if ($this->generationDirectory === null) { diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index 12dcaa02d95ea..ce47a2f1d86c3 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -66,6 +66,9 @@ public function getFileContents() * Extracts the fully qualified class name from a file. It only searches for the first match and stops looking * as soon as it enters the class definition itself. * + * Warnings are suppressed for this method due to a micro-optimization that only really shows up when this logic + * is called several millions of times, which can happen quite easily with even moderately sized codebases. + * * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) * @return array From 77d9d2e1737f3326d8a2b462bf3f0c4a0ba371f5 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Mon, 27 Mar 2017 09:29:27 -0500 Subject: [PATCH 52/61] Updated to follow @schmengler's recommendation --- .../Module/Di/Code/Reader/ClassesScanner.php | 23 ++++--------------- .../Di/Code/Reader/ClassesScannerTest.php | 8 ++++++- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index d8144a7e511f9..2713c1a31af3f 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -33,28 +33,16 @@ class ClassesScanner implements ClassesScannerInterface * @param string $generationDirectory */ - public function __construct(array $excludePatterns = [], $generationDirectory = null) + public function __construct(array $excludePatterns = [], DirectoryList $directoryList = null) { $this->excludePatterns = $excludePatterns; - $this->generationDirectory = $generationDirectory; - } - - /** - * Retrieves the fully qualified path for var/generation. - * - * @return string - */ - - public function getGenerationDirectory() - { - if ($this->generationDirectory === null) { + if (!$directoryList instanceof DirectoryList) { $directoryList = ObjectManager::getInstance()->get(DirectoryList::class); - /* @var $directoryList DirectoryList */ - $this->generationDirectory = $directoryList->getPath(DirectoryList::GENERATION); } - return $this->generationDirectory; + $this->generationDirectory = $directoryList->getPath(DirectoryList::GENERATION); } + /** * Adds exclude patterns * @@ -75,8 +63,7 @@ public function addExcludePatterns(array $excludePatterns) public function isGeneration($path) { - $generation = $this->getGenerationDirectory(); - return strpos($path, $generation) === 0; + return strpos($path, $this->generationDirectory) === 0; } /** diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php index a8c25f7bfea1e..b68178ef85b38 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php @@ -5,6 +5,8 @@ */ namespace Magento\Setup\Test\Unit\Module\Di\Code\Reader; +use Magento\Framework\App\Filesystem\DirectoryList; + class ClassesScannerTest extends \PHPUnit_Framework_TestCase { /** @@ -23,7 +25,11 @@ class ClassesScannerTest extends \PHPUnit_Framework_TestCase protected function setUp() { $this->generation = realpath(__DIR__ . '/../../_files/var/generation'); - $this->model = new \Magento\Setup\Module\Di\Code\Reader\ClassesScanner([], $this->generation); + $mock = $this->getMockBuilder(DirectoryList::class)->disableOriginalConstructor()->setMethods( + ['getPath'] + )->getMock(); + $mock->method('getPath')->willReturn($this->generation); + $this->model = new \Magento\Setup\Module\Di\Code\Reader\ClassesScanner([], $mock); } public function testGetList() From 04b7dda4fe15a27fa4600a35cc25ec6ebaf1bdb4 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Mon, 27 Mar 2017 10:31:34 -0500 Subject: [PATCH 53/61] Updated based on recommendations --- .../Module/Di/Code/Reader/ClassesScanner.php | 18 +++--------------- .../Module/Di/Code/Reader/FileClassScanner.php | 6 +++--- .../Di/Code/Reader/ClassesScannerTest.php | 10 ---------- .../Di/Code/Reader/FileClassScannerTest.php | 14 +++++++------- 4 files changed, 13 insertions(+), 35 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 2713c1a31af3f..a28b8aeb9bdbe 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -20,13 +20,13 @@ class ClassesScanner implements ClassesScannerInterface * @var array */ - protected $fileResults = []; + private $fileResults = []; /** * @var string */ - protected $generationDirectory; + private $generationDirectory; /** * @param array $excludePatterns @@ -54,18 +54,6 @@ public function addExcludePatterns(array $excludePatterns) $this->excludePatterns = array_merge($this->excludePatterns, $excludePatterns); } - /** - * Determines if the path provided is in the var/generation folder - * - * @param string $path - * @return bool - */ - - public function isGeneration($path) - { - return strpos($path, $this->generationDirectory) === 0; - } - /** * Retrieves list of classes for given path * @@ -77,7 +65,7 @@ public function getList($path) { $realPath = realpath($path); - $isGeneration = $this->isGeneration($realPath); + $isGeneration = strpos($realPath, $this->generationDirectory) === 0; // Generation folders should not have their results cached since they may actually change during compile if (!$isGeneration && isset($this->fileResults[$realPath])) { diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index ce47a2f1d86c3..560d3ef63429f 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -15,7 +15,7 @@ class FileClassScanner * @var string */ - protected $filename; + private $filename; /** * The list of classes found in the file. @@ -23,13 +23,13 @@ class FileClassScanner * @var bool */ - protected $classNames = false; + private $classNames = false; /** * @var array */ - protected $tokens; + private $tokens; /** * Constructor for the file class scanner. Requires the filename diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php index b68178ef85b38..1448a757f669b 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassesScannerTest.php @@ -39,14 +39,4 @@ public function testGetList() $this->assertTrue(is_array($actual)); $this->assertCount(5, $actual); } - - public function testIsGenerationIgnoresRegularPath() - { - self::assertFalse($this->model->isGeneration(__DIR__)); - } - - public function testIsGenerationNotesGenerationPath() - { - self::assertTrue($this->model->isGeneration($this->generation)); - } } diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php index d2ba088b01e5e..66d7dc4a20a9c 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php @@ -35,7 +35,7 @@ public function testEmptyArrayForFileWithoutNamespaceOrClass() } PHP ); - /* @var $scanner FileClassScanner */ + /** @var $scanner FileClassScanner */ $result = $scanner->getClassNames(); self::assertCount(0, $result); @@ -55,7 +55,7 @@ class ThisIsATest { } PHP ); - /* @var $scanner FileClassScanner */ + /** @var $scanner FileClassScanner */ $result = $scanner->getClassNames(); @@ -79,7 +79,7 @@ class ThisIsMyTest { } PHP ); - /* @var $scanner FileClassScanner */ + /** @var $scanner FileClassScanner */ $result = $scanner->getClassNames(); @@ -112,7 +112,7 @@ public function test() } PHP ); - /* @var $scanner FileClassScanner */ + /** @var $scanner FileClassScanner */ $result = $scanner->getClassNames(); @@ -151,7 +151,7 @@ class ThisIsForBreaking { PHP ); - /* @var $scanner FileClassScanner */ + /** @var $scanner FileClassScanner */ $result = $scanner->getClassNames(); @@ -196,7 +196,7 @@ class ThisIsNotMyTest PHP ); - /* @var $scanner FileClassScanner */ + /** @var $scanner FileClassScanner */ $result = $scanner->getClassNames(); @@ -236,7 +236,7 @@ class ThisIsMyTest PHP ); - /* @var $scanner FileClassScanner */ + /** @var $scanner FileClassScanner */ $scanner->getClassNames(); } From 9a7711e94df270ba677c8f86df0bacba917f1892 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Wed, 29 Mar 2017 08:40:02 -0500 Subject: [PATCH 54/61] Removed a line --- setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 1 - 1 file changed, 1 deletion(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index a28b8aeb9bdbe..c6450c22c7d59 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -42,7 +42,6 @@ public function __construct(array $excludePatterns = [], DirectoryList $director $this->generationDirectory = $directoryList->getPath(DirectoryList::GENERATION); } - /** * Adds exclude patterns * From 00a91db0cd8b139377952f6d1b8839e7bc005cbc Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Tue, 11 Apr 2017 11:35:02 -0500 Subject: [PATCH 55/61] Changed visibility for includeClasses() --- .../src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index fadc2b3481fea..3a3e373a7e232 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -115,7 +115,7 @@ private function extract(\RecursiveIteratorIterator $recursiveIterator) return $classes; } - protected function includeClasses(array $classNames, $fileItemPath) + private function includeClasses(array $classNames, $fileItemPath) { foreach ($classNames as $className) { if (!class_exists($className)) { From 81d82be3573ffe1107a8eeca65a38ec227bfd3dd Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Tue, 11 Apr 2017 11:35:33 -0500 Subject: [PATCH 56/61] Changed type check --- .../src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 3a3e373a7e232..897b0839376e5 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -36,7 +36,7 @@ class ClassesScanner implements ClassesScannerInterface public function __construct(array $excludePatterns = [], DirectoryList $directoryList = null) { $this->excludePatterns = $excludePatterns; - if (!$directoryList instanceof DirectoryList) { + if ($directoryList === null) { $directoryList = ObjectManager::getInstance()->get(DirectoryList::class); } $this->generationDirectory = $directoryList->getPath(DirectoryList::GENERATION); From 1f55c6ba6622a0805e14df1db224d39d1e8a7667 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Tue, 11 Apr 2017 11:38:28 -0500 Subject: [PATCH 57/61] Changed visibility --- .../Setup/Module/Di/Code/Reader/FileClassScanner.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index 560d3ef63429f..16642024119bc 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -74,7 +74,7 @@ public function getFileContents() * @return array */ - protected function extract() + private function extract() { $allowedOpenBraces = [T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES, T_STRING_VARNAME]; $classes = []; @@ -141,8 +141,7 @@ protected function extract() * @param integer $index * @return bool */ - - protected function isBracedNamespace($index) + private function isBracedNamespace($index) { $len = count($this->tokens); while ($index++ < $len) { @@ -168,7 +167,6 @@ protected function isBracedNamespace($index) * * @return array */ - public function getClassNames() { if ($this->classNames === false) { From 978ae409f81df1cc5ea77cd1c0a796280964c856 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Tue, 11 Apr 2017 11:39:55 -0500 Subject: [PATCH 58/61] Changed some spaces --- .../Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 5 ++++- .../Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php | 3 --- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 897b0839376e5..1b99295615549 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -92,7 +92,6 @@ public function getList($path) * @param \RecursiveIteratorIterator $recursiveIterator * @return array */ - private function extract(\RecursiveIteratorIterator $recursiveIterator) { $classes = []; @@ -115,6 +114,10 @@ private function extract(\RecursiveIteratorIterator $recursiveIterator) return $classes; } + /** + * @param array $classNames + * @param $fileItemPath + */ private function includeClasses(array $classNames, $fileItemPath) { foreach ($classNames as $className) { diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index 16642024119bc..122bb7793b29e 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -36,7 +36,6 @@ class FileClassScanner * * @param string $filename */ - public function __construct($filename) { $filename = realpath($filename); @@ -56,7 +55,6 @@ public function __construct($filename) * * @return string */ - public function getFileContents() { return file_get_contents($this->filename); @@ -73,7 +71,6 @@ public function getFileContents() * @SuppressWarnings(PHPMD.NPathComplexity) * @return array */ - private function extract() { $allowedOpenBraces = [T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES, T_STRING_VARNAME]; From d7e601b14644c8f540fe2c7767ef5e16a396f02f Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Tue, 11 Apr 2017 11:41:33 -0500 Subject: [PATCH 59/61] Changed some spaces --- .../src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 3 --- .../Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php | 3 --- 2 files changed, 6 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 1b99295615549..90eed36e2118c 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -19,20 +19,17 @@ class ClassesScanner implements ClassesScannerInterface /** * @var array */ - private $fileResults = []; /** * @var string */ - private $generationDirectory; /** * @param array $excludePatterns * @param string $generationDirectory */ - public function __construct(array $excludePatterns = [], DirectoryList $directoryList = null) { $this->excludePatterns = $excludePatterns; diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php index 122bb7793b29e..30dad35a2bcb9 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileClassScanner.php @@ -14,7 +14,6 @@ class FileClassScanner * * @var string */ - private $filename; /** @@ -22,13 +21,11 @@ class FileClassScanner * * @var bool */ - private $classNames = false; /** * @var array */ - private $tokens; /** From cc725908a4a755c4a4db517573c57b67e8ae6ee5 Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Mon, 17 Apr 2017 15:58:41 -0500 Subject: [PATCH 60/61] Updated for MD --- .../Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 90eed36e2118c..a86558ce898ce 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -113,16 +113,18 @@ private function extract(\RecursiveIteratorIterator $recursiveIterator) /** * @param array $classNames - * @param $fileItemPath + * @param string $fileItemPath + * @return bool Whether the clas is included or not */ private function includeClasses(array $classNames, $fileItemPath) { foreach ($classNames as $className) { if (!class_exists($className)) { require_once $fileItemPath; - return; + return true; } } + return false; } /** From 8f043c1d7e0e7e0e53ab16fb1e3051e72b40dccb Mon Sep 17 00:00:00 2001 From: Kevin Schroeder Date: Wed, 19 Apr 2017 11:33:17 -0500 Subject: [PATCH 61/61] Updated for MD --- .../Module/Di/Code/Reader/FileClassScannerTest.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php index 66d7dc4a20a9c..e9f487c5c3b15 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/FileClassScannerTest.php @@ -25,7 +25,7 @@ public function testEmptyArrayForFileWithoutNamespaceOrClass() 'getFileContents' ])->getMock(); $scanner->expects(self::once())->method('getFileContents')->willReturn( -<<getMock(); $scanner->expects(self::once())->method('getFileContents')->willReturn( -<<getMock(); $scanner->expects(self::once())->method('getFileContents')->willReturn( -<<getMock(); $scanner->expects(self::once())->method('getFileContents')->willReturn( -<<getMock(); $scanner->expects(self::once())->method('getFileContents')->willReturn( -<<getMock(); $scanner->expects(self::once())->method('getFileContents')->willReturn( -<<