mirror of
https://github.com/danog/class-finder.git
synced 2024-11-30 04:29:03 +01:00
Refactor agressively to namespaces that map to multiple directories.
This commit is contained in:
parent
f0423a39d4
commit
a1a1926351
@ -3,6 +3,7 @@
|
||||
namespace HaydenPierce\ClassFinder;
|
||||
|
||||
use HaydenPierce\ClassFinder\Exception\ClassFinderException;
|
||||
use HaydenPierce\ClassFinder\Finder\PSR4NamespaceFactory;
|
||||
|
||||
/**
|
||||
* Class AppConfig
|
||||
@ -11,11 +12,16 @@ use HaydenPierce\ClassFinder\Exception\ClassFinderException;
|
||||
*/
|
||||
class AppConfig
|
||||
{
|
||||
/** @var PSR4NamespaceFactory */
|
||||
private $psr4NamespaceFactory;
|
||||
|
||||
/** @var string */
|
||||
private $appRoot;
|
||||
|
||||
public function __construct()
|
||||
public function __construct(PSR4NamespaceFactory $PSR4NamespaceFactory)
|
||||
{
|
||||
$this->appRoot = $this->findAppRoot();
|
||||
$this->psr4NamespaceFactory = $PSR4NamespaceFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -67,9 +73,17 @@ class AppConfig
|
||||
public function getPSR4Namespaces()
|
||||
{
|
||||
$namespaces = $this->getUserDefinedPSR4Namespaces();
|
||||
$vendorNamespaces = require($this->getAppRoot() . 'vendor/composer/autoload_psr4.php');
|
||||
|
||||
// This is broken.
|
||||
// $vendorNamespaces = require($this->getAppRoot() . 'vendor/composer/autoload_psr4.php');
|
||||
$namespaces = array_merge($vendorNamespaces, $namespaces);
|
||||
|
||||
// There's some wackiness going on here for PHP 5.3 compatibility.
|
||||
$names = array_keys($namespaces);
|
||||
$directories = array_values($namespaces);
|
||||
$self = $this;
|
||||
$namespaces = array_map(function($index) use ($self, $names, $directories) {
|
||||
return $self->psr4NamespaceFactory->createNamespace($names[$index], $directories[$index], $this->appRoot);
|
||||
},range(0, count($namespaces) - 1));
|
||||
|
||||
return $namespaces;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
namespace HaydenPierce\ClassFinder;
|
||||
|
||||
use HaydenPierce\ClassFinder\Finder\PSR4Finder;
|
||||
use HaydenPierce\ClassFinder\Finder\PSR4NamespaceFactory;
|
||||
|
||||
class ClassFinder
|
||||
{
|
||||
@ -14,7 +15,8 @@ class ClassFinder
|
||||
private static function initialize()
|
||||
{
|
||||
if (!(self::$config instanceof AppConfig)) {
|
||||
self::$config = new AppConfig();
|
||||
$PSR4Factory = new PSR4NamespaceFactory();
|
||||
self::$config = new AppConfig($PSR4Factory);
|
||||
}
|
||||
|
||||
if (!(self::$psr4 instanceof PSR4Finder)) {
|
||||
|
@ -13,58 +13,31 @@ class PSR4Finder implements FinderInterface
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function findClasses($namespace)
|
||||
{
|
||||
$files = scandir($this->getNamespaceDirectory($namespace));
|
||||
|
||||
$classes = array_map(function($file) use ($namespace){
|
||||
return $namespace . '\\' . str_replace('.php', '', $file);
|
||||
}, $files);
|
||||
|
||||
$classes = array_filter($classes, function($possibleClass){
|
||||
return class_exists($possibleClass);
|
||||
});
|
||||
|
||||
return $classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $namespace
|
||||
* @return bool|string
|
||||
* @throws \Exception
|
||||
* @throws ClassFinderException
|
||||
*/
|
||||
private function getNamespaceDirectory($namespace)
|
||||
public function findClasses($namespace)
|
||||
{
|
||||
$appRoot = $this->config->getAppRoot();
|
||||
|
||||
$composerNamespaces = $this->config->getPSR4Namespaces();
|
||||
|
||||
$namespaceFragments = explode('\\', $namespace);
|
||||
$undefinedNamespaceFragments = [];
|
||||
|
||||
while($namespaceFragments) {
|
||||
$possibleNamespace = implode('\\', $namespaceFragments) . '\\';
|
||||
|
||||
if(array_key_exists($possibleNamespace, $composerNamespaces)){
|
||||
$resolvedDirectory = $appRoot . $composerNamespaces[$possibleNamespace] . implode('/', $undefinedNamespaceFragments);
|
||||
$realDirectory = realpath($resolvedDirectory);
|
||||
if ($realDirectory !== false) {
|
||||
return $realDirectory;
|
||||
} else {
|
||||
throw new ClassFinderException(sprintf("Unknown namespace '%s'. Checked for files in %s, but that directory did not exist. See %s for details.",
|
||||
$namespace,
|
||||
$resolvedDirectory,
|
||||
'https://gitlab.com/hpierce1102/ClassFinder/blob/master/docs/exceptions/unknownSubNamespace.md'
|
||||
));
|
||||
}
|
||||
/** @var PSR4Namespace $bestNamespace */
|
||||
$bestNamespace = array_reduce($composerNamespaces, function($carry, PSR4Namespace $potentialNamespace) use ($namespace) {
|
||||
if ($potentialNamespace->matches($namespace)) {
|
||||
return $potentialNamespace;
|
||||
} else {
|
||||
return $carry;
|
||||
}
|
||||
}, null);
|
||||
|
||||
array_unshift($undefinedNamespaceFragments, array_pop($namespaceFragments));
|
||||
if ($bestNamespace instanceof PSR4Namespace) {
|
||||
return $bestNamespace->findClasses($namespace);
|
||||
} else {
|
||||
throw new ClassFinderException(sprintf("Unknown namespace '%s'. You should add the namespace prefix to composer.json. See '%s' for details.",
|
||||
$namespace,
|
||||
'https://gitlab.com/hpierce1102/ClassFinder/blob/master/docs/exceptions/unregisteredRoot.md'
|
||||
));
|
||||
}
|
||||
|
||||
throw new ClassFinderException(sprintf("Unknown namespace '%s'. You should add the namespace prefix to composer.json. See '%s' for details.",
|
||||
$namespace,
|
||||
'https://gitlab.com/hpierce1102/ClassFinder/blob/master/docs/exceptions/unregisteredRoot.md'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
67
src/Finder/PSR4Namespace.php
Normal file
67
src/Finder/PSR4Namespace.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
namespace HaydenPierce\ClassFinder\Finder;
|
||||
|
||||
use HaydenPierce\ClassFinder\Exception\ClassFinderException;
|
||||
|
||||
class PSR4Namespace
|
||||
{
|
||||
private $namespace;
|
||||
private $directories;
|
||||
|
||||
public function __construct($namespace, $directories)
|
||||
{
|
||||
$this->namespace = $namespace;
|
||||
$this->directories = $directories;
|
||||
}
|
||||
|
||||
public function matches($namespace)
|
||||
{
|
||||
$namespaceFragments = explode('\\', $namespace);
|
||||
$undefinedNamespaceFragments = [];
|
||||
|
||||
while($namespaceFragments) {
|
||||
$possibleNamespace = implode('\\', $namespaceFragments) . '\\';
|
||||
|
||||
if($this->namespace === $possibleNamespace){
|
||||
return true;
|
||||
}
|
||||
|
||||
array_unshift($undefinedNamespaceFragments, array_pop($namespaceFragments));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function findClasses($namespace)
|
||||
{
|
||||
// TODO: revisit this. It probably doesn't work.
|
||||
$relativePath = substr($namespace, strlen($this->namespace));
|
||||
|
||||
$directories = array_reduce($this->directories, function($carry, $directory) use ($relativePath, $namespace){
|
||||
$realDirectory = realpath($directory . '/' . $relativePath);
|
||||
if ($realDirectory !== false) {
|
||||
return array_merge($carry, array($realDirectory));
|
||||
} else {
|
||||
throw new ClassFinderException(sprintf("Unknown namespace '%s'. Checked for files in %s, but that directory did not exist. See %s for details.",
|
||||
$namespace,
|
||||
$realDirectory,
|
||||
'https://gitlab.com/hpierce1102/ClassFinder/blob/master/docs/exceptions/unknownSubNamespace.md'
|
||||
));
|
||||
}
|
||||
}, array());
|
||||
|
||||
$arraysOfClasses = array_map(function($directory) {
|
||||
return scandir($directory);
|
||||
}, $directories);
|
||||
|
||||
$potentialClassFiles = array_reduce($arraysOfClasses, function($carry, $arrayOfClasses) {
|
||||
return array_merge($carry, $arrayOfClasses);
|
||||
}, array());
|
||||
|
||||
$potentialClasses = array_map(function($file) use ($namespace){
|
||||
return $namespace . '\\' . str_replace('.php', '', $file);
|
||||
}, $potentialClassFiles);
|
||||
|
||||
return array_filter($potentialClasses, 'class_exists');
|
||||
}
|
||||
}
|
37
src/Finder/PSR4NamespaceFactory.php
Normal file
37
src/Finder/PSR4NamespaceFactory.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
namespace HaydenPierce\ClassFinder\Finder;
|
||||
|
||||
use HaydenPierce\ClassFinder\Exception\ClassFinderException;
|
||||
|
||||
class PSR4NamespaceFactory
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Figure out a way to stop passing in $appRoot. This will probably be a refactoring.
|
||||
* Creates a namespace from composer_psr4.php and composer.json's autoload.psr4 items
|
||||
* @param $namespace
|
||||
* @param $directories
|
||||
* @throws ClassFinderException
|
||||
*/
|
||||
public function createNamespace($namespace, $directories, $appRoot)
|
||||
{
|
||||
if (is_string($directories)) {
|
||||
// This is an acceptable format according to composer.json
|
||||
$directories = array($appRoot . $directories);
|
||||
} elseif (is_array($directories)) {
|
||||
// composer_psr4.php seems to put everything in this format
|
||||
} else {
|
||||
throw new ClassFinderException('Unknown PSR4 definition.');
|
||||
}
|
||||
|
||||
$directories = array_map(function($directory) {
|
||||
return realpath($directory);
|
||||
}, $directories);
|
||||
|
||||
return new PSR4Namespace($namespace, $directories);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user