File: /www/wwwroot/kk.ibovsl.com/vendor/dcat/laravel-admin/src/Extend/Manager.php
<?php
namespace Dcat\Admin\Extend;
use Dcat\Admin\Admin;
use Dcat\Admin\Exception\AdminException;
use Dcat\Admin\Exception\RuntimeException;
use Dcat\Admin\Models\Extension;
use Dcat\Admin\Models\Extension as ExtensionModel;
use Dcat\Admin\Support\Composer;
use Dcat\Admin\Support\Helper;
use Dcat\Admin\Support\Zip;
use Illuminate\Contracts\Container\Container;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
class Manager
{
use Note;
/**
* @var Container
*/
protected $app;
/**
* @var ServiceProvider[]|Collection
*/
protected $extensions;
/**
* @var array
*/
protected $extensionPaths = [];
/**
* @var ExtensionModel[]|Collection
*/
protected $settings;
/**
* @var Filesystem
*/
protected $files;
public function __construct(Container $app)
{
$this->app = $app;
$this->extensions = new Collection();
$this->files = app('files');
}
/**
* 注册扩展.
*
* @return void
*/
public function register()
{
$this->load();
$this->extensions->each->register();
}
/**
* 初始化扩展.
*/
public function boot()
{
$this->extensions->each->boot();
}
/**
* 判断扩展是否启用.
*
* @param string|null $name
*
* @return bool
*/
public function enabled(?string $name)
{
return (bool) optional($this->settings()->get($name))->is_enabled;
}
/**
* 启用或禁用扩展.
*
* @param string|null $name
* @param bool $enable
*
* @return void
*/
public function enable(?string $name, bool $enable = true)
{
$name = $this->getName($name);
$extension = Extension::where('name', $name)->first();
if (! $extension) {
throw new RuntimeException(sprintf('Please install the extension(%s) first!', $name));
}
$extension->is_enabled = $enable;
$extension->save();
}
/**
* 加载扩展,注册自动加载规则.
*
* @return $this
*/
public function load()
{
foreach ($this->getExtensionDirectories() as $directory) {
try {
$this->loadExtension($directory);
} catch (\Throwable $e) {
$this->reportException($e);
}
}
return $this;
}
/**
* 获取扩展路径.
*
* @param string|ServiceProvider $name
* @param string|null $path
*
* @return string|void
*
* @throws \ReflectionException
*/
public function path($name, $path = null)
{
if (! $extension = $this->get($name)) {
return;
}
return $extension->path($path);
}
/**
* 获取扩展对象.
*
* @param string|ServiceProvider $name
*
* @return ServiceProvider|null
*/
public function get($name)
{
if ($name instanceof ServiceProvider) {
return $name;
}
return $this->extensions->get($this->formatName($name));
}
/**
* 判断插件是否存在.
*
* @param string $name
*
* @return bool
*/
public function has($name)
{
return $this->extensions->has($this->formatName($name));
}
/**
* @param string $name
*
* @return mixed
*/
protected function formatName($name)
{
if (! is_string($name)) {
return $name;
}
return str_replace('/', '.', $name);
}
/**
* 获取所有扩展.
*
* @return ServiceProvider[]|Collection
*/
public function all()
{
return $this->extensions;
}
/**
* 获取已启用的扩展.
*
* @return ServiceProvider[]|Collection
*/
public function available()
{
return $this->all()->filter->enabled();
}
/**
* 加载扩展.
*
* @param string $directory
* @param bool $addPsr4
*
* @return ServiceProvider|null
*/
public function loadExtension(string $directory, bool $addPsr4 = true)
{
if (array_key_exists($directory, $this->extensionPaths)) {
return $this->extensionPaths[$directory];
}
$this->extensionPaths[$directory] = $serviceProvider = $this->resolveExtension($directory, $addPsr4);
if ($serviceProvider) {
$this->addExtension($serviceProvider);
}
return $serviceProvider;
}
/**
* 获取扩展类实例.
*
* @param string $directory
* @param bool $addPsr4
*
* @return ServiceProvider
*/
public function resolveExtension(string $directory, bool $addPsr4 = true)
{
$composerProperty = Composer::parse($directory.'/composer.json');
$serviceProvider = $composerProperty->get('extra.dcat-admin');
$psr4 = $composerProperty->get('autoload.psr-4');
if (! $serviceProvider || ! $psr4) {
return;
}
if ($addPsr4) {
$this->registerPsr4($directory, $psr4);
}
$serviceProvider = new $serviceProvider($this->app);
return $serviceProvider->withComposerProperty($composerProperty);
}
/**
* 获取扩展目录.
*
* @param string $dirPath
*
* @return array
*/
public function getExtensionDirectories($dirPath = null)
{
$extensions = [];
$dirPath = $dirPath ?: admin_extension_path();
if (! is_dir($dirPath)) {
return $extensions;
}
$it = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dirPath, RecursiveDirectoryIterator::FOLLOW_SYMLINKS)
);
$it->setMaxDepth(2);
$it->rewind();
while ($it->valid()) {
if ($it->getDepth() > 1 && $it->getFilename() === 'composer.json') {
$extensions[] = dirname($it->getPathname());
}
$it->next();
}
return $extensions;
}
/**
* 添加扩展.
*
* @param \Dcat\Admin\Extend\ServiceProvider $serviceProvider
*/
public function addExtension(ServiceProvider $serviceProvider)
{
if (! $serviceProvider->getName()) {
$json = dirname(dirname(Helper::guessClassFileName($serviceProvider))).'/composer.json';
if (! is_file($json)) {
throw new RuntimeException(sprintf('Error extension "%s"', get_class($serviceProvider)));
}
$serviceProvider->withComposerProperty(Composer::parse($json));
}
$this->extensions->put($serviceProvider->getName(), $serviceProvider);
$this->app->instance($abstract = get_class($serviceProvider), $serviceProvider);
$this->app->alias($abstract, $serviceProvider->getName());
}
/**
* 获取扩展名称.
*
* @param $extension
*
* @return string
*/
public function getName($extension)
{
if ($extension instanceof ServiceProvider) {
return $extension->getName();
}
return $this->formatName($extension);
}
/**
* 解压缩扩展包.
*
* @param string $filePath
* @param bool $force
*
* @return string
*/
public function extract($filePath, bool $force = false)
{
$filePath = is_file($filePath) ? $filePath : $this->getFilePath($filePath);
$name = $this->extractZip($filePath, $force);
@unlink($filePath);
return $name;
}
/**
* @param string $filePath
* @param bool $force
*
* @return bool
*/
public function extractZip($filePath, bool $force = false)
{
// 创建临时目录.
$tempPath = $this->makeTempDirectory();
try {
$filePath = is_file($filePath) ? $filePath : $this->getFilePath($filePath);
if (! Zip::extract($filePath, $tempPath)) {
throw new AdminException(sprintf('Unable to extract core file \'%s\'.', $filePath));
}
$extensions = $this->getExtensionDirectories($tempPath);
// 无上层目录
$directory = $tempPath;
if (count($extensions) === 1) {
// 双层目录
$directory = current($extensions);
} elseif (count($results = $this->scandir($tempPath)) === 1) {
// 单层目录
$directory = current($results);
}
// 验证扩展包内容是否正确.
if (! $this->checkFiles($directory)) {
throw new RuntimeException(sprintf('Error extension file "%s".', $filePath));
}
$composerProperty = Composer::parse($directory.'/composer.json');
$extensionDir = admin_extension_path($composerProperty->name);
if (! $force && is_dir($extensionDir)) {
throw new RuntimeException(sprintf('The extension [%s] already exist!', $composerProperty->name));
}
if (! is_dir($extensionDir)) {
$this->files->makeDirectory($extensionDir, 0755, true);
}
$this->files->copyDirectory($directory, $extensionDir);
return $composerProperty->name;
} finally {
$this->files->deleteDirectory($tempPath);
}
}
/**
* 校验扩展包内容是否正确.
*
* @param $directory
*
* @return bool
*/
protected function checkFiles($directory)
{
if (
! is_dir($directory.'/src')
|| ! is_file($directory.'/composer.json')
|| ! is_file($directory.'/version.php')
) {
return false;
}
$composerProperty = Composer::parse($directory.'/composer.json');
if (! $composerProperty->name || ! $composerProperty->get('extra.dcat-admin')) {
return false;
}
return true;
}
/**
* 生成临时文件.
*
* @param string $fileCode A unique file code
* @return string Full path on the disk
*/
protected function getFilePath($fileCode)
{
$name = md5($fileCode).'.arc';
return $this->makeTempDirectory('extensions').'/'.$name;
}
/**
* 获取配置.
*
* @return ExtensionModel[]|Collection
*/
public function settings()
{
if ($this->settings === null) {
try {
$this->settings = ExtensionModel::all()->keyBy('name');
} catch (\Throwable $e) {
$this->reportException($e);
$this->settings = new Collection();
}
}
return $this->settings;
}
/**
* @return UpdateManager
*/
public function updateManager()
{
return app('admin.extend.update');
}
/**
* @return VersionManager
*/
public function versionManager()
{
return app('admin.extend.version');
}
/**
* 创建临时目录.
*
* @param string $dir
*
* @return string
*/
protected function makeTempDirectory($dir = null)
{
$tempDir = storage_path('tmp/'.($dir ?: time().Str::random()));
if (! is_dir($tempDir)) {
if (! $this->files->makeDirectory($tempDir, 0777, true)) {
throw new RuntimeException(sprintf('Cannot write to directory "%s"', storage_path()));
}
}
return $tempDir;
}
/**
* 注册 PSR4 验证规则.
*
* @param string $directory
* @param array $psr4
*/
protected function registerPsr4($directory, array $psr4)
{
$classLoader = Admin::classLoader();
foreach ($psr4 as $namespace => $path) {
$path = $directory.'/'.trim($path, '/').'/';
$classLoader->addPsr4($namespace, $path);
}
}
/**
* 上报异常.
*
* @param \Throwable $e
*/
protected function reportException(\Throwable $e)
{
Admin::reportException($e);
}
/**
* @param string $dir
*
* @return array
*/
protected function scandir($dir)
{
$results = [];
foreach (scandir($dir) as $value) {
if (
$value !== '.'
&& $value !== '..'
&& is_dir($value = $dir.'/'.$value)
) {
$results[] = $value;
}
}
return $results;
}
}