Merge remote-tracking branch 'vicb/classmap'
commit
8a0c8560b7
|
@ -40,42 +40,49 @@ class ClassMapGenerator
|
||||||
/**
|
/**
|
||||||
* Iterate over all files in the given directory searching for classes
|
* 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
|
* @param string $whitelist Regex that matches against the file path
|
||||||
*
|
*
|
||||||
* @return array A class map array
|
* @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_string($path)) {
|
||||||
if (is_file($dir)) {
|
if (is_file($path)) {
|
||||||
$dir = array(new \SplFileInfo($dir));
|
$path = array(new \SplFileInfo($path));
|
||||||
|
} else if (is_dir($path)) {
|
||||||
|
$path = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path));
|
||||||
} else {
|
} 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();
|
$map = array();
|
||||||
|
|
||||||
foreach ($dir as $file) {
|
foreach ($path as $file) {
|
||||||
if (!$file->isFile()) {
|
if (!$file->isFile()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$path = $file->getRealPath();
|
$filePath = $file->getRealPath();
|
||||||
|
|
||||||
if (pathinfo($path, PATHINFO_EXTENSION) !== 'php') {
|
if (pathinfo($filePath, PATHINFO_EXTENSION) !== 'php') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($whitelist && !preg_match($whitelist, strtr($path, '\\', '/'))) {
|
if ($whitelist && !preg_match($whitelist, strtr($filePath, '\\', '/'))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$classes = self::findClasses($path);
|
$classes = self::findClasses($filePath);
|
||||||
|
|
||||||
foreach ($classes as $class) {
|
foreach ($classes as $class) {
|
||||||
$map[$class] = $path;
|
$map[$class] = $filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -96,28 +103,36 @@ class ClassMapGenerator
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$contents = php_strip_whitespace($path);
|
$contents = php_strip_whitespace($path);
|
||||||
if (!preg_match('{\b(?:class|interface'.$traits.')\b}i', $contents)) {
|
} catch (\Exception $e) {
|
||||||
return array();
|
throw new \RuntimeException('Could not scan for classes inside '.$path.": \n".$e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// strip heredocs/nowdocs
|
// strip heredocs/nowdocs
|
||||||
$contents = preg_replace('{<<<\'?(\w+)\'?(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)\\1(?=\r\n|\n|\r|;)}s', 'null', $contents);
|
$contents = preg_replace('{<<<\'?(\w+)\'?(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)\\1(?=\r\n|\n|\r|;)}s', 'null', $contents);
|
||||||
// strip strings
|
// strip strings
|
||||||
$contents = preg_replace('{"[^"\\\\]*(\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(\\\\.[^\'\\\\]*)*\'}', 'null', $contents);
|
$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('{
|
preg_match_all('{
|
||||||
(?:
|
(?:
|
||||||
\b(?<![\$:>])(?<type>class|interface'.$traits.') \s+ (?<name>\S+)
|
\b(?<![\$:>])(?<type>class|interface'.$traits.') \s+ (?<name>\S+)
|
||||||
| \b(?<![\$:>])(?<ns>namespace) (?<nsname>\s+[^\s;{}\\\\]+(?:\s*\\\\\s*[^\s;{}\\\\]+)*)? \s*[\{;]
|
| \b(?<![\$:>])(?<ns>namespace) (?<nsname>\s+[^\s;{}\\\\]+(?:\s*\\\\\s*[^\s;{}\\\\]+)*)? \s*[\{;]
|
||||||
)
|
)
|
||||||
}ix', $contents, $matches);
|
}ix', $phpContents, $matches);
|
||||||
$classes = array();
|
$classes = array();
|
||||||
|
|
||||||
$namespace = '';
|
$namespace = '';
|
||||||
|
|
||||||
for ($i = 0, $len = count($matches['type']); $i < $len; $i++) {
|
for ($i = 0, $len = count($matches['type']); $i < $len; $i++) {
|
||||||
$name = $matches['name'][$i];
|
|
||||||
|
|
||||||
if (!empty($matches['ns'][$i])) {
|
if (!empty($matches['ns'][$i])) {
|
||||||
$namespace = str_replace(array(' ', "\t", "\r", "\n"), '', $matches['nsname'][$i]) . '\\';
|
$namespace = str_replace(array(' ', "\t", "\r", "\n"), '', $matches['nsname'][$i]) . '\\';
|
||||||
} else {
|
} else {
|
||||||
|
@ -126,8 +141,6 @@ class ClassMapGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
return $classes;
|
return $classes;
|
||||||
} catch (\Exception $e) {
|
|
||||||
throw new \RuntimeException('Could not scan for classes inside '.$path.": \n".$e->getMessage(), 0, $e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ class ClassMapGeneratorTest extends \PHPUnit_Framework_TestCase
|
||||||
'ClassMap\\SomeParent' => realpath(__DIR__).'/Fixtures/classmap/SomeParent.php',
|
'ClassMap\\SomeParent' => realpath(__DIR__).'/Fixtures/classmap/SomeParent.php',
|
||||||
'ClassMap\\SomeClass' => realpath(__DIR__).'/Fixtures/classmap/SomeClass.php',
|
'ClassMap\\SomeClass' => realpath(__DIR__).'/Fixtures/classmap/SomeClass.php',
|
||||||
)),
|
)),
|
||||||
|
array(__DIR__.'/Fixtures/template', array()),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (version_compare(PHP_VERSION, '5.4', '>=')) {
|
if (version_compare(PHP_VERSION, '5.4', '>=')) {
|
||||||
|
@ -84,6 +85,28 @@ class ClassMapGeneratorTest extends \PHPUnit_Framework_TestCase
|
||||||
), ClassMapGenerator::createMap($finder));
|
), 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)
|
protected function assertEqualsNormalized($expected, $actual, $message = null)
|
||||||
{
|
{
|
||||||
foreach ($expected as $ns => $path) {
|
foreach ($expected as $ns => $path) {
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
/*
|
||||||
|
* class templateClass_1
|
||||||
|
* interface templateInterface_1
|
||||||
|
* trait temlpateTrait_1
|
||||||
|
*/
|
||||||
|
<?php echo $code
|
|
@ -0,0 +1,8 @@
|
||||||
|
/*
|
||||||
|
* class templateClass_2
|
||||||
|
* interface templateInterface_2
|
||||||
|
* trait temlpateTrait_2
|
||||||
|
*/
|
||||||
|
<?php
|
||||||
|
echo $code
|
||||||
|
?>
|
Loading…
Reference in New Issue