Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom StreamLoader of LiipImagineBundle never instantiated #698

Closed
mappedinn opened this issue Jan 22, 2016 · 22 comments
Closed

Custom StreamLoader of LiipImagineBundle never instantiated #698

mappedinn opened this issue Jan 22, 2016 · 22 comments

Comments

@mappedinn
Copy link

My images are stored in google cloud storage. It has been done through VichUploaderBundle and KnpGaufretteBunldewith success. Below is how I configured them:

Services

services:           
    app.google_cloud_storage.service:
        class: \Google_Service_Storage
        factory: [Minn\AdsBundle\Factory\GoogleCloudStorageServiceFactory, createService]

    minn.liip_imagine.cache.resolver.gcs:
        class: Minn\AdsBundle\Resolver\GoogleCloudStorageResolver 
        arguments:
            - @logger            
            - @app.google_cloud_storage.service
            - '%bucket%'
            - 'public-write'

knp_gaufrette and vich_uploader config

knp_gaufrette:
    stream_wrapper: ~
    adapters:
        motors_adapter:
            local:
                directory: %kernel.root_dir%/../web/files/motors
        gcsmotors_adapter:
            google_cloud_storage:
                service_id: 'app.google_cloud_storage.service'
                bucket_name: '%bucket%'
                options:
                    directory: motors

    filesystems:
        motors_fs:
            adapter:    motors_adapter
        gcsmotors_fs:
            adapter: gcsmotors_adapter

vich_uploader:
    db_driver: orm
    storage: gaufrette
    mappings:
        motors_file:
            uri_prefix:         motors
            upload_destination: gcsmotors_fs
            namer: vich_uploader.namer_uniqid 
            delete_on_remove: true   

Now, I need to read my images form the google cloud storage through LiipImagineBundle. Unfortunately, Google Cloud Storage is not supported by LiipImagineBundle. So, I tried to implement a Google Cloud Storage Resolver in similar way as specified here: Custom cache resolver. Below is how I configured my resolver:

minn.liip_imagine.cache.resolver.gcs:
    class: Minn\AdsBundle\Resolver\GoogleCloudStorageResolver
    arguments:
        - @logger            
        - @app.google_cloud_storage.service
        - '%bucket%'
        - 'public-write'
    tags:                                                                                                                                                                                 
         - { name: monolog.logger, channel: tester } 
         - { name: 'liip_imagine.cache.resolver', resolver: 'gcs' }

The resolver is instantiated when ever there twig call for an image. It checks if the images is stored or not (the function isStored($path) is called and logger is telling that)! The function resolve($path, $filter) and store(BinaryInterface $binary, $path, $filter) are never called. Strange! I say this may be because the data loader is not working properly. So, I created a new data loader which is defined as follows:

minn.liip_imagine.binary.loader.stream.gcsmotors_fs:
    class: Minn\AdsBundle\Loader\GCSStreamLoader
    arguments:
        - @logger
        - gaufrette://gcsmotors_fs/
    tags:
        - { name: monolog.logger, channel: tester } 
        - { name: 'liip_imagine.binary.loader', loader: 'stream.gcsmotors_fs' } 

Guess what? The custom data loader is never instantiated! Have I missed some thing?

Thanks.


Resolver and Data loader

<?php

namespace Minn\AdsBundle\Resolver;

use \Google_Service_Storage;
use Liip\ImagineBundle\Imagine\Cache\Resolver\ResolverInterface;
use Liip\ImagineBundle\Binary\BinaryInterface;
use Liip\ImagineBundle\Exception\Imagine\Cache\Resolver\NotStorableException;
use Psr\Log\LoggerInterface;

/**
 * Description of GoogleCloudStorageResolver
 *
 * @author Amine Jallouli <[email protected]>
 */
class GoogleCloudStorageResolver  implements ResolverInterface {

    /**
     * @var LoggerInterface
     */
    protected $logger;

    /**
     * @var Google_Service_Storage
     */
    protected $service;

    /**
     * @var \Gaufrette\Adapter\GoogleCloudStorage
     */
    protected $adatpter;

    /**
     * @var \Gaufrette\Filesystem
     */
    protected $filesystem;

    /**
     * @var string
     */
    protected $bucket;

    /**
     * @var string
     */

    protected $acl;
    /**
     * @var array
     */
    protected $getOptions;

    /**
     * Object options added to PUT requests.
     *
     * @var array
     */
    protected $putOptions;

