Merge pull request #1091 from nlegoff/yeah-yeah-yeah

[3.8.6][PHRAS-136] Add static file mode to serve thumbnails
This commit is contained in:
Nicolas Le Goff
2014-09-24 14:07:06 +02:00
24 changed files with 828 additions and 11 deletions

View File

@@ -19,6 +19,8 @@ namespace KonsoleKommander;
use Alchemy\Phrasea\Command\Plugin\ListPlugin;
use Alchemy\Phrasea\Command\Setup\H264ConfigurationDumper;
use Alchemy\Phrasea\Command\Setup\H264MappingGenerator;
use Alchemy\Phrasea\Command\Setup\StaticConfigurationDumper;
use Alchemy\Phrasea\Command\Setup\StaticMappingGenerator;
use Alchemy\Phrasea\Core\Version;
use Alchemy\Phrasea\Command\BuildMissingSubdefs;
use Alchemy\Phrasea\Command\CreateCollection;
@@ -105,6 +107,9 @@ $cli->command(new H264MappingGenerator());
$cli->command(new XSendFileConfigurationDumper());
$cli->command(new XSendFileMappingGenerator());
$cli->command(new StaticConfigurationDumper());
$cli->command(new StaticMappingGenerator());
$cli->loadPlugins();
exit(is_int($cli->run()) ? : 1);

View File

@@ -157,8 +157,12 @@ api_cors:
max_age: 0
hosts: []
session:
idle: 0
lifetime: 604800 # 1 week
idle: 0
lifetime: 604800 # 1 week
static-file:
enabled: false
type: nginx
symlink-directory: ''
crossdomain:
site-control: 'master-only'
allow-access-from:

View File

@@ -0,0 +1,60 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Command\Setup;
use Alchemy\Phrasea\Command\Command;
use Alchemy\Phrasea\Exception\RuntimeException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class StaticConfigurationDumper extends Command
{
public function __construct($name = null)
{
parent::__construct('static-file:dump-configuration');
$this->setDescription('Dump the virtual host configuration depending on Phraseanet configuration');
}
/**
* {@inheritdoc}
*/
protected function doExecute(InputInterface $input, OutputInterface $output)
{
$output->writeln('');
if ($this->container['phraseanet.xsendfile-factory']->isXSendFileModeEnabled()) {
throw new \LogicException('XSendFile mode is already activated');
}
if (!$this->container['phraseanet.static-file-factory']->isStaticFileModeEnabled()) {
$output->writeln('Static file support is <error>disabled</error>');
$ret = 1;
} else {
$output->writeln('Static file support is <info>enabled</info>');
$ret = 0;
}
try {
$configuration = $this->container['phraseanet.static-file-factory']->getMode(true, true)->getVirtualHostConfiguration();
$output->writeln('Static file configuration seems <info>OK</info>');
$output->writeln($configuration);
} catch (RuntimeException $e) {
$output->writeln('Static file configuration seems <error>invalid</error>');
$ret = 1;
}
$output->writeln('');
return $ret;
}
}

View File

@@ -0,0 +1,64 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Command\Setup;
use Alchemy\Phrasea\Command\Command;
use Alchemy\Phrasea\Http\StaticFile\StaticFileFactory;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Yaml\Yaml;
class StaticMappingGenerator extends Command
{
public function __construct($name = null)
{
parent::__construct('static-file:generate-mapping');
$this->addOption('write', 'w', null, 'Writes the configuration')
->addOption('enabled', 'e', null, 'Set the enable toggle to `true`')
->addArgument('type', InputArgument::REQUIRED, 'The configuration type, either `nginx` or `apache`')
->setDescription('Generates Phraseanet Static file configuration');
}
/**
* {@inheritdoc}
*/
protected function doExecute(InputInterface $input, OutputInterface $output)
{
$enabled = $input->getOption('enabled');
$type = strtolower($input->getArgument('type'));
$factory = new StaticFileFactory($this->container['monolog'], true, $type, $this->container['phraseanet.thumb-symlinker']);
$mode = $factory->getMode(true);
$conf = array(
'enabled' => $enabled,
'type' => $type,
'mapping' => $mode->getMapping(),
);
if ($input->getOption('write')) {
$output->write("Writing configuration ...");
$this->container['phraseanet.configuration']['static-file'] = $conf;
$output->writeln(" <info>OK</info>");
$output->writeln("");
$output->write("It is now strongly recommended to use <info>static-file:dump-configuration</info> command to upgrade your virtual-host");
} else {
$output->writeln("Configuration will <info>not</info> be written, use <info>--write</info> option to write it");
$output->writeln("");
$output->writeln(Yaml::dump(array('static-file' => $conf), 4));
}
return 0;
}
}

