Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
5cd209f
add / to cache prefix start to prevent duplicate // in case the cache…
lsmith77 Jul 21, 2011
4b47493
renamed filter() to filterAction()
lsmith77 Jul 21, 2011
9ad85ed
added ability to resolve the real path to the cache path resolver
lsmith77 Jul 21, 2011
06b00bb
refactored the controller
lsmith77 Jul 21, 2011
e21973a
properly set status code depending on if caching is active or not
lsmith77 Jul 21, 2011
7dff516
added support for 'json' format
lsmith77 Jul 21, 2011
9e0acb4
make the FileSytemLoader extensible
lsmith77 Jul 21, 2011
c051308
fixed content type for jpg
lsmith77 Jul 21, 2011
8608b6c
fixed handling of quality
lsmith77 Jul 21, 2011
a0a398a
add support for defining a filter without a type to return the origin…
lsmith77 Jul 22, 2011
0c7fd4a
typo fix
lsmith77 Jul 22, 2011
70e3415
make it possible to omit either the width or the heigth
lsmith77 Jul 22, 2011
5420858
make the Request instance a parameter to the resolve() method so that…
lsmith77 Jul 22, 2011
1dfffe3
assume that an unknown format is simply part of the name
lsmith77 Jul 26, 2011
5c1ba0d
allow a filter to be an empty string
lsmith77 Jul 26, 2011
939151c
minor cleanups to the json handling
lsmith77 Jul 26, 2011
9482895
added support for XML output
lsmith77 Jul 27, 2011
6b58fd0
Merge remote branch 'origin/master' into refactoring
lsmith77 Jul 29, 2011
c0f4c6f
cosmetics
lsmith77 Jul 31, 2011
21826a8
removed support for json/xml
lsmith77 Jul 31, 2011
0328bfb
removed outdated documentation
lsmith77 Jul 31, 2011
de3554c
accept request as an action parameter
lsmith77 Aug 4, 2011
2f941a8
filter loader already apply filter, by default do not upscale thumbnails
lsmith77 Aug 12, 2011
c8dda4c
moved quality to the main filter definition
lsmith77 Sep 11, 2011
366b914
added Configuration class for better validation
lsmith77 Sep 11, 2011
90b505c
tweaked options handling
lsmith77 Sep 11, 2011
460bddc
fixed driver validation
lsmith77 Sep 11, 2011
a0527b2
xml fix for options
lsmith77 Sep 11, 2011
274341c
added support for 'loader' config
lsmith77 Sep 11, 2011
ca2b88a
Added some tests for the DI extension
stof Sep 11, 2011
c72dab9
Added gmagick as valid driver
stof Sep 11, 2011
bbef47d
Merge pull request #1 from stof/liip-refactoring
lsmith77 Sep 11, 2011
9687337
typo fix
lsmith77 Sep 24, 2011
38ec845
handle path normaliztion inside the extension
lsmith77 Sep 25, 2011
b3ac477
fixed handling of options
lsmith77 Sep 26, 2011
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/phpunit.xml
145 changes: 47 additions & 98 deletions Controller/ImagineController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,140 +2,89 @@

namespace Avalanche\Bundle\ImagineBundle\Controller;

use Avalanche\Bundle\ImagineBundle\Imagine\CachePathResolver;
use Avalanche\Bundle\ImagineBundle\Imagine\Filter\FilterManager;
use Imagine\Image\ImagineInterface;
use Symfony\Component\HttpKernel\Util\Filesystem;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Avalanche\Bundle\ImagineBundle\Imagine\CachePathResolver;
use Avalanche\Bundle\ImagineBundle\Imagine\DataLoader\LoaderInterface;
use Avalanche\Bundle\ImagineBundle\Imagine\Filter\FilterManager;

