diff --git a/.travis.yml b/.travis.yml
index 0bc8f6589..4bb90fd4e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -32,6 +32,7 @@ before_install:
- sh -c 'if [ "${TRAVIS_PHP_VERSION}" != "hhvm" ]; then echo "memory_limit = -1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; fi;'
- sh -c 'if [ "${TRAVIS_PHP_VERSION}" != "hhvm" && "${TRAVIS_PHP_VERSION}" != "7.0" ]; then yes "" | pecl -q install -f mongo; fi;'
- sh -c 'if [ "${TRAVIS_PHP_VERSION}" != "hhvm" && "${TRAVIS_PHP_VERSION}" != "7.0" ]; then composer require --dev doctrine/mongodb-odm:~1.0 --no-update; fi;'
+ - sh -c 'if [ "${TRAVIS_PHP_VERSION}" != "hhvm" && "${TRAVIS_PHP_VERSION}" >= "5.4" ]; then composer require --dev league/flysystem:~1.0 --no-update; fi;'
- composer self-update
- if [ "$SYMFONY_VERSION" != "" ]; then composer require "symfony/symfony:${SYMFONY_VERSION}" --no-update; fi;
diff --git a/Binary/Loader/FlysystemLoader.php b/Binary/Loader/FlysystemLoader.php
new file mode 100644
index 000000000..1d0902ab9
--- /dev/null
+++ b/Binary/Loader/FlysystemLoader.php
@@ -0,0 +1,47 @@
+extensionGuesser = $extensionGuesser;
+ $this->filesystem = $filesystem;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function find($path)
+ {
+ if ($this->filesystem->has($path) === false) {
+ throw new NotLoadableException(sprintf('Source image "%s" not found.', $path));
+ }
+
+ $mimeType = $this->filesystem->getMimetype($path);
+
+ return new Binary(
+ $this->filesystem->read($path),
+ $mimeType,
+ $this->extensionGuesser->guess($mimeType)
+ );
+ }
+}
diff --git a/DependencyInjection/Factory/Loader/FlysystemLoaderFactory.php b/DependencyInjection/Factory/Loader/FlysystemLoaderFactory.php
new file mode 100644
index 000000000..d5a417c5e
--- /dev/null
+++ b/DependencyInjection/Factory/Loader/FlysystemLoaderFactory.php
@@ -0,0 +1,48 @@
+replaceArgument(1, new Reference($config['filesystem_service']));
+ $loaderDefinition->addTag('liip_imagine.binary.loader', array(
+ 'loader' => $loaderName,
+ ));
+ $loaderId = 'liip_imagine.binary.loader.'.$loaderName;
+
+ $container->setDefinition($loaderId, $loaderDefinition);
+
+ return $loaderId;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'flysystem';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addConfiguration(ArrayNodeDefinition $builder)
+ {
+ $builder
+ ->children()
+ ->scalarNode('filesystem_service')->isRequired()->cannotBeEmpty()->end()
+ ->end()
+ ;
+ }
+}
diff --git a/LiipImagineBundle.php b/LiipImagineBundle.php
index 5894f33a7..0e080cdf1 100644
--- a/LiipImagineBundle.php
+++ b/LiipImagineBundle.php
@@ -8,6 +8,7 @@
use Liip\ImagineBundle\DependencyInjection\Compiler\ResolversCompilerPass;
use Liip\ImagineBundle\DependencyInjection\Factory\Loader\FileSystemLoaderFactory;
use Liip\ImagineBundle\DependencyInjection\Factory\Loader\StreamLoaderFactory;
+use Liip\ImagineBundle\DependencyInjection\Factory\Loader\FlysystemLoaderFactory;
use Liip\ImagineBundle\DependencyInjection\Factory\Resolver\AwsS3ResolverFactory;
use Liip\ImagineBundle\DependencyInjection\Factory\Resolver\WebPathResolverFactory;
use Liip\ImagineBundle\DependencyInjection\LiipImagineExtension;
@@ -36,5 +37,6 @@ public function build(ContainerBuilder $container)
$extension->addLoaderFactory(new StreamLoaderFactory());
$extension->addLoaderFactory(new FileSystemLoaderFactory());
+ $extension->addLoaderFactory(new FlysystemLoaderFactory());
}
}
diff --git a/Resources/config/imagine.xml b/Resources/config/imagine.xml
index dc4928539..ead54cc31 100644
--- a/Resources/config/imagine.xml
+++ b/Resources/config/imagine.xml
@@ -49,6 +49,7 @@
Liip\ImagineBundle\Binary\Loader\FileSystemLoader
Liip\ImagineBundle\Binary\Loader\StreamLoader
+ Liip\ImagineBundle\Binary\Loader\FlysystemLoader
@@ -205,6 +206,11 @@
+
+
+
+
+
diff --git a/Resources/doc/configuration.rst b/Resources/doc/configuration.rst
index 72a075581..289665322 100644
--- a/Resources/doc/configuration.rst
+++ b/Resources/doc/configuration.rst
@@ -56,10 +56,10 @@ There are several configuration options available:
* ``data_loader`` - name of a custom data loader. Default value: ``filesystem``
(which means the standard filesystem loader is used).
* ``controller``
- * ``filter_action`` - name of the controller action to use in the route loader.
- Default value: ``liip_imagine.controller:filterAction``
- * ``filter_runtime_action`` - name of the controller action to use in the route
- loader for runtimeconfig images. Default value: ``liip_imagine.controller:filterRuntimeAction``
+ * ``filter_action`` - name of the controller action to use in the route loader.
+ Default value: ``liip_imagine.controller:filterAction``
+ * ``filter_runtime_action`` - name of the controller action to use in the route
+ loader for runtimeconfig images. Default value: ``liip_imagine.controller:filterRuntimeAction``
* ``driver`` - one of the three drivers: ``gd``, ``imagick``, ``gmagick``.
Default value: ``gd``
* ``filter_sets`` - specify the filter sets that you want to define and use.
diff --git a/Resources/doc/data-loader/flysystem.rst b/Resources/doc/data-loader/flysystem.rst
new file mode 100644
index 000000000..b41706d6d
--- /dev/null
+++ b/Resources/doc/data-loader/flysystem.rst
@@ -0,0 +1,35 @@
+FlysystemLoader
+===============
+
+This loader lets you load images from `Flysystem`_ filesystem abstraction layer,
+which can be used in Symfony projects by installing, for example, `OneupFlysystemBundle`_.
+
+Value of ``filesystem_service`` property must be a service,
+which returns an instance of League\\Flysystem\\Filesystem.
+
+For implementation using `OneupFlysystemBundle`_ look below.
+
+Using factory
+-------------
+
+.. code-block:: yaml
+
+ liip_imagine:
+ loaders:
+ profile_photos:
+ flysystem:
+ filesystem_service: oneup_flysystem.profile_photos_filesystem
+
+ oneup_flysystem:
+ adapters:
+ profile_photos:
+ local:
+ directory: "path/to/profile/photos"
+
+ filesystems:
+ profile_photos:
+ adapter: profile_photos
+
+
+.. _`Flysystem`: /~https://github.com/thephpleague/flysystem
+.. _`OneupFlysystemBundle`: /~https://github.com/1up-lab/OneupFlysystemBundle
diff --git a/Resources/doc/data-loaders.rst b/Resources/doc/data-loaders.rst
index d42f759b4..f05de8a8b 100644
--- a/Resources/doc/data-loaders.rst
+++ b/Resources/doc/data-loaders.rst
@@ -7,6 +7,7 @@ Built-In DataLoader
data-loader/filesystem
data-loader/gridfs
data-loader/stream
+ data-loader/flysystem
Other data loaders
------------------
diff --git a/Resources/doc/filters.rst b/Resources/doc/filters.rst
index 60a516614..7307d1119 100644
--- a/Resources/doc/filters.rst
+++ b/Resources/doc/filters.rst
@@ -237,7 +237,7 @@ To tell the bundle about your new filter loader, register it in the service
container and apply the ``liip_imagine.filter.loader`` tag to it (example here
in XML):
-.. contiguration-block::
+.. configuration-block::
.. code-block:: yaml
@@ -322,7 +322,7 @@ should return the ``BinaryInterface`` as well.
To tell the bundle about your post-processor, register it in the service
container and apply the ``liip_imagine.filter.post_processor`` tag to it:
-.. contiguration-block::
+.. configuration-block::
.. code-block:: yaml
diff --git a/Tests/Binary/Loader/FlysystemLoaderTest.php b/Tests/Binary/Loader/FlysystemLoaderTest.php
new file mode 100644
index 000000000..afd2c1268
--- /dev/null
+++ b/Tests/Binary/Loader/FlysystemLoaderTest.php
@@ -0,0 +1,73 @@
+markTestSkipped(
+ 'The league/flysystem PHP library is not available.'
+ );
+ }
+
+ $adapter = new \League\Flysystem\Adapter\Local($this->fixturesDir);
+ $this->flyFilesystem = new \League\Flysystem\Filesystem($adapter);
+ }
+
+ public function testShouldImplementLoaderInterface()
+ {
+ $rc = new \ReflectionClass('Liip\ImagineBundle\Binary\Loader\FlysystemLoader');
+
+ $this->assertTrue($rc->implementsInterface('Liip\ImagineBundle\Binary\Loader\LoaderInterface'));
+ }
+
+ public function testCouldBeConstructedWithExpectedArguments()
+ {
+ return new FlysystemLoader(
+ ExtensionGuesser::getInstance(),
+ $this->flyFilesystem
+ );
+ }
+
+ /**
+ * @depends testCouldBeConstructedWithExpectedArguments
+ */
+ public function testReturnImageContentOnFind($loader)
+ {
+ $expectedContent = file_get_contents($this->fixturesDir.'/assets/cats.jpeg');
+
+ $this->assertSame(
+ $expectedContent,
+ $loader->find('assets/cats.jpeg')->getContent()
+ );
+ }
+
+ /**
+ * @depends testCouldBeConstructedWithExpectedArguments
+ */
+ public function testThrowsIfInvalidPathGivenOnFind($loader)
+ {
+ $path = 'invalid.jpeg';
+
+ $this->setExpectedException(
+ 'Liip\ImagineBundle\Exception\Binary\Loader\NotLoadableException',
+ sprintf('Source image "%s" not found.', $path)
+ );
+
+ $loader->find($path);
+ }
+}
diff --git a/Tests/DependencyInjection/Factory/Loader/FlysystemLoaderFactoryTest.php b/Tests/DependencyInjection/Factory/Loader/FlysystemLoaderFactoryTest.php
new file mode 100644
index 000000000..46d713116
--- /dev/null
+++ b/Tests/DependencyInjection/Factory/Loader/FlysystemLoaderFactoryTest.php
@@ -0,0 +1,113 @@
+
+ */
+class FlysystemLoaderFactoryTest extends \Phpunit_Framework_TestCase
+{
+ public function setUp()
+ {
+ parent::setUp();
+
+ if (!class_exists('\League\Flysystem\Filesystem')) {
+ $this->markTestSkipped(
+ 'The league/flysystem PHP library is not available.'
+ );
+ }
+ }
+
+ public function testImplementsLoaderFactoryInterface()
+ {
+ $rc = new \ReflectionClass('Liip\ImagineBundle\DependencyInjection\Factory\Loader\FlysystemLoaderFactory');
+
+ $this->assertTrue($rc->implementsInterface('Liip\ImagineBundle\DependencyInjection\Factory\Loader\LoaderFactoryInterface'));
+ }
+
+ public function testCouldBeConstructedWithoutAnyArguments()
+ {
+ new FlysystemLoaderFactory();
+ }
+
+ public function testReturnExpectedName()
+ {
+ $loader = new FlysystemLoaderFactory();
+
+ $this->assertEquals('flysystem', $loader->getName());
+ }
+
+ public function testCreateLoaderDefinitionOnCreate()
+ {
+ $container = new ContainerBuilder();
+
+ $loader = new FlysystemLoaderFactory();
+
+ $loader->create($container, 'theLoaderName', array(
+ 'filesystem_service' => 'flyfilesystemservice',
+ ));
+
+ $this->assertTrue($container->hasDefinition('liip_imagine.binary.loader.theloadername'));
+
+ $loaderDefinition = $container->getDefinition('liip_imagine.binary.loader.theloadername');
+ $this->assertInstanceOf('Symfony\Component\DependencyInjection\DefinitionDecorator', $loaderDefinition);
+ $this->assertEquals('liip_imagine.binary.loader.prototype.flysystem', $loaderDefinition->getParent());
+
+ $reference = $loaderDefinition->getArgument(1);
+ $this->assertEquals('flyfilesystemservice', "$reference");
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
+ * @expectedExceptionMessage The child node "filesystem_service" at path "flysystem" must be configured.
+ */
+ public function testThrowIfFileSystemServiceNotSetOnAddConfiguration()
+ {
+ $treeBuilder = new TreeBuilder();
+ $rootNode = $treeBuilder->root('flysystem', 'array');
+
+ $resolver = new FlysystemLoaderFactory();
+ $resolver->addConfiguration($rootNode);
+
+ $this->processConfigTree($treeBuilder, array());
+ }
+
+ public function testProcessCorrectlyOptionsOnAddConfiguration()
+ {
+ $expectedService = 'theService';
+
+ $treeBuilder = new TreeBuilder();
+ $rootNode = $treeBuilder->root('flysystem', 'array');
+
+ $loader = new FlysystemLoaderFactory();
+ $loader->addConfiguration($rootNode);
+
+ $config = $this->processConfigTree($treeBuilder, array(
+ 'flysystem' => array(
+ 'filesystem_service' => $expectedService,
+ ),
+ ));
+
+ $this->assertArrayHasKey('filesystem_service', $config);
+ $this->assertEquals($expectedService, $config['filesystem_service']);
+ }
+
+ /**
+ * @param TreeBuilder $treeBuilder
+ * @param array $configs
+ *
+ * @return array
+ */
+ protected function processConfigTree(TreeBuilder $treeBuilder, array $configs)
+ {
+ $processor = new Processor();
+
+ return $processor->process($treeBuilder->buildTree(), $configs);
+ }
+}
diff --git a/Tests/LiipImagineBundleTest.php b/Tests/LiipImagineBundleTest.php
index 7e7a826ee..3acd257a5 100644
--- a/Tests/LiipImagineBundleTest.php
+++ b/Tests/LiipImagineBundleTest.php
@@ -185,6 +185,28 @@ public function testAddFilesystemLoaderFactoryOnBuild()
$bundle->build($containerMock);
}
+ public function testAddFlysystemLoaderFactoryOnBuild()
+ {
+ $extensionMock = $this->createExtensionMock();
+ $extensionMock
+ ->expects($this->at(4))
+ ->method('addLoaderFactory')
+ ->with($this->isInstanceOf('Liip\ImagineBundle\DependencyInjection\Factory\Loader\FlysystemLoaderFactory'))
+ ;
+
+ $containerMock = $this->createContainerBuilderMock();
+ $containerMock
+ ->expects($this->atLeastOnce())
+ ->method('getExtension')
+ ->with('liip_imagine')
+ ->will($this->returnValue($extensionMock))
+ ;
+
+ $bundle = new LiipImagineBundle();
+
+ $bundle->build($containerMock);
+ }
+
protected function createContainerBuilderMock()
{
return $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder', array(), array(), '', false);
diff --git a/composer.json b/composer.json
index fedaef89a..565007734 100644
--- a/composer.json
+++ b/composer.json
@@ -45,7 +45,8 @@
"twig/twig": "If you'd want to use some handy twig filters, version 1.12 or greater required",
"aws/aws-sdk-php": "Add it if you'd like to use aws v2 or v3 resolver",
"amazonwebservices/aws-sdk-for-php": "Add it if you'd like to use aws v1 resolver",
- "monolog/monolog": "If you'd want to write logs"
+ "monolog/monolog": "If you'd want to write logs",
+ "league/flysystem": "If you'd want to use Flysystem binary loader"
},