    /**
     * @var string
     */
    protected $cachePrefix= null;

    /**
     * @var string
     */
    protected $key= null;

    /**
     * Constructs a cache resolver storing images on Google Cloud Storage.
     *
     * @param LoggerInterface        $logger     monolog logger.
     * @param Google_Service_Storage $service    The Google Cloud Storage API. It's required to know authentication information.
     * @param string                 $bucket     The bucket name to operate on.
     * @param string                 $acl        The ACL
     * @param array                  $getOptions A list of options to be passed when retrieving the object url from Google Cloud Storage.
     * @param array                  $putOptions A list of options to be passed when saving the object to Google Cloud Storage.
     */
    public function __construct(
            LoggerInterface $logger,
            Google_Service_Storage $service,
            $bucket, 
            $acl,
            array $getOptions = array(),
            array $putOptions = array()
            ) {        
        $this->logger = $logger;
        $this->service = $service;
        $this->bucket = $bucket;
        $this->acl = $acl;
        $this->getOptions = $getOptions;
        $this->putOptions = $putOptions;

        $this->logger->info( "__construct: bucket=".$bucket);
    }

    /**
     * @param string $cachePrefix
     * 
     */
    protected function setCachePrefix($cachePrefix){
        $this->logger->info("cachePrefix= ".$cachePrefix);
        $this->cachePrefix = $cachePrefix;
    }

    /**
     * @param string $path
     */
    public function setKeyCachePrefix($path){
        $pos=  strpos($path, "/");
        $tmp=$path;
        while($pos!==false ){
            //$this->logger->notice("getKey [path=$path , pos=$pos" );
            $path = substr($path,$pos+1);
            $pos=  strpos($path, "/");
        }
        $this->logger->notice("getKey: key=".$path );
        $this->key = $path;

        $this->setCachePrefix(substr($tmp, 0, strpos($tmp, $path)-1));
        //$this->logger->notice("getKey: cachePrefix=". substr($tmp, 0, strpos($tmp, $path)-1));
    }


    /**
     * {@inheritDoc}
     */
    public function isStored($path, $filter){
        $this->logger->info("isStored? =  path=$path , filter=$filter");
        return $this->objectExists($path, $filter);
    }

    /**
     * {@inheritDoc}
     */
    public function resolve($path, $filter){
        $this->logger->info("resovle: path=$path , filter=$filter");
        return $this->getObjectUrl($path, $filter);
    }

