Skip to content

Commit

Permalink
allow multiple root paths for filesystem loader
Browse files Browse the repository at this point in the history
  • Loading branch information
robfrawley committed Jan 14, 2017
1 parent 966f419 commit beeeb5a
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 39 deletions.
65 changes: 47 additions & 18 deletions Binary/Loader/FileSystemLoader.php
Expand Up @@ -32,47 +32,76 @@ class FileSystemLoader implements LoaderInterface
/**
* @var string
*/
protected $rootPath;
protected $dataRoots;

/**
* @param MimeTypeGuesserInterface $mimeTypeGuesser
* @param ExtensionGuesserInterface $extensionGuesser
* @param string $rootPath
* @param string[] $dataRoots
*/
public function __construct(
MimeTypeGuesserInterface $mimeTypeGuesser,
ExtensionGuesserInterface $extensionGuesser,
$rootPath
$dataRoots
) {
$this->mimeTypeGuesser = $mimeTypeGuesser;
$this->extensionGuesser = $extensionGuesser;

if (empty($rootPath) || !($realRootPath = realpath($rootPath))) {
throw new InvalidArgumentException(sprintf('Root image path not resolvable "%s"', $rootPath));
}
$this->dataRoots = array_map(function ($root) {
if (!empty($root) && false !== $realRoot = realpath($root)) {
return $realRoot;
}

throw new InvalidArgumentException(sprintf('Root image path not resolvable "%s"', $root));
}, (array) $dataRoots);

$this->rootPath = $realRootPath;
if (count($this->dataRoots) === 0) {
throw new InvalidArgumentException('One or more data root paths must be specified.');
}
}

/**
* {@inheritdoc}
*/
public function find($path)
{
if (!($absolutePath = realpath($this->rootPath.DIRECTORY_SEPARATOR.$path))) {
throw new NotLoadableException(sprintf('Source image not resolvable "%s"', $path));
}
$path = $this->absolutePathRestrict($this->absolutePathLocate($path));
$mime = $this->mimeTypeGuesser->guess($path);

if (0 !== strpos($absolutePath, $this->rootPath)) {
throw new NotLoadableException(sprintf('Source image invalid "%s" as it is outside of the defined root path', $absolutePath));
return new FileBinary($path, $mime, $this->extensionGuesser->guess($mime));
}

/**
* @param string $path
*
* @return string
*/
private function absolutePathLocate($path)
{
foreach ($this->dataRoots as $root) {
if (false !== $realPath = realpath($root.DIRECTORY_SEPARATOR.$path)) {
return $realPath;
}
}

$mimeType = $this->mimeTypeGuesser->guess($absolutePath);
throw new NotLoadableException(sprintf('Source image not resolvable "%s" in root path(s) "%s"',
$path, implode(':', $this->dataRoots)));
}

/**
* @param string $path
*
* @return mixed
*/
private function absolutePathRestrict($path)
{
foreach ($this->dataRoots as $root) {
if (0 === strpos($path, $root)) {
return $path;
}
}

return new FileBinary(
$absolutePath,
$mimeType,
$this->extensionGuesser->guess($mimeType)
);
throw new NotLoadableException(sprintf('Source image invalid "%s" as it is outside of the defined root path(s) "%s"',
$path, implode(':', $this->dataRoots)));
}
}
14 changes: 11 additions & 3 deletions DependencyInjection/Factory/Loader/FileSystemLoaderFactory.php
Expand Up @@ -49,8 +49,16 @@ public function addConfiguration(ArrayNodeDefinition $builder)
{
$builder
->children()
->scalarNode('data_root')->defaultValue('%kernel.root_dir%/../web')->cannotBeEmpty()->end()
->end()
;
->arrayNode('data_root')
->beforeNormalization()
->ifString()
->then(function ($value) { return array($value); })
->end()
->defaultValue(array('%kernel.root_dir%/../web'))
->prototype('scalar')
->cannotBeEmpty()
->end()
->end()
->end();
}
}
74 changes: 59 additions & 15 deletions Tests/Binary/Loader/FileSystemLoaderTest.php
Expand Up @@ -16,24 +16,10 @@
use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser;

/**
* @covers Liip\ImagineBundle\Binary\Loader\FileSystemLoader
* @covers \Liip\ImagineBundle\Binary\Loader\FileSystemLoader
*/
class FileSystemLoaderTest extends \PHPUnit_Framework_TestCase
{
public static function provideLoadCases()
{
$fileName = pathinfo(__FILE__, PATHINFO_BASENAME);

return array(
array(__DIR__, $fileName),
array(__DIR__.'/', $fileName),
array(__DIR__, '/'.$fileName),
array(__DIR__.'/../../Binary/Loader', '/'.$fileName),
array(realpath(__DIR__.'/..'), 'Loader/'.$fileName),
array(__DIR__.'/../', '/Loader/../../Binary/Loader/'.$fileName),
);
}

public function testShouldImplementLoaderInterface()
{
$rc = new \ReflectionClass('Liip\ImagineBundle\Binary\Loader\FileSystemLoader');
Expand All @@ -50,6 +36,20 @@ public function testCouldBeConstructedWithExpectedArguments()
);
}