View File

@@ -14,6 +14,7 @@ namespace Alchemy\Phrasea\Core\Provider;
use Alchemy\Phrasea\Core\Event\Subscriber\XSendFileSubscriber;
use Alchemy\Phrasea\Http\H264PseudoStreaming\H264Factory;
use Alchemy\Phrasea\Http\ServeFileResponseFactory;
use Alchemy\Phrasea\Http\StaticFile\StaticFileFactory;
use Alchemy\Phrasea\Http\XSendFile\XSendFileFactory;
use Silex\Application;
use Silex\ServiceProviderInterface;
@@ -33,10 +34,18 @@ class FileServeServiceProvider implements ServiceProviderInterface
return H264Factory::create($app);
});
$app['phraseanet.static-file-factory'] = $app->share(function ($app) {
return StaticFileFactory::create($app);
});
$app['phraseanet.h264'] = $app->share(function ($app) {
return $app['phraseanet.h264-factory']->createMode(false);
});
$app['phraseanet.static-file'] = $app->share(function ($app) {
return $app['phraseanet.static-file-factory']->getMode(false);
});
$app['phraseanet.file-serve'] = $app->share(function (Application $app) {
return ServeFileResponseFactory::create($app);
});

View File

@@ -11,6 +11,8 @@
namespace Alchemy\Phrasea\Core\Provider;
use Alchemy\Phrasea\Http\StaticFile\Symlink\SymLinker;
use Alchemy\Phrasea\Http\StaticFile\Symlink\SymLinkerEncoder;
use Alchemy\Phrasea\Metadata\PhraseanetMetadataReader;
use Alchemy\Phrasea\Metadata\PhraseanetMetadataSetter;
use Alchemy\Phrasea\Security\Firewall;
@@ -41,6 +43,14 @@ class PhraseanetServiceProvider implements ServiceProviderInterface
return $events;
});
$app['phraseanet.thumb-symlinker'] = $app->share(function (SilexApplication $app) {
return SymLinker::create($app);
});
$app['phraseanet.thumb-symlinker-encoder'] = $app->share(function (SilexApplication $app) {
return SymLinkerEncoder::create($app);
});
$app['phraseanet.metadata-reader'] = $app->share(function (SilexApplication $app) {
$reader = new PhraseanetMetadataReader();

View File

@@ -11,14 +11,9 @@
namespace Alchemy\Phrasea\Core;
/**
*
* @license http://opensource.org/licenses/gpl-3.0 GPLv3
* @link www.phraseanet.com
*/
class Version
{
protected static $number = '3.8.6-alpha.2';
protected static $number = '3.8.6-alpha.3';
protected static $name = 'Falcarius';
public static function getNumber()

View File

@@ -0,0 +1,50 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Http\StaticFile;
use Alchemy\Phrasea\Http\AbstractServerMode;
use Alchemy\Phrasea\Http\StaticFile\Symlink\SymLinker;
use Guzzle\Http\Url;
abstract class AbstractStaticMode extends AbstractServerMode
{
protected $symlinker;
public function __construct(array $mapping, SymLinker $symlinker)
{
$this->symlinker = $symlinker;
parent::__construct($mapping);
}
/**
* {@inheritdoc}
*/
public function getUrl($pathFile)
{
$this->ensureSymlink($pathFile);
return Url::factory(sprintf('%s/%s', $this->mapping['mount-point'], $this->symlinker->getSymlinkBasePath($pathFile)));
}
/**
* Creates a link if it does not exists
*
* @param $pathFile
*/
private function ensureSymlink($pathFile)
{
if (false === $this->symlinker->hasSymlink($pathFile)) {
$this->symlinker->symlink($pathFile);
}
}
}

View File

@@ -0,0 +1,52 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Http\StaticFile;
use Alchemy\Phrasea\Exception\InvalidArgumentException;
class Apache extends AbstractStaticMode implements StaticFileModeInterface
{
/**
* @params array $mapping
*
* @throws InvalidArgumentException if mapping is invalid;
*/
public function setMapping(array $mapping)
{
if (!isset($mapping['directory'])) {
throw new InvalidArgumentException('Static file mapping entry must contain at least a "directory" key');
}
if (!isset($mapping['mount-point'])) {
throw new InvalidArgumentException('Static file mapping entry must contain at least a "mount-point" key');
}
$this->mapping = $mapping;
}
/**
* {@inheritdoc}
*/
public function getVirtualHostConfiguration()
{
$output = "\n";
$output .= " Alias ".$this->mapping['mount-point']." ".$this->mapping['directory']."\n";
$output .= "\n";
$output .= " <Location ".$this->mapping['directory'].">\n";
$output .= " Order allow,deny\n";
$output .= " Allow from all\n";
$output .= " </Location>\n";
$output .= "\n";
return $output;
}
}

View File

@@ -0,0 +1,48 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Http\StaticFile;
use Alchemy\Phrasea\Exception\InvalidArgumentException;
class Nginx extends AbstractStaticMode implements StaticFileModeInterface
{
/**
* @params array $mapping
*
* @throws InvalidArgumentException if mapping is invalid;
*/
public function setMapping(array $mapping)
{
if (!isset($mapping['directory'])) {
throw new InvalidArgumentException('Static file mapping entry must contain at least a "directory" key');
}
if (!isset($mapping['mount-point'])) {
throw new InvalidArgumentException('Static file mapping entry must contain at least a "mount-point" key');
}
$this->mapping = $mapping;
}
/**
* {@inheritdoc}
*/
public function getVirtualHostConfiguration()
{
$output = "\n";
$output .= " location " . $this->mapping['mount-point']. " {\n";
$output .= " alias ".$this->mapping['directory'].";\n";
$output .= " }\n";
return $output;
}
}

View File

@@ -0,0 +1,30 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Http\StaticFile;
class NullMode implements StaticFileModeInterface
{
/**
* {@inheritdoc}
*/
public function getVirtualHostConfiguration()
{
return "\n";
}
/**
* {@inheritdoc}
*/
public function getUrl($pathFile)
{
}
}

View File

@@ -0,0 +1,104 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Http\StaticFile;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Exception\InvalidArgumentException;
use Alchemy\Phrasea\Http\StaticFile\Symlink\SymLinker;
use Psr\Log\LoggerInterface;
class StaticFileFactory
{
private $enabled;
private $logger;
private $type;
/** @var Symlink\SymLinker */
private $symlinker;
/**
* Constructor
*
* @param LoggerInterface $logger
* @param bool $enabled
* @param string $type
* @param SymLinker $symlinker
*/
public function __construct(LoggerInterface $logger, $enabled, $type, SymLinker $symlinker)
{
$this->logger = $logger;
$this->enabled = (Boolean) $enabled;
$this->type = strtolower($type);
$this->symlinker = $symlinker;
$this->mapping = array(
'mount-point' => $symlinker->getDefaultAlias(),
'directory' => $symlinker->getSymlinkDir()
);
}
/**
* Creates a new instance of StaticFileFactory Factory according to the application
* configuration.
*
* @param Application $app
* @return StaticFileFactory
*/
public static function create(Application $app)
{
$conf = $app['phraseanet.configuration']['static-file'];
return new self($app['monolog'], $conf['enabled'], $conf['type'], $app['phraseanet.thumb-symlinker']);
}
/**
* Returns a new instance of ModeInterface
*
* @param bool $throwException
* @param bool $forceMode
*
* @return Apache|Nginx|NullMode
* @throws InvalidArgumentException
*/
public function getMode($throwException = false, $forceMode = false)
{
if (false === $this->enabled && true !== $forceMode) {
return new NullMode();
}
switch ($this->type) {
case 'nginx':
return new Nginx($this->mapping, $this->symlinker);
break;
case 'apache':
case 'apache2':
return new Apache($this->mapping, $this->symlinker);
default:
$this->logger->error('Invalid static file configuration.');
if ($throwException) {
throw new InvalidArgumentException(sprintf(
'Invalid static file type value "%s"',
$this->type
));
}
return new NullMode();
}
}
/**
* @return bool
*/
public function isStaticFileModeEnabled()
{
return $this->enabled;
}
}

View File

@@ -0,0 +1,25 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Http\StaticFile;
use Alchemy\Phrasea\Http\ServerModeInterface;
use Guzzle\Http\Url;
interface StaticFileModeInterface extends ServerModeInterface
{
/**
* @param $pathFile
*
* @return Url|null
*/
public function getUrl($pathFile);
}

View File

@@ -0,0 +1,93 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Http\StaticFile\Symlink;
use Alchemy\Phrasea\Exception\InvalidArgumentException;
use Silex\Application;
use Symfony\Component\Filesystem\Filesystem;
use Guzzle\Http\Url;
/**
* Create & retrieve symlinks
*/
class SymLinker
{
/** Mount Point Alias Name */
const ALIAS = 'thumb';
protected $encoder;
protected $fs;
protected $symlinkDir;
protected $registry;
public static function create(Application $app)
{
return new SymLinker(
$app['phraseanet.thumb-symlinker-encoder'],
$app['filesystem'],
$app['phraseanet.registry'],
isset($app['phraseanet.configuration']['static-file']['symlink-directory']) ? $app['phraseanet.configuration']['static-file']['symlink-directory'] : $app['root.path'] . '/symlinks'
);
}
public function __construct(SymLinkerEncoder $encoder, Filesystem $fs, \registryInterface $registry, $symlinkDir)
{
$this->encoder = $encoder;
$this->fs = $fs;
$this->symlinkDir = rtrim($symlinkDir, '/');
}
public function getSymlinkDir()
{
return $this->symlinkDir;
}
public function getDefaultAlias()
{
return sprintf('/%s', self::ALIAS);
}
public function symlink($pathFile)
{
$this->fs->symlink($pathFile, $this->getSymlinkPath($pathFile)) ;
}
public function getSymlink($pathFile)
{
return $this->encoder->encode($pathFile);
}
public function getSymlinkBasePath($pathFile)
{
$symlinkName = $this->getSymlink($pathFile);
return sprintf('%s/%s/%s',
substr($symlinkName, 0, 2),
substr($symlinkName, 2, 2),
substr($symlinkName, 4)
);
}
public function getSymlinkPath($pathFile)
{
return sprintf(
'%s/%s',
$this->symlinkDir,
$this->getSymlinkBasePath($pathFile)
);
}
public function hasSymlink($pathFile)
{
return file_exists($this->getSymlinkPath($pathFile));
}
}

View File

@@ -0,0 +1,38 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Http\StaticFile\Symlink;
use Silex\Application;
use Symfony\Component\Filesystem\Filesystem;
use Guzzle\Http\Url;
class SymLinkerEncoder
{
protected $key;
public static function create(Application $app)
{
return new self(
$app['phraseanet.configuration']['main']['key']
);
}
public function __construct($key)
{
$this->key = $key;
}
public function encode($pathFile)
{
return hash_hmac('sha512', $pathFile , $this->key);
}
}

View File

@@ -445,6 +445,21 @@ class databox extends base
public function unmount_databox()
{
if ($this->app['phraseanet.static-file-factory']->isStaticFileModeEnabled()) {
$sql = "SELECT path, file FROM subdef WHERE `name`='thumbnail'";
$stmt = $this->get_connection()->prepare($sql);
$stmt->execute();
$rows = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$stmt->closeCursor();
foreach ($rows as $row) {
$pathfile = $this->app['phraseanet.thumb-symlinker']->getSymlinkPath(sprintf(
'%s/%s',
rtrim($row['path'], '/'),
$row['file']
));
$this->app['filesystem']->remove($pathfile);
}
}
foreach ($this->get_collections() as $collection) {
$collection->unmount_collection($this->app);
}

View File

@@ -730,6 +730,10 @@ class media_subdef extends media_abstract implements cache_cacheableInterface
$subdef->get_permalink()->delete_data_from_cache();
}
if ($name === 'thumbnail' && $app['phraseanet.static-file-factory']->isStaticFileModeEnabled()) {
$app['phraseanet.thumb-symlinker']->symlink($subdef->get_pathfile());
}
unset($media);
return $subdef;
@@ -742,10 +746,18 @@ class media_subdef extends media_abstract implements cache_cacheableInterface
*/
protected function generate_url()
{
if ( ! $this->is_physically_present()) {
if (!$this->is_physically_present()) {
return;
}
if ($this->get_name() === 'thumbnail') {
if ($this->app['phraseanet.static-file-factory']->isStaticFileModeEnabled() && null !== $url = $this->app['phraseanet.static-file']->getUrl($this->get_pathfile())) {
$this->url = $url;
return;
}
}
if ($this->app['phraseanet.h264-factory']->isH264Enabled() && in_array($this->mime, array('video/mp4'))) {
if (null !== $url = $this->app['phraseanet.h264']->getUrl($this->get_pathfile())) {
$this->url = $url;
@@ -758,6 +770,7 @@ class media_subdef extends media_abstract implements cache_cacheableInterface
. "/" . $this->record->get_record_id() . "/"
. $this->get_name() . "/");
return;
}

View File

@@ -0,0 +1,65 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Alchemy\Phrasea\Application;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Filesystem\Filesystem;
class patch_386alpha3a implements patchInterface
{
/** @var string */
private $release = '3.8.5-alpha.1';
/** @var array */
private $concern = array(base::APPLICATION_BOX);
/**
* {@inheritdoc}
*/
public function get_release()
{
return $this->release;
}
/**
* {@inheritdoc}
*/
public function require_all_upgrades()
{
return false;
}
/**
* {@inheritdoc}
*/
public function concern()
{
return $this->concern;
}
/**
* {@inheritdoc}
*/
public function apply(base $appbox, Application $app)
{
$config = $app['phraseanet.configuration']->getConfig();
$config['static-file'] = array(
'enabled' => false,
'type' => '',
'symlink-directory' => '',
);
$app['phraseanet.configuration']->setConfig($config);
return true;
}
}

View File

@@ -1514,6 +1514,10 @@ class record_adapter implements record_Interface, cache_cacheableInterface
if (!$subdef->is_physically_present())
continue;
if ($subdef->get_name() === 'thumbnail' && $this->app['phraseanet.static-file-factory']->isStaticFileModeEnabled()) {
$this->app['filesystem']->remove($this->app['phraseanet.thumb-symlinker']->getSymlinkPath($subdef->get_pathfile()));
}
$ftodel[] = $subdef->get_pathfile();
$watermark = $subdef->get_path() . 'watermark_' . $subdef->get_file();
if (file_exists($watermark))

View File

@@ -163,6 +163,10 @@ session:
idle: 0
# 1 week
lifetime: 604800
static-file:
enabled: false
type: nginx
symlink-directory: ''
crossdomain:
allow-access-from:
-

View File

@@ -59,9 +59,10 @@
{% if rollover_gif %}
{% set extraclass = 'rollover-gif-out' %}
{% endif %}
{{thumbnail.format(record.get_thumbnail(), th_size, th_size, extraclass, true, true)}}
{% set lazyload = not app['phraseanet.static-file-factory'].isStaticFileModeEnabled %}
{{thumbnail.format(record.get_thumbnail(), th_size, th_size, extraclass, true, lazyload)}}
{% if rollover_gif %}
{{thumbnail.format(rollover_gif, th_size, th_size, 'rollover-gif-hover', true, true)}}
{{thumbnail.format(rollover_gif, th_size, th_size, 'rollover-gif-hover', true, lazyload)}}
{% endif %}
</div>
</div>

View File

@@ -0,0 +1,37 @@
<?php
namespace Alchemy\Tests\Phrasea\Http\StaticFile;
use Alchemy\Phrasea\Http\StaticFile\Apache;
use Symfony\Component\HttpFoundation\Request;
class ApacheModeTest extends \PhraseanetPHPUnitAbstract
{
public function testGetVirtualHost()
{
$mode = new Apache(array(
'directory' => __DIR__,
'mount-point' => '/thumbs'
), self::$DI['app']['phraseanet.thumb-symlinker']);
$conf = $mode->getVirtualHostConfiguration();
$this->assertRegExp('#'.__DIR__ . '#', $conf);
}
/**
* @dataProvider provideMappings
* @expectedException Alchemy\Phrasea\Exception\InvalidArgumentException
*/
public function testInvalidMapping($mapping)
{
new Apache($mapping, self::$DI['app']['phraseanet.thumb-symlinker']);
}
public function provideMappings()
{
return array(
array(array('Directory' => __DIR__)),
array(array('wrong-key' => __DIR__, 'mount-point' => '/')),
array(array('directory' => __DIR__, 'wrong-key' => '/')),
);
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Alchemy\Tests\Phrasea\Http\StaticFile;
use Alchemy\Phrasea\Http\StaticFile\Nginx;
use Symfony\Component\HttpFoundation\Request;
class NginxModeTest extends \PhraseanetPHPUnitAbstract
{
public function testGetVirtualHost()
{
$mode = new Nginx(array(
'directory' => __DIR__,
'mount-point' => '/thumbs'
), self::$DI['app']['phraseanet.thumb-symlinker']);
$conf = $mode->getVirtualHostConfiguration();
$this->assertRegExp('#'.__DIR__ . '#', $conf);
}
/**
* @dataProvider provideMappings
* @expectedException Alchemy\Phrasea\Exception\InvalidArgumentException
*/
public function testInvalidMapping($mapping)
{
new Nginx($mapping, self::$DI['app']['phraseanet.thumb-symlinker']);
}
public function provideMappings()
{
return array(
array(array('Directory' => __DIR__)),
array(array('wrong-key' => __DIR__, 'mount-point' => '/')),
array(array('directory' => __DIR__, 'wrong-key' => '/')),
);
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace Alchemy\Tests\Phrasea\Http\XSendFile;
use Alchemy\Phrasea\Http\StaticFile\StaticFileFactory;
class StaticFileFactoryTest extends \PhraseanetPHPUnitAbstract
{
public function testFactoryCreation()
{
$factory = StaticFileFactory::create(self::$DI['app']);
$this->assertInstanceOf('Alchemy\Phrasea\Http\StaticFile\StaticFileFactory', $factory);
}
public function testFactoryWithStaticFileEnable()
{
$logger = $this->getMock('Psr\Log\LoggerInterface');
$factory = new StaticFileFactory($logger, true, 'nginx', self::$DI['app']['phraseanet.thumb-symlinker']);
$this->assertInstanceOf('Alchemy\Phrasea\Http\StaticFile\AbstractStaticMode', $factory->getMode());
}
public function testFactoryWithStaticFileDisabled()
{
$logger = $this->getMock('Psr\Log\LoggerInterface');
$factory = new StaticFileFactory($logger, false, 'nginx', self::$DI['app']['phraseanet.thumb-symlinker']);
$this->assertInstanceOf('Alchemy\Phrasea\Http\StaticFile\NullMode', $factory->getMode());
$this->assertFalse($factory->isStaticFileModeEnabled());
}
/**
* @expectedException Alchemy\Phrasea\Exception\InvalidArgumentException
*/
public function testFactoryWithWrongTypeThrowsAnExceptionIfRequired()
{
$logger = $this->getMock('Psr\Log\LoggerInterface');
$factory = new StaticFileFactory($logger, true, 'wrong-type', self::$DI['app']['phraseanet.thumb-symlinker']);
$factory->getMode(true);
}
public function testFactoryWithWrongTypeDoesNotThrowsAnException()
{
$logger = $this->getMock('Psr\Log\LoggerInterface');
$logger->expects($this->once())
->method('error')
->with($this->isType('string'));
$factory = new StaticFileFactory($logger, true, 'wrong-type', self::$DI['app']['phraseanet.thumb-symlinker']);
$this->assertInstanceOf('Alchemy\Phrasea\Http\StaticFile\NullMode', $factory->getMode(false));
}
}