class ImagineController
{
/**
* @var Symfony\Component\HttpFoundation\Request
* @var Avalanche\Bundle\ImagineBundle\Imagine\DataLoader\LoaderInterface
*/
private $request;
private $dataLoader;

/**
* @var Avalanche\Bundle\ImagineBundle\Imagine\CachePathResolver
*/
private $cachePathResolver;

/**
* @var Imagine\Image\ImagineInterface
*/
private $imagine;

/**
* @var Avalanche\Bundle\ImagineBundle\Imagine\FilterManager
* @var Avalanche\Bundle\ImagineBundle\Imagine\Filter\FilterManager
*/
private $filterManager;

/**
* @var Symfony\Component\HttpKernel\Util\Filesystem
* @var Avalanche\Bundle\ImagineBundle\Imagine\CachePathResolver
*/
private $filesystem;
private $cachePathResolver;

/**
* @var string
* Constructor
*
* @param Avalanche\Bundle\ImagineBundle\Imagine\DataLoader\LoaderInterface $dataLoader
* @param Avalanche\Bundle\ImagineBundle\Imagine\Filter\FilterManager $filterManager
* @param Avalanche\Bundle\ImagineBundle\Imagine\CachePathResolver $cachePathResolver
*/
private $webRoot;
public function __construct(LoaderInterface $dataLoader, FilterManager $filterManager, CachePathResolver $cachePathResolver = null)
{
$this->dataLoader = $dataLoader;
$this->filterManager = $filterManager;
$this->cachePathResolver = $cachePathResolver;
}

/**
* Constructs by setting $cachePathResolver
* Resolve the requested path to a local path or a Response
*
* @param Symfony\Component\HttpFoundation\Request $request
* @param Avalanche\Bundle\ImagineBundle\Imagine\CachePathResolver $cachePathResolver
* @param Imagine\Image\ImagineInterface $imagine
* @param Avalanche\Bundle\ImagineBundle\Imagine\FilterManager $filterManager
* @param string $webRoot
* @param Symfony\Component\HttpFoundation\Request $request
* @param string $path
* @param string $filter
*
* @return string|Symfony\Component\HttpFoundation\Response
*/
public function __construct(
Request $request,
CachePathResolver $cachePathResolver,
ImagineInterface $imagine,
FilterManager $filterManager,
Filesystem $filesystem,
$webRoot
)
protected function resolve(Request $request, $path, $filter)
{
$this->request = $request;
$this->cachePathResolver = $cachePathResolver;
$this->imagine = $imagine;
$this->filterManager = $filterManager;
$this->filesystem = $filesystem;
$this->webRoot = $webRoot;
$realPath = null;
if ($this->cachePathResolver) {
$realPath = $this->cachePathResolver->resolve($request, $path, $filter);
if (!$realPath) {
throw new NotFoundHttpException('Image doesn\'t exist');
}
}

return $realPath;
}

/**
* This action applies a given filter to a given image, saves the image and
* This action applies a given filter to a given image,
* optionally saves the image and
* outputs it to the browser at the same time
*
* @param Symfony\Component\HttpFoundation\Request $request
* @param string $path
* @param string $filter
*
* @return Response
*/
public function filter($path, $filter)
public function filterAction(Request $request, $path, $filter)
{
$path = '/'.ltrim($path, '/');

//TODO: find out why I need double urldecode to get a valid path
$browserPath = urldecode(urldecode($this->cachePathResolver->getBrowserPath($path, $filter)));
$basePath = $this->request->getBaseUrl();

if (!empty($basePath) && 0 === strpos($browserPath, $basePath)) {
$browserPath = substr($browserPath, strlen($basePath));
}

// if cache path cannot be determined, return 404
if (null === $browserPath) {
throw new NotFoundHttpException('Image doesn\'t exist');
}

$realPath = $this->webRoot.$browserPath;
$sourcePath = $this->webRoot.$path;

// if the file has already been cached, we're probably not rewriting
// correctly, hence make a 301 to proper location, so browser remembers
if (file_exists($realPath)) {
return new Response('', 301, array(
'location' => $this->request->getBasePath().$browserPath
));
}

if (!file_exists($sourcePath)) {
throw new NotFoundHttpException(sprintf(
'Source image not found in "%s"', $sourcePath
));
}

$dir = pathinfo($realPath, PATHINFO_DIRNAME);
list($actualPath, $image, $format) = $this->dataLoader->find($path);

if (!is_dir($dir)) {
if (!$this->filesystem->mkdir($dir)) {
throw new \RuntimeException(sprintf(
'Could not create directory %s', $dir
));
}
$realPath = $this->resolve($request, $actualPath, $filter);
if ($realPath instanceof Response) {
return $realPath;
}

ob_start();
try {
// TODO: get rid of hard-coded quality and format
$this->filterManager->get($filter)
->apply($this->imagine->open($sourcePath))
->save($realPath, array('quality' => 100))
->show('png');

// TODO: add more media headers
return new Response(ob_get_clean(), 201, array(
'content-type' => 'image/png',
));
} catch (\Exception $e) {
ob_end_clean();
throw $e;
}
$image = $this->filterManager->get($filter, $image, $realPath, $format);
$statusCode = $this->cachePathResolver ? 201 : 200;
$contentType = 'image/'.($format == 'jpg' ? 'jpeg' : $format);
return new Response($image, $statusCode, array('Content-Type' => $contentType));
}
}
53 changes: 20 additions & 33 deletions DependencyInjection/AvalancheImagineExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Reference;

class AvalancheImagineExtension extends Extension
{
Expand All @@ -15,47 +16,33 @@ class AvalancheImagineExtension extends Extension
*/
public function load(array $configs, ContainerBuilder $container)
{
$config = $this->processConfiguration(new Configuration(), $configs);

$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('imagine.xml');

$config = $this->mergeConfig($configs);

$driver = 'gd';

if (isset($config['driver'])) {
$driver = strtolower($config['driver']);
}

if (!in_array($driver, array('gd', 'imagick'))) {
throw new \InvalidArgumentException('Invalid imagine driver specified');
}

$container->setAlias('imagine', new Alias('imagine.'.$driver));
$container->setAlias('imagine', new Alias('imagine.'.$config['driver']));

foreach (array('cache_prefix', 'web_root', 'filters') as $key) {
if (isset($config[$key])) {
$container->setParameter('imagine.'.$key, $config[$key]);
$cachePrefix = $config['cache_prefix'] ? '/'.trim($config['cache_prefix'], '/') : '';
$container->setParameter('imagine.cache_prefix', $cachePrefix);
$container->setParameter('imagine.web_root', $config['web_root']);
$container->setParameter('imagine.formats', $config['formats']);
$container->setParameter('imagine.cache', $config['cache']);
foreach ($config['filters'] as $filter => $options) {
if (isset($options['path'])) {
$config['filters'][$filter]['path'] = '/'.trim($options['path'], '/');
}
}
}
$container->setParameter('imagine.filters', $config['filters']);

private function mergeConfig(array $configs)
{
$config = array();

foreach ($configs as $cnf) {
$config = array_merge($config, $cnf);
if ($container->getParameter('imagine.cache')) {
$controller = $container->getDefinition('imagine.controller');
$controller->addArgument(new Reference('imagine.cache.path.resolver'));
}

return $config;
}

/**
* @see Symfony\Component\DependencyInjection\Extension.ExtensionInterface::getAlias()
* @codeCoverageIgnore
*/
function getAlias()
{
return 'avalanche_imagine';
if (!empty($config['loader'])) {
$controller = $container->getDefinition('imagine.controller');
$controller->replaceArgument(0, new Reference($config['loader']));
}
}
}
24 changes: 12 additions & 12 deletions DependencyInjection/Compiler/CreateCacheDirectoriesCompilerPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,24 @@ class CreateCacheDirectoriesCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->getParameter('imagine.cache')) {
return;
}

$webRoot = $container->getParameter('imagine.web_root');
$cachePrefix = $container->getParameter('imagine.cache_prefix');
$filters = $container->getParameter('imagine.filters');

foreach ($filters as $filter => $options) {
if (isset($options['path'])) {
$dir = $webRoot.'/'.$options['path'];
} else {
$dir = $webRoot.'/'.$cachePrefix.'/'.$filter;
}
$dir = isset($options['path'])
? $webRoot.$options['path']
: $webRoot.$cachePrefix.'/'.$filter;

if (!is_dir($dir)) {
if (!mkdir($dir, 0777, true)) {
throw new \RuntimeException(sprintf(
'Could not create directory for caching processed '.
'images in "%s"', $dir
));
}
if (!is_dir($dir) && !mkdir($dir, 0777, true)) {
throw new \RuntimeException(sprintf(
'Could not create directory for caching processed '.
'images in "%s"', $dir
));
}
}
}
Expand Down
59 changes: 59 additions & 0 deletions DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

namespace Avalanche\Bundle\ImagineBundle\DependencyInjection;

use Symfony\Component\Config\Definition\Builder\TreeBuilder,
Symfony\Component\Config\Definition\ConfigurationInterface;

class Configuration implements ConfigurationInterface
{
/**
* Generates the configuration tree.
*
* @return TreeBuilder
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('avalanche_imagine', 'array');

$rootNode
->fixXmlConfig('format', 'formats')
->fixXmlConfig('filter', 'filters')
->children()
->scalarNode('driver')->defaultValue('gd')
->validate()
->ifTrue(function($v) { return !in_array($v, array('gd', 'imagick', 'gmagick')); })
->thenInvalid('Invalid imagine driver specified: %s')
->end()
->end()
->scalarNode('web_root')->defaultValue('%kernel.root_dir%/../web')->end()
->scalarNode('cache_prefix')->defaultValue('/media/cache')->end()
->scalarNode('cache')->defaultTrue()->end()
->scalarNode('loader')->defaultNull()->end()
->arrayNode('formats')
->defaultValue(array())
->prototype('scalar')->end()
->end()
->arrayNode('filters')
->useAttributeAsKey('name')
->prototype('array')
->fixXmlConfig('option', 'options')
->useAttributeAsKey('name')
->children()
->scalarNode('type')->end()
->scalarNode('path')->end()
->scalarNode('quality')->defaultValue(100)->end()
->arrayNode('options')
->useAttributeAsKey('name')
->prototype('variable')->end()
->end()
->end()
->end()
->end()
->end()
->end();

return $treeBuilder;
}
}
Loading