S3Adapter::class, 'webdav' => WebdavAdapter::class, 'sftp' => SftpAdapter::class, 'gcs' => GoogleCloudAdapter::class, 'azure' => AzureBlobAdapter::class, 'dropbox' => DropboxAdapter::class, 'google-drive' => GoogleDriveAdapter::class, 'onedrive' => OneDriveAdapter::class, ]; /** * Crea un Filesystem basado en la configuración proporcionada * * @param array $config Configuración del filesystem * @return Filesystem * @throws InvalidArgumentException Si el proveedor no es válido */ public static function create(array $config): Filesystem { $provider = $config['provider'] ?? ''; if (empty($provider)) { throw new InvalidArgumentException('Provider is required in configuration'); } $adapter = self::createAdapter($provider, $config); // Aplicar prefijo global si está configurado if (!empty($config['prefix'])) { $adapter = new PrefixedAdapter($adapter, $config['prefix']); } return new Filesystem($adapter); } /** * Crea un adaptador específico basado en el proveedor * * @param string $provider Nombre del proveedor * @param array $config Configuración del adaptador * @return FilesystemAdapter * @throws InvalidArgumentException Si el proveedor no es soportado */ private static function createAdapter(string $provider, array $config): FilesystemAdapter { $provider = strtolower(trim($provider)); if (!isset(self::ADAPTER_MAP[$provider])) { throw new InvalidArgumentException( sprintf( 'Unsupported provider: %s. Supported providers: %s', $provider, implode(', ', array_keys(self::ADAPTER_MAP)) ) ); } $adapterClass = self::ADAPTER_MAP[$provider]; if (!class_exists($adapterClass)) { throw new InvalidArgumentException( sprintf('Adapter class not found: %s', $adapterClass) ); } /** @var AdapterInterface $adapterInstance */ $adapterInstance = new $adapterClass(); if (!$adapterInstance instanceof AdapterInterface) { throw new InvalidArgumentException( sprintf('Adapter must implement AdapterInterface: %s', $adapterClass) ); } // Normalizar configuración específica del proveedor $normalizedConfig = self::normalizeConfig($provider, $config); return $adapterInstance->createAdapter($normalizedConfig); } /** * Normaliza la configuración según el proveedor * * @param string $provider Nombre del proveedor * @param array $config Configuración original * @return array Configuración normalizada */ private static function normalizeConfig(string $provider, array $config): array { $normalized = $config; // Normalizar permisos para WebDAV y SFTP if (in_array($provider, ['webdav', 'sftp'], true)) { $normalized = self::normalizePermissions($normalized); } // Normalizar configuración específica de S3 if ($provider === 's3') { $normalized = self::normalizeS3Config($normalized); } return $normalized; } /** * Normaliza permisos de archivos y directorios * * @param array $config Configuración original * @return array Configuración con permisos normalizados */ private static function normalizePermissions(array $config): array { $permissionKeys = ['file_public', 'file_private', 'dir_public', 'dir_private']; foreach ($permissionKeys as $key) { if (isset($config[$key])) { // Si es string, mantenerlo como string (el adaptador lo convertirá) // Si es int, mantenerlo como int // Esto permite flexibilidad en la configuración continue; } } // Establecer valores por defecto si no existen $config['file_public'] = $config['file_public'] ?? 0644; $config['file_private'] = $config['file_private'] ?? 0600; $config['dir_public'] = $config['dir_public'] ?? 0755; $config['dir_private'] = $config['dir_private'] ?? 0700; return $config; } /** * Normaliza configuración específica de S3 * * @param array $config Configuración original * @return array Configuración normalizada */ private static function normalizeS3Config(array $config): array { // Asegurar que use_path_style_endpoint sea booleano if (isset($config['use_path_style_endpoint'])) { $config['use_path_style_endpoint'] = filter_var( $config['use_path_style_endpoint'], FILTER_VALIDATE_BOOLEAN ); } // Normalizar región if (isset($config['region'])) { $config['region'] = strtolower(trim($config['region'])); } return $config; } /** * Obtiene la lista de proveedores soportados * * @return array */ public static function getSupportedProviders(): array { return array_keys(self::ADAPTER_MAP); } /** * Verifica si un proveedor es soportado * * @param string $provider Nombre del proveedor * @return bool */ public static function isProviderSupported(string $provider): bool { return isset(self::ADAPTER_MAP[strtolower(trim($provider))]); } /** * Obtiene información sobre un proveedor específico * * @param string $provider Nombre del proveedor * @return array Información del proveedor * @throws InvalidArgumentException Si el proveedor no es soportado */ public static function getProviderInfo(string $provider): array { $provider = strtolower(trim($provider)); if (!self::isProviderSupported($provider)) { throw new InvalidArgumentException("Unsupported provider: {$provider}"); } $adapterClass = self::ADAPTER_MAP[$provider]; $adapter = new $adapterClass(); return [ 'name' => $provider, 'class' => $adapterClass, 'required_keys' => $adapter->getRequiredConfigKeys(), 'optional_keys' => $adapter->getOptionalConfigKeys(), 'description' => method_exists($adapter, 'getDescription') ? $adapter->getDescription() : '', ]; } }