Sunday, 29 September 2024

Create a Storage System Like Laravel’s in EC-CUBE

Here’s the complete implementation of a storage system in EC-CUBE 4.2 that allows you to switch between storage drivers (Local, S3, Cloudinary) using an interface, similar to Laravel's storage system.

1. Update Your .env File

Set the default storage driver in your .env file:

STORAGE_DRIVER=local # Change to "s3" or "cloudinary" as needed

2. Create the Storage Interface

Create a new interface for your storage system.

// src/Service/StorageInterface.php namespace App\Service; interface StorageInterface { public function put(string $path, $contents); public function get(string $path); public function delete(string $path); public function url(string $path); }

3. Implement Storage Drivers

Local Storage Driver

// src/Service/Drivers/LocalStorageDriver.php namespace App\Service\Drivers; use App\Service\StorageInterface; class LocalStorageDriver implements StorageInterface { protected $root; public function __construct($root) { $this->root = $root; } public function put(string $path, $contents) { return file_put_contents($this->root . '/' . $path, $contents); } public function get(string $path) { return file_get_contents($this->root . '/' . $path); } public function delete(string $path) { return unlink($this->root . '/' . $path); } public function url(string $path) { return '/storage/' . $path; // Adjust this according to your URL structure } }

S3 Storage Driver

// src/Service/Drivers/S3StorageDriver.php namespace App\Service\Drivers; use Aws\S3\S3Client; use App\Service\StorageInterface; class S3StorageDriver implements StorageInterface { protected $client; protected $bucket; public function __construct(array $config) { $this->client = new S3Client([ 'version' => 'latest', 'region' => $config['region'], 'credentials' => [ 'key' => $config['key'], 'secret' => $config['secret'], ], ]); $this->bucket = $config['bucket']; } public function put(string $path, $contents) { $this->client->putObject([ 'Bucket' => $this->bucket, 'Key' => $path, 'Body' => $contents, 'ACL' => 'public-read', ]); return $this->url($path); } public function get(string $path) { $result = $this->client->getObject([ 'Bucket' => $this->bucket, 'Key' => $path, ]); return (string) $result['Body']; } public function delete(string $path) { return $this->client->deleteObject([ 'Bucket' => $this->bucket, 'Key' => $path, ]); } public function url(string $path) { return $this->client->getObjectUrl($this->bucket, $path); } }

Cloudinary Storage Driver

// src/Service/Drivers/CloudinaryStorageDriver.php namespace App\Service\Drivers; use Cloudinary\Cloudinary; use App\Service\StorageInterface; class CloudinaryStorageDriver implements StorageInterface { protected $cloudinary; public function __construct(array $config) { $this->cloudinary = new Cloudinary([ 'cloud' => [ 'cloud_name' => $config['cloud_name'], 'api_key' => $config['api_key'], 'api_secret' => $config['api_secret'], ], ]); } public function put(string $path, $contents) { return $this->cloudinary->uploadApi()->upload($contents, ['public_id' => $path]); } public function get(string $path) { return $this->cloudinary->adminApi()->asset($path)['secure_url']; } public function delete(string $path) { return $this->cloudinary->adminApi()->deleteAssets([$path]); } public function url(string $path) { return $this->cloudinary->adminApi()->asset($path)['secure_url']; } }

4. Create the Storage Manager

Create a class to manage storage operations.

// src/Service/StorageManager.php namespace App\Service; class StorageManager { private $storage; public function __construct(StorageInterface $storage) { $this->storage = $storage; } public function uploadFile(string $path, $contents) { return $this->storage->put($path, $contents); } public function retrieveFile(string $path) { return $this->storage->get($path); } public function deleteFile(string $path) { return $this->storage->delete($path); } public function getFileUrl(string $path) { return $this->storage->url($path); } }

5. Create the Storage Factory

This factory will dynamically return the correct storage driver.

// src/Service/StorageFactory.php namespace App\Service; use Symfony\Component\DependencyInjection\ContainerInterface; class StorageFactory { private $container; public function __construct(ContainerInterface $container) { $this->container = $container; } public function create(): StorageInterface { $driver = getenv('STORAGE_DRIVER') ?: 'local'; // Default to local if not set switch ($driver) { case 's3': return $this->container->get(Drivers\S3StorageDriver::class); case 'cloudinary': return $this->container->get(Drivers\CloudinaryStorageDriver::class); case 'local': default: return $this->container->get(Drivers\LocalStorageDriver::class); } } }

6. Update the Service Configuration

Modify your config/services.yaml to bind the storage interface and set up services.

services: App\Service\StorageInterface: factory: ['@App\Service\StorageFactory', 'create'] App\Service\Drivers\LocalStorageDriver: arguments: $root: '%kernel.project_dir%/var/storage' App\Service\Drivers\S3StorageDriver: arguments: $config: key: '%env(AWS_ACCESS_KEY_ID)%' secret: '%env(AWS_SECRET_ACCESS_KEY)%' region: '%env(AWS_DEFAULT_REGION)%' bucket: '%env(AWS_BUCKET)%' App\Service\Drivers\CloudinaryStorageDriver: arguments: $config: cloud_name: '%env(CLOUDINARY_CLOUD_NAME)%' api_key: '%env(CLOUDINARY_API_KEY)%' api_secret: '%env(CLOUDINARY_API_SECRET)%'

7. Using the Storage Manager

You can now inject StorageManager into your controllers or services and use it as needed:

// src/Controller/YourController.php namespace App\Controller; use App\Service\StorageManager; class YourController { private $storageManager; public function __construct(StorageManager $storageManager) { $this->storageManager = $storageManager; } public function uploadAction() { $filePath = 'uploads/product.jpg'; $fileContents = file_get_contents('path/to/local/file.jpg'); $this->storageManager->uploadFile($filePath, $fileContents); $fileUrl = $this->storageManager->getFileUrl($filePath); // Do something with $fileUrl } }

Summary

This implementation allows you to switch between different storage drivers by changing the STORAGE_DRIVER variable in your .env file without modifying your code. You have a clean interface and the necessary drivers to handle local, S3, and Cloudinary storage in EC-CUBE 4.2.

Feel free to reach out if you have any further questions or need assistance!

Thank you

No comments:

Post a Comment

Golang Advanced Interview Q&A