Pārlūkot izejas kodu

Merge remote-tracking branch 'vicb/classmap'

Jordi Boggiano 12 gadi atpakaļ
vecāks
revīzija
8a0c8560b7

+ 55 - 42
src/Composer/Autoload/ClassMapGenerator.php

@@ -40,42 +40,49 @@ class ClassMapGenerator
     /**
      * Iterate over all files in the given directory searching for classes
      *
-     * @param Iterator|string $dir       The directory to search in or an iterator
+     * @param Iterator|string $path      The path to search in or an iterator
      * @param string          $whitelist Regex that matches against the file path
      *
      * @return array A class map array
+     *
+     * @throws \RuntimeException When the path is neither an existing file nor directory
      */
-    public static function createMap($dir, $whitelist = null)
+    public static function createMap($path, $whitelist = null)
     {
-        if (is_string($dir)) {
-            if (is_file($dir)) {
-                $dir = array(new \SplFileInfo($dir));
+        if (is_string($path)) {
+            if (is_file($path)) {
+                $path = array(new \SplFileInfo($path));
+            } else if (is_dir($path)) {
+                $path = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path));
             } else {
-                $dir = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir));
+                throw new \RuntimeException(
+                    'Could not scan for classes inside "'.$path.
+                    '" which does not appear to be a file nor a folder'
+                );
             }
         }
 
         $map = array();
 
-        foreach ($dir as $file) {
+        foreach ($path as $file) {
             if (!$file->isFile()) {
                 continue;
             }
 
-            $path = $file->getRealPath();
+            $filePath = $file->getRealPath();
 
-            if (pathinfo($path, PATHINFO_EXTENSION) !== 'php') {
+            if (pathinfo($filePath, PATHINFO_EXTENSION) !== 'php') {
                 continue;
             }
 
-            if ($whitelist && !preg_match($whitelist, strtr($path, '\\', '/'))) {
+            if ($whitelist && !preg_match($whitelist, strtr($filePath, '\\', '/'))) {
                 continue;
             }
 
-            $classes = self::findClasses($path);
+            $classes = self::findClasses($filePath);
 
             foreach ($classes as $class) {
-                $map[$class] = $path;
+                $map[$class] = $filePath;
             }
 
         }
@@ -96,38 +103,44 @@ class ClassMapGenerator
 
         try {
             $contents = php_strip_whitespace($path);
-            if (!preg_match('{\b(?:class|interface'.$traits.')\b}i', $contents)) {
-                return array();
-            }
-
-            // strip heredocs/nowdocs
-            $contents = preg_replace('{<<<\'?(\w+)\'?(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)\\1(?=\r\n|\n|\r|;)}s', 'null', $contents);
-            // strip strings
-            $contents = preg_replace('{"[^"\\\\]*(\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(\\\\.[^\'\\\\]*)*\'}', 'null', $contents);
-
-            preg_match_all('{
-                (?:
-                     \b(?<![\$:>])(?<type>class|interface'.$traits.') \s+ (?<name>\S+)
-                   | \b(?<![\$:>])(?<ns>namespace) (?<nsname>\s+[^\s;{}\\\\]+(?:\s*\\\\\s*[^\s;{}\\\\]+)*)? \s*[\{;]
-                )
-            }ix', $contents, $matches);
-            $classes = array();
-
-            $namespace = '';
-
-            for ($i = 0, $len = count($matches['type']); $i < $len; $i++) {
-                $name = $matches['name'][$i];
-
-                if (!empty($matches['ns'][$i])) {
-                    $namespace = str_replace(array(' ', "\t", "\r", "\n"), '', $matches['nsname'][$i]) . '\\';
-                } else {
-                    $classes[] = ltrim($namespace . $matches['name'][$i], '\\');
-                }
-            }
-
-            return $classes;
         } catch (\Exception $e) {
             throw new \RuntimeException('Could not scan for classes inside '.$path.": \n".$e->getMessage(), 0, $e);
         }
+
+        // strip heredocs/nowdocs
+        $contents = preg_replace('{<<<\'?(\w+)\'?(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)\\1(?=\r\n|\n|\r|;)}s', 'null', $contents);
+        // strip strings
+        $contents = preg_replace('{"[^"\\\\]*(\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(\\\\.[^\'\\\\]*)*\'}', 'null', $contents);
+        // keep only php code
+        $phpContents = preg_match_all('{<\?(?:php)?(.*)\?>}s', $contents, $m) ? join($m[1], ' ') : '';
+        $contents = preg_replace('{<\?(php)?.*\?>}s', '', $contents);
+        if (preg_match('{<\?(?:php)?(.*)}s', $contents, $m)) {
+            $phpContents .= ' ' . $m[1];
+        }
+
+        if (!preg_match('{\b(?:class|interface'.$traits.')\b}i', $phpContents)) {
+            return array();
+        }
+
+        preg_match_all('{
+            (?:
+                 \b(?<![\$:>])(?<type>class|interface'.$traits.') \s+ (?<name>\S+)
+               | \b(?<![\$:>])(?<ns>namespace) (?<nsname>\s+[^\s;{}\\\\]+(?:\s*\\\\\s*[^\s;{}\\\\]+)*)? \s*[\{;]
+            )
+        }ix', $phpContents, $matches);
+        $classes = array();
+
+        $namespace = '';
+
+        for ($i = 0, $len = count($matches['type']); $i < $len; $i++) {
+            if (!empty($matches['ns'][$i])) {
+                $namespace = str_replace(array(' ', "\t", "\r", "\n"), '', $matches['nsname'][$i]) . '\\';
+            } else {
+                $classes[] = ltrim($namespace . $matches['name'][$i], '\\');
+            }
+        }
+
+        return $classes;
+
     }
 }

+ 23 - 0
tests/Composer/Test/Autoload/ClassMapGeneratorTest.php

@@ -53,6 +53,7 @@ class ClassMapGeneratorTest extends \PHPUnit_Framework_TestCase
                 'ClassMap\\SomeParent'    => realpath(__DIR__).'/Fixtures/classmap/SomeParent.php',
                 'ClassMap\\SomeClass'     => realpath(__DIR__).'/Fixtures/classmap/SomeClass.php',
             )),
+            array(__DIR__.'/Fixtures/template', array()),
         );
 
         if (version_compare(PHP_VERSION, '5.4', '>=')) {
@@ -84,6 +85,28 @@ class ClassMapGeneratorTest extends \PHPUnit_Framework_TestCase
         ), ClassMapGenerator::createMap($finder));
     }
 
