diff --git a/.gitignore b/.gitignore
index a039125aae..d25188dda0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,9 @@
/www/assets
/tmp-assets
+# Exclude thumbnails folder
+/www/thumbnails
+
# Exclude node.js dependencies folder
/node_modules
diff --git a/bin/console b/bin/console
index d47a71301e..7125fcf91b 100755
--- a/bin/console
+++ b/bin/console
@@ -15,7 +15,6 @@ use Alchemy\Phrasea\Command\BuildSubdefs;
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\Core\Version;
use Alchemy\Phrasea\Command\BuildMissingSubdefs;
use Alchemy\Phrasea\Command\CreateCollection;
@@ -30,7 +29,6 @@ use Alchemy\Phrasea\Command\Plugin\RemovePlugin;
use Alchemy\Phrasea\Command\CheckConfig;
use Alchemy\Phrasea\Command\Setup\XSendFileMappingGenerator;
use Alchemy\Phrasea\Command\Setup\XSendFileConfigurationDumper;
-use Alchemy\Phrasea\Command\Setup\StaticMappingGenerator;
use Alchemy\Phrasea\Command\Task\SchedulerResumeTasks;
use Alchemy\Phrasea\Command\Task\SchedulerState;
use Alchemy\Phrasea\Command\Task\SchedulerPauseTasks;
@@ -117,9 +115,6 @@ $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);
diff --git a/config/configuration.sample.yml b/config/configuration.sample.yml
index eae521e4e9..4a830d8405 100644
--- a/config/configuration.sample.yml
+++ b/config/configuration.sample.yml
@@ -206,10 +206,6 @@ api_cors:
session:
idle: 0
lifetime: 604800 # 1 week
-static-file:
- enabled: false
- type: nginx
- symlink-directory: ''
crossdomain:
site-control: 'master-only'
allow-access-from:
diff --git a/lib/Alchemy/Phrasea/Application.php b/lib/Alchemy/Phrasea/Application.php
index 819089a497..2c8dcced55 100644
--- a/lib/Alchemy/Phrasea/Application.php
+++ b/lib/Alchemy/Phrasea/Application.php
@@ -702,6 +702,8 @@ class Application extends SilexApplication
$this['tmp.path'] = $this['root.path'].'/tmp';
// plugin path
$this['plugin.path'] = $dir = $this['root.path'].'/plugins';
+ // thumbnails path
+ $this['thumbnail.path'] = $dir = $this['root.path'].'/www/thumbnails';
// cache path for dev env
$this['cache.dev.path'] = $this->share(function() {
diff --git a/lib/Alchemy/Phrasea/Command/Setup/StaticConfigurationDumper.php b/lib/Alchemy/Phrasea/Command/Setup/StaticConfigurationDumper.php
deleted file mode 100644
index de5b0bffca..0000000000
--- a/lib/Alchemy/Phrasea/Command/Setup/StaticConfigurationDumper.php
+++ /dev/null
@@ -1,56 +0,0 @@
-setDescription('Dump the virtual host configuration depending on Phraseanet configuration');
- }
-
- /**
- * {@inheritdoc}
- */
- protected function doExecute(InputInterface $input, OutputInterface $output)
- {
- $output->writeln('');
-
- if (!$this->container['phraseanet.static-file-factory']->isStaticFileModeEnabled()) {
- $output->writeln('Static file support is disabled');
- $ret = 1;
- } else {
- $output->writeln('Static file support is enabled');
- $ret = 0;
- }
-
- try {
- $configuration = $this->container['phraseanet.static-file-factory']->getMode(true, true)->getVirtualHostConfiguration();
- $output->writeln('Static file configuration seems OK');
- $output->writeln($configuration);
- } catch (RuntimeException $e) {
- $output->writeln('Static file configuration seems invalid');
- $ret = 1;
- }
-
- $output->writeln('');
-
- return $ret;
- }
-}
diff --git a/lib/Alchemy/Phrasea/Command/Setup/StaticMappingGenerator.php b/lib/Alchemy/Phrasea/Command/Setup/StaticMappingGenerator.php
deleted file mode 100644
index c09b1a3e33..0000000000
--- a/lib/Alchemy/Phrasea/Command/Setup/StaticMappingGenerator.php
+++ /dev/null
@@ -1,64 +0,0 @@
-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(" OK");
- $output->writeln("");
- $output->write("It is now strongly recommended to use static-file:dump-configuration command to upgrade your virtual-host");
- } else {
- $output->writeln("Configuration will not be written, use --write option to write it");
- $output->writeln("");
- $output->writeln(Yaml::dump(array('static-file' => $conf), 4));
- }
-
- return 0;
- }
-}
diff --git a/lib/Alchemy/Phrasea/Core/Provider/FileServeServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/FileServeServiceProvider.php
index 82c9983af7..d110c2f9bb 100644
--- a/lib/Alchemy/Phrasea/Core/Provider/FileServeServiceProvider.php
+++ b/lib/Alchemy/Phrasea/Core/Provider/FileServeServiceProvider.php
@@ -15,6 +15,8 @@ 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\StaticFile\StaticMode;
+use Alchemy\Phrasea\Http\StaticFile\Symlink\SymLinker;
use Alchemy\Phrasea\Http\XSendFile\XSendFileFactory;
use Silex\Application;
use Silex\ServiceProviderInterface;
@@ -34,16 +36,12 @@ 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.static-file'] = $app->share(function (Application $app) {
+ return new StaticMode(SymLinker::create($app));
});
$app['phraseanet.file-serve'] = $app->share(function (Application $app) {
diff --git a/lib/Alchemy/Phrasea/Http/StaticFile/Apache.php b/lib/Alchemy/Phrasea/Http/StaticFile/Apache.php
deleted file mode 100644
index 10b97d41bb..0000000000
--- a/lib/Alchemy/Phrasea/Http/StaticFile/Apache.php
+++ /dev/null
@@ -1,52 +0,0 @@
-mapping = $mapping;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getVirtualHostConfiguration()
- {
- $output = "\n";
- $output .= " Alias ".$this->mapping['mount-point']." ".$this->mapping['directory']."\n";
- $output .= "\n";
- $output .= " mapping['directory'].">\n";
- $output .= " Order allow,deny\n";
- $output .= " Allow from all\n";
- $output .= " \n";
- $output .= "\n";
-
- return $output;
- }
-}
diff --git a/lib/Alchemy/Phrasea/Http/StaticFile/Nginx.php b/lib/Alchemy/Phrasea/Http/StaticFile/Nginx.php
deleted file mode 100644
index 31960dbfbe..0000000000
--- a/lib/Alchemy/Phrasea/Http/StaticFile/Nginx.php
+++ /dev/null
@@ -1,50 +0,0 @@
-mapping = $mapping;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getVirtualHostConfiguration()
- {
- $output = "\n";
- $output .= " location " . $this->mapping['mount-point']. " {\n";
- $output .= " alias ".$this->mapping['directory'].";\n";
- $output .= " types { }";
- $output .= " default_type image/jpeg;";
- $output .= " }\n";
-
- return $output;
- }
-}
diff --git a/lib/Alchemy/Phrasea/Http/StaticFile/NullMode.php b/lib/Alchemy/Phrasea/Http/StaticFile/NullMode.php
deleted file mode 100644
index fc021e75fe..0000000000
--- a/lib/Alchemy/Phrasea/Http/StaticFile/NullMode.php
+++ /dev/null
@@ -1,30 +0,0 @@
-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;
- }
-}
diff --git a/lib/Alchemy/Phrasea/Http/StaticFile/StaticFileModeInterface.php b/lib/Alchemy/Phrasea/Http/StaticFile/StaticFileModeInterface.php
deleted file mode 100644
index 96f5773475..0000000000
--- a/lib/Alchemy/Phrasea/Http/StaticFile/StaticFileModeInterface.php
+++ /dev/null
@@ -1,25 +0,0 @@
-symlinker = $symlinker;
-
- parent::__construct($mapping);
}
/**
@@ -33,7 +31,7 @@ abstract class AbstractStaticMode extends AbstractServerMode
{
$this->ensureSymlink($pathFile);
- return Url::factory(sprintf('%s/%s', $this->mapping['mount-point'], $this->symlinker->getSymlinkBasePath($pathFile)));
+ return Url::factory(sprintf('/thumbnails/%s', $this->symlinker->getSymlinkBasePath($pathFile)));
}
/**
diff --git a/lib/Alchemy/Phrasea/Http/StaticFile/Symlink/SymLinker.php b/lib/Alchemy/Phrasea/Http/StaticFile/Symlink/SymLinker.php
index 99f8ad9a34..9141c6e7f1 100644
--- a/lib/Alchemy/Phrasea/Http/StaticFile/Symlink/SymLinker.php
+++ b/lib/Alchemy/Phrasea/Http/StaticFile/Symlink/SymLinker.php
@@ -21,9 +21,6 @@ use Guzzle\Http\Url;
*/
class SymLinker
{
- /** Mount Point Alias Name */
- const ALIAS = 'thumb';
-
protected $encoder;
protected $fs;
protected $symlinkDir;
@@ -33,7 +30,7 @@ class SymLinker
return new SymLinker(
$app['phraseanet.thumb-symlinker-encoder'],
$app['filesystem'],
- isset($app['phraseanet.configuration']['static-file']['symlink-directory']) ? $app['phraseanet.configuration']['static-file']['symlink-directory'] : $app['root.path'] . '/tmp/symlinks'
+ $app['thumbnail.path']
);
}
@@ -49,11 +46,6 @@ class SymLinker
return $this->symlinkDir;
}
- public function getDefaultAlias()
- {
- return sprintf('/%s', self::ALIAS);
- }
-
public function symlink($pathFile)
{
$this->fs->symlink($pathFile, $this->getSymlinkPath($pathFile)) ;
@@ -68,7 +60,7 @@ class SymLinker
{
$symlinkName = $this->getSymlink($pathFile);
- return sprintf('%s/%s/%s',
+ return sprintf('%s/%s/%s.jpg',
substr($symlinkName, 0, 2),
substr($symlinkName, 2, 2),
substr($symlinkName, 4)
diff --git a/lib/classes/databox.php b/lib/classes/databox.php
index cd699f51d6..de124ee17c 100644
--- a/lib/classes/databox.php
+++ b/lib/classes/databox.php
@@ -451,21 +451,6 @@ 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);
}
diff --git a/lib/classes/media/subdef.php b/lib/classes/media/subdef.php
index a49ac8a8ec..c2b0f7750a 100644
--- a/lib/classes/media/subdef.php
+++ b/lib/classes/media/subdef.php
@@ -735,7 +735,7 @@ 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()) {
+ if ($name === 'thumbnail') {
$app['phraseanet.thumb-symlinker']->symlink($subdef->get_pathfile());
}
@@ -755,8 +755,9 @@ class media_subdef extends media_abstract implements cache_cacheableInterface
return;
}
+ // serve thumbnails using static file service
if ($this->get_name() === 'thumbnail') {
- if ($this->app['phraseanet.static-file-factory']->isStaticFileModeEnabled() && null !== $url = $this->app['phraseanet.static-file']->getUrl($this->get_pathfile())) {
+ if (null !== $url = $this->app['phraseanet.static-file']->getUrl($this->get_pathfile())) {
$this->url = $url. "?etag=".$this->getEtag();
return;
diff --git a/lib/classes/patch/390alpha21a.php b/lib/classes/patch/390alpha21a.php
new file mode 100644
index 0000000000..f530f70307
--- /dev/null
+++ b/lib/classes/patch/390alpha21a.php
@@ -0,0 +1,67 @@
+release;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function require_all_upgrades()
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function concern()
+ {
+ return $this->concern;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDoctrineMigrations()
+ {
+ return [];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(base $appbox, Application $app)
+ {
+ $main = $app['conf']->get(['main']);
+ if (isset($main['static-file'])) {
+ unset($main['static-file']);
+ }
+ $app['conf']->set(['main'], $main);
+
+ return true;
+ }
+}
diff --git a/lib/classes/record/adapter.php b/lib/classes/record/adapter.php
index d0295e4b06..92350ed7b5 100644
--- a/lib/classes/record/adapter.php
+++ b/lib/classes/record/adapter.php
@@ -1564,7 +1564,7 @@ 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()) {
+ if ($subdef->get_name() === 'thumbnail') {
$this->app['filesystem']->remove($this->app['phraseanet.thumb-symlinker']->getSymlinkPath($subdef->get_pathfile()));
}
diff --git a/lib/conf.d/configuration.yml b/lib/conf.d/configuration.yml
index ee77da7513..355ae28797 100644
--- a/lib/conf.d/configuration.yml
+++ b/lib/conf.d/configuration.yml
@@ -203,10 +203,6 @@ session:
idle: 0
# 1 week
lifetime: 604800
-static-file:
- enabled: false
- type: nginx
- symlink-directory: ''
crossdomain:
allow-access-from:
-
diff --git a/tests/Alchemy/Tests/Phrasea/Http/StaticFile/ApacheModeTest.php b/tests/Alchemy/Tests/Phrasea/Http/StaticFile/ApacheModeTest.php
deleted file mode 100644
index 6ab211fc19..0000000000
--- a/tests/Alchemy/Tests/Phrasea/Http/StaticFile/ApacheModeTest.php
+++ /dev/null
@@ -1,37 +0,0 @@
- __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' => '/')),
- );
- }
-}
diff --git a/tests/Alchemy/Tests/Phrasea/Http/StaticFile/NginxModeTest.php b/tests/Alchemy/Tests/Phrasea/Http/StaticFile/NginxModeTest.php
deleted file mode 100644
index ad8b948f9e..0000000000
--- a/tests/Alchemy/Tests/Phrasea/Http/StaticFile/NginxModeTest.php
+++ /dev/null
@@ -1,37 +0,0 @@
- __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' => '/')),
- );
- }
-}
diff --git a/tests/Alchemy/Tests/Phrasea/Http/StaticFile/StaticFileFactoryTest.php b/tests/Alchemy/Tests/Phrasea/Http/StaticFile/StaticFileFactoryTest.php
deleted file mode 100644
index e0e8d39838..0000000000
--- a/tests/Alchemy/Tests/Phrasea/Http/StaticFile/StaticFileFactoryTest.php
+++ /dev/null
@@ -1,54 +0,0 @@
-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));
- }
-}
diff --git a/www/thumbnails/.gitkeep b/www/thumbnails/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2