    /**
     * {@inheritDoc}
     */
    public function store(BinaryInterface $binary, $path, $filter){
        $this->logger->notice("*-*-*-*-*-*-*-*- store() -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
        $this->setKeyCachePrefix($path);

        // Creation of the $adatpter
         $this->adapter = new \Gaufrette\Adapter\GoogleCloudStorage(
                 $this->service,
                 $this->bucket, array(
                     'directory'=>$this->cachePrefix .'/'. $filter,
                     'acl'=>$this->acl), true);

         // Creation of the $filesystem
         $this->filesystem = new \Gaufrette\Filesystem($this->adapter);


         // I assume here that the file is already in the bucket. That's why, a BinaryInterface is given.
         // Consequently, Binary will be directly re-written in the bucket according to its filter.

         // let's log a little bit out store() function to know what is happening!
         $this->logger->info('store: key='.$this->key);
         $this->logger->info('store: filter='.$filter);
         $this->logger->info('store: binary='.$binary->getMimeType());

        try {
            $this->filesystem->write($this->key, $binary);
            $this->logger->info('store: filtered image='. $this->getObjectUrl($path, $filter));

        } catch (\Exception $e) {
            $this->logError('The object could not be created on Google Cloud Storage.', array(
                'objectPath'  => $this->getObjectPath($path, null),
                'filter'      => $filter,
                'bucket'      => $this->bucket,
                'exception'   => $e,
            ));
            throw new NotStorableException('The object could not be created on Google Cloud Storage.', null, $e);
        }
    }    

    /**
     * {@inheritDoc}
     */
    public function remove(array $paths, array $filters)
    {
        if (empty($paths) && empty($filters)) {
            return;
        }

        if (empty($paths)) {
            // I don't to do any thing for the moment!!
            // Not urgent for the moment!
            return;
        }

        foreach ($filters as $filter) {
            foreach ($paths as $path) {
                if (!$this->objectExists($path, $filter)) {
                    continue; 
                }

                try {
                    $this->adapter = new \Gaufrette\Adapter\GoogleCloudStorage(
                            $this->service,
                            $this->bucket, array(
                                'directory'=>$this->cachePrefix .'/'. $filter,
                                'acl'=>$this->acl), true);

                    // Creation of the $filesystem
                    $this->filesystem = new \Gaufrette\Filesystem($this->adapter);

                    // the file to be delete is here
                    $f = $this->getObjectUrl($path, $filter);

                    // deleting the file
                    $this->filesystem->delete($path);
                    $this->logger->info('delete(): DONE FOR '.$f);

                } catch (\Exception $e) {
                    $this->logError('The object could not be deleted from Google Cloud Storage.', array(
                        'path'        => $path,
                        'filter'      => $filter,
                        'bucket'      => $this->bucket,
                        'exception'   => $e,
                    ));
                }
            }
        }
    }    

    /**
     * Returns the object path within the bucket.
     *
     * @param string $path   The base path of the resource.
     * @param string $filter The name of the imagine filter in effect.
     *
     * @return string The path of the object on Google Cloud Storage.
     */
    public function getObjectPath($path, $filter){
        $this->setKeyCachePrefix($path);
        $path= $this->key;
        $path = $this->cachePrefix
            ? sprintf('%s/%s/%s', $this->cachePrefix, $filter, $path)
            : sprintf('%s/%s', $filter, $path);

        return str_replace('//', '/', $path);
    }

    /**
     * Returns the URL for an object saved on Google Cloud Storage.
     *
     * @param string $path
     * @param string $filter
     *
     * @return string
     */
    public function getObjectUrl($path, $filter){
        // AWS S3 solution (No need for it!)
        //return $this->storage->getObjectUrl($this->bucket, $path, 0, $this->getOptions);

        // Google Cloud Storage solution 
        return 'https://storage.googleapis.com/' .$this->bucket. '/' . $this->getObjectPath($path, $filter);
    }

    /**
     * Checks whether an object exists.
     *
     * @param string $objectPath
     *
     * @return bool
     */
    protected function objectExists($path, $filter){
        // AWS S3 solution... (No need for it!)
        //return $this->storage->doesObjectExist($this->bucket, $objectPath);

        // Google Cloud Storage solution
        $file = $this->getObjectUrl($path, $filter);
        $file_headers = @get_headers($file);
        $this->logger->info("objectExists: file=".$file);
        if($file_headers[0] == 'HTTP/1.0 200 OK' || $file_headers[0] == 'HTTP/1.1 200 OK') {
            $this->logger->info("objectExists: file_headers[0]=". $file_headers[0]);
            $exists = true;
        }
        else {
            $this->logger->info("objectExists: file_headers[0]=". $file_headers[0]);
            $exists = false;
        }
        return $exists;
    } 
    /**
     * @param mixed $message
     * @param array $context
     */
    protected function logError($message, array $context = array())
    {
        if ($this->logger) {
            $this->logger->error($message, $context);
        }
    }    
}

Here is my custom StreamLoader:

<?php

namespace Minn\AdsBundle\Loader;

//use Imagine\Image\ImagineInterface;
use Liip\ImagineBundle\Imagine\Data\Loader\LoaderInterface;
use Liip\ImagineBundle\Exception\Binary\Loader\NotLoadableException;

class GCSStreamLoader implements LoaderInterface{

    /**
     * @var LoggerInterface
     */
    protected $logger;

    /*
     * @var ImagineInterface
     */
    //protected $imagine; 

    /**
     * The wrapper prefix to append to the path to be loaded.
     *
     * @var string
     */
    protected $wrapperPrefix;

    /**
     * A stream context resource to use.
     *
     * @var resource|null
     */
    protected $context;


    /**
     * @param LoggerInterface $logger
     * @param string          $wrapperPrefix
     * @param resource|null   $context
     *
     * @throws \InvalidArgumentException
     */
    public function __construct(LoggerInterface $logger/*, ImagineInterface $imagine*/, $wrapperPrefix, $context = null){

        $this->logger = $logger;
        /*$this->imagine= $imagine;*/

        $this->logger->notice("*************__construct (StreamLoader)*********************");
        $this->wrapperPrefix = $wrapperPrefix;
        $this->logger->notice("__construct: wrapperPrefix=$wrapperPrefix");
        $this->logger->notice("__construct: context=$context");
        if ($context && !is_resource($context)) {
            $this->logger->notice("__construct: InvalidArgumentException!!!");
            throw new \InvalidArgumentException('The given context is no valid resource.');
        }

        $this->context = $context;
    }