+    /**
+     * @expectedException \RuntimeException
+     * @expectedExceptionMessage Could not scan for classes inside
+     */
+    public function testFindClassesThrowsWhenFileDoesNotExist()
+    {
+        $r = new \ReflectionClass('Composer\\Autoload\\ClassMapGenerator');
+        $find = $r->getMethod('findClasses');
+        $find->setAccessible(true);
+
+        $find->invoke(null, __DIR__.'/no-file');
+    }
+
+    /**
+     * @expectedException \RuntimeException
+     * @expectedExceptionMessage Could not scan for classes inside
+     */
+    public function testCreateMapThrowsWhenDirectoryDoesNotExist()
+    {
+        ClassMapGenerator::createMap(__DIR__.'/no-file.no-foler');
+    }
+
     protected function assertEqualsNormalized($expected, $actual, $message = null)
     {
         foreach ($expected as $ns => $path) {

+ 6 - 0
tests/Composer/Test/Autoload/Fixtures/template/template_1.php

@@ -0,0 +1,6 @@
+/*
+ * class templateClass_1
+ * interface templateInterface_1
+ * trait temlpateTrait_1
+ */
+<?php echo $code

+ 8 - 0
tests/Composer/Test/Autoload/Fixtures/template/template_2.php

@@ -0,0 +1,8 @@
+/*
+ * class templateClass_2
+ * interface templateInterface_2
+ * trait temlpateTrait_2
+ */
+<?php
+    echo $code
+?>