From 25b458096b5be4428bd2260105c243a4a7084dc8 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Mon, 17 Mar 2025 21:10:13 +0400 Subject: [PATCH 1/3] Making sure to use native php functions in Loader and Environment classes --- src/Environment/Environment.php | 29 +++++------------------------ src/Loader/Loader.php | 7 ++----- 2 files changed, 7 insertions(+), 29 deletions(-) diff --git a/src/Environment/Environment.php b/src/Environment/Environment.php index 0029d66b..e6b2d6f4 100644 --- a/src/Environment/Environment.php +++ b/src/Environment/Environment.php @@ -9,14 +9,12 @@ * @author Arman Ag. * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org) * @link http://quantum.softberg.org/ - * @since 2.9.5 + * @since 2.9.6 */ namespace Quantum\Environment; -use Quantum\Libraries\Storage\Factories\FileSystemFactory; use Quantum\Environment\Exceptions\EnvException; -use Quantum\Libraries\Storage\FileSystem; use Quantum\Di\Exceptions\DiException; use Quantum\Exceptions\BaseException; use Quantum\Loader\Loader; @@ -34,12 +32,6 @@ class Environment { - /** - * FileSystem instance - * @var FileSystem - */ - private $fs; - /** * Environment file * @var string @@ -65,14 +57,6 @@ class Environment */ private static $instance = null; - /** - * @throws BaseException - */ - private function __construct() - { - $this->fs = FileSystemFactory::get(); - } - /** * GetInstance * @return Environment @@ -197,14 +181,11 @@ public function updateRow(string $key, ?string $value) $envFilePath = App::getBaseDir() . DS . $this->envFile; if ($row) { - $this->fs->put($envFilePath, preg_replace( - '/^' . $row . '/m', - $key . "=" . $value, - $this->fs->get($envFilePath) - ) - ); + $envFileContent = file_get_contents($envFilePath); + $envFileContent = preg_replace('/^' . preg_quote($row, '/') . '/m', $key . "=" . $value, $envFileContent); + file_put_contents($envFilePath, $envFileContent); } else { - $this->fs->append($envFilePath, PHP_EOL . $key . "=" . $value . PHP_EOL); + file_put_contents($envFilePath, PHP_EOL . $key . "=" . $value . PHP_EOL, FILE_APPEND); } $this->envContent = Dotenv::createMutable(App::getBaseDir(), $this->envFile)->load(); diff --git a/src/Loader/Loader.php b/src/Loader/Loader.php index 6b27912c..bfbd47c2 100644 --- a/src/Loader/Loader.php +++ b/src/Loader/Loader.php @@ -9,12 +9,11 @@ * @author Arman Ag. * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org) * @link http://quantum.softberg.org/ - * @since 2.9.5 + * @since 2.9.6 */ namespace Quantum\Loader; -use Quantum\Libraries\Storage\Factories\FileSystemFactory; use Quantum\Loader\Exceptions\LoaderException; use Quantum\Exceptions\BaseException; use ReflectionException; @@ -157,9 +156,7 @@ public function loadClassFromFile( callable $notDefinedException, array $constructorArgs = [] ) { - $fs = FileSystemFactory::get(); - - if (!$fs->exists($filePath)) { + if (!file_exists($filePath)) { throw $notFoundException(); } From 12279ae791a765b074cc8dba3e8c0b569bded684 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Mon, 17 Mar 2025 21:12:04 +0400 Subject: [PATCH 2/3] Cloud storage library simplifications --- .../Exceptions/FileSystemException.php | 10 +- .../Storage/Factories/FileSystemFactory.php | 112 +++++++++++++++--- src/Libraries/Storage/Helpers/fs.php | 37 ++++++ tests/Unit/AppTestCase.php | 4 +- .../Factories/FileSystemFactoryTest.php | 50 ++------ .../Helpers/FileSystemHelperFunctionsTest.php | 41 +++++++ tests/_root/shared/Services/TokenService.php | 25 ++++ tests/_root/shared/config/fs.php | 21 ++++ 8 files changed, 244 insertions(+), 56 deletions(-) create mode 100644 src/Libraries/Storage/Helpers/fs.php create mode 100644 tests/Unit/Libraries/Storage/Helpers/FileSystemHelperFunctionsTest.php create mode 100644 tests/_root/shared/Services/TokenService.php create mode 100644 tests/_root/shared/config/fs.php diff --git a/src/Libraries/Storage/Exceptions/FileSystemException.php b/src/Libraries/Storage/Exceptions/FileSystemException.php index 0bf39473..29f73718 100644 --- a/src/Libraries/Storage/Exceptions/FileSystemException.php +++ b/src/Libraries/Storage/Exceptions/FileSystemException.php @@ -9,7 +9,7 @@ * @author Arman Ag. * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org) * @link http://quantum.softberg.org/ - * @since 2.9.5 + * @since 2.9.6 */ namespace Quantum\Libraries\Storage\Exceptions; @@ -48,4 +48,12 @@ public static function fileAlreadyExists(): FileSystemException { return new static(t('exception.file_already_exists'), E_WARNING); } + + /** + * @return FileSystemException + */ + public static function incorrectTokenService(): FileSystemException + { + return new static(t('exception.incorrect_auth_service'), E_WARNING); + } } \ No newline at end of file diff --git a/src/Libraries/Storage/Factories/FileSystemFactory.php b/src/Libraries/Storage/Factories/FileSystemFactory.php index dcfe951d..fad18c69 100644 --- a/src/Libraries/Storage/Factories/FileSystemFactory.php +++ b/src/Libraries/Storage/Factories/FileSystemFactory.php @@ -9,7 +9,7 @@ * @author Arman Ag. * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org) * @link http://quantum.softberg.org/ - * @since 2.9.5 + * @since 2.9.6 */ namespace Quantum\Libraries\Storage\Factories; @@ -17,10 +17,20 @@ use Quantum\Libraries\Storage\Adapters\GoogleDrive\GoogleDriveFileSystemAdapter; use Quantum\Libraries\Storage\Adapters\Dropbox\DropboxFileSystemAdapter; use Quantum\Libraries\Storage\Adapters\Local\LocalFileSystemAdapter; +use Quantum\Libraries\Storage\Adapters\GoogleDrive\GoogleDriveApp; +use Quantum\Libraries\Storage\Contracts\TokenServiceInterface; use Quantum\Libraries\Storage\Exceptions\FileSystemException; +use Quantum\Libraries\Storage\Adapters\Dropbox\DropboxApp; use Quantum\Libraries\Storage\Contracts\CloudAppInterface; +use Quantum\Libraries\Config\Exceptions\ConfigException; +use Quantum\Libraries\HttpClient\HttpClient; use Quantum\Libraries\Storage\FileSystem; +use Quantum\Exceptions\ServiceException; +use Quantum\Di\Exceptions\DiException; use Quantum\Exceptions\BaseException; +use Quantum\Factory\ServiceFactory; +use Quantum\Loader\Setup; +use ReflectionException; /** * Class FileSystemFactory @@ -38,40 +48,114 @@ class FileSystemFactory FileSystem::GDRIVE => GoogleDriveFileSystemAdapter::class, ]; + /** + * Supported apps + */ + const APPS = [ + FileSystem::DROPBOX => DropboxApp::class, + FileSystem::GDRIVE => GoogleDriveApp::class, + ]; + /** * @var array */ private static $instances = []; /** - * @param string $type - * @param CloudAppInterface|null $cloudApp + * @param string|null $adapter * @return FileSystem * @throws BaseException + * @throws DiException + * @throws ReflectionException + * @throws ConfigException */ - public static function get(string $type = FileSystem::LOCAL, ?CloudAppInterface $cloudApp = null): FileSystem + public static function get(?string $adapter = null): FileSystem { - if (!isset(self::$instances[$type])) { - self::$instances[$type] = self::createInstance($type, $cloudApp); + if (!config()->has('fs')) { + config()->import(new Setup('Config', 'fs')); + } + + $adapter = $adapter ?? config()->get('fs.default'); + + $adapterClass = self::getAdapterClass($adapter); + + if (!isset(self::$instances[$adapter])) { + self::$instances[$adapter] = self::createInstance($adapterClass, $adapter); } - return self::$instances[$type]; + return self::$instances[$adapter]; } /** - * @param string $type - * @param CloudAppInterface|null $cloudApp + * @param string $adapterClass + * @param string $adapter * @return FileSystem + * @throws DiException + * @throws FileSystemException + * @throws ReflectionException + * @throws ServiceException + */ + private static function createInstance(string $adapterClass, string $adapter): FileSystem + { + return new FileSystem(new $adapterClass( + self::createCloudApp($adapter) + )); + } + + /** + * @param string $adapter + * @return string * @throws BaseException */ - private static function createInstance(string $type, ?CloudAppInterface $cloudApp = null): FileSystem + private static function getAdapterClass(string $adapter): string + { + if (!array_key_exists($adapter, self::ADAPTERS)) { + throw FileSystemException::adapterNotSupported($adapter); + } + + return self::ADAPTERS[$adapter]; + } + + /** + * @param string $adapter + * @return CloudAppInterface|null + * @throws DiException + * @throws FileSystemException + * @throws ReflectionException + * @throws ServiceException + */ + private static function createCloudApp(string $adapter): ?CloudAppInterface { - if (!isset(self::ADAPTERS[$type])) { - throw FileSystemException::adapterNotSupported($type); + if ($adapter === FileSystem::LOCAL || !isset(self::APPS[$adapter])) { + return null; } - $adapterClass = self::ADAPTERS[$type]; + $cloudAppClass = self::APPS[$adapter]; + + return new $cloudAppClass( + config()->get('fs.' . $adapter . '.params.app_key'), + config()->get('fs.' . $adapter . '.params.app_secret'), + self::createTokenService($adapter), + new HttpClient() + ); + } + + /** + * @param string $adapter + * @return TokenServiceInterface + * @throws FileSystemException + * @throws DiException + * @throws ServiceException + * @throws ReflectionException + */ + private static function createTokenService(string $adapter): TokenServiceInterface + { + $authService = ServiceFactory::create(config()->get('fs.' . $adapter . '.service')); + + if (!$authService instanceof TokenServiceInterface) { + throw FileSystemException::incorrectTokenService(); + } - return new FileSystem(new $adapterClass($cloudApp)); + return $authService; } } \ No newline at end of file diff --git a/src/Libraries/Storage/Helpers/fs.php b/src/Libraries/Storage/Helpers/fs.php new file mode 100644 index 00000000..a94523f7 --- /dev/null +++ b/src/Libraries/Storage/Helpers/fs.php @@ -0,0 +1,37 @@ + + * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org) + * @link http://quantum.softberg.org/ + * @since 2.9.6 + */ + +use Quantum\Libraries\Storage\Factories\FileSystemFactory; +use Quantum\Libraries\Config\Exceptions\ConfigException; +use Quantum\Libraries\Auth\Exceptions\AuthException; +use Quantum\Libraries\Storage\FileSystem; +use Quantum\Exceptions\ServiceException; +use Quantum\Di\Exceptions\DiException; +use Quantum\Exceptions\BaseException; + +/** + * Gets the FileSystem handler + * @param string|null $adapter + * @return FileSystem + * @throws AuthException + * @throws BaseException + * @throws ConfigException + * @throws DiException + * @throws ReflectionException + * @throws ServiceException + */ +function fs(?string $adapter = null): FileSystem +{ + return FileSystemFactory::get($adapter); +} \ No newline at end of file diff --git a/tests/Unit/AppTestCase.php b/tests/Unit/AppTestCase.php index d6b2c9a1..53ffb31c 100644 --- a/tests/Unit/AppTestCase.php +++ b/tests/Unit/AppTestCase.php @@ -18,8 +18,6 @@ abstract class AppTestCase extends TestCase public function setUp(): void { - $this->fs = FileSystemFactory::get(); - AppFactory::create(App::WEB, PROJECT_ROOT); Config::getInstance()->flush(); @@ -30,6 +28,8 @@ public function setUp(): void Config::getInstance() ->load(new Setup('config', 'config')); + + $this->fs = FileSystemFactory::get(); } protected function setPrivateProperty($object, $property, $value): void diff --git a/tests/Unit/Libraries/Storage/Factories/FileSystemFactoryTest.php b/tests/Unit/Libraries/Storage/Factories/FileSystemFactoryTest.php index 415eb104..b62bd26e 100644 --- a/tests/Unit/Libraries/Storage/Factories/FileSystemFactoryTest.php +++ b/tests/Unit/Libraries/Storage/Factories/FileSystemFactoryTest.php @@ -30,58 +30,30 @@ public function testFileSystemFactoryInstance() $this->assertInstanceOf(FileSystem::class, $fs); } - public function testFileSystemFactoryLocalAdapter() + public function testFileSystemFactoryDefaultAdapter() { $fs = FileSystemFactory::get(); $this->assertInstanceOf(LocalFileSystemAdapter::class, $fs->getAdapter()); } - public function testFileSystemFactoryDropboxAdapter() + public function testFileSystemFactoryLocalAdapter() { - $dropboxAppMock = Mockery::mock(DropboxApp::class); - - $dropboxAppMock - ->shouldReceive('rpcRequest') - ->andReturnUsing(function ($endpoint, $params) { - self::$response = array_merge(self::$response, $params); - return self::$response; - }); - - $dropboxAppMock - ->shouldReceive('contentRequest') - ->andReturnUsing(function ($endpoint, $params, $content = '') { - if ($content) { - self::$response['content'] = $content; - } - - return self::$response['content'] ?? false; - }); + $fs = FileSystemFactory::get(FileSystem::LOCAL); - $dropboxAppMock - ->shouldReceive('path') - ->andReturnUsing(function ($path) { - return ['path' => '/' . trim($path, '/')]; - }); + $this->assertInstanceOf(LocalFileSystemAdapter::class, $fs->getAdapter()); + } - $fs = FileSystemFactory::get(FileSystem::DROPBOX, $dropboxAppMock); + public function testFileSystemFactoryDropboxAdapter() + { + $fs = FileSystemFactory::get(FileSystem::DROPBOX); $this->assertInstanceOf(DropboxFileSystemAdapter::class, $fs->getAdapter()); } public function testFileSystemFactoryGoogleDriveAdapter() { - $googleDriveAppMock = Mockery::mock(GoogleDriveApp::class)->makePartial(); - - $googleDriveAppMock->shouldReceive('rpcRequest')->andReturnUsing(function ($endpoint, $params) { - if(str_contains($endpoint, '?alt=media')){ - return self::$response[array_key_last(self::$response)]; - } - self::$response = array_merge(self::$response, (array)$params); - return (object)self::$response; - }); - - $fs = FileSystemFactory::get(FileSystem::GDRIVE, $googleDriveAppMock); + $fs = FileSystemFactory::get(FileSystem::GDRIVE); $this->assertInstanceOf(GoogleDriveFileSystemAdapter::class, $fs->getAdapter()); } @@ -97,8 +69,8 @@ public function testFileSystemFactoryInvalidTypeAdapter() public function testFileSystemFactoryReturnsSameInstance() { - $fs1 = FileSystemFactory::get(); - $fs2 = FileSystemFactory::get(); + $fs1 = FileSystemFactory::get(FileSystem::LOCAL); + $fs2 = FileSystemFactory::get(FileSystem::LOCAL); $this->assertSame($fs1, $fs2); } diff --git a/tests/Unit/Libraries/Storage/Helpers/FileSystemHelperFunctionsTest.php b/tests/Unit/Libraries/Storage/Helpers/FileSystemHelperFunctionsTest.php new file mode 100644 index 00000000..43d92b86 --- /dev/null +++ b/tests/Unit/Libraries/Storage/Helpers/FileSystemHelperFunctionsTest.php @@ -0,0 +1,41 @@ +assertInstanceOf(FileSystem::class, fs()); + + $this->assertInstanceOf(LocalFileSystemAdapter::class, fs()->getAdapter()); + } + + public function testFileSystemHelperGetLocalFileSystem() + { + $this->assertInstanceOf(FileSystem::class, fs(FileSystem::LOCAL)); + + $this->assertInstanceOf(LocalFileSystemAdapter::class, fs(FileSystem::LOCAL)->getAdapter()); + } + + public function testFileSystemHelperGetDropboxFileSystem() + { + $this->assertInstanceOf(FileSystem::class, fs(FileSystem::DROPBOX)); + + $this->assertInstanceOf(DropboxFileSystemAdapter::class, fs(FileSystem::DROPBOX)->getAdapter()); + } + + public function testFileSystemHelperGetGoogleDriveFileSystem() + { + $this->assertInstanceOf(FileSystem::class, fs(FileSystem::GDRIVE)); + + $this->assertInstanceOf(GoogleDriveFileSystemAdapter::class, fs(FileSystem::GDRIVE)->getAdapter()); + } +} \ No newline at end of file diff --git a/tests/_root/shared/Services/TokenService.php b/tests/_root/shared/Services/TokenService.php new file mode 100644 index 00000000..1d37309e --- /dev/null +++ b/tests/_root/shared/Services/TokenService.php @@ -0,0 +1,25 @@ + 'local', + + 'dropbox' => [ + 'service' => Quantum\Tests\_root\shared\Services\TokenService::class, + 'params' => [ + 'app_key' => '', + 'app_secret' => '', + ] + ], + + 'gdrive' => [ + 'service' => Quantum\Tests\_root\shared\Services\TokenService::class, + 'params' => [ + 'app_key' => '', + 'app_secret' => '', + ] + ] +]; From 8d760870bef694dfcf73c530b1f5f4746465e915 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Tue, 18 Mar 2025 18:27:20 +0400 Subject: [PATCH 3/3] Variable name change --- src/Libraries/Storage/Factories/FileSystemFactory.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Libraries/Storage/Factories/FileSystemFactory.php b/src/Libraries/Storage/Factories/FileSystemFactory.php index fad18c69..a149cd70 100644 --- a/src/Libraries/Storage/Factories/FileSystemFactory.php +++ b/src/Libraries/Storage/Factories/FileSystemFactory.php @@ -150,12 +150,12 @@ private static function createCloudApp(string $adapter): ?CloudAppInterface */ private static function createTokenService(string $adapter): TokenServiceInterface { - $authService = ServiceFactory::create(config()->get('fs.' . $adapter . '.service')); + $tokenService = ServiceFactory::create(config()->get('fs.' . $adapter . '.service')); - if (!$authService instanceof TokenServiceInterface) { + if (!$tokenService instanceof TokenServiceInterface) { throw FileSystemException::incorrectTokenService(); } - return $authService; + return $tokenService; } } \ No newline at end of file