public function testThrowExceptionIfNoRootPathsProvided()
{
$this->setExpectedException(
'Liip\ImagineBundle\Exception\InvalidArgumentException',
'One or more data root paths must be specified.'
);

new FileSystemLoader(
MimeTypeGuesser::getInstance(),
ExtensionGuesser::getInstance(),
array()
);
}

public function testThrowExceptionIfRootPathIsEmpty()
{
$this->setExpectedException(
Expand Down Expand Up @@ -137,6 +137,20 @@ public function testThrowExceptionIfFileNotExist()
$loader->find('fileNotExist');
}

public static function provideLoadCases()
{
$fileName = pathinfo(__FILE__, PATHINFO_BASENAME);

return array(
array(__DIR__, $fileName),
array(__DIR__.'/', $fileName),
array(__DIR__, '/'.$fileName),
array(__DIR__.'/../../Binary/Loader', '/'.$fileName),
array(realpath(__DIR__.'/..'), 'Loader/'.$fileName),
array(__DIR__.'/../', '/Loader/../../Binary/Loader/'.$fileName),
);
}

/**
* @dataProvider provideLoadCases
*/
Expand All @@ -153,4 +167,34 @@ public function testLoad($rootDir, $path)
$this->assertInstanceOf('Liip\ImagineBundle\Model\FileBinary', $binary);
$this->assertStringStartsWith('text/', $binary->getMimeType());
}

public static function provideMultipleRootLoadCases()
{
$prepend = array(
realpath(__DIR__.'/../'),
realpath(__DIR__.'/../../'),
realpath(__DIR__.'/../../../'),
);

return array_map(function ($params) use ($prepend) {
return array(array($prepend[mt_rand(0, count($prepend) - 1)], $params[0]), $params[1]);
}, static::provideLoadCases());
}

/**
* @dataProvider provideMultipleRootLoadCases
*/
public function testMultipleRootLoadCases($rootDirs, $path)
{
$loader = new FileSystemLoader(
MimeTypeGuesser::getInstance(),
ExtensionGuesser::getInstance(),
$rootDirs
);

$binary = $loader->find($path);

$this->assertInstanceOf('Liip\ImagineBundle\Model\FileBinary', $binary);
$this->assertStringStartsWith('text/', $binary->getMimeType());
}
}
Expand Up @@ -17,7 +17,7 @@
use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
* @covers Liip\ImagineBundle\DependencyInjection\Factory\Loader\FileSystemLoaderFactory<extended>
* @covers \Liip\ImagineBundle\DependencyInjection\Factory\Loader\FileSystemLoaderFactory<extended>
*/
class FileSystemLoaderFactoryTest extends \Phpunit_Framework_TestCase
{
Expand Down Expand Up @@ -61,7 +61,7 @@ public function testCreateLoaderDefinitionOnCreate()

public function testProcessCorrectlyOptionsOnAddConfiguration()
{
$expectedDataRoot = 'theDataRoot';
$expectedDataRoot = array('theDataRoot');

$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('filesystem', 'array');
Expand All @@ -81,7 +81,7 @@ public function testProcessCorrectlyOptionsOnAddConfiguration()

public function testAddDefaultOptionsIfNotSetOnAddConfiguration()
{
$expectedDataRoot = '%kernel.root_dir%/../web';
$expectedDataRoot = array('%kernel.root_dir%/../web');

$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('filesystem', 'array');
Expand All @@ -97,6 +97,26 @@ public function testAddDefaultOptionsIfNotSetOnAddConfiguration()
$this->assertEquals($expectedDataRoot, $config['data_root']);
}

public function testAddAsScalarExpectingArrayNormalizationOfConfiguration()
{
$expectedDataRoot = array('%kernel.root_dir%/../web');

$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('filesystem', 'array');

$loader = new FileSystemLoaderFactory();
$loader->addConfiguration($rootNode);

$config = $this->processConfigTree($treeBuilder, array(
'filesystem' => array(
'data_root' => $expectedDataRoot[0],
),
));

$this->assertArrayHasKey('data_root', $config);
$this->assertEquals($expectedDataRoot, $config['data_root']);
}

/**
* @param TreeBuilder $treeBuilder
* @param array $configs
Expand Down

0 comments on commit beeeb5a

Please sign in to comment.