    /**
     * {@inheritDoc}
     */    
    public function find($path)
    {
        $name = $this->wrapperPrefix.$path;

        /*
         * This looks strange, but at least in PHP 5.3.8 it will raise an E_WARNING if the 4th parameter is null.
         * fopen() will be called only once with the correct arguments.
         *
         * The error suppression is solely to determine whether the file exists.
         * file_exists() is not used as not all wrappers support stat() to actually check for existing resources.
         */
        if (($this->context && !$resource = @fopen($name, 'r', null, $this->context)) || !$resource = @fopen($name, 'r')) {
            $this->logger->notice("find: NotLoadableException (3)!!! Source image %s not found".$name);
            throw new NotLoadableException(sprintf('Source image %s not found.', $name));
        }

        // Closing the opened stream to avoid locking of the resource to find.
        fclose($resource);

        try {
            $content = file_get_contents($name, null, $this->context);
        } catch (\Exception $e) {
            $this->logger->notice("find: NotLoadableException (2)!!! Source image %s could not be loaded". $name);
            throw new NotLoadableException(sprintf('Source image %s could not be loaded.', $name, $e));
        }

        if (false === $content) {
            $this->logger->notice("find: NotLoadableException (3)!!! Source image %s could not be loaded". $name);
            throw new NotLoadableException(sprintf('Source image %s could not be loaded.', $name));
        }

        return $content;
    }
}
@mappedinn
Copy link
Author

@makasim here is a trial for developing a Google Cloud Storage as promised here #666

@makasim
Copy link
Collaborator

makasim commented Jan 22, 2016

That's okay that resolve and store are not called at first time. They will be called when the filterAction is called. What is the url actually put into the template? How does it look like?

@mappedinn
Copy link
Author

The url returned is
http://localhost/tuto/web/app_dev.php/media/cache/resolve/display/motors/569fd92884baa.jpg

This is not what I am expecting...

@makasim
Copy link
Collaborator

makasim commented Jan 22, 2016

The bundle works correctly, if the image is not in the cache it generates the link to the filter action which will store the origin image to the cache

@mappedinn
Copy link
Author

The url I am expecting to have is: https://storage.googleapis.com/the-bucket/cache/the-filter/image-name.jpg

The original image is in https://storage.googleapis.com/the-bucket/img/image-name.jpg

Could you please just tell me why the custom data loader is never instantiated?
Idem. for the functions resolve() and store()?

@makasim
Copy link
Collaborator

makasim commented Jan 22, 2016

Because you configured something wrong. Sorry I dont have enough time to look into details right now.

@mappedinn
Copy link
Author

Don't worry!

@mappedinn
Copy link
Author

If you have goods links I will be happy ;)

@acanimal
Copy link

Hi @mappedinn
I have a similar problem with the returned URL but in my case is due a "file not supported" problem.

In my case I'm working with LiipImagine, VichUploader and KnpGaufrette using aws-s3 adapter. Files are correctly uploaded by VichUploader but seems LiipImagene can generate images dues a [2016-02-14 03:20:58] php.DEBUG: exif_read_data(D99WsJFgEESggAAAABJRU5ErkJggg==): File not supported {"type":2,"file":"xxxxx","line":96,"level":28928} [].

Did you found any solution? Thanks

@girayk
Copy link

girayk commented Mar 6, 2016

Here is the my solution, Thanks to @mappedinn ,
I hope its helps

Config.yml

knp_gaufrette:
    adapters:
        product_photos_google_storage:
            google_cloud_storage:
                service_id: 'app.factory.google_auth'
                bucket_name: 'Your Bucket URL'
                options:
                    directory: 'products'
                    acl:  'public'

        product_photos_local:
            local:
                directory:  %kernel.root_dir%/../web/images/products
                create:     true

    filesystems:
        product_photos_cloud_fs:
            adapter:    product_photos_google_storage
        product_photos_local_fs:
            adapter:    product_photos_local

    stream_wrapper: ~

vich_uploader:
    db_driver: orm
    twig:       true
    storage:   gaufrette

    mappings:
        product_image:
            upload_destination: product_photos_cloud_fs
            uri_prefix:         "Your bucket URL"
            namer:              vich_uploader.namer_origname

