fake
方法
/**
* Replace the given disk with a local testing disk.
*
* @param string|null $disk
*
* @return void
*/
public static function fake($disk = null)
{
$disk = $disk ?: self::$app['config']->get('filesystems.default');
(new Filesystem)->cleanDirectory(
$root = storage_path('framework/testing/disks/'.$disk)
);
static::set($disk, self::createLocalDriver(['root' => $root]));
}
獲取儲存驅動名稱和子路徑
$disk = $disk ?: self:$app['config']->get('filesystems.default');
判斷是否有傳遞測試路徑 用於儲存
刪除存在的目錄
(new Filesystem)->cleanDirectory(
$root = storage_path('framework/testing/disks/'.$disk)
);
建立檔案物件(Filesystem)通過cleanDirectory
方法 來刪除已經存在的目錄
Filesystem 檔案 cleanDirectory
刪除程式碼
/**
* Empty the specified directory of all files and folders.
*
* @param string $directory
* @return bool
*/
public function cleanDirectory($directory)
{
return $this->deleteDirectory($directory, true);
}
在cleanDirectory
可以看到呼叫自身的deleteDirectory
方法
/**
* Recursively delete a directory.
*
* The directory itself may be optionally preserved.
*
* @param string $directory
* @param bool $preserve
* @return bool
*/
public function deleteDirectory($directory, $preserve = false)
{
if (! $this->isDirectory($directory)) {
return false;
}
$items = new FilesystemIterator($directory);
foreach ($items as $item) {
// If the item is a directory, we can just recurse into the function and
// delete that sub-directory otherwise we'll just delete the file and
// keep iterating through each file until the directory is cleaned.
if ($item->isDir() && ! $item->isLink()) {
$this->deleteDirectory($item->getPathname());
}
// If the item is just a file, we can go ahead and delete it since we're
// just looping through and waxing all of the files in this directory
// and calling directories recursively, so we delete the real path.
else {
$this->delete($item->getPathname());
}
}
if (! $preserve) {
@rmdir($directory);
}
return true;
}
deleteDirectory
方法中的第一行是驗證方法是否存在
if (! $this->isDirectory($directory)) {
return false;
}
isDirectory
方法
/**
* Determine if the given path is a directory.
*
* @param string $directory
* @return bool
*/
public function isDirectory($directory)
{
return is_dir($directory);
}
deleteDirectory
第二行程式碼建立一個 FilesystemIterator
來獲取當前目錄下所有檔案和刪除所有檔案和目錄
$items = new FilesystemIterator($directory);
foreach ($items as $item) {
// If the item is a directory, we can just recurse into the function and
// delete that sub-directory otherwise we'll just delete the file and
// keep iterating through each file until the directory is cleaned.
if ($item->isDir() && ! $item->isLink()) {
$this->deleteDirectory($item->getPathname());
}
// If the item is just a file, we can go ahead and delete it since we're
// just looping through and waxing all of the files in this directory
// and calling directories recursively, so we delete the real path.
else {
$this->delete($item->getPathname());
}
}
- 第一個條件驗證是否目錄和是否有完整路徑, 呼叫自身遞迴刪除
- 如果不是目錄呼叫自身
delete
方法刪除檔案和軟連線
/**
* Delete the file at a given path.
*
* @param string|array $paths
* @return bool
*/
public function delete($paths)
{
$paths = is_array($paths) ? $paths : func_get_args();
$success = true;
foreach ($paths as $path) {
try {
if (! @unlink($path)) {
$success = false;
}
} catch (ErrorException $e) {
$success = false;
}
}
return $success;
}
建立目錄
static::set($disk, self::createLocalDriver(['root' => $root]));
呼叫 Illuminate\Filesystem\FilesystemManager
類中的方法建立本地測試驅動
/**
* Create an instance of the local driver.
*
* @param array $config
* @return \Illuminate\Contracts\Filesystem\Filesystem
*/
public function createLocalDriver(array $config)
{
$permissions = $config['permissions'] ?? [];
$links = ($config['links'] ?? null) === 'skip'
? LocalAdapter::SKIP_LINKS
: LocalAdapter::DISALLOW_LINKS;
return $this->adapt($this->createFlysystem(new LocalAdapter(
$config['root'], LOCK_EX, $links, $permissions
), $config));
}
獲取檔案和目錄寫入的許可權
$permissions = $config['permissions'] ?? [];
獲取是否有軟連線寫入
$links = ($config['links'] ?? null) === 'skip'
? LocalAdapter::SKIP_LINKS
: LocalAdapter::DISALLOW_LINKS;
建立一個新的本地檔案介面卡 (League\Flysystem\Adapter\LocalAdapter
) 類物件
/**
* Constructor.
*
* @param string $root
* @param int $writeFlags
* @param int $linkHandling
* @param array $permissions
*
* @throws LogicException
*/
public function __construct($root, $writeFlags = LOCK_EX, $linkHandling = self::DISALLOW_LINKS, array $permissions = [])
{
$root = is_link($root) ? realpath($root) : $root;
$this->permissionMap = array_replace_recursive(static::$permissions, $permissions);
$this->ensureDirectory($root);
if ( ! is_dir($root) || ! is_readable($root)) {
throw new LogicException('The root path ' . $root . ' is not readable.');
}
$this->setPathPrefix($root);
$this->writeFlags = $writeFlags;
$this->linkHandling = $linkHandling;
}
獲取檔案絕對路徑, 驗證是否絕對路徑如果不是轉換為絕對路徑
$root = is_link($root) ? realpath($root) : $root;
獲取檔案或者資料夾許可權
$this->permissionMap = array_replace_recursive(static::$permissions, $permissions);
ensureDirectory
驗證目錄是否存在不存在重新建立
/**
* Ensure the root directory exists.
*
* @param string $root root directory path
*
* @return void
*
* @throws Exception in case the root directory can not be created
*/
protected function ensureDirectory($root)
{
if ( ! is_dir($root)) {
$umask = umask(0);
if ( ! @mkdir($root, $this->permissionMap['dir']['public'], true)) {
$mkdirError = error_get_last();
}
umask($umask);
clearstatcache(false, $root);
if ( ! is_dir($root)) {
$errorMessage = isset($mkdirError['message']) ? $mkdirError['message'] : '';
throw new Exception(sprintf('Impossible to create the root directory "%s". %s', $root, $errorMessage));
}
}
}
setPathPrefix
設定絕對目錄
/**
* Set the path prefix.
*
* @param string $prefix
*
* @return void
*/
public function setPathPrefix($prefix)
{
$prefix = (string) $prefix;
if ($prefix === '') {
$this->pathPrefix = null;
return;
}
$this->pathPrefix = rtrim($prefix, '\\/') . $this->pathSeparator;
}
建立檔案物件 createFlysystem
建立程式碼
$this->createFlysystem(
new LocalAdapter($config['root'], LOCK_EX, $links, $permissions),
$config);
/**
* Create a Flysystem instance with the given adapter.
*
* @param \League\Flysystem\AdapterInterface $adapter
* @param array $config
* @return \League\Flysystem\FilesystemInterface
*/
protected function createFlysystem(AdapterInterface $adapter, array $config)
{
$cache = Arr::pull($config, 'cache');
$config = Arr::only($config, ['visibility', 'disable_asserts', 'url']);
if ($cache) {
$adapter = new CachedAdapter($adapter, $this->createCacheStore($cache));
}
return new Flysystem($adapter, count($config) > 0 ? $config : null);
}
獲取配置資料
$cache = Arr::pull($config, 'cache');
$config = Arr::only($config, ['visibility', 'disable_asserts', 'url']);
看是否需要快取配置, 需要的話建立 快取介面卡
替換之前的 本地介面卡
if ($cache) {
$adapter = new CachedAdapter($adapter, $this->createCacheStore($cache));
}
建立 League\Flysystem\Filesystem
return new Flysystem($adapter, count($config) > 0 ? $config : null);
儲存使用紀錄
static::set($disk, self::createLocalDriver(['root' => $root]));
/**
* Set the given disk instance.
*
* @param string $name
* @param mixed $disk
* @return $this
*/
public function set($name, $disk)
{
$this->disks[$name] = $disk;
return $this;
}
關於 Storage
門面如何對映 FilesystemManager
說明
通過 laravel框架提供 IOC
(控制反轉) 來進行對映
由 Illuminate\Support\Facades\Storage
門面方法中 getFacadeAccessor
提供的名稱來訪問(對映)
其中 Storage
中的 getFacadeAccessor
返回了 filesystem
名稱
<?php
namespace Illuminate\Support\Facades;
use Illuminate\Filesystem\Filesystem;
/**
* @method static \Illuminate\Contracts\Filesystem\Filesystem disk(string $name = null)
*
* @see \Illuminate\Filesystem\FilesystemManager
*/
class Storage extends Facade
{
...
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'filesystem';
}
}
然後在 Illuminate\Filesystem\FilesystemServiceProvider
檔案服務提供者註冊單例
<?php
namespace Illuminate\Filesystem;
use Illuminate\Support\ServiceProvider;
class FilesystemServiceProvider extends ServiceProvider
{
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->registerNativeFilesystem();
$this->registerFlysystem();
}
/**
* Register the native filesystem implementation.
*
* @return void
*/
protected function registerNativeFilesystem()
{
$this->app->singleton('files', function () {
return new Filesystem;
});
}
/**
* Register the driver based filesystem.
*
* @return void
*/
protected function registerFlysystem()
{
$this->registerManager();
$this->app->singleton('filesystem.disk', function () {
return $this->app['filesystem']->disk($this->getDefaultDriver());
});
$this->app->singleton('filesystem.cloud', function () {
return $this->app['filesystem']->disk($this->getCloudDriver());
});
}
/**
* Register the filesystem manager.
*
* @return void
*/
protected function registerManager()
{
$this->app->singleton('filesystem', function () {
return new FilesystemManager($this->app);
});
}
...
}
說明
由於個人技術知識有限, 在部分說明中可能會出現錯誤解釋, 已經說明不完整的地方, 可以指出幫忙改正, 謝謝
本作品採用《CC 協議》,轉載必須註明作者和本文連結