vd/vendor/dipper/console/src/Finder.php
2018-11-05 09:26:30 +08:00

413 lines
10 KiB
PHP

<?php
namespace Dipper\Console;
use Exception;
use Illuminate\Support\Str;
use InvalidArgumentException;
use Dipper\Console\Components\Job;
use Illuminate\Support\Collection;
use Dipper\Console\Components\Domain;
use Dipper\Console\Components\Service;
use Symfony\Component\Finder\Finder as SymfonyFinder;
/**
* @author HollyTeng <n.haoyuan@gmail.com>
*/
trait Finder
{
/**
* The name of the source directory.
*
* @var string
*/
protected $srcDirectoryName = 'app';
/**
* Get the base path of the Laravel installation.
*
* @param string $path Optionally, a path to append to the base path
* @return string
*/
public function basePath($path = '')
{
return DIPPER_BASE_PATH.($path ? DIRECTORY_SEPARATOR.$path : $path);
}
/**
* Get the source directory name.
* In a microservice installation this will be `app`. `src` otherwise.
*
* @return string
*/
public function getSourceDirectoryName()
{
if (file_exists($this->basePath($this->srcDirectoryName))) {
return $this->srcDirectoryName;
}
return 'app';
}
/**
* Get the namespace used for the application.
*
* @throws \Exception
* @return string
*/
public function findRootNamespace()
{
// read composer.json file contents to determine the namespace
$composer = json_decode(file_get_contents($this->basePath('composer.json')), true);
// see which one refers to the "app/" directory
foreach ($composer['autoload']['psr-4'] as $namespace => $directory) {
if ($directory === $this->getSourceDirectoryName() . '/') {
return trim($namespace, '\\');
}
}
throw new Exception('App namespace not set in composer.json');
}
/**
* Find the namespace of the foundation.
*
* @return string
*/
public function findFoundationNamespace()
{
return 'Dipper\Foundation';
}
/**
* get the root of the source directory.
*
* @return string
*/
public function findSourceRoot()
{
return $this->basePath($this->srcDirectoryName);
}
/**
* Get the path to the Composer.json file.
*
* @return string
*/
protected function getComposerPath()
{
return $this->basePath('composer.json');
}
/**
* Get the path to the given configuration file.
*
* @param string $name
*
* @return string
*/
protected function getConfigPath($name)
{
return base_path('config/' . $name . '.php');
}
/**
* 解析输入的数据,适应文件夹深度.
*
* @param string $name
*
* @return string
*/
protected function prepareNamespace($name)
{
if (strpos($name, '/')) {
$arr = explode('/', $name);
array_pop($arr);
foreach ($arr as $value) {
$this->lastNamespace .= '\\' . $value;
}
}
}
/**
* Get the full namespace for a given class, without the class name.
*
* @param string $name
* @return string
*/
protected function getNamespace($name)
{
return trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\');
}
/**
* Find the root path of domains.
*
* @return string
*/
public function findDomainsRootPath()
{
return $this->findSourceRoot() . '/Domains';
}
/**
* Find the path for the given domain.
*
* @param string $domain
*
* @return string
*/
public function findDomainPath($domain)
{
return (!$domain) ? $this->findSourceRoot() : $this->findDomainsRootPath() . "/$domain";
}
/**
* Get the list of domains.
*
* @return \Illuminate\Support\Collection;
*/
public function listDomains()
{
$finder = new SymfonyFinder();
$directories = $finder
->depth(0)
->in($this->findDomainsRootPath())
->directories();
$domains = new Collection();
foreach ($directories as $directory) {
$name = $directory->getRelativePathName();
$domain = new Domain(
$this->realName($name),
$this->findDomainNamespace($name),
$directory->getRealPath(),
$this->relativeFromReal($directory->getRealPath())
);
$domains->push($domain);
}
return $domains;
}
/**
* Find the namespace for the given domain.
*
* @param string $domain
*
* @return string
*/
public function findDomainNamespace($domain)
{
$root = $this->findRootNamespace();
return (!$domain) ? $root : "$root\\Domains\\$domain";
}
/**
* Get the path to the tests of the given domain.
*
* @param string $domain
*
* @return string
*/
public function findDomainTestsNamespace($domain)
{
return $this->findDomainNamespace($domain) . '\\' . 'Tests';
}
/**
* Get the path to the tests of the given domain.
*
* @param string $domain
*
* @return string
*/
public function findDomainTestsPath($domain)
{
return $this->findDomainPath($domain) . DIRECTORY_SEPARATOR . 'Tests';
}
/**
* Find the domain for the given domain name.
*
* @param string $domain
*
* @return \Dipper\Console\Components\Domain
*/
public function findDomain($domain)
{
$finder = new SymfonyFinder();
$dirs = $finder->name($domain)->in($this->findDomainsRootPath())->directories();
if ($dirs->count() < 1) {
throw new Exception('Domain "' . $domain . '" could not be found.');
}
foreach ($dirs as $dir) {
$path = $dir->getRealPath();
return new Domain(
Str::studly($domain),
$this->findDomainNamespace($domain),
$path,
$this->relativeFromReal($path)
);
}
}
/**
* List the jobs per domain,
* optionally provide a domain name to list its jobs.
*
* @param string $domain
*
* @return Collection
*/
public function listJobs($domainName = null)
{
$domains = ($domainName) ? [$this->findDomain(Str::studly($domainName))] : $this->listDomains();
$jobs = new Collection();
foreach ($domains as $domain) {
$jobs[$domain->name] = new Collection();
$finder = new SymfonyFinder();
try {
$files = $finder->name('*Job.php')->in($domain->realPath.DIRECTORY_SEPARATOR.'Jobs')->files();
} catch (\Exception $e) {
continue;
}
foreach ($files as $file) {
$name = $file->getRelativePathName();
$job = new Job(
$this->realName($name, '/Job.php/'),
$this->getNamespace($name),
$name,
$file->getRealPath(),
$this->relativeFromReal($file->getRealPath()),
$domain,
file_get_contents($file->getRealPath())
);
$jobs[$domain->name]->push($job);
}
}
return $jobs;
}
/**
* Get the list of services,
* optionally withing a specified domain.
*
* @param string $domainName
*
* @throws \Exception
* @return \Illuminate\Support\Collection
*/
public function listServices($domainName = '')
{
$domains = $this->listDomains();
if (!empty($domainName)) {
$domains = $domains->filter(function ($domain) use ($domainName) {
return $domain->name === $domainName || $domain->slug === $domainName;
});
if ($domains->isEmpty()) {
throw new InvalidArgumentException('Domain "' . $domainName . '" could not be found.');
}
}
$services = [];
foreach ($domains as $domain) {
$services[$domain->name] = new Collection();
$finder = new SymfonyFinder();
try {
$files = $finder->name('*Service.php')->in($domain->realPath.DIRECTORY_SEPARATOR.'Services')->files();
} catch (\Exception $e) {
continue;
}
foreach ($files as $file) {
$fileName = $file->getRelativePathName();
$title = $this->realName($fileName, '/Service.php/');
$realPath = $file->getRealPath();
$relativePath = $this->relativeFromReal($realPath);
$services[$domain->name]->push(new Service($title, $fileName, $realPath, $relativePath, $domain));
}
}
return $services;
}
/**
* 获取Domain的 ServiceProvider
*
* @return void
*/
public function getDomainServiceProvider($domain)
{
if ($domain instanceof Domain) {
return $domain->namespace . '\\Providers\\' . $domain->name . 'ServiceProvider';
}
$rootNamespace = $this->findRootNamespace();
$domainNamespace = $this->findDomainNamespace($name);
return $domainNamespace . '\\Providers\\' . $name . 'ServiceProvider';
}
/**
* Get the path to the cached packages.php file.
*
* @return string
*/
public function getCachedPackagesPath()
{
return storage_path('framework/cache/packages.php');
}
/**
* Get the relative version of the given real path.
*
* @param string $path
* @param string $needle
*
* @return string
*/
protected function relativeFromReal($path, $needle = '')
{
if (!$needle) {
$needle = $this->getSourceDirectoryName() . '/';
}
return strstr($path, $needle);
}
/**
* Determine the real name of the given name,
* excluding the given pattern.
* i.e. the name: "CreateArticleService.php" with pattern '/Service.php'
* will result in "Create Article".
*
* @param string $name
* @param string $pattern
*
* @return string
*/
protected function realName($name, $pattern = '//')
{
$name = preg_replace($pattern, '', $name);
return implode(' ', preg_split('/(?=[A-Z])/', $name, -1, PREG_SPLIT_NO_EMPTY));
}
}