liip_imagine:
    cache: 'storage_cache_product_photos'
    loaders:
        loader_press_photos_cloud:
            stream:
                wrapper: gaufrette://press_photos_cloud_fs/
        loader_product_photos_cloud:
            stream:
                wrapper: gaufrette://product_photos_cloud_fs/

        product_small_thumb:
            data_loader: loader_product_photos_cloud
            cache: storage_cache_product_photos
            quality: 75
            filters:
                thumbnail: { size: [100, 100], mode: outbound }

Service.yml

parameters:
    app.factory.google_cloud_storage.class: App\Factory\GoogleCloudStorageServiceFactory
    app.resolver.google_storage.class: App\Resolver\GoogleStorageResolver

services:
    app.factory.goole_auth:
        class: \Google_Service_Storage
        factory: ["%app.factory.goole_auth.class%", "createService"]

    app.resolver.product_photos:
        class: %app.resolver.google_storage.class%
        arguments:
            - "@app.factory.google_cloud_storage.class"
            - { Bucket : "content.groupe-noir.com" , Directory : "press", Acl : "public" }
        tags:
            - { name: 'liip_imagine.cache.resolver', resolver: 'storage_cache_product_photos' }

The Resolver

<?php
namespace App\YourBundle\Resolver;

use Gaufrette\Filesystem;
use Gaufrette\Adapter\GoogleCloudStorage;
use Liip\ImagineBundle\Binary\BinaryInterface;
use Liip\ImagineBundle\Exception\Imagine\Cache\Resolver\NotStorableException;
use Liip\ImagineBundle\Imagine\Cache\Resolver\ResolverInterface;
use Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException;

class GoogleStorageResolver implements ResolverInterface
{

    private $service;

    private $bucket;

    private $directory;

    private $acl = "public";

    /**
     * GoogleStorageResolver constructor.
     * @param \Google_Service_Storage                                   $service
     * @param array                                                     $settings
     */
    public function __construct(\Google_Service_Storage $service, array $settings = array())
    {
        $missingKey = isset($settings["Bucket"])? "Directory" : "Bucket";

        if(!array_key_exists("Bucket", $settings) || !array_key_exists("Directory", $settings))
        {
            throw new UndefinedOptionsException(sprintf("The %s must be configurated", $missingKey));
        }

        if(array_key_exists("Acl", $settings))
        {
            $this->acl = $settings["Acl"];
        }

        $this->bucket = $settings["Bucket"];
        $this->directory = $settings["Directory"];
        $this->service = $service;
    }

    private function getOptions()
    {
        $options = array(
            'acl' => $this->acl,
            'directory' => $this->directory
        );

        return $options;
    }

    private function getStorage()
    {
        return New GoogleCloudStorage($this->service, $this->bucket, $this->getOptions(), true);
    }

    /**
     * {@inheritDoc}
     */
    public function isStored($path, $filter){
        return $this->objectExists($this->getObjectPath($path, $filter));
    }

    /**
     * {@inheritDoc}
     */
    public function resolve($path, $filter){
        return $this->getObjectUrl($this->getObjectPath($path, $filter));
    }


    /**
     * Stores the content of the given binary.
     *
     * @param BinaryInterface $binary The image binary to store.
     * @param string          $path   The path where the original file is expected to be.
     * @param string          $filter The name of the imagine filter in effect.
     */
    public function store(BinaryInterface $binary, $path, $filter){

        $filesystem = new Filesystem($this->getStorage());

        try{
            $filesystem->write($this->getObjectPath($path, $filter), $binary->getContent(), true);

        } catch (\Exception $e) {

            throw new NotStorableException('The object could not be created on Google Cloud Storage.', null, $e);
        }
    }

    /**
     * @param string[] $paths   The paths where the original files are expected to be.
     * @param string[] $filters The imagine filters in effect.
     */
    public function remove(array $paths, array $filters)
    {
        $storage = New GoogleCloudStorage($this->service, $this->bucket);
        $filesystem = new Filesystem($storage);

        if (empty($paths) && empty($filters)) {
            return;
        }

        if (empty($paths)) {
            foreach ($filters as $filter)
            {
                $directory = sprintf("%s/cache/%s", $this->directory,  $filter);
                $files = $storage->listKeys($directory);

                foreach ($files as $file)
                {
                    if($storage->exists($file))
                    {
                        if(!$filesystem->delete($file)){
                            throw new NotStorableException('The object could not be deleted on Google Cloud Storage.', null, $e);
                        }
                    }
                }
            }
        }


        foreach ($filters as $filter)
        {
            foreach ($paths as $path)
            {
                $directory = sprintf("%s/cache/%s", $path,  $filter);
                $files = $storage->listKeys($directory);

                foreach ($files as $file)
                {
                    if($storage->exists($file))
                    {
                        if(!$filesystem->delete($file)){
                            throw new NotStorableException('The object could not be deleted on Google Cloud Storage.', null, $e);
                        }
                    }
                }
            }
        }
    }


