diff --git a/.scrutinizer.yml b/.scrutinizer.yml
index 03d854415..cca530320 100644
--- a/.scrutinizer.yml
+++ b/.scrutinizer.yml
@@ -6,7 +6,7 @@ before_commands:
# - "composer install --prefer-source --dev"
filter:
- excluded_paths: [vendor/*, tests/*, bin/*]
+ excluded_paths: [vendor/*, Tests/*, bin/*]
tools:
php_sim: true
@@ -24,5 +24,5 @@ tools:
excluded_dirs: [vendor]
php_pdepend:
enabled: true
- excluded_dirs: [vendor, tests, bin]
+ excluded_dirs: [vendor, Tests, bin]
# php_hhvm: true
diff --git a/DependencyInjection/Factory/Resolver/FlysystemResolverFactory.php b/DependencyInjection/Factory/Resolver/FlysystemResolverFactory.php
new file mode 100644
index 000000000..54f542ccf
--- /dev/null
+++ b/DependencyInjection/Factory/Resolver/FlysystemResolverFactory.php
@@ -0,0 +1,52 @@
+replaceArgument(0, new Reference($config['filesystem_service']));
+ $resolverDefinition->replaceArgument(2, $config['root_url']);
+ $resolverDefinition->replaceArgument(3, $config['cache_prefix']);
+ $resolverDefinition->addTag('liip_imagine.cache.resolver', array(
+ 'resolver' => $resolverName,
+ ));
+ $resolverId = 'liip_imagine.cache.resolver.'.$resolverName;
+
+ $container->setDefinition($resolverId, $resolverDefinition);
+
+ return $resolverId;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'flysystem';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addConfiguration(ArrayNodeDefinition $builder)
+ {
+ $builder
+ ->children()
+ ->scalarNode('filesystem_service')->isRequired()->cannotBeEmpty()->end()
+ ->scalarNode('cache_prefix')->defaultValue(null)->end()
+ ->scalarNode('root_url')->isRequired()->cannotBeEmpty()->end()
+ ->end()
+ ;
+ }
+}
diff --git a/Imagine/Cache/Resolver/FlysystemResolver.php b/Imagine/Cache/Resolver/FlysystemResolver.php
new file mode 100644
index 000000000..91f21a25c
--- /dev/null
+++ b/Imagine/Cache/Resolver/FlysystemResolver.php
@@ -0,0 +1,152 @@
+flysystem = $flysystem;
+ $this->requestContext = $requestContext;
+
+ $this->webRoot = rtrim($rootUrl, '/');
+ $this->cachePrefix = ltrim(str_replace('//', '/', $cachePrefix), '/');
+ $this->cacheRoot = $this->cachePrefix;
+ }
+
+ /**
+ * Checks whether the given path is stored within this Resolver.
+ *
+ * @param string $path
+ * @param string $filter
+ *
+ * @return bool
+ */
+ public function isStored($path, $filter)
+ {
+ return $this->flysystem->has($this->getFilePath($path, $filter));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getFilePath($path, $filter)
+ {
+ return $this->getFileUrl($path, $filter);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getFileUrl($path, $filter)
+ {
+ // crude way of sanitizing URL scheme ("protocol") part
+ $path = str_replace('://', '---', $path);
+
+ return $this->cachePrefix.'/'.$filter.'/'.ltrim($path, '/');
+ }
+
+ /**
+ * Resolves filtered path for rendering in the browser.
+ *
+ * @param string $path The path where the original file is expected to be.
+ * @param string $filter The name of the imagine filter in effect.
+ *
+ * @return string The absolute URL of the cached image.
+ *
+ * @throws NotResolvableException
+ */
+ public function resolve($path, $filter)
+ {
+ return sprintf(
+ '%s/%s',
+ $this->webRoot,
+ $this->getFileUrl($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)
+ {
+ $this->flysystem->put(
+ $this->getFilePath($path, $filter),
+ $binary->getContent()
+ );
+ }
+
+ /**
+ * @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)
+ {
+ if (empty($paths) && empty($filters)) {
+ return;
+ }
+
+ if (empty($paths)) {
+ foreach ($filters as $filter) {
+ $filterCacheDir = $this->cacheRoot.'/'.$filter;
+ $this->flysystem->deleteDir($filterCacheDir);
+ }
+
+ return;
+ }
+
+ foreach ($paths as $path) {
+ foreach ($filters as $filter) {
+ if ($this->flysystem->has($this->getFilePath($path, $filter))) {
+ $this->flysystem->delete($this->getFilePath($path, $filter));
+ }
+ }
+ }
+ }
+}
diff --git a/LiipImagineBundle.php b/LiipImagineBundle.php
index 0e080cdf1..a0dbd2a6c 100644
--- a/LiipImagineBundle.php
+++ b/LiipImagineBundle.php
@@ -10,6 +10,7 @@
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\FlysystemResolverFactory;
use Liip\ImagineBundle\DependencyInjection\Factory\Resolver\WebPathResolverFactory;
use Liip\ImagineBundle\DependencyInjection\LiipImagineExtension;
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -34,6 +35,7 @@ public function build(ContainerBuilder $container)
$extension->addResolverFactory(new WebPathResolverFactory());
$extension->addResolverFactory(new AwsS3ResolverFactory());
+ $extension->addResolverFactory(new FlysystemResolverFactory());
$extension->addLoaderFactory(new StreamLoaderFactory());
$extension->addLoaderFactory(new FileSystemLoaderFactory());
diff --git a/Resources/config/imagine.xml b/Resources/config/imagine.xml
index 1f678d67c..19116386e 100644
--- a/Resources/config/imagine.xml
+++ b/Resources/config/imagine.xml
@@ -57,6 +57,7 @@
Liip\ImagineBundle\Imagine\Cache\Resolver\NoCacheWebPathResolver
Liip\ImagineBundle\Imagine\Cache\Resolver\AwsS3Resolver
Liip\ImagineBundle\Imagine\Cache\Resolver\CacheResolver
+ Liip\ImagineBundle\Imagine\Cache\Resolver\FlysystemResolver
Liip\ImagineBundle\Imagine\Cache\Resolver\ProxyResolver
@@ -208,7 +209,7 @@
-
+
@@ -236,6 +237,13 @@
+
+
+
+
+
+
+
diff --git a/Resources/doc/cache-resolver/flysystem.rst b/Resources/doc/cache-resolver/flysystem.rst
new file mode 100644
index 000000000..688e332ae
--- /dev/null
+++ b/Resources/doc/cache-resolver/flysystem.rst
@@ -0,0 +1,63 @@
+FlysystemResolver
+=================
+
+This resolver lets you load images onto `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.
+
+Create resolver
+---------------
+
+.. code-block:: yaml
+
+ liip_imagine:
+ resolvers:
+ profile_photos:
+ flysystem:
+ filesystem_service: oneup_flysystem.profile_photos_filesystem
+ root_url: http://images.example.com
+ cache_prefix: media/cache
+ oneup_flysystem:
+ adapters:
+ profile_photos:
+ local:
+ directory: "path/to/profile/photos"
+
+ filesystems:
+ profile_photos:
+ adapter: profile_photos
+
+There are several configuration options available:
+
+* ``root_url`` - must be a valid url to the target system the flysystem adapter
+ points to. This is used to determine how the url should be generated upon request.
+ Default value: ``null``
+* ``cache_prefix`` - this is used for the image path generation. This will be the
+ prefix inside the given Flysystem.
+ Default value: ``media/cache``
+
+Usage
+-----
+
+.. code-block:: yaml
+
+ liip_imagine:
+ cache: profile_photos
+
+Usage on a specific filter
+--------------------------
+
+.. code-block:: yaml
+
+ liip_imagine:
+ filter_sets:
+ cache: ~
+ my_thumb:
+ cache: profile_photos
+ quality: 75
+ filters:
+ thumbnail: { size: [120, 90], mode: outbound }
diff --git a/Tests/DependencyInjection/Factory/Resolver/FlysystemResolverFactoryTest.php b/Tests/DependencyInjection/Factory/Resolver/FlysystemResolverFactoryTest.php
new file mode 100644
index 000000000..e79569b7d
--- /dev/null
+++ b/Tests/DependencyInjection/Factory/Resolver/FlysystemResolverFactoryTest.php
@@ -0,0 +1,125 @@
+
+ */
+class FlysystemResolverFactoryTest 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 testImplementsResolverFactoryInterface()
+ {
+ $rc = new \ReflectionClass('Liip\ImagineBundle\DependencyInjection\Factory\Resolver\FlysystemResolverFactory');
+
+ $this->assertTrue($rc->implementsInterface('Liip\ImagineBundle\DependencyInjection\Factory\Resolver\ResolverFactoryInterface'));
+ }
+
+ public function testCouldBeConstructedWithoutAnyArguments()
+ {
+ new FlysystemResolverFactory();
+ }
+
+ public function testReturnExpectedName()
+ {
+ $resolver = new FlysystemResolverFactory();
+
+ $this->assertEquals('flysystem', $resolver->getName());
+ }
+
+ public function testCreateResolverDefinitionOnCreate()
+ {
+ $container = new ContainerBuilder();
+
+ $resolver = new FlysystemResolverFactory();
+
+ $resolver->create($container, 'theResolverName', array(
+ 'filesystem_service' => 'flyfilesystemservice',
+ 'root_url' => 'http://images.example.com',
+ 'cache_prefix' => 'theCachePrefix',
+ ));
+
+ $this->assertTrue($container->hasDefinition('liip_imagine.cache.resolver.theresolvername'));
+
+ $resolverDefinition = $container->getDefinition('liip_imagine.cache.resolver.theresolvername');
+ $this->assertInstanceOf('Symfony\Component\DependencyInjection\DefinitionDecorator', $resolverDefinition);
+ $this->assertEquals('liip_imagine.cache.resolver.prototype.flysystem', $resolverDefinition->getParent());
+
+ $this->assertEquals('http://images.example.com', $resolverDefinition->getArgument(2));
+ $this->assertEquals('theCachePrefix', $resolverDefinition->getArgument(3));
+ }
+
+ public function testProcessCorrectlyOptionsOnAddConfiguration()
+ {
+ $expectedRootUrl = 'http://images.example.com';
+ $expectedCachePrefix = 'theCachePrefix';
+ $expectedFlysystemService = 'flyfilesystemservice';
+
+ $treeBuilder = new TreeBuilder();
+ $rootNode = $treeBuilder->root('flysystem', 'array');
+
+ $resolver = new FlysystemResolverFactory();
+ $resolver->addConfiguration($rootNode);
+
+ $config = $this->processConfigTree($treeBuilder, array(
+ 'flysystem' => array(
+ 'root_url' => $expectedRootUrl,
+ 'cache_prefix' => $expectedCachePrefix,
+ 'filesystem_service' => $expectedFlysystemService,
+ ),
+ ));
+
+ $this->assertArrayHasKey('filesystem_service', $config);
+ $this->assertEquals($expectedFlysystemService, $config['filesystem_service']);
+
+ $this->assertArrayHasKey('root_url', $config);
+ $this->assertEquals($expectedRootUrl, $config['root_url']);
+
+ $this->assertArrayHasKey('cache_prefix', $config);
+ $this->assertEquals($expectedCachePrefix, $config['cache_prefix']);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
+ */
+ public function testAddDefaultOptionsIfNotSetOnAddConfiguration()
+ {
+ $treeBuilder = new TreeBuilder();
+ $rootNode = $treeBuilder->root('flysystem', 'array');
+
+ $resolver = new FlysystemResolverFactory();
+ $resolver->addConfiguration($rootNode);
+
+ $config = $this->processConfigTree($treeBuilder, array(
+ 'flysystem' => array(),
+ ));
+ }
+
+ /**
+ * @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/Imagine/Cache/Resolver/FlysystemResolverTest.php b/Tests/Imagine/Cache/Resolver/FlysystemResolverTest.php
new file mode 100644
index 000000000..c3746adb6
--- /dev/null
+++ b/Tests/Imagine/Cache/Resolver/FlysystemResolverTest.php
@@ -0,0 +1,287 @@
+markTestSkipped(
+ 'The league/flysystem PHP library is not available.'
+ );
+ }
+ }
+
+ public function testImplementsResolverInterface()
+ {
+ $rc = new \ReflectionClass('Liip\ImagineBundle\Imagine\Cache\Resolver\FlysystemResolver');
+
+ $this->assertTrue($rc->implementsInterface('Liip\ImagineBundle\Imagine\Cache\Resolver\ResolverInterface'));
+ }
+
+ public function testResolveUriForFilter()
+ {
+ $fs = $this->getFlysystemMock();
+
+ $resolver = new FlysystemResolver($fs, new RequestContext(), 'http://images.example.com');
+ $uri = $resolver->resolve('/some-folder/path.jpg', 'thumb');
+ $this->assertEquals('http://images.example.com/media/cache/thumb/some-folder/path.jpg', $uri);
+ }
+
+ public function testRemoveObjectsForFilter()
+ {
+ $expectedFilter = 'theFilter';
+ $fs = $this->getFlysystemMock();
+ $fs
+ ->expects($this->once())
+ ->method('deleteDir')
+ ->with('media/cache/theFilter')
+ ;
+
+ $resolver = new FlysystemResolver($fs, new RequestContext(), 'http://images.example.com');
+ $resolver->remove(array(), array($expectedFilter));
+ }
+
+ public function testCreateObjectInAdapter()
+ {
+ $binary = new Binary('aContent', 'image/jpeg', 'jpeg');
+
+ $fs = $this->getFlysystemMock();
+ $fs
+ ->expects($this->once())
+ ->method('put')
+ ->will($this->returnValue(true))
+ ;
+
+ $resolver = new FlysystemResolver($fs, new RequestContext(), 'http://images.example.com');
+
+ $this->assertNull($resolver->store($binary, 'thumb/foobar.jpg', 'thumb'));
+ }
+
+ public function testIsStoredChecksObjectExistence()
+ {
+ $fs = $this->getFlysystemMock();
+ $fs
+ ->expects($this->once())
+ ->method('has')
+ ->will($this->returnValue(false))
+ ;
+
+ $resolver = new FlysystemResolver($fs, new RequestContext(), 'http://images.example.com');
+
+ $this->assertFalse($resolver->isStored('/some-folder/path.jpg', 'thumb'));
+ }
+
+ public function testReturnResolvedImageUrlOnResolve()
+ {
+ $fs = $this->getFlysystemMock();
+
+ $resolver = new FlysystemResolver($fs, new RequestContext(), 'http://images.example.com');
+
+ $this->assertEquals(
+ 'http://images.example.com/media/cache/thumb/some-folder/path.jpg',
+ $resolver->resolve('/some-folder/path.jpg', 'thumb')
+ );
+ }
+
+ public function testRemoveCacheForPathAndFilterOnRemove()
+ {
+ $fs = $this->getFlysystemMock();
+ $fs
+ ->expects($this->once())
+ ->method('has')
+ ->with('media/cache/thumb/some-folder/path.jpg')
+ ->will($this->returnValue(true))
+ ;
+ $fs
+ ->expects($this->once())
+ ->method('delete')
+ ->with('media/cache/thumb/some-folder/path.jpg')
+ ->will($this->returnValue(true))
+ ;
+
+ $resolver = new FlysystemResolver($fs, new RequestContext(), 'http://images.example.com');
+
+ $resolver->remove(array('some-folder/path.jpg'), array('thumb'));
+ }
+
+ public function testRemoveCacheForSomePathsAndFilterOnRemove()
+ {
+ $fs = $this->getFlysystemMock();
+ $fs
+ ->expects($this->at(0))
+ ->method('has')
+ ->with('media/cache/thumb/pathOne.jpg')
+ ->will($this->returnValue(true))
+ ;
+ $fs
+ ->expects($this->at(1))
+ ->method('delete')
+ ->with('media/cache/thumb/pathOne.jpg')
+ ->will($this->returnValue(true))
+ ;
+ $fs
+ ->expects($this->at(2))
+ ->method('has')
+ ->with('media/cache/thumb/pathTwo.jpg')
+ ->will($this->returnValue(true))
+ ;
+ $fs
+ ->expects($this->at(3))
+ ->method('delete')
+ ->with('media/cache/thumb/pathTwo.jpg')
+ ->will($this->returnValue(true))
+ ;
+
+ $resolver = new FlysystemResolver($fs, new RequestContext(), 'http://images.example.com');
+
+ $resolver->remove(
+ array('pathOne.jpg', 'pathTwo.jpg'),
+ array('thumb')
+ );
+ }
+
+ public function testRemoveCacheForSomePathsAndSomeFiltersOnRemove()
+ {
+ $fs = $this->getFlysystemMock();
+ $fs
+ ->expects($this->at(0))
+ ->method('has')
+ ->with('media/cache/filterOne/pathOne.jpg')
+ ->will($this->returnValue(true))
+ ;
+ $fs
+ ->expects($this->at(1))
+ ->method('delete')
+ ->with('media/cache/filterOne/pathOne.jpg')
+ ->will($this->returnValue(true))
+ ;
+ $fs
+ ->expects($this->at(2))
+ ->method('has')
+ ->with('media/cache/filterTwo/pathOne.jpg')
+ ->will($this->returnValue(true))
+ ;
+ $fs
+ ->expects($this->at(3))
+ ->method('delete')
+ ->with('media/cache/filterTwo/pathOne.jpg')
+ ->will($this->returnValue(true))
+ ;
+ $fs
+ ->expects($this->at(4))
+ ->method('has')
+ ->with('media/cache/filterOne/pathTwo.jpg')
+ ->will($this->returnValue(true))
+ ;
+ $fs
+ ->expects($this->at(5))
+ ->method('delete')
+ ->with('media/cache/filterOne/pathTwo.jpg')
+ ->will($this->returnValue(true))
+ ;
+ $fs
+ ->expects($this->at(6))
+ ->method('has')
+ ->with('media/cache/filterTwo/pathTwo.jpg')
+ ->will($this->returnValue(true))
+ ;
+ $fs
+ ->expects($this->at(7))
+ ->method('delete')
+ ->with('media/cache/filterTwo/pathTwo.jpg')
+ ->will($this->returnValue(true))
+ ;
+
+ $resolver = new FlysystemResolver($fs, new RequestContext(), 'http://images.example.com');
+
+ $resolver->remove(
+ array('pathOne.jpg', 'pathTwo.jpg'),
+ array('filterOne', 'filterTwo')
+ );
+ }
+
+ public function testDoNothingWhenObjectNotExistForPathAndFilterOnRemove()
+ {
+ $fs = $this->getFlysystemMock();
+ $fs
+ ->expects($this->once())
+ ->method('has')
+ ->with('media/cache/thumb/some-folder/path.jpg')
+ ->will($this->returnValue(false))
+ ;
+ $fs
+ ->expects($this->never())
+ ->method('delete')
+ ;
+
+ $resolver = new FlysystemResolver($fs, new RequestContext(), 'http://images.example.com');
+ $resolver->remove(array('some-folder/path.jpg'), array('thumb'));
+ }
+
+ public function testRemoveCacheForFilterOnRemove()
+ {
+ $expectedFilter = 'theFilter';
+
+ $fs = $this->getFlysystemMock();
+ $fs
+ ->expects($this->once())
+ ->method('deleteDir')
+ ->with('media/cache/theFilter')
+ ;
+
+ $resolver = new FlysystemResolver($fs, new RequestContext(), 'http://images.example.com');
+
+ $resolver->remove(array(), array($expectedFilter));
+ }
+
+ public function testRemoveCacheForSomeFiltersOnRemove()
+ {
+ $expectedFilterOne = 'theFilterOne';
+ $expectedFilterTwo = 'theFilterTwo';
+
+ $fs = $this->getFlysystemMock();
+ $fs
+ ->expects($this->at(0))
+ ->method('deleteDir')
+ ->with('media/cache/theFilterOne')
+ ;
+ $fs
+ ->expects($this->at(1))
+ ->method('deleteDir')
+ ->with('media/cache/theFilterTwo')
+ ;
+
+ $resolver = new FlysystemResolver($fs, new RequestContext(), 'http://images.example.com');
+
+ $resolver->remove(array(), array($expectedFilterOne, $expectedFilterTwo));
+ }
+
+ /**
+ * @return \PHPUnit_Framework_MockObject_MockObject|Filesystem
+ */
+ protected function getFlysystemMock()
+ {
+ $mockedMethods = array(
+ 'delete',
+ 'deleteDir',
+ 'has',
+ 'put',
+ 'remove',
+ );
+
+ return $this->getMock('League\Flysystem\Filesystem', $mockedMethods, array(), '', false);
+ }
+}
diff --git a/Tests/LiipImagineBundleTest.php b/Tests/LiipImagineBundleTest.php
index 3acd257a5..64a1e253a 100644
--- a/Tests/LiipImagineBundleTest.php
+++ b/Tests/LiipImagineBundleTest.php
@@ -141,11 +141,33 @@ public function testAddAwsS3ResolverFactoryOnBuild()
$bundle->build($containerMock);
}
- public function testAddStreamLoaderFactoryOnBuild()
+ public function testAddFlysystemResolverFactoryOnBuild()
{
$extensionMock = $this->createExtensionMock();
$extensionMock
->expects($this->at(2))
+ ->method('addResolverFactory')
+ ->with($this->isInstanceOf('Liip\ImagineBundle\DependencyInjection\Factory\Resolver\FlysystemResolverFactory'))
+ ;
+
+ $containerMock = $this->createContainerBuilderMock();
+ $containerMock
+ ->expects($this->atLeastOnce())
+ ->method('getExtension')
+ ->with('liip_imagine')
+ ->will($this->returnValue($extensionMock))
+ ;
+
+ $bundle = new LiipImagineBundle();
+
+ $bundle->build($containerMock);
+ }
+
+ public function testAddStreamLoaderFactoryOnBuild()
+ {
+ $extensionMock = $this->createExtensionMock();
+ $extensionMock
+ ->expects($this->at(3))
->method('addLoaderFactory')
->with($this->isInstanceOf('Liip\ImagineBundle\DependencyInjection\Factory\Loader\StreamLoaderFactory'))
;
@@ -167,7 +189,7 @@ public function testAddFilesystemLoaderFactoryOnBuild()
{
$extensionMock = $this->createExtensionMock();
$extensionMock
- ->expects($this->at(3))
+ ->expects($this->at(4))
->method('addLoaderFactory')
->with($this->isInstanceOf('Liip\ImagineBundle\DependencyInjection\Factory\Loader\FilesystemLoaderFactory'))
;
@@ -189,7 +211,7 @@ public function testAddFlysystemLoaderFactoryOnBuild()
{
$extensionMock = $this->createExtensionMock();
$extensionMock
- ->expects($this->at(4))
+ ->expects($this->at(5))
->method('addLoaderFactory')
->with($this->isInstanceOf('Liip\ImagineBundle\DependencyInjection\Factory\Loader\FlysystemLoaderFactory'))
;
diff --git a/Tests/bootstrap.php b/Tests/bootstrap.php
index 79e186b78..c1bc09a44 100644
--- a/Tests/bootstrap.php
+++ b/Tests/bootstrap.php
@@ -20,5 +20,5 @@
interface ExpressionFunctionProviderInterface
{
- };
+ }
}