    /**
     * Returns the object path within the bucket.
     *
     * @param string $path   The base path of the resource.
     * @param string $filter The name of the imagine filter in effect.
     *
     * @return string The path of the object on Google Cloud Storage.
     */
    public function getObjectPath($path, $filter){

        return str_replace('//', '/', sprintf('cache/%s/%s', $filter, $path));
    }

    /**
     * @param $path
     * @return string
     */
    public function getObjectUrl($path){

        $media = $this->service->objects->get($this->bucket, sprintf("%s/%s", $this->directory, $path));
        return $media->getMediaLink();

    }

    /**
     * @param $objectPath
     * @return bool
     */
    protected function objectExists($objectPath){
        return $this->getStorage()->exists($objectPath) ? true : false;
    }
}

The Factory

<?php

namespace App\YourBundle\Factory;

use Gaufrette\Adapter\GoogleCloudStorage;

class GoogleCloudStorageServiceFactory
{
    public static function createService() {

        // creating the google client
        $client = new \Google_Client();

        // setting the service acount credentials
        $serviceAccountName = 'your account name';
        $scopes = array(
            'https://www.googleapis.com/auth/devstorage.full_control',
        );
        $privateKey = file_get_contents("your-secret.p12');
        $privateKeyPassword = 'your secret';

        $credential = new \Google_Auth_AssertionCredentials(
            $serviceAccountName, $scopes, $privateKey, $privateKeyPassword);

        // set assertion credentials
        $client->setAssertionCredentials($credential);

        return new \Google_Service_Storage($client);
    }
}

@mappedinn
Copy link
Author

@acanimal sorry for answering you late. I do not use AWS S3. I use google cloud storage (but it did not worked for me).

@girayk the solution you are proposing is working? You can read images and filtered image from google cloud storage?

@girayk
Copy link

girayk commented Mar 7, 2016

@acanimal Yes its working, for read images you can set gaufrette

liip_imagine:
cache: 'google_storage'
loaders:
loader_product_photos_cloud:
stream:
wrapper: gaufrette://product_photos_cloud_fs/

@mappedinn
Copy link
Author

@girayk Is there any special configuration in the google cloud storage?

Thank you very

PS: can you fix the indentations?

@girayk
Copy link

girayk commented Mar 7, 2016

@mappedinn I updated my post with better indentations and i added google cloud storage factory example as well. I hope its will help.

@mappedinn
Copy link
Author

Thank you very much... I have to try it :)

@alexwilson
Copy link
Collaborator

Hey, any luck @mappedinn?

@acanimal
Copy link

Hi, If it can help anyone here I paste a link with my experiences using LiipImagineBundle, VichUploaderBundle and Gaufrette on S3: http://www.acuriousanimal.com/2016/03/25/symfony-and-s3.html.

Cheers

@pdoreau
Copy link

pdoreau commented Sep 22, 2016

Thanks guys!
@mappedinn have you finally made it with the girayk's solution ?
Do you guys think this could be integreted into the git repository ?

@cedricziel
Copy link
Collaborator

Hey @pdoreau ,

I don't know whether you ask specifically about a Gaufrette stream-wrapper, or GCS. If it's about the latter, we recently merged a flysystem resolver so that you can use the bundle with any given flysystem adapter. Incidentally I happened to write a flysystem adapter for gcs-you might want to have a look (https://github.com/cedricziel/flysystem-gcs).

@pdoreau
Copy link

pdoreau commented Sep 23, 2016

@cedricziel I was asking about a way to use GCS (both for data loader and cache) based on the source code posted in this issue. The method would be documented beside s3 and others.
Is flysystem another way to make GCS work both for data loader and cache resolver ?

@cedricziel
Copy link
Collaborator

Flysystem is a generic way to abstract filesystems. Much like gaufrette. With a flysystem filesystem and an adapter registered as documented, you can use it, amongst other usages of course, as a way to load pictures and resolve caches with LiipImagineBundle. Yes.

@michellesanver
Copy link
Contributor

I would use Flysystem as cedricziel pointed out. Thus closing this issue. Please open a new issue if there are any further requests and thanks a lot! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants