Merge branch 'master' into feature/ansible-provision

This commit is contained in:
Benoît Burnichon
2016-02-09 17:37:41 +01:00
237 changed files with 11257 additions and 4593 deletions

View File

@@ -9,11 +9,8 @@ env:
php: php:
- 5.5 - 5.5
- 5.6 - 5.6
- 7.0
matrix: matrix:
fast_finish: true fast_finish: true
allow_failures:
- php: 7.0
services: services:
- mysql - mysql
- memcached - memcached

View File

@@ -27,7 +27,7 @@
"bootstrap-sass": "v2.3.2.2", "bootstrap-sass": "v2.3.2.2",
"jquery.lazyload": "~1.9.7", "jquery.lazyload": "~1.9.7",
"jquery-treeview": "~1.4.2", "jquery-treeview": "~1.4.2",
"alchemy-embed-medias": "~0.1.0" "alchemy-embed-medias": "~0.2.0"
}, },
"devDependencies": { "devDependencies": {
"mocha": "latest", "mocha": "latest",

View File

@@ -36,14 +36,14 @@ database:
override: override:
- mysql -u ubuntu -e 'CREATE DATABASE update39_test;CREATE DATABASE ab_test;CREATE DATABASE db_test;SET @@global.sql_mode=STRICT_ALL_TABLES;SET @@global.max_allowed_packet=33554432;SET @@global.wait_timeout=999999;'; - mysql -u ubuntu -e 'CREATE DATABASE update39_test;CREATE DATABASE ab_test;CREATE DATABASE db_test;SET @@global.sql_mode=STRICT_ALL_TABLES;SET @@global.max_allowed_packet=33554432;SET @@global.wait_timeout=999999;';
post: post:
- "./bin/developer system:uninstall" - "./bin/developer system:uninstall -v"
- "./bin/setup system:install --email=test@phraseanet.com --password=test --db-host=127.0.0.1 --db-user=ubuntu --db-template=fr --db-password= --databox=db_test --appbox=ab_test --server-name=http://127.0.0.1 -y;" - "./bin/setup system:install -v --email=test@phraseanet.com --password=test --db-host=127.0.0.1 --db-user=ubuntu --db-template=fr --db-password= --databox=db_test --appbox=ab_test --server-name=http://127.0.0.1 -y;"
- "./bin/developer ini:setup-tests-dbs" - "./bin/developer ini:setup-tests-dbs -v"
- "./bin/console searchengine:index:create" - "./bin/console searchengine:index:create -v"
- "./bin/developer phraseanet:regenerate-sqlite" - "./bin/developer phraseanet:regenerate-sqlite -v"
- "./bin/developer phraseanet:generate-js-fixtures" - "./bin/developer phraseanet:generate-js-fixtures -v"
test: test:
override: override:
- case $CIRCLE_NODE_INDEX in 0) php -d memory_limit=-1 bin/phpunit --exclude-group legacy ;; 1) ./node_modules/.bin/gulp test ;; 2) php -d memory_limit=-1 bin/phpunit --group legacy --exclude-group web ;; 3) php -d memory_limit=-1 bin/phpunit --group web ;; esac: - case $CIRCLE_NODE_INDEX in 0) php -d memory_limit=-1 bin/phpunit --log-junit $CIRCLE_TEST_REPORTS/phpunit/junit.xml --exclude-group legacy ;; 1) ./node_modules/.bin/gulp test ;; 2) php -d memory_limit=-1 bin/phpunit --log-junit $CIRCLE_TEST_REPORTS/phpunit/junit.xml --group legacy --exclude-group web ;; 3) php -d memory_limit=-1 bin/phpunit --log-junit $CIRCLE_TEST_REPORTS/phpunit/junit.xml --group web ;; esac:
parallel: true parallel: true

View File

@@ -22,10 +22,6 @@
"type": "vcs", "type": "vcs",
"url": "https://github.com/alchemy-fr/JMSTranslationBundle" "url": "https://github.com/alchemy-fr/JMSTranslationBundle"
}, },
{
"type": "git",
"url": "https://github.com/alchemy-fr/symfony-cors"
},
{ {
"type": "vcs", "type": "vcs",
"url": "https://github.com/alchemy-fr/embed-bundle.git" "url": "https://github.com/alchemy-fr/embed-bundle.git"
@@ -34,7 +30,7 @@
"require": { "require": {
"php": ">=5.5", "php": ">=5.5",
"alchemy-fr/tcpdf-clone": "~6.0", "alchemy-fr/tcpdf-clone": "~6.0",
"alchemy/embed-bundle": "~0.1.0", "alchemy/embed-bundle": "^0.2.0",
"alchemy/geonames-api-consumer": "~0.1.0", "alchemy/geonames-api-consumer": "~0.1.0",
"alchemy/google-plus-api-client": "~0.6.2", "alchemy/google-plus-api-client": "~0.6.2",
"alchemy/mediavorus": "^0.4.4", "alchemy/mediavorus": "^0.4.4",
@@ -68,6 +64,8 @@
"jms/serializer": "~0.10", "jms/serializer": "~0.10",
"jms/translation-bundle": "dev-rebase-2015-10-20", "jms/translation-bundle": "dev-rebase-2015-10-20",
"justinrainbow/json-schema": "~1.3", "justinrainbow/json-schema": "~1.3",
"league/flysystem": "^1.0",
"league/flysystem-aws-s3-v2": "^1.0",
"media-alchemyst/media-alchemyst": "~0.4", "media-alchemyst/media-alchemyst": "~0.4",
"monolog/monolog": "~1.3", "monolog/monolog": "~1.3",
"mrclay/minify": "~2.1.6", "mrclay/minify": "~2.1.6",
@@ -113,7 +111,7 @@
"include-path": ["vendor/zend/gdata/library"], "include-path": ["vendor/zend/gdata/library"],
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "4.0.x-dev" "dev-master": "4.1.x-dev"
} }
} }
} }

967
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -11,15 +11,13 @@
namespace Alchemy\Phrasea; namespace Alchemy\Phrasea;
use Alchemy\Cors\Options\DefaultProvider;
use Alchemy\CorsProvider\CorsServiceProvider;
use Alchemy\Geonames\GeonamesServiceProvider; use Alchemy\Geonames\GeonamesServiceProvider;
use Alchemy\Phrasea\Application\Environment;
use Alchemy\Phrasea\Application\Helper\AclAware; use Alchemy\Phrasea\Application\Helper\AclAware;
use Alchemy\Phrasea\Application\Helper\ApplicationBoxAware; use Alchemy\Phrasea\Application\Helper\ApplicationBoxAware;
use Alchemy\Phrasea\Application\Helper\AuthenticatorAware; use Alchemy\Phrasea\Application\Helper\AuthenticatorAware;
use Alchemy\Phrasea\Application\RouteLoader;
use Alchemy\Phrasea\Authorization\AuthorizationServiceProvider; use Alchemy\Phrasea\Authorization\AuthorizationServiceProvider;
use Alchemy\Phrasea\Cache\Factory;
use Alchemy\Phrasea\Cache\Manager;
use Alchemy\Phrasea\Core\Event\Subscriber\BasketSubscriber; use Alchemy\Phrasea\Core\Event\Subscriber\BasketSubscriber;
use Alchemy\Phrasea\Core\Event\Subscriber\BridgeSubscriber; use Alchemy\Phrasea\Core\Event\Subscriber\BridgeSubscriber;
use Alchemy\Phrasea\Core\Event\Subscriber\ExportSubscriber; use Alchemy\Phrasea\Core\Event\Subscriber\ExportSubscriber;
@@ -29,6 +27,11 @@ use Alchemy\Phrasea\Core\Event\Subscriber\OrderSubscriber;
use Alchemy\Phrasea\Core\Event\Subscriber\PhraseaInstallSubscriber; use Alchemy\Phrasea\Core\Event\Subscriber\PhraseaInstallSubscriber;
use Alchemy\Phrasea\Core\Event\Subscriber\RegistrationSubscriber; use Alchemy\Phrasea\Core\Event\Subscriber\RegistrationSubscriber;
use Alchemy\Phrasea\Core\Event\Subscriber\ValidationSubscriber; use Alchemy\Phrasea\Core\Event\Subscriber\ValidationSubscriber;
use Alchemy\Phrasea\Core\MetaProvider\DatabaseMetaProvider;
use Alchemy\Phrasea\Core\MetaProvider\HttpStackMetaProvider;
use Alchemy\Phrasea\Core\MetaProvider\MediaUtilitiesMetaServiceProvider;
use Alchemy\Phrasea\Core\MetaProvider\TemplateEngineMetaProvider;
use Alchemy\Phrasea\Core\MetaProvider\TranslationMetaProvider;
use Alchemy\Phrasea\Core\Middleware\ApiApplicationMiddlewareProvider; use Alchemy\Phrasea\Core\Middleware\ApiApplicationMiddlewareProvider;
use Alchemy\Phrasea\Core\Middleware\BasketMiddlewareProvider; use Alchemy\Phrasea\Core\Middleware\BasketMiddlewareProvider;
use Alchemy\Phrasea\Core\Middleware\TokenMiddlewareProvider; use Alchemy\Phrasea\Core\Middleware\TokenMiddlewareProvider;
@@ -43,7 +46,6 @@ use Alchemy\Phrasea\Core\Provider\CacheConnectionServiceProvider;
use Alchemy\Phrasea\Core\Provider\CacheServiceProvider; use Alchemy\Phrasea\Core\Provider\CacheServiceProvider;
use Alchemy\Phrasea\Core\Provider\ConfigurationServiceProvider; use Alchemy\Phrasea\Core\Provider\ConfigurationServiceProvider;
use Alchemy\Phrasea\Core\Provider\ConfigurationTesterServiceProvider; use Alchemy\Phrasea\Core\Provider\ConfigurationTesterServiceProvider;
use Alchemy\Phrasea\Core\Provider\ContentNegotiationServiceProvider;
use Alchemy\Phrasea\Core\Provider\ConvertersServiceProvider; use Alchemy\Phrasea\Core\Provider\ConvertersServiceProvider;
use Alchemy\Phrasea\Core\Provider\CSVServiceProvider; use Alchemy\Phrasea\Core\Provider\CSVServiceProvider;
use Alchemy\Phrasea\Core\Provider\FeedServiceProvider; use Alchemy\Phrasea\Core\Provider\FeedServiceProvider;
@@ -54,7 +56,6 @@ use Alchemy\Phrasea\Core\Provider\JMSSerializerServiceProvider;
use Alchemy\Phrasea\Core\Provider\LocaleServiceProvider; use Alchemy\Phrasea\Core\Provider\LocaleServiceProvider;
use Alchemy\Phrasea\Core\Provider\ManipulatorServiceProvider; use Alchemy\Phrasea\Core\Provider\ManipulatorServiceProvider;
use Alchemy\Phrasea\Core\Provider\NotificationDelivererServiceProvider; use Alchemy\Phrasea\Core\Provider\NotificationDelivererServiceProvider;
use Alchemy\Phrasea\Core\Provider\ORMServiceProvider;
use Alchemy\Phrasea\Core\Provider\PhraseaEventServiceProvider; use Alchemy\Phrasea\Core\Provider\PhraseaEventServiceProvider;
use Alchemy\Phrasea\Core\Provider\PhraseanetServiceProvider; use Alchemy\Phrasea\Core\Provider\PhraseanetServiceProvider;
use Alchemy\Phrasea\Core\Provider\PhraseaVersionServiceProvider; use Alchemy\Phrasea\Core\Provider\PhraseaVersionServiceProvider;
@@ -64,69 +65,45 @@ use Alchemy\Phrasea\Core\Provider\RegistrationServiceProvider;
use Alchemy\Phrasea\Core\Provider\RepositoriesServiceProvider; use Alchemy\Phrasea\Core\Provider\RepositoriesServiceProvider;
use Alchemy\Phrasea\Core\Provider\SearchEngineServiceProvider; use Alchemy\Phrasea\Core\Provider\SearchEngineServiceProvider;
use Alchemy\Phrasea\Core\Provider\SerializerServiceProvider; use Alchemy\Phrasea\Core\Provider\SerializerServiceProvider;
use Alchemy\Phrasea\Core\Provider\SessionHandlerServiceProvider;
use Alchemy\Phrasea\Core\Provider\StatusServiceProvider; use Alchemy\Phrasea\Core\Provider\StatusServiceProvider;
use Alchemy\Phrasea\Core\Provider\SubdefServiceProvider; use Alchemy\Phrasea\Core\Provider\SubdefServiceProvider;
use Alchemy\Phrasea\Core\Provider\TasksServiceProvider; use Alchemy\Phrasea\Core\Provider\TasksServiceProvider;
use Alchemy\Phrasea\Core\Provider\TemporaryFilesystemServiceProvider;
use Alchemy\Phrasea\Core\Provider\TokensServiceProvider; use Alchemy\Phrasea\Core\Provider\TokensServiceProvider;
use Alchemy\Phrasea\Core\Provider\TranslationServiceProvider;
use Alchemy\Phrasea\Core\Provider\UnicodeServiceProvider; use Alchemy\Phrasea\Core\Provider\UnicodeServiceProvider;
use Alchemy\Phrasea\Core\Provider\WebhookServiceProvider;
use Alchemy\Phrasea\Core\Provider\ZippyServiceProvider; use Alchemy\Phrasea\Core\Provider\ZippyServiceProvider;
use Alchemy\Phrasea\Core\Provider\WebProfilerServiceProvider as PhraseaWebProfilerServiceProvider;
use Alchemy\Phrasea\Exception\InvalidArgumentException; use Alchemy\Phrasea\Exception\InvalidArgumentException;
use Alchemy\Phrasea\Filesystem\FilesystemServiceProvider;
use Alchemy\Phrasea\Filesystem\ApplicationPathServiceGenerator;
use Alchemy\Phrasea\Form\Extension\HelpTypeExtension; use Alchemy\Phrasea\Form\Extension\HelpTypeExtension;
use Alchemy\Phrasea\Media\DatafilesResolver;
use Alchemy\Phrasea\Media\MediaAccessorResolver;
use Alchemy\Phrasea\Media\PermalinkMediaResolver;
use Alchemy\Phrasea\Model\Entities\User; use Alchemy\Phrasea\Model\Entities\User;
use Alchemy\Phrasea\Twig\BytesConverter;
use Alchemy\Phrasea\Twig\Camelize;
use Alchemy\Phrasea\Twig\Fit;
use Alchemy\Phrasea\Twig\JSUniqueID;
use Alchemy\Phrasea\Twig\PhraseanetExtension;
use Alchemy\Phrasea\Utilities\CachedTranslator;
use Dflydev\Silex\Provider\DoctrineOrm\DoctrineOrmServiceProvider;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Event\ConnectionEventArgs; use Doctrine\DBAL\Event\ConnectionEventArgs;
use Doctrine\DBAL\Events;
use Doctrine\ORM\Configuration;
use FFMpeg\FFMpegServiceProvider;
use Gedmo\DoctrineExtensions as GedmoExtension;
use MediaAlchemyst\MediaAlchemystServiceProvider;
use MediaVorus\Media\MediaInterface; use MediaVorus\Media\MediaInterface;
use MediaVorus\MediaVorus; use MediaVorus\MediaVorus;
use MediaVorus\MediaVorusServiceProvider;
use Monolog\Handler\NullHandler;
use Monolog\Handler\RotatingFileHandler; use Monolog\Handler\RotatingFileHandler;
use Monolog\Handler\SyslogHandler;
use Monolog\Logger; use Monolog\Logger;
use Monolog\Processor\IntrospectionProcessor;
use MP4Box\MP4BoxServiceProvider;
use Neutron\ReCaptcha\ReCaptchaServiceProvider; use Neutron\ReCaptcha\ReCaptchaServiceProvider;
use Neutron\Silex\Provider\FilesystemServiceProvider;
use Neutron\Silex\Provider\ImagineServiceProvider;
use PHPExiftool\PHPExiftoolServiceProvider;
use Silex\Application as SilexApplication; use Silex\Application as SilexApplication;
use Silex\Application\TranslationTrait; use Silex\Application\TranslationTrait;
use Silex\Application\UrlGeneratorTrait; use Silex\Application\UrlGeneratorTrait;
use Silex\ControllerProviderInterface;
use Silex\Provider\DoctrineServiceProvider;
use Silex\Provider\FormServiceProvider; use Silex\Provider\FormServiceProvider;
use Silex\Provider\HttpFragmentServiceProvider;
use Silex\Provider\MonologServiceProvider; use Silex\Provider\MonologServiceProvider;
use Silex\Provider\ServiceControllerServiceProvider; use Silex\Provider\ServiceControllerServiceProvider;
use Silex\Provider\SessionServiceProvider;
use Silex\Provider\SwiftmailerServiceProvider; use Silex\Provider\SwiftmailerServiceProvider;
use Silex\Provider\TwigServiceProvider;
use Silex\Provider\UrlGeneratorServiceProvider;
use Silex\Provider\ValidatorServiceProvider; use Silex\Provider\ValidatorServiceProvider;
use Silex\Provider\WebProfilerServiceProvider;
use Sorien\Provider\PimpleDumpProvider; use Sorien\Provider\PimpleDumpProvider;
use Symfony\Bridge\Twig\Extension\TranslationExtension; use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Exception\ExceptionInterface; use Symfony\Component\Form\Exception\ExceptionInterface;
use Symfony\Component\Form\Exception\FormException; use Symfony\Component\Form\Exception\FormException;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormTypeInterface; use Symfony\Component\Form\FormTypeInterface;
use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Unoconv\UnoconvServiceProvider; use Unoconv\UnoconvServiceProvider;
use XPDF\PdfToText; use XPDF\PdfToText;
use XPDF\XPDFServiceProvider; use XPDF\XPDFServiceProvider;
@@ -139,6 +116,10 @@ class Application extends SilexApplication
use UrlGeneratorTrait; use UrlGeneratorTrait;
use TranslationTrait; use TranslationTrait;
const ENV_DEV = 'dev';
const ENV_PROD = 'prod';
const ENV_TEST = 'test';
protected static $availableLanguages = [ protected static $availableLanguages = [
'de' => 'Deutsch', 'de' => 'Deutsch',
'en' => 'English', 'en' => 'English',
@@ -147,38 +128,31 @@ class Application extends SilexApplication
]; ];
private static $flashTypes = ['warning', 'info', 'success', 'error']; private static $flashTypes = ['warning', 'info', 'success', 'error'];
/**
* @var Environment
*/
private $environment; private $environment;
const ENV_DEV = 'dev'; /**
const ENV_PROD = 'prod'; * @param Environment|string $environment
const ENV_TEST = 'test'; */
public function __construct($environment = null)
public function getEnvironment()
{ {
return $this->environment; if (is_string($environment)) {
} $environment = new Environment($environment, false);
}
public function __construct($environment = self::ENV_PROD) $this->environment = $environment ?: new Environment(self::ENV_PROD, false);
{
parent::__construct();
error_reporting(-1); parent::__construct([
'debug' => $this->environment->isDebug()
$this->environment = $environment; ]);
$this->setupCharset(); $this->setupCharset();
$this->setupApplicationPaths(); $this->setupApplicationPaths();
$this->setupConstants(); $this->setupConstants();
$this['debug'] = !in_array($environment, [
Application::ENV_PROD,
Application::ENV_TEST,
]);
if ($this['debug']) {
ini_set('log_errors', 'on');
ini_set('error_log', $this['root.path'].'/logs/php_error.log');
}
if ('allowed' == getenv('APP_CONTAINER_DUMP')) { if ('allowed' == getenv('APP_CONTAINER_DUMP')) {
$this->register(new PimpleDumpProvider()); $this->register(new PimpleDumpProvider());
} }
@@ -191,11 +165,9 @@ class Application extends SilexApplication
$this->register(new CacheConnectionServiceProvider()); $this->register(new CacheConnectionServiceProvider());
$this->register(new PhraseanetServiceProvider()); $this->register(new PhraseanetServiceProvider());
$this->register(new ConfigurationTesterServiceProvider()); $this->register(new ConfigurationTesterServiceProvider());
$this->register(new DoctrineServiceProvider());
$this->setupDBAL(); $this->register(new DatabaseMetaProvider());
$this->register(new DoctrineOrmServiceProvider());
$this->setupOrms();
$this->register(new ORMServiceProvider());
$this->register(new BasketMiddlewareProvider()); $this->register(new BasketMiddlewareProvider());
$this->register(new TokenMiddlewareProvider()); $this->register(new TokenMiddlewareProvider());
$this->register(new AccountServiceProvider()); $this->register(new AccountServiceProvider());
@@ -208,25 +180,19 @@ class Application extends SilexApplication
$this->register(new ConvertersServiceProvider()); $this->register(new ConvertersServiceProvider());
$this->register(new CSVServiceProvider()); $this->register(new CSVServiceProvider());
$this->register(new RegistrationServiceProvider()); $this->register(new RegistrationServiceProvider());
$this->register(new ImagineServiceProvider());
$this->setUpImagine();
$this->register(new JMSSerializerServiceProvider()); $this->register(new JMSSerializerServiceProvider());
$this->register(new FFMpegServiceProvider());
$this->register(new FeedServiceProvider()); $this->register(new FeedServiceProvider());
$this->register(new FtpServiceProvider()); $this->register(new FtpServiceProvider());
$this->register(new GeonamesServiceProvider()); $this->register(new GeonamesServiceProvider());
$this->register(new StatusServiceProvider()); $this->register(new StatusServiceProvider());
$this->setupGeonames(); $this->setupGeonames();
$this->register(new MediaAlchemystServiceProvider());
$this->setupMediaAlchemyst();
$this->register(new MediaVorusServiceProvider());
$this->register(new MP4BoxServiceProvider());
$this->register(new NotificationDelivererServiceProvider()); $this->register(new NotificationDelivererServiceProvider());
$this->register(new RepositoriesServiceProvider()); $this->register(new RepositoriesServiceProvider());
$this->register(new ManipulatorServiceProvider()); $this->register(new ManipulatorServiceProvider());
$this->register(new InstallerServiceProvider()); $this->register(new InstallerServiceProvider());
$this->register(new PhraseaVersionServiceProvider()); $this->register(new PhraseaVersionServiceProvider());
$this->register(new PHPExiftoolServiceProvider());
$this->register(new RandomGeneratorServiceProvider()); $this->register(new RandomGeneratorServiceProvider());
$this->register(new ReCaptchaServiceProvider()); $this->register(new ReCaptchaServiceProvider());
$this->register(new SubdefServiceProvider()); $this->register(new SubdefServiceProvider());
@@ -238,37 +204,23 @@ class Application extends SilexApplication
$this->register(new BorderManagerServiceProvider()); $this->register(new BorderManagerServiceProvider());
} }
$this->register(new SessionHandlerServiceProvider());
$this->register(new SessionServiceProvider(), [
'session.test' => $this->getEnvironment() === static::ENV_TEST,
'session.storage.options' => ['cookie_lifetime' => 0]
]);
$this->setupSession();
$this->register(new SerializerServiceProvider()); $this->register(new SerializerServiceProvider());
$this->register(new ServiceControllerServiceProvider()); $this->register(new ServiceControllerServiceProvider());
$this->register(new SwiftmailerServiceProvider()); $this->register(new SwiftmailerServiceProvider());
$this->setupSwiftMailer(); $this->setupSwiftMailer();
$this->register(new TasksServiceProvider()); $this->register(new TasksServiceProvider());
$this->register(new TemporaryFilesystemServiceProvider());
$this->register(new TokensServiceProvider()); $this->register(new TokensServiceProvider());
$this->register(new HttpFragmentServiceProvider());
$this->register(new TwigServiceProvider()); $this->register(new TemplateEngineMetaProvider());
$this->setupTwig(); $this->register(new HttpStackMetaProvider());
$this->register(new TranslationServiceProvider(), [ $this->register(new MediaUtilitiesMetaServiceProvider());
'locale_fallbacks' => ['fr'], $this->register(new TranslationMetaProvider());
'translator.cache-options' => [
'debug' => $this['debug'],
'cache_dir' => $this->share(function($app) {
return $app['cache.path'].'/translations';
}),
],
]);
$this->setupTranslation();
$this->register(new FormServiceProvider()); $this->register(new FormServiceProvider());
$this->setupForm(); $this->setupForm();
$this->register(new UnoconvServiceProvider()); $this->register(new UnoconvServiceProvider());
$this->register(new UrlGeneratorServiceProvider());
$this->setupUrlGenerator();
$this->register(new UnicodeServiceProvider()); $this->register(new UnicodeServiceProvider());
$this->register(new ValidatorServiceProvider()); $this->register(new ValidatorServiceProvider());
$this->register(new XPDFServiceProvider()); $this->register(new XPDFServiceProvider());
@@ -277,108 +229,58 @@ class Application extends SilexApplication
$this->register(new ManipulatorServiceProvider()); $this->register(new ManipulatorServiceProvider());
$this->register(new PluginServiceProvider()); $this->register(new PluginServiceProvider());
$this->register(new PhraseaEventServiceProvider()); $this->register(new PhraseaEventServiceProvider());
$this->register(new ContentNegotiationServiceProvider());
$this->register(new CorsServiceProvider(), [
'alchemy_cors.debug' => $this['debug'],
'alchemy_cors.cache_path' => function (Application $app) {
return rtrim($app['cache.path'], '/\\') . '/alchemy_cors.cache.php';
},
]);
$this['phraseanet.api_cors.options_provider'] = function (Application $app) {
$paths = [];
if (isset($app['phraseanet.configuration']['api_cors'])) {
$config = $app['phraseanet.configuration']['api_cors'];
if (isset($config['enabled']) && $config['enabled']) {
unset($config['enabled']);
$paths['/api/v\d+/'] = $config;
}
}
return new DefaultProvider($paths, []);
};
$this['alchemy_cors.options_providers'][] = 'phraseanet.api_cors.options_provider';
$this->register(new LocaleServiceProvider()); $this->register(new LocaleServiceProvider());
$this->setupEventDispatcher(); $this->setupEventDispatcher();
$this->register(new WebhookServiceProvider());
$this['phraseanet.exception_handler'] = $this->share(function ($app) { $this['phraseanet.exception_handler'] = $this->share(function ($app) {
/** @var PhraseaExceptionHandler $handler */
$handler = PhraseaExceptionHandler::register($app['debug']); $handler = PhraseaExceptionHandler::register($app['debug']);
$handler->setTranslator($app['translator']); $handler->setTranslator($app['translator']);
$handler->setLogger($app['monolog']); $handler->setLogger($app['monolog']);
return $handler; return $handler;
}); });
$providers = [ $resolvers = $this['alchemy_embed.resource_resolvers'];
'Alchemy\Phrasea\ControllerProvider\Admin\Collection' => [], $resolvers['datafile'] = $resolvers->share(function () {
'Alchemy\Phrasea\ControllerProvider\Admin\ConnectedUsers' => [], return new DatafilesResolver($this->getApplicationBox());
'Alchemy\Phrasea\ControllerProvider\Admin\Dashboard' => [], });
'Alchemy\Phrasea\ControllerProvider\Admin\Databox' => [],
'Alchemy\Phrasea\ControllerProvider\Admin\Databoxes' => [], $resolvers['permalinks_permalink'] = $resolvers->share(function () {
'Alchemy\Phrasea\ControllerProvider\Admin\Feeds' => [], return new PermalinkMediaResolver($this->getApplicationBox());
'Alchemy\Phrasea\ControllerProvider\Admin\Fields' => [], });
'Alchemy\Phrasea\ControllerProvider\Admin\Plugins' => [],
'Alchemy\Phrasea\ControllerProvider\Admin\Root' => [], $resolvers['media_accessor'] = $resolvers->share(function () {
'Alchemy\Phrasea\ControllerProvider\Admin\SearchEngine' => [], return new MediaAccessorResolver(
'Alchemy\Phrasea\ControllerProvider\Admin\Setup' => [], $this->getApplicationBox(), $this['controller.media_accessor']
'Alchemy\Phrasea\ControllerProvider\Admin\Subdefs' => [], );
'Alchemy\Phrasea\ControllerProvider\Admin\TaskManager' => [], });
'Alchemy\Phrasea\ControllerProvider\Admin\Users' => [],
'Alchemy\Phrasea\ControllerProvider\Client\Root' => [], if (self::ENV_DEV === $this->getEnvironment()) {
'Alchemy\Phrasea\ControllerProvider\Datafiles' => [], $this->register($p = new WebProfilerServiceProvider(), [
'Alchemy\Phrasea\ControllerProvider\Lightbox' => [], 'profiler.cache_dir' => $this['cache.path'].'/profiler',
'Alchemy\Phrasea\ControllerProvider\MediaAccessor' => [], ]);
'Alchemy\Phrasea\ControllerProvider\Minifier' => [],
'Alchemy\Phrasea\ControllerProvider\Permalink' => [], $this->register(new PhraseaWebProfilerServiceProvider());
'Alchemy\Phrasea\ControllerProvider\Prod\BasketProvider' => [], $this->mount('/_profiler', $p);
'Alchemy\Phrasea\ControllerProvider\Prod\Bridge' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\DoDownload' => [], if ($this['phraseanet.configuration-tester']->isInstalled()) {
'Alchemy\Phrasea\ControllerProvider\Prod\Download' => [], $this['db'] = $this->share(function (self $app) {
'Alchemy\Phrasea\ControllerProvider\Prod\Edit' => [], return $app['orm.em']->getConnection();
'Alchemy\Phrasea\ControllerProvider\Prod\Export' => [], });
'Alchemy\Phrasea\ControllerProvider\Prod\Feed' => [], }
'Alchemy\Phrasea\ControllerProvider\Prod\Language' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\Lazaret' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\MoveCollection' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\Order' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\Printer' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\Property' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\Push' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\Query' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\Record' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\Root' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\Share' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\Story' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\Tools' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\Tooltip' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\TOU' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\Upload' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\UsrLists' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\WorkZone' => [],
'Alchemy\Phrasea\ControllerProvider\Report\Activity' => [],
'Alchemy\Phrasea\ControllerProvider\Report\Information' => [],
'Alchemy\Phrasea\ControllerProvider\Report\Root' => [],
'Alchemy\Phrasea\ControllerProvider\Root\Account' => [],
'Alchemy\Phrasea\ControllerProvider\Root\Developers' => [],
'Alchemy\Phrasea\ControllerProvider\Root\Login' => [],
'Alchemy\Phrasea\ControllerProvider\Root\Root' => [],
'Alchemy\Phrasea\ControllerProvider\Root\RSSFeeds' => [],
'Alchemy\Phrasea\ControllerProvider\Root\Session' => [],
'Alchemy\Phrasea\ControllerProvider\Setup' => [],
'Alchemy\Phrasea\ControllerProvider\Thesaurus\Thesaurus' => [],
'Alchemy\Phrasea\ControllerProvider\Thesaurus\Xmlhttp' => [],
'Alchemy\Phrasea\ControllerProvider\User\Notifications' => [],
'Alchemy\Phrasea\ControllerProvider\User\Preferences' => [],
'Alchemy\EmbedProvider\EmbedServiceProvider' => [],
'Alchemy\EmbedProvider\OembedServiceProvider' => [],
];
foreach ($providers as $class => $values) {
$this->register(new $class, $values);
} }
} }
public function getEnvironment()
{
return $this->environment->getName();
}
/** /**
* Loads Phraseanet plugins * Loads Phraseanet plugins
*/ */
@@ -436,113 +338,6 @@ class Application extends SilexApplication
return $this->redirect($this->url($route, $parameters)); return $this->redirect($this->url($route, $parameters));
} }
public function setupTwig()
{
$this['twig'] = $this->share(
$this->extend('twig', function (\Twig_Environment $twig, $app) {
$twig->setCache($app['cache.path'].'/twig');
$paths = [];
if (file_exists($app['plugin.path'] . '/twig-paths.php')) {
$paths = require $app['plugin.path'] . '/twig-paths.php';
}
if ($app['browser']->isTablet() || $app['browser']->isMobile()) {
$paths[] = $app['root.path'] . '/config/templates/mobile';
$paths[] = $app['root.path'] . '/templates/mobile';
$paths['phraseanet'] = $app['root.path'] . '/config/templates/mobile';
$paths['phraseanet'] = $app['root.path'] . '/templates/mobile';
}
$paths[] = $app['root.path'] . '/config/templates/web';
$paths[] = $app['root.path'] . '/templates/web';
$paths['phraseanet'] = $app['root.path'] . '/config/templates/web';
$paths['phraseanet'] = $app['root.path'] . '/templates/web';
foreach ($paths as $namespace => $path) {
if (!is_int($namespace)) {
$app['twig.loader.filesystem']->addPath($path, $namespace);
} else {
$app['twig.loader.filesystem']->addPath($path);
}
}
$twig->addGlobal('current_date', new \DateTime());
$twig->addExtension(new \Twig_Extension_Core());
$twig->addExtension(new \Twig_Extension_Optimizer());
$twig->addExtension(new \Twig_Extension_Escaper());
if ($app['debug']) {
$twig->addExtension(new \Twig_Extension_Debug());
}
// add filter trans
$twig->addExtension(new TranslationExtension($app['translator']));
// add filter localizeddate
$twig->addExtension(new \Twig_Extensions_Extension_Intl());
// add filters truncate, wordwrap, nl2br
$twig->addExtension(new \Twig_Extensions_Extension_Text());
$twig->addExtension(new JSUniqueID());
$twig->addExtension(new Fit());
$twig->addExtension(new Camelize());
$twig->addExtension(new BytesConverter());
$twig->addExtension(new PhraseanetExtension($app));
$twig->addFilter('serialize', new \Twig_Filter_Function('serialize'));
$twig->addFilter('stristr', new \Twig_Filter_Function('stristr'));
$twig->addFilter('get_class', new \Twig_Filter_Function('get_class'));
$twig->addFilter('stripdoublequotes', new \Twig_Filter_Function('stripdoublequotes'));
$twig->addFilter('get_collection_logo', new \Twig_Filter_Function('collection::getLogo'));
$twig->addFilter('floor', new \Twig_Filter_Function('floor'));
$twig->addFilter('ceil', new \Twig_Filter_Function('ceil'));
$twig->addFilter('max', new \Twig_Filter_Function('max'));
$twig->addFilter('min', new \Twig_Filter_Function('min'));
$twig->addFilter('bas_labels', new \Twig_Filter_Function('phrasea::bas_labels'));
$twig->addFilter('sbas_names', new \Twig_Filter_Function('phrasea::sbas_names'));
$twig->addFilter('sbas_labels', new \Twig_Filter_Function('phrasea::sbas_labels'));
$twig->addFilter('sbas_from_bas', new \Twig_Filter_Function('phrasea::sbasFromBas'));
$twig->addFilter('key_exists', new \Twig_Filter_Function('array_key_exists'));
$twig->addFilter('round', new \Twig_Filter_Function('round'));
$twig->addFilter('count', new \Twig_Filter_Function('count'));
$twig->addFilter('formatOctets', new \Twig_Filter_Function('p4string::format_octets'));
$twig->addFilter('base_from_coll', new \Twig_Filter_Function('phrasea::baseFromColl'));
$twig->addFilter(new \Twig_SimpleFilter('escapeSimpleQuote', function ($value) {
return str_replace("'", "\\'", $value);
}));
$twig->addFilter(new \Twig_SimpleFilter('highlight', function (\Twig_Environment $twig, $string) {
return str_replace(['[[em]]', '[[/em]]'], ['<em>', '</em>'], $string);
}, ['needs_environment' => true,'is_safe' => ['html']]));
$twig->addFilter(new \Twig_SimpleFilter('linkify', function (\Twig_Environment $twig, $string) {
return preg_replace(
"(([^']{1})((https?|file):((/{2,4})|(\\{2,4}))[\w:#%/;$()~_?/\-=\\\.&]*)([^']{1}))"
, '$1 $2 <a title="' . _('Open the URL in a new window') . '" class="ui-icon ui-icon-extlink" href="$2" style="display:inline;padding:2px 5px;margin:0 4px 0 2px;" target="_blank"> &nbsp;</a>$7'
, $string
);
}, ['needs_environment' => true, 'is_safe' => ['html']]));
$twig->addFilter(new \Twig_SimpleFilter('bounce', function (\Twig_Environment $twig, $fieldValue, $fieldName, $searchRequest, $sbasId) {
// bounce value if it is present in thesaurus as well
return "<a class=\"bounce\" onclick=\"bounce('" .$sbasId . "','"
. str_replace("'", "\\'",$searchRequest)
. "', '"
. str_replace("'", "\\'", $fieldName)
. "');return(false);\">"
. $fieldValue
. "</a>";
}, ['needs_environment' => true, 'is_safe' => ['html']]));
$twig->addFilter(new \Twig_SimpleFilter('escapeDoubleQuote', function ($value) {
return str_replace('"', '\"', $value);
}));
return $twig;
})
);
}
/** /**
* Adds a flash message for type. * Adds a flash message for type.
* *
@@ -619,6 +414,14 @@ class Application extends SilexApplication
return $this; return $this;
} }
/**
* @return bool
*/
public function isDebug()
{
return $this->environment->isDebug();
}
/** /**
* Returns true if a captcha is required for next authentication * Returns true if a captcha is required for next authentication
* *
@@ -674,75 +477,11 @@ class Application extends SilexApplication
*/ */
public function bindRoutes() public function bindRoutes()
{ {
$providers = [ $loader = new RouteLoader();
'/account/' => 'Alchemy\Phrasea\ControllerProvider\Root\Account',
'/admin/' => 'Alchemy\Phrasea\ControllerProvider\Admin\Root',
'/admin/collection' => 'Alchemy\Phrasea\ControllerProvider\Admin\Collection',
'/admin/connected-users' => 'Alchemy\Phrasea\ControllerProvider\Admin\ConnectedUsers',
'/admin/dashboard' => 'Alchemy\Phrasea\ControllerProvider\Admin\Dashboard',
'/admin/databox' => 'Alchemy\Phrasea\ControllerProvider\Admin\Databox',
'/admin/databoxes' => 'Alchemy\Phrasea\ControllerProvider\Admin\Databoxes',
'/admin/fields' => 'Alchemy\Phrasea\ControllerProvider\Admin\Fields',
'/admin/publications' => 'Alchemy\Phrasea\ControllerProvider\Admin\Feeds',
'/admin/plugins' => 'Alchemy\Phrasea\ControllerProvider\Admin\Plugins',
'/admin/search-engine' => 'Alchemy\Phrasea\ControllerProvider\Admin\SearchEngine',
'/admin/setup' => 'Alchemy\Phrasea\ControllerProvider\Admin\Setup',
'/admin/subdefs' => 'Alchemy\Phrasea\ControllerProvider\Admin\Subdefs',
'/admin/task-manager' => 'Alchemy\Phrasea\ControllerProvider\Admin\TaskManager',
'/admin/users' => 'Alchemy\Phrasea\ControllerProvider\Admin\Users',
'/client/' => 'Alchemy\Phrasea\ControllerProvider\Client\Root',
'/datafiles' => 'Alchemy\Phrasea\ControllerProvider\Datafiles',
'/developers/' => 'Alchemy\Phrasea\ControllerProvider\Root\Developers',
'/download/' => 'Alchemy\Phrasea\ControllerProvider\Prod\DoDownload',
'/embed/' => 'Alchemy\EmbedProvider\EmbedServiceProvider',
'/oembed/' => 'Alchemy\EmbedProvider\OembedServiceProvider',
'/feeds/' => 'Alchemy\Phrasea\ControllerProvider\Root\RSSFeeds',
'/include/minify' => 'Alchemy\Phrasea\ControllerProvider\Minifier',
'/login/' => 'Alchemy\Phrasea\ControllerProvider\Root\Login',
'/lightbox' => 'Alchemy\Phrasea\ControllerProvider\Lightbox',
'/permalink' => 'Alchemy\Phrasea\ControllerProvider\Permalink',
'/prod/baskets' => 'Alchemy\Phrasea\ControllerProvider\Prod\BasketProvider',
'/prod/bridge/' => 'Alchemy\Phrasea\ControllerProvider\Prod\Bridge',
'/prod/download' => 'Alchemy\Phrasea\ControllerProvider\Prod\Download',
'/prod/export/' => 'Alchemy\Phrasea\ControllerProvider\Prod\Export',
'/prod/feeds' => 'Alchemy\Phrasea\ControllerProvider\Prod\Feed',
'/prod/language' => 'Alchemy\Phrasea\ControllerProvider\Prod\Language',
'/prod/lazaret/' => 'Alchemy\Phrasea\ControllerProvider\Prod\Lazaret',
'/prod/lists' => 'Alchemy\Phrasea\ControllerProvider\Prod\UsrLists',
'/prod/order/' => 'Alchemy\Phrasea\ControllerProvider\Prod\Order',
'/prod/printer/' => 'Alchemy\Phrasea\ControllerProvider\Prod\Printer',
'/prod/push/' => 'Alchemy\Phrasea\ControllerProvider\Prod\Push',
'/prod/query/' => 'Alchemy\Phrasea\ControllerProvider\Prod\Query',
'/prod/records/' => 'Alchemy\Phrasea\ControllerProvider\Prod\Record',
'/prod/records/edit' => 'Alchemy\Phrasea\ControllerProvider\Prod\Edit',
'/prod/records/movecollection' => 'Alchemy\Phrasea\ControllerProvider\Prod\MoveCollection',
'/prod/records/property' => 'Alchemy\Phrasea\ControllerProvider\Prod\Property',
'/prod/share/' => 'Alchemy\Phrasea\ControllerProvider\Prod\Share',
'/prod/story' => 'Alchemy\Phrasea\ControllerProvider\Prod\Story',
'/prod/tools/' => 'Alchemy\Phrasea\ControllerProvider\Prod\Tools',
'/prod/tooltip' => 'Alchemy\Phrasea\ControllerProvider\Prod\Tooltip',
'/prod/TOU/' => 'Alchemy\Phrasea\ControllerProvider\Prod\TOU',
'/prod/upload/' => 'Alchemy\Phrasea\ControllerProvider\Prod\Upload',
'/prod/WorkZone' => 'Alchemy\Phrasea\ControllerProvider\Prod\WorkZone',
'/prod/' => 'Alchemy\Phrasea\ControllerProvider\Prod\Root',
'/report/activity' => 'Alchemy\Phrasea\ControllerProvider\Report\Activity',
'/report/informations' => 'Alchemy\Phrasea\ControllerProvider\Report\Information',
'/report/' => 'Alchemy\Phrasea\ControllerProvider\Report\Root',
'/session/' => 'Alchemy\Phrasea\ControllerProvider\Root\Session',
'/setup' => 'Alchemy\Phrasea\ControllerProvider\Setup',
'/thesaurus' => 'Alchemy\Phrasea\ControllerProvider\Thesaurus\Thesaurus',
'/user/notifications/' => 'Alchemy\Phrasea\ControllerProvider\User\Notifications',
'/user/preferences/' => 'Alchemy\Phrasea\ControllerProvider\User\Preferences',
'/xmlhttp' => 'Alchemy\Phrasea\ControllerProvider\Thesaurus\Xmlhttp',
'/' => 'Alchemy\Phrasea\ControllerProvider\Root\Root',
];
// controllers with routes referenced by api $loader->registerProviders(RouteLoader::$defaultProviders);
$providers[$this['controller.media_accessor.route_prefix']] = 'Alchemy\Phrasea\ControllerProvider\MediaAccessor';
foreach ($providers as $prefix => $class) {
$this->mount($prefix, new $class);
}
$loader->bindRoutes($this);
$this->bindPluginRoutes('plugin.controller_providers.root'); $this->bindPluginRoutes('plugin.controller_providers.root');
} }
@@ -786,86 +525,53 @@ class Application extends SilexApplication
// app root path // app root path
$this['root.path'] = realpath(__DIR__ . '/../../..'); $this['root.path'] = realpath(__DIR__ . '/../../..');
// temporary resources default path such as download zip, quarantined documents etc .. // temporary resources default path such as download zip, quarantined documents etc ..
$this['tmp.path'] = $this['root.path'].'/tmp'; $this['tmp.path'] = getenv('PHRASEANET_TMP') ?: $this['root.path'].'/tmp';
// plugin path // plugin path
$this['plugin.path'] = $dir = $this['root.path'].'/plugins'; $this['plugin.path'] = $this['root.path'].'/plugins';
// thumbnails path // thumbnails path
$this['thumbnail.path'] = $dir = $this['root.path'].'/www/thumbnails'; $this['thumbnail.path'] = $this['root.path'].'/www/thumbnails';
// cache path (twig, minify, translations, configuration, doctrine metas serializer metas, profiler etc ...) $factory = new ApplicationPathServiceGenerator();
$this['cache.path'] = $this->share(function() {
$defaultPath = $path = $this['root.path'].'/cache'; $this['cache.path'] = $factory->createDefinition(
if ($this['phraseanet.configuration']->isSetup()) { ['main', 'storage', 'cache'],
$path = $this['conf']->get(['main', 'storage', 'cache'], $path); function (Application $app) {
return $app['root.path'].'/cache';
} }
$path = $path ?: $defaultPath; );
// ensure path is created
$this['filesystem']->mkdir($path);
return $path;
});
$this['cache.paths'] = function (Application $app) { $this['cache.paths'] = function (Application $app) {
return new \ArrayObject([ return new \ArrayObject([
$app['cache.path'], $app['cache.path'],
]); ]);
}; };
// log path $this['log.path'] = $factory->createDefinition(
$this['log.path'] = $this->share(function() { ['main', 'storage', 'log'],
$defaultPath = $path = $this['root.path'].'/logs'; function (Application $app) {
if ($this['phraseanet.configuration']->isSetup()) { return $app['root.path'].'/logs';
return $this['conf']->get(['main', 'storage', 'log'], $path);
} }
$path = $path ?: $defaultPath; );
// ensure path is created $this['tmp.download.path'] = $factory->createDefinition(
$this['filesystem']->mkdir($path); ['main', 'storage', 'download'],
function (Application $app) {
return $path; return $app['tmp.path'].'/download';
});
// temporary download file path (zip file)
$this['tmp.download.path'] = $this->share(function() {
$defaultPath = $path = $this['tmp.path'].'/download';
if ($this['phraseanet.configuration']->isSetup()) {
return $this['conf']->get(['main', 'storage', 'download'], $path);
} }
$path = $path ?: $defaultPath; );
// ensure path is created $this['tmp.lazaret.path'] = $factory->createDefinition(
$this['filesystem']->mkdir($path); ['main', 'storage', 'quarantine'],
function (Application $app) {
return $path; return $app['tmp.path'].'/lazaret';
});
// quarantined file path
$this['tmp.lazaret.path'] = $this->share(function() {
$defaultPath = $path = $this['tmp.path'].'/lazaret';
if ($this['phraseanet.configuration']->isSetup()) {
return $this['conf']->get(['main', 'storage', 'quarantine'], $path);
} }
$path = $path ?: $defaultPath; );
// ensure path is created $this['tmp.caption.path'] = $factory->createDefinition(
$this['filesystem']->mkdir($path); ['main', 'storage', 'caption'],
function (Application $app) {
return $path; return $app['tmp.path'].'/caption';
});
// document caption file path
$this['tmp.caption.path'] = $this->share(function() {
$defaultPath = $path = $this['tmp.path'].'/caption';
if ($this['phraseanet.configuration']->isSetup()) {
return $this['conf']->get(['main', 'storage', 'caption'], $path);
} }
$path = $path ?: $defaultPath; );
// ensure path is created
$this['filesystem']->mkdir($path);
return $path;
});
} }
@@ -891,98 +597,6 @@ class Application extends SilexApplication
})); }));
} }
private function setUpImagine()
{
$this['imagine.factory'] = $this->share(function (Application $app) {
if ($app['conf']->get(['registry', 'executables', 'imagine-driver']) != '') {
return $app['conf']->get(['registry', 'executables', 'imagine-driver']);
}
if (class_exists('\Gmagick')) {
return 'gmagick';
}
if (class_exists('\Imagick')) {
return 'imagick';
}
if (extension_loaded('gd')) {
return 'gd';
}
throw new \RuntimeException('No Imagine driver available');
});
}
private function setupTranslation()
{
$this['translator'] = $this->share($this->extend('translator', function (CachedTranslator $translator, Application $app) {
$translator->addResource('xlf', __DIR__.'/../../../resources/locales/messages.fr.xlf', 'fr', 'messages');
$translator->addResource('xlf', __DIR__.'/../../../resources/locales/validators.fr.xlf', 'fr', 'validators');
$translator->addResource('xlf', __DIR__.'/../../../resources/locales/messages.en.xlf', 'en', 'messages');
$translator->addResource('xlf', __DIR__.'/../../../resources/locales/validators.en.xlf', 'en', 'validators');
$translator->addResource('xlf', __DIR__.'/../../../resources/locales/messages.de.xlf', 'de', 'messages');
$translator->addResource('xlf', __DIR__.'/../../../resources/locales/validators.de.xlf', 'de', 'validators');
$translator->addResource('xlf', __DIR__.'/../../../resources/locales/messages.nl.xlf', 'nl', 'messages');
$translator->addResource('xlf', __DIR__.'/../../../resources/locales/validators.nl.xlf', 'nl', 'validators');
return $translator;
}));
}
private function setupOrms()
{
$app = $this;
// Override "orm.cache.configurer" service provided for benefiting
// of "phraseanet.cache-service"
$app['orm.cache.configurer'] = $app->protect(function($name, Configuration $config, $options) use ($app) {
/** @var Manager $service */
$service = $app['phraseanet.cache-service'];
$config->setMetadataCacheImpl(
$service->factory('ORM_metadata', $app['orm.cache.driver'], $app['orm.cache.options'])
);
$config->setQueryCacheImpl(
$service->factory('ORM_query', $app['orm.cache.driver'], $app['orm.cache.options'])
);
$config->setResultCacheImpl(
$service->factory('ORM_result', $app['orm.cache.driver'], $app['orm.cache.options'])
);
$config->setHydrationCacheImpl(
$service->factory('ORM_hydration', $app['orm.cache.driver'], $app['orm.cache.options'])
);
});
$app['orm.proxies_dir'] = $app['root.path'].'/resources/proxies';
$app['orm.auto_generate_proxies'] = $app['debug'];
$app['orm.proxies_namespace'] = 'Alchemy\Phrasea\Model\Proxies';
$this['orm.ems'] = $this->share($this->extend('orm.ems', function (\Pimple $ems, $app) {
GedmoExtension::registerAnnotations();
foreach ($ems->keys() as $key) {
$app['orm.annotation.register']($key);
$connection = $ems[$key]->getConnection();
$app['connection.pool.manager']->add($connection);
$types = $app['orm.ems.options'][$key]['types'];
$app['dbal.type.register']($connection, $types);
}
return $ems;
}));
}
private function setupSession()
{
$this['session.storage.test'] = $this->share(function (Application $app) {
return new MockArraySessionStorage();
});
$this['session.storage.handler'] = $this->share(function (Application $app) {
if (!$this['phraseanet.configuration-tester']->isInstalled()) {
return new NullSessionHandler();
}
return $this['session.storage.handler.factory']->create($app['conf']);
});
}
private function setupRecaptacha() private function setupRecaptacha()
{ {
$this['recaptcha.public-key'] = $this->share(function (Application $app) { $this['recaptcha.public-key'] = $this->share(function (Application $app) {
@@ -1000,38 +614,10 @@ class Application extends SilexApplication
private function setupGeonames() private function setupGeonames()
{ {
$this['geonames.server-uri'] = $this->share(function (Application $app) { $this['geonames.server-uri'] = $this->share(function (Application $app) {
return $app['conf']->get(['registry', 'webservices', 'geonames-server'], 'http://geonames.alchemyasp.com/'); return $app['conf']->get(['registry', 'webservices', 'geonames-server'], 'http://geonames.alchemyasp.com/');
}); });
} }
private function setupDBAL()
{
$this['dbs.config'] = $this->share($this->extend('dbs.config', function ($configs, $app) {
if ($app->getEnvironment() !== self::ENV_DEV) {
return $configs;
}
foreach($configs->keys() as $service) {
$app['dbal.config.register.loggers']($configs[$service]);
}
return $configs;
}));
$this['dbs.event_manager'] = $this->share($this->extend('dbs.event_manager', function ($eventManagers, $app) {
foreach ($eventManagers->keys() as $name) {
/** @var EventManager $eventManager */
$eventManager = $eventManagers[$name];
$app['dbal.evm.register.listeners']($eventManager);
$eventManager->addEventListener(Events::postConnect, $this);
}
return $eventManagers;
}));
}
/** /**
* @param ConnectionEventArgs $args * @param ConnectionEventArgs $args
* @throws \Doctrine\DBAL\DBALException * @throws \Doctrine\DBAL\DBALException
@@ -1043,60 +629,6 @@ class Application extends SilexApplication
} }
} }
private function setupMediaAlchemyst()
{
$this['media-alchemyst.configuration'] = $this->share(function (Application $app) {
$configuration = [];
foreach ([
'swftools.pdf2swf.binaries' => 'pdf2swf_binary',
'swftools.swfrender.binaries' => 'swf_render_binary',
'swftools.swfextract.binaries' => 'swf_extract_binary',
'unoconv.binaries' => 'unoconv_binary',
'mp4box.binaries' => 'mp4box_binary',
'gs.binaries' => 'ghostscript_binary',
'ffmpeg.ffmpeg.binaries' => 'ffmpeg_binary',
'ffmpeg.ffprobe.binaries' => 'ffprobe_binary',
'ffmpeg.ffmpeg.timeout' => 'ffmpeg_timeout',
'ffmpeg.ffprobe.timeout' => 'ffprobe_timeout',
'gs.timeout' => 'gs_timeout',
'mp4box.timeout' => 'mp4box_timeout',
'swftools.timeout' => 'swftools_timeout',
'unoconv.timeout' => 'unoconv_timeout',
] as $parameter => $key) {
if ($this['conf']->has(['main', 'binaries', $key])) {
$configuration[$parameter] = $this['conf']->get(['main', 'binaries', $key]);
}
}
$configuration['ffmpeg.threads'] = $app['conf']->get(['registry', 'executables', 'ffmpeg-threads']) ?: null;
$configuration['imagine.driver'] = $app['conf']->get(['registry', 'executables', 'imagine-driver']) ?: null;
return $configuration;
});
$this['media-alchemyst.logger'] = $this->share(function (Application $app) {
return $app['monolog'];
});
}
private function setupUrlGenerator()
{
$this['url_generator'] = $this->share($this->extend('url_generator', function ($urlGenerator, Application $app) {
if ($app['configuration.store']->isSetup()) {
$data = parse_url($app['conf']->get('servername'));
if (isset($data['scheme'])) {
$urlGenerator->getContext()->setScheme($data['scheme']);
}
if (isset($data['host'])) {
$urlGenerator->getContext()->setHost($data['host']);
}
}
return $urlGenerator;
}));
}
private function setupSwiftMailer() private function setupSwiftMailer()
{ {
$this['swiftmailer.transport'] = $this->share(function (Application $app) { $this['swiftmailer.transport'] = $this->share(function (Application $app) {
@@ -1161,8 +693,7 @@ class Application extends SilexApplication
private function setupEventDispatcher() private function setupEventDispatcher()
{ {
$this['dispatcher'] = $this->share( $this['dispatcher'] = $this->share(
$this->extend('dispatcher', function ($dispatcher, Application $app) { $this->extend('dispatcher', function (EventDispatcherInterface $dispatcher, Application $app) {
//$dispatcher->addListener(KernelEvents::RESPONSE, [$app, 'addUTF8Charset'], -128);
$dispatcher->addSubscriber($app['phraseanet.logout-subscriber']); $dispatcher->addSubscriber($app['phraseanet.logout-subscriber']);
$dispatcher->addSubscriber($app['phraseanet.locale-subscriber']); $dispatcher->addSubscriber($app['phraseanet.locale-subscriber']);
$dispatcher->addSubscriber($app['phraseanet.content-negotiation-subscriber']); $dispatcher->addSubscriber($app['phraseanet.content-negotiation-subscriber']);
@@ -1190,12 +721,15 @@ class Application extends SilexApplication
if (!defined('JETON_MAKE_SUBDEF')) { if (!defined('JETON_MAKE_SUBDEF')) {
define('JETON_MAKE_SUBDEF', 0x01); define('JETON_MAKE_SUBDEF', 0x01);
} }
if (!defined('JETON_WRITE_META_DOC')) { if (!defined('JETON_WRITE_META_DOC')) {
define('JETON_WRITE_META_DOC', 0x02); define('JETON_WRITE_META_DOC', 0x02);
} }
if (!defined('JETON_WRITE_META_SUBDEF')) { if (!defined('JETON_WRITE_META_SUBDEF')) {
define('JETON_WRITE_META_SUBDEF', 0x04); define('JETON_WRITE_META_SUBDEF', 0x04);
} }
if (!defined('JETON_WRITE_META')) { if (!defined('JETON_WRITE_META')) {
define('JETON_WRITE_META', 0x06); define('JETON_WRITE_META', 0x06);
} }
@@ -1212,30 +746,8 @@ class Application extends SilexApplication
*/ */
public function bindPluginRoutes($routeParameter) public function bindPluginRoutes($routeParameter)
{ {
foreach ($this[$routeParameter] as $provider) { $loader = new RouteLoader();
$prefix = '';
if (is_array($provider)) { $loader->bindPluginRoutes($this, $routeParameter);
$providerDefinition = $provider;
list($prefix, $provider) = $providerDefinition;
}
if (!is_string($prefix) || !is_string($provider)) {
continue;
}
$prefix = '/' . ltrim($prefix, '/');
if (!isset($this[$provider])) {
continue;
}
$provider = $this[$provider];
if (!$provider instanceof ControllerProviderInterface) {
continue;
}
$this->mount($prefix, $provider);
}
} }
} }

View File

@@ -52,10 +52,10 @@ return call_user_func(function ($environment = PhraseaApplication::ENV_PROD) {
})); }));
$app['phraseanet.content-negotiation.priorities'] = array_merge( $app['phraseanet.content-negotiation.priorities'] = array_merge(
['application/json', 'application/yaml', 'text/yaml', 'text/javascript', 'application/javascript'],
V1::$extendedContentTypes['json'], V1::$extendedContentTypes['json'],
V1::$extendedContentTypes['jsonp'], V1::$extendedContentTypes['jsonp'],
V1::$extendedContentTypes['yaml'], V1::$extendedContentTypes['yaml']
['application/json', 'application/yaml', 'text/yaml', 'text/javascript', 'application/javascript']
); );
$app['phraseanet.content-negotiation.custom_formats'] = [ $app['phraseanet.content-negotiation.custom_formats'] = [

View File

@@ -0,0 +1,56 @@
<?php
namespace Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Core\Event\Subscriber\BridgeExceptionSubscriber;
use Alchemy\Phrasea\Core\Event\Subscriber\DebuggerSubscriber;
use Alchemy\Phrasea\Core\Event\Subscriber\FirewallSubscriber;
use Alchemy\Phrasea\Core\Event\Subscriber\JsonRequestSubscriber;
use Alchemy\Phrasea\Core\Event\Subscriber\PhraseaExceptionHandlerSubscriber;
use Alchemy\Phrasea\Core\Middleware\SetupMiddlewareProvider;
use Monolog\Logger;
use Symfony\Bridge\Monolog\Processor\WebProcessor;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class ApplicationLoader
{
public function buildWebApplication($environment = Application::ENV_PROD, $forceDebug = false)
{
$env = new Environment($environment, false);
$app = new Application($env);
$app->register(new SetupMiddlewareProvider());
$app->loadPlugins();
$app['exception_handler'] = $app->share(function ($app) {
return new PhraseaExceptionHandlerSubscriber($app['phraseanet.exception_handler']);
});
$app['monolog'] = $app->share($app->extend('monolog', function (Logger $monolog) {
$monolog->pushProcessor(new WebProcessor());
return $monolog;
}));
$app->before($app['setup.validate-config'], Application::EARLY_EVENT);
$app->bindRoutes();
$app['dispatcher'] = $app->share(
$app->extend('dispatcher', function (EventDispatcherInterface $dispatcher, Application $app) {
$dispatcher->addSubscriber(new BridgeExceptionSubscriber($app));
$dispatcher->addSubscriber(new FirewallSubscriber());
$dispatcher->addSubscriber(new JsonRequestSubscriber());
if ($app->isDebug()){
$dispatcher->addSubscriber(new DebuggerSubscriber($app));
}
return $dispatcher;
})
);
return $app;
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Application;
class Environment
{
/**
* @var string
*/
private $name;
/**
* @var bool
*/
private $debug = false;
public function __construct($name, $debug)
{
$this->name = (string) $name;
$this->debug = ((bool) $debug) || ! in_array($name, [
Application::ENV_PROD, Application::ENV_TEST
]);
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return bool
*/
public function isDebug()
{
return $this->debug;
}
}

View File

@@ -9,6 +9,8 @@
*/ */
namespace Alchemy\Phrasea\Application\Helper; namespace Alchemy\Phrasea\Application\Helper;
use Alchemy\Phrasea\Collection\CollectionService;
trait ApplicationBoxAware trait ApplicationBoxAware
{ {
/** @var \appbox|callable */ /** @var \appbox|callable */
@@ -61,6 +63,14 @@ trait ApplicationBoxAware
return $this->applicationBox; return $this->applicationBox;
} }
/**
* @return CollectionService
*/
public function getCollectionService()
{
return $this['services.collection'];
}
/** /**
* Find a registered Databoxes. * Find a registered Databoxes.
* *

View File

@@ -10,6 +10,7 @@
namespace Alchemy\Phrasea\Application\Helper; namespace Alchemy\Phrasea\Application\Helper;
use Alchemy\Phrasea\Http\DeliverDataInterface; use Alchemy\Phrasea\Http\DeliverDataInterface;
use Symfony\Component\HttpFoundation\Response;
trait DelivererAware trait DelivererAware
{ {
@@ -57,28 +58,15 @@ trait DelivererAware
/** /**
* Returns a HTTP Response ready to deliver a binary file * Returns a HTTP Response ready to deliver a binary file
* *
* @param string $file * @param string $file
* @param string $filename * @param string $filename
* @param string $disposition * @param string $disposition
* @param string|null $mimeType * @param string|null $mimeType
* @param integer $cacheDuration * @param integer $cacheDuration
* @return Response
*/ */
public function deliverFile($file, $filename = null, $disposition = DeliverDataInterface::DISPOSITION_INLINE, $mimeType = null, $cacheDuration = null) public function deliverFile($file, $filename = null, $disposition = DeliverDataInterface::DISPOSITION_INLINE, $mimeType = null, $cacheDuration = null)
{ {
return $this->getDeliverer()->deliverFile($file, $filename, $disposition, $mimeType, $cacheDuration); return $this->getDeliverer()->deliverFile($file, $filename, $disposition, $mimeType, $cacheDuration);
} }
/**
* Return a HTTP Response ready to deliver data
*
* @param string $data
* @param string $filename
* @param string $mimeType
* @param string $disposition
* @param integer $cacheDuration
*/
public function deliverData($data, $filename, $mimeType, $disposition = DeliverDataInterface::DISPOSITION_INLINE, $cacheDuration = null)
{
return $this->getDeliverer()->deliverData($data, $filename, $disposition, $mimeType, $cacheDuration);
}
} }

View File

@@ -10,7 +10,6 @@
namespace Alchemy\Phrasea\Application\Helper; namespace Alchemy\Phrasea\Application\Helper;
use Neutron\TemporaryFilesystem\Manager; use Neutron\TemporaryFilesystem\Manager;
use Neutron\TemporaryFilesystem\TemporaryFilesystemInterface;
use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Filesystem\Filesystem;
trait FilesystemAware trait FilesystemAware

View File

@@ -9,80 +9,9 @@
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
namespace Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Core\Event\Subscriber\PhraseaExceptionHandlerSubscriber;
use Alchemy\Phrasea\Core\Event\Subscriber\BridgeExceptionSubscriber;
use Alchemy\Phrasea\Core\Event\Subscriber\FirewallSubscriber;
use Alchemy\Phrasea\Core\Event\Subscriber\JsonRequestSubscriber;
use Alchemy\Phrasea\Core\Event\Subscriber\DebuggerSubscriber;
use Monolog\Logger;
use Monolog\Processor\WebProcessor;
use Silex\Provider\WebProfilerServiceProvider;
use Sorien\Provider\DoctrineProfilerServiceProvider;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
return call_user_func(function ($environment = PhraseaApplication::ENV_PROD) { return (new Application\ApplicationLoader())->buildWebApplication(
$app = new PhraseaApplication($environment); isset($environment) ? $environment : Application::ENV_PROD,
$app->loadPlugins(); isset($forceDebug) ? $forceDebug : false
);
$app['exception_handler'] = $app->share(function ($app) {
return new PhraseaExceptionHandlerSubscriber($app['phraseanet.exception_handler']);
});
$app['monolog'] = $app->share($app->extend('monolog', function (Logger $monolog) {
$monolog->pushProcessor(new WebProcessor());
return $monolog;
}));
$app->before(function (Request $request) use ($app) {
if (0 === strpos($request->getPathInfo(), '/setup')) {
if (!$app['phraseanet.configuration-tester']->isInstalled()) {
if (!$app['phraseanet.configuration-tester']->isBlank()) {
if ('setup_upgrade_instructions' !== $app['request']->attributes->get('_route')) {
return $app->redirectPath('setup_upgrade_instructions');
}
}
} elseif (!$app['phraseanet.configuration-tester']->isBlank()) {
return $app->redirectPath('homepage');
}
} else {
if (false === strpos($request->getPathInfo(), '/include/minify')) {
$app['firewall']->requireSetup();
}
}
}, Application::EARLY_EVENT);
$app->bindRoutes();
if (PhraseaApplication::ENV_DEV === $app->getEnvironment()) {
$app->register($p = new WebProfilerServiceProvider(), [
'profiler.cache_dir' => $app['cache.path'].'/profiler',
]);
$app->mount('/_profiler', $p);
if ($app['phraseanet.configuration-tester']->isInstalled()) {
$app->register(new DoctrineProfilerServiceProvider());
$app['db'] = $app->share(function (PhraseaApplication $app) {
return $app['orm.em']->getConnection();
});
}
}
$app['dispatcher'] = $app->share(
$app->extend('dispatcher', function (EventDispatcherInterface $dispatcher, PhraseaApplication $app) {
$dispatcher->addSubscriber(new BridgeExceptionSubscriber($app));
$dispatcher->addSubscriber(new FirewallSubscriber());
$dispatcher->addSubscriber(new JsonRequestSubscriber());
$dispatcher->addSubscriber(new DebuggerSubscriber($app));
return $dispatcher;
})
);
return $app;
}, isset($environment) ? $environment : PhraseaApplication::ENV_PROD);

View File

@@ -0,0 +1,155 @@
<?php
namespace Alchemy\Phrasea\Application;
use Alchemy\EmbedProvider\EmbedServiceProvider;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\ControllerProvider as Providers;
use Assert\Assertion;
use Silex\ControllerProviderInterface;
class RouteLoader
{
public static $defaultProviders = [
'/account/' => Providers\Root\Account::class,
'/admin/' => Providers\Admin\Root::class,
'/admin/collection' => Providers\Admin\Collection::class,
'/admin/connected-users' => Providers\Admin\ConnectedUsers::class,
'/admin/dashboard' => Providers\Admin\Dashboard::class,
'/admin/databox' => Providers\Admin\Databox::class,
'/admin/databoxes' => Providers\Admin\Databoxes::class,
'/admin/fields' => Providers\Admin\Fields::class ,
'/admin/publications' => Providers\Admin\Feeds::class,
'/admin/plugins' => Providers\Admin\Plugins::class,
'/admin/search-engine' => Providers\Admin\SearchEngine::class,
'/admin/setup' => Providers\Admin\Setup::class,
'/admin/subdefs' => Providers\Admin\Subdefs::class,
'/admin/task-manager' => Providers\Admin\TaskManager::class,
'/admin/users' => Providers\Admin\Users::class,
'/client/' => Providers\Client\Root::class,
'/datafiles' => Providers\Datafiles::class,
'/developers/' => Providers\Root\Developers::class,
'/download/' => Providers\Prod\DoDownload::class,
'/embed/' => EmbedServiceProvider::class,
'/feeds/' => Providers\Root\RSSFeeds::class,
'/include/minify' => Providers\Minifier::class,
'/login/' => Providers\Root\Login::class,
'/lightbox' => Providers\Lightbox::class,
'/permalink' => Providers\Permalink::class,
'/prod/baskets' => Providers\Prod\BasketProvider::class,
'/prod/bridge/' => Providers\Prod\Bridge::class,
'/prod/download' => Providers\Prod\Download::class,
'/prod/export/' => Providers\Prod\Export::class,
'/prod/feeds' => Providers\Prod\Feed::class,
'/prod/language' => Providers\Prod\Language::class,
'/prod/lazaret/' => Providers\Prod\Lazaret::class,
'/prod/lists' => Providers\Prod\UsrLists::class,
'/prod/order/' => Providers\Prod\Order::class,
'/prod/printer/' => Providers\Prod\Printer::class,
'/prod/push/' => Providers\Prod\Push::class,
'/prod/query/' => Providers\Prod\Query::class,
'/prod/records/' => Providers\Prod\Record::class,
'/prod/records/edit' => Providers\Prod\Edit::class,
'/prod/records/movecollection' => Providers\Prod\MoveCollection::class,
'/prod/records/property' => Providers\Prod\Property::class,
'/prod/share/' => Providers\Prod\Share::class,
'/prod/story' => Providers\Prod\Story::class,
'/prod/tools/' => Providers\Prod\Tools::class,
'/prod/tooltip' => Providers\Prod\Tooltip::class,
'/prod/TOU/' => Providers\Prod\TOU::class,
'/prod/upload/' => Providers\Prod\Upload::class,
'/prod/WorkZone' => Providers\Prod\WorkZone::class,
'/prod/' => Providers\Prod\Root::class,
'/report/activity' => Providers\Report\Activity::class,
'/report/informations' => Providers\Report\Information::class,
'/report/' => Providers\Report\Root::class,
'/session/' => Providers\Root\Session::class,
'/setup' => Providers\Setup::class,
'/thesaurus' => Providers\Thesaurus\Thesaurus::class,
'/user/notifications/' => Providers\User\Notifications::class,
'/user/preferences/' => Providers\User\Preferences::class,
'/xmlhttp' => Providers\Thesaurus\Xmlhttp::class,
'/' => Providers\Root\Root::class,
];
/**
* @var string[]
*/
private $controllerProviders = [];
/**
* @param string $prefix
* @param string $providerClass
* @throws \InvalidArgumentException
*/
public function registerProvider($prefix, $providerClass)
{
Assertion::classExists($providerClass);
$this->controllerProviders[$prefix] = $providerClass;
}
public function registerProviders(array $providers)
{
foreach ($providers as $prefix => $providerClass) {
$this->registerProvider($prefix, $providerClass);
}
}
/**
* @param Application $app
*/
public function bindRoutes(Application $app)
{
// @todo Move me out of here !
// Controllers with routes referenced by api
$this->controllerProviders[$app['controller.media_accessor.route_prefix']] = Providers\MediaAccessor::class;
foreach ($this->controllerProviders as $prefix => $class) {
$app->mount($prefix, new $class);
}
}
/**
* @param Application $app
* @param $routeParameter
*/
public function bindPluginRoutes(Application $app, $routeParameter)
{
foreach ($app[$routeParameter] as $providerDefinition) {
$prefix = '';
$providerKey = $providerDefinition;
if (is_array($providerDefinition)) {
list($prefix, $providerKey) = $providerDefinition;
}
if (! $this->isValidProviderDefinition($app, $prefix, $providerKey)) {
continue;
}
$prefix = '/' . ltrim($prefix, '/');
$provider = $app[$providerKey];
if (!$provider instanceof ControllerProviderInterface) {
continue;
}
$app->mount($prefix, $provider);
}
}
private function isValidProviderDefinition(Application $app, $prefix, $provider)
{
if (!is_string($prefix) || !is_string($provider)) {
return false;
}
if (!isset($app[$provider])) {
return false;
}
return true;
}
}

View File

@@ -333,7 +333,7 @@ class RegistrationService
return; return;
} }
$collection = \collection::get_from_base_id($this->app, $baseId); $collection = \collection::getByBaseId($this->app, $baseId);
$registrationManipulator->createRegistration($user, $collection); $registrationManipulator->createRegistration($user, $collection);
$successfulRegistrations[$baseId] = $collection; $successfulRegistrations[$baseId] = $collection;
}); });

View File

@@ -19,8 +19,19 @@ use Alchemy\Phrasea\Border\File;
*/ */
abstract class AbstractChecker implements CheckerInterface abstract class AbstractChecker implements CheckerInterface
{ {
/**
* @var Application
*/
protected $app; protected $app;
/**
* @var \databox[]
*/
protected $databoxes = []; protected $databoxes = [];
/**
* @var \collection[]
*/
protected $collections = []; protected $collections = [];
public function __construct(Application $app) public function __construct(Application $app)
@@ -32,8 +43,8 @@ abstract class AbstractChecker implements CheckerInterface
* Restrict the checker to a set of databoxes. * Restrict the checker to a set of databoxes.
* Warning, you can not restrict on both databoxes and collections * Warning, you can not restrict on both databoxes and collections
* *
* @param databox|array $databoxes A databox or an array of databoxes * @param \databox[] $databoxes A databox or an array of databoxes
* @return Boolean * @return bool
* *
* @throws \LogicException If already restricted to collections * @throws \LogicException If already restricted to collections
* @throws \InvalidArgumentException In case invalid databoxes are provided * @throws \InvalidArgumentException In case invalid databoxes are provided
@@ -60,8 +71,8 @@ abstract class AbstractChecker implements CheckerInterface
* Restrict the checker to a set of collections. * Restrict the checker to a set of collections.
* Warning, you can not restrict on both databoxes and collections * Warning, you can not restrict on both databoxes and collections
* *
* @param collection|array $collections * @param \collection[] $collections
* @return Boolean * @return bool
* *
* @throws \LogicException If already restricted to databoxes * @throws \LogicException If already restricted to databoxes
* @throws \InvalidArgumentException In case invalid collections are provided * @throws \InvalidArgumentException In case invalid collections are provided
@@ -93,6 +104,10 @@ abstract class AbstractChecker implements CheckerInterface
*/ */
public function isApplicable(File $file) public function isApplicable(File $file)
{ {
if (empty($this->databoxes) && empty($this->collections)) {
return true;
}
if (null === $file->getCollection()) { if (null === $file->getCollection()) {
return true; return true;
} }

View File

@@ -134,14 +134,12 @@ class File
$metadatas->add(new Metadata(TagFactory::getFromRDFTagname($tagname), $value)); $metadatas->add(new Metadata(TagFactory::getFromRDFTagname($tagname), $value));
} }
/**
* PHPExiftool throws exception on some files not supported
*/
try { try {
$this->app['exiftool.writer']->reset(); $writer = $this->app['exiftool.writer'];
$this->app['exiftool.writer']->write($this->getFile()->getRealPath(), $metadatas); $writer->reset();
$writer->write($this->getFile()->getRealPath(), $metadatas);
} catch (PHPExiftoolException $e) { } catch (PHPExiftoolException $e) {
// PHPExiftool throws exception on some files not supported
} }
} }

View File

@@ -11,6 +11,7 @@
namespace Alchemy\Phrasea\Border; namespace Alchemy\Phrasea\Border;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Border\Checker\CheckerInterface; use Alchemy\Phrasea\Border\Checker\CheckerInterface;
use Alchemy\Phrasea\Border\Attribute\AttributeInterface; use Alchemy\Phrasea\Border\Attribute\AttributeInterface;
use Alchemy\Phrasea\Exception\RuntimeException; use Alchemy\Phrasea\Exception\RuntimeException;
@@ -27,12 +28,9 @@ use Alchemy\Phrasea\Model\Entities\LazaretAttribute;
use Alchemy\Phrasea\Model\Entities\LazaretCheck; use Alchemy\Phrasea\Model\Entities\LazaretCheck;
use Alchemy\Phrasea\Model\Entities\LazaretFile; use Alchemy\Phrasea\Model\Entities\LazaretFile;
use Alchemy\Phrasea\Model\Entities\LazaretSession; use Alchemy\Phrasea\Model\Entities\LazaretSession;
use MediaAlchemyst\Exception\ExceptionInterface as MediaAlchemystException;
use MediaAlchemyst\Specification\Image as ImageSpec;
use PHPExiftool\Driver\Metadata\Metadata; use PHPExiftool\Driver\Metadata\Metadata;
use PHPExiftool\Driver\Value\Mono as MonoValue; use PHPExiftool\Driver\Value\Mono as MonoValue;
use PHPExiftool\Driver\Value\Multi; use PHPExiftool\Driver\Value\Multi;
use Silex\Application;
use Symfony\Component\Filesystem\Exception\IOException; use Symfony\Component\Filesystem\Exception\IOException;
/** /**
@@ -44,6 +42,9 @@ use Symfony\Component\Filesystem\Exception\IOException;
*/ */
class Manager class Manager
{ {
/**
* @var CheckerInterface[]
*/
protected $checkers = []; protected $checkers = [];
protected $app; protected $app;
protected $filesystem; protected $filesystem;
@@ -159,7 +160,9 @@ class Manager
} }
foreach ($this->checkers as $checker) { foreach ($this->checkers as $checker) {
$visa->addResponse($checker->check($this->app['orm.em'], $file)); if ($checker->isApplicable($file)) {
$visa->addResponse($checker->check($this->app['orm.em'], $file));
}
} }
return $visa; return $visa;
@@ -242,42 +245,11 @@ class Manager
return array_values($this->checkers); return array_values($this->checkers);
} }
/**
* Find an available Lazaret filename and creates the empty file.
*
* @param string $filename The desired filename
* @param string $suffix A suffix to the filename
* @return string The available filename to use
*/
protected function bookLazaretPathfile($filename, $suffix = '')
{
$output = $this->app['tmp.path'].'/lazaret/lzrt_' . substr($filename, 0, 3) . '_' . $suffix . '.' . pathinfo($filename, PATHINFO_EXTENSION);
$infos = pathinfo($output);
$n = 0;
$this->app['filesystem']->mkdir($this->app['tmp.lazaret.path']);
while (true) {
$output = sprintf('%s/%s-%d%s', $infos['dirname'], $infos['filename'], ++ $n, (isset($infos['extension']) ? '.' . $infos['extension'] : ''));
try {
if ( ! $this->app['filesystem']->exists($output)) {
$this->app['filesystem']->touch($output);
break;
}
} catch (IOException $e) {
}
}
return realpath($output);
}
/** /**
* Adds a record to Phraseanet * Adds a record to Phraseanet
* *
* @param File $file The package file * @param File $file The package file
* @return \record_adater * @return \record_adapter
*/ */
protected function createRecord(File $file, $nosubdef=false) protected function createRecord(File $file, $nosubdef=false)
{ {
@@ -384,21 +356,8 @@ class Manager
) )
); );
$lazaretPathname = $this->bookLazaretPathfile($file->getOriginalName()); $lazaretFilesystemService = $this->app['phraseanet.lazaret_filesystem'];
$lazaretPathnameThumb = $this->bookLazaretPathfile($file->getOriginalName(), 'thumb'); $persistedLazaret = $lazaretFilesystemService->writeLazaret($file);
$this->app['filesystem']->copy($file->getFile()->getRealPath(), $lazaretPathname, true);
$spec = new ImageSpec();
$spec->setResizeMode(ImageSpec::RESIZE_MODE_INBOUND_FIXEDRATIO);
$spec->setDimensions(375, 275);
try {
$this->app['media-alchemyst']->turnInto($file->getFile()->getPathname(), $lazaretPathnameThumb, $spec);
} catch (MediaAlchemystException $e) {
}
$lazaretFile = new LazaretFile(); $lazaretFile = new LazaretFile();
$lazaretFile->setBaseId($file->getCollection()->get_base_id()); $lazaretFile->setBaseId($file->getCollection()->get_base_id());
@@ -408,8 +367,8 @@ class Manager
$lazaretFile->setForced($forced); $lazaretFile->setForced($forced);
$lazaretFile->setFilename(pathinfo($lazaretPathname, PATHINFO_BASENAME)); $lazaretFile->setFilename($persistedLazaret->getFilename());
$lazaretFile->setThumbFileName(pathinfo($lazaretPathnameThumb, PATHINFO_BASENAME)); $lazaretFile->setThumbFileName($persistedLazaret->getThumbnailFilename());
$lazaretFile->setSession($session); $lazaretFile->setSession($session);

View File

@@ -0,0 +1,250 @@
<?php
namespace Alchemy\Phrasea\Collection;
use Alchemy\Phrasea\Collection\Reference\CollectionReference;
use PHPExiftool\Exception\LogicException;
class Collection
{
/**
* @var int
*/
private $databoxId;
/**
* @var int
*/
private $collectionId;
/**
* @var string
*/
private $name;
/**
* @var string[]
*/
private $labels = [];
/**
* @var string|int[] Binary representation of logo
*/
private $logo;
/**
* @var \DateTimeInterface
*/
private $logoUpdatedAt;
/**
* @var string
*/
private $publicWatermark;
/**
* @var string
*/
private $preferences;
/**
* @var CollectionReference
*/
private $collectionReference;
public function __construct($databoxId, $collectionId, $name)
{
$this->databoxId = (int) $databoxId;
$this->collectionId = (int) $collectionId;
$this->name = (string) $name;
$this->preferences = <<<EOT
<?xml version="1.0" encoding="UTF-8"?>
<baseprefs>
<status>0</status>
<sugestedValues></sugestedValues>
</baseprefs>
EOT;
$this->logo = '';
$this->labels = array(
'en' => '',
'fr' => '',
'de' => '',
'nl' => ''
);
$this->publicWatermark = '';
}
/**
* @return int
*/
public function getDataboxId()
{
return $this->databoxId;
}
/**
* @return int
*/
public function getCollectionId()
{
return $this->collectionId;
}
/**
* @param $collectionId
*/
public function setCollectionId($collectionId)
{
if ($this->collectionId > 0) {
throw new LogicException('Cannot change the ID of an existing collection.');
}
$this->collectionId = (int) $collectionId;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
*/
public function setName($name)
{
$name = trim(strip_tags($name));
if ($name === '') {
throw new \InvalidArgumentException();
}
$this->name = $name;
}
/**
* @return \string[]
*/
public function getLabels()
{
return $this->labels;
}
/**
* @param \string[] $labels
*/
public function setLabels($labels)
{
$this->labels = $labels;
}
/**
* @param $lang
* @param bool $substitute
* @return string
*/
public function getLabel($lang, $substitute = true)
{
if (!array_key_exists($lang, $this->labels)) {
throw new \InvalidArgumentException(sprintf('Code %s is not defined', $lang));
}
if ($substitute) {
return isset($this->labels[$lang]) ? $this->labels[$lang] : $this->name;
} else {
return $this->labels[$lang];
}
}
/**
* @param $lang
* @param $label
*/
public function setLabel($lang, $label)
{
if (!array_key_exists($lang, $this->labels)) {
throw new \InvalidArgumentException(sprintf("Language '%s' is not defined.", $lang));
}
$this->labels[$lang] = $label;
}
/**
* @return \int[]|string|null
*/
public function getLogo()
{
return $this->logo;
}
/**
* @param \int[]|string $logo
*/
public function setLogo($logo)
{
$this->logo = $logo;
}
/**
* @return \DateTimeInterface
*/
public function getLogoUpdatedAt()
{
return $this->logoUpdatedAt;
}
/**
* @return string
*/
public function getPublicWatermark()
{
return $this->publicWatermark;
}
/**
* @param string $publicWatermark
*/
public function setPublicWatermark($publicWatermark)
{
if (! in_array($publicWatermark, ['none', 'wm', 'stamp'])) {
return;
}
$this->publicWatermark = $publicWatermark;
}
/**
* @return string
*/
public function getPreferences()
{
return $this->preferences;
}
/**
* @param string $preferences
*/
public function setPreferences($preferences)
{
$this->preferences = $preferences;
}
/**
* @return CollectionReference
*/
public function getCollectionReference()
{
return $this->collectionReference;
}
/**
* @param CollectionReference $collectionReference
*/
public function setCollectionReference($collectionReference)
{
$this->collectionReference = $collectionReference;
}
}

View File

@@ -0,0 +1,72 @@
<?php
namespace Alchemy\Phrasea\Collection;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Collection\Reference\CollectionReference;
use Assert\Assertion;
class CollectionFactory
{
/**
* @var Application
*/
private $app;
/**
* @param Application $application
*/
public function __construct(Application $application)
{
$this->app = $application;
}
/**
* @param int $databoxId
* @param CollectionReference $reference
* @param array $row
* @return \collection
*/
public function create($databoxId, CollectionReference $reference, array $row)
{
if ($databoxId != $reference->getDataboxId()) {
throw new \InvalidArgumentException('Reference does not belong to given databoxId.');
}
$collection = new Collection($databoxId, $row['coll_id'], $row['asciiname']);
$collection->setLabel('en', $row['label_en']);
$collection->setLabel('fr', $row['label_fr']);
$collection->setLabel('de', $row['label_de']);
$collection->setLabel('nl', $row['label_nl']);
$collection->setLogo($row['logo']);
$collection->setPreferences($row['prefs']);
$collection->setPublicWatermark($row['pub_wm']);
return new \collection($this->app, $collection, $reference, $row);
}
/**
* @param int $databoxId
* @param CollectionReference[] $collectionReferences
* @param array $rows
* @return array
*/
public function createMany($databoxId, $collectionReferences, array $rows)
{
Assertion::allIsInstanceOf($collectionReferences, CollectionReference::class);
$collections = [];
$indexedReferences = [];
foreach ($collectionReferences as $reference) {
$indexedReferences[$reference->getCollectionId()] = $reference;
}
foreach ($rows as $row) {
$collections[$row['coll_id']] = $this->create($databoxId, $indexedReferences[$row['coll_id']], $row);
}
return $collections;
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Alchemy\Phrasea\Collection;
interface CollectionRepository
{
/**
* @return \collection[]
*/
public function findAll();
/**
* @param int $collectionId
* @return \collection|null
*/
public function find($collectionId);
/**
* @param Collection $collection
* @return void
*/
public function save(Collection $collection);
/**
* @param Collection $collection
* @return void
*/
public function delete(Collection $collection);
}

View File

@@ -0,0 +1,12 @@
<?php
namespace Alchemy\Phrasea\Collection;
interface CollectionRepositoryFactory
{
/**
* @param int $databoxId
* @return CollectionRepository
*/
public function createRepositoryForDatabox($databoxId);
}

View File

@@ -0,0 +1,99 @@
<?php
namespace Alchemy\Phrasea\Collection;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Collection\Reference\CollectionReferenceRepository;
class CollectionRepositoryRegistry
{
private $baseIdMap = null;
/**
* @var Application
*/
private $application;
/**
* @var CollectionRepository[]
*/
private $repositories = array();
/**
* @var CollectionReferenceRepository
*/
private $referenceRepository;
/**
* @var CollectionRepositoryFactory
*/
private $repositoryFactory;
/**
* @param Application $app
* @param CollectionRepositoryFactory $collectionRepositoryFactory
* @param CollectionReferenceRepository $referenceRepository
*/
public function __construct(
Application $app,
CollectionRepositoryFactory $collectionRepositoryFactory,
CollectionReferenceRepository $referenceRepository
) {
$this->application = $app;
$this->repositoryFactory = $collectionRepositoryFactory;
$this->referenceRepository = $referenceRepository;
}
/**
* @param $databoxId
* @return CollectionRepository
*/
public function getRepositoryByDatabox($databoxId)
{
if (!isset($this->repositories[$databoxId])) {
$this->repositories[$databoxId] = $this->repositoryFactory->createRepositoryForDatabox($databoxId);
}
return $this->repositories[$databoxId];
}
/**
* @param int $baseId
* @return CollectionRepository
* @throws \OutOfBoundsException if no repository was found for the given baseId.
*/
public function getRepositoryByBase($baseId)
{
if ($this->baseIdMap === null) {
$this->loadBaseIdMap();
}
if (isset($this->baseIdMap[$baseId])) {
return $this->getRepositoryByDatabox($this->baseIdMap[$baseId]);
}
throw new \OutOfBoundsException('No repository available for given base [baseId: ' . $baseId . ' ].');
}
public function purgeRegistry()
{
$this->baseIdMap = null;
$appBox = $this->application->getApplicationBox();
\phrasea::reset_baseDatas($appBox);
\phrasea::reset_sbasDatas($appBox);
}
private function loadBaseIdMap()
{
$references = $this->referenceRepository->findAll();
$this->baseIdMap = [];
foreach ($references as $reference) {
$this->baseIdMap[$reference->getBaseId()] = $reference->getDataboxId();
}
}
}

View File

@@ -0,0 +1,266 @@
<?php
namespace Alchemy\Phrasea\Collection;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Collection\Reference\CollectionReference;
use Alchemy\Phrasea\Databox\DataboxConnectionProvider;
use Alchemy\Phrasea\Model\Entities\User;
use Doctrine\DBAL\Connection;
class CollectionService
{
/**
* @var Application
*/
private $app;
private $connection;
private $connectionProvider;
public function __construct(Application $application, Connection $connection, DataboxConnectionProvider $connectionProvider)
{
$this->app = $application;
$this->connection = $connection;
$this->connectionProvider = $connectionProvider;
}
/**
* @param Collection $collection
* @return int|null
* @throws \Doctrine\DBAL\DBALException
*/
public function getRecordCount(Collection $collection)
{
$connection = $this->connectionProvider->getConnection($collection->getDataboxId());
$sql = "SELECT COALESCE(COUNT(record_id), 0) AS recordCount FROM record WHERE coll_id = :coll_id";
$stmt = $connection->prepare($sql);
$stmt->execute([':coll_id' => $collection->getCollectionId()]);
$rowbas = $stmt->fetch(\PDO::FETCH_ASSOC);
$stmt->closeCursor();
$amount = $rowbas ? (int) $rowbas["recordCount"] : null;
return $amount;
}
/**
* @param Collection $collection
* @return array
*/
public function getRecordDetails(Collection $collection)
{
$sql = "SELECT record.coll_id,name,COALESCE(asciiname, CONCAT('_',record.coll_id)) AS asciiname,
SUM(1) AS n, SUM(size) AS size
FROM record NATURAL JOIN subdef
INNER JOIN coll ON record.coll_id=coll.coll_id AND coll.coll_id = :coll_id
GROUP BY record.coll_id, subdef.name";
$connection = $this->connectionProvider->getConnection($collection->getDataboxId());
$stmt = $connection->prepare($sql);
$stmt->execute([':coll_id' => $collection->getCollectionId()]);
$rs = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$stmt->closeCursor();
$ret = [];
foreach ($rs as $row) {
$ret[] = [
"coll_id" => (int) $row["coll_id"],
"name" => $row["name"],
"amount" => (int) $row["n"],
"size" => (int) $row["size"]];
}
return $ret;
}
/**
* @param Collection $collection
* @return $this
* @throws \Doctrine\DBAL\DBALException
*/
public function resetWatermark(Collection $collection)
{
$sql = 'SELECT path, file FROM record r INNER JOIN subdef s USING(record_id)
WHERE r.coll_id = :coll_id AND r.type="image" AND s.name="preview"';
$connection = $this->connectionProvider->getConnection($collection->getDataboxId());
$stmt = $connection->prepare($sql);
$stmt->execute([':coll_id' => $collection->getCollectionId()]);
while ($row2 = $stmt->fetch(\PDO::FETCH_ASSOC)) {
@unlink(\p4string::addEndSlash($row2['path']) . 'watermark_' . $row2['file']);
}
$stmt->closeCursor();
return $this;
}
/**
* @param Collection $collection
* @param int|null $record_id
* @return $this
* @throws \Doctrine\DBAL\DBALException
*/
public function resetStamp(Collection $collection, $record_id = null)
{
$sql = 'SELECT path, file FROM record r INNER JOIN subdef s USING(record_id)
WHERE r.coll_id = :coll_id
AND r.type="image" AND s.name IN ("preview", "document")';
$params = [':coll_id' => $collection->getCollectionId()];
if ($record_id) {
$sql .= ' AND record_id = :record_id';
$params[':record_id'] = $record_id;
}
$connection = $this->connectionProvider->getConnection($collection->getDataboxId());
$stmt = $connection->prepare($sql);
$stmt->execute($params);
while ($row2 = $stmt->fetch(\PDO::FETCH_ASSOC)) {
@unlink(\p4string::addEndSlash($row2['path']) . 'stamp_' . $row2['file']);
}
$stmt->closeCursor();
return $this;
}
/**
* @param \databox $databox
* @param Collection $collection
* @param CollectionReference $reference
* @throws \Doctrine\DBAL\DBALException
*/
public function delete(\databox $databox, Collection $collection, CollectionReference $reference)
{
while ($this->getRecordCount($collection) > 0) {
$this->emptyCollection($databox, $collection);
}
$connection = $this->connectionProvider->getConnection($collection->getDataboxId());
$sql = "DELETE FROM coll WHERE coll_id = :coll_id";
$stmt = $connection->prepare($sql);
$stmt->execute([':coll_id' => $collection->getCollectionId()]);
$stmt->closeCursor();
$sql = "DELETE FROM bas WHERE base_id = :base_id";
$stmt = $this->connection->prepare($sql);
$stmt->execute([':base_id' => $reference->getBaseId()]);
$stmt->closeCursor();
$sql = "DELETE FROM basusr WHERE base_id = :base_id";
$stmt = $this->connection->prepare($sql);
$stmt->execute([':base_id' => $reference->getBaseId()]);
$stmt->closeCursor();
return;
}
/**
* @param \databox $databox
* @param Collection $collection
* @param int $pass_quantity
* @return $this
* @throws \Doctrine\DBAL\DBALException
*/
public function emptyCollection(\databox $databox, Collection $collection, $pass_quantity = 100)
{
$pass_quantity = (int) $pass_quantity > 200 ? 200 : (int) $pass_quantity;
$pass_quantity = (int) $pass_quantity < 10 ? 10 : (int) $pass_quantity;
$sql = "SELECT record_id FROM record WHERE coll_id = :coll_id
ORDER BY record_id DESC LIMIT 0, " . $pass_quantity;
$connection = $this->connectionProvider->getConnection($collection->getDataboxId());
$stmt = $connection->prepare($sql);
$stmt->execute([':coll_id' => $collection->getCollectionId()]);
$rs = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$stmt->closeCursor();
foreach ($rs as $row) {
$record = $databox->get_record($row['record_id']);
$record->delete();
unset($record);
}
return $this;
}
/**
* @param CollectionReference $reference
* @return $this
* @throws \Doctrine\DBAL\DBALException
*/
public function unmountCollection(CollectionReference $reference)
{
$params = [':base_id' => $reference->getBaseId()];
$query = $this->app['phraseanet.user-query'];
$total = $query->on_base_ids([$reference->getBaseId()])
->include_phantoms(false)
->include_special_users(true)
->include_invite(true)
->include_templates(true)->get_total();
$n = 0;
while ($n < $total) {
$results = $query->limit($n, 50)->execute()->get_results();
foreach ($results as $user) {
$this->app->getAclForUser($user)->delete_data_from_cache(\ACL::CACHE_RIGHTS_SBAS);
$this->app->getAclForUser($user)->delete_data_from_cache(\ACL::CACHE_RIGHTS_BAS);
}
$n+=50;
}
$sql = "DELETE FROM basusr WHERE base_id = :base_id";
$stmt = $this->connection->prepare($sql);
$stmt->execute($params);
$stmt->closeCursor();
$sql = "DELETE FROM bas WHERE base_id = :base_id";
$stmt = $this->connection->prepare($sql);
$stmt->execute($params);
$stmt->closeCursor();
}
/**
* @param CollectionReference $reference
* @param User $user
*/
public function grantAdminRights(CollectionReference $reference, User $user)
{
$rights = [
"canputinalbum" => "1",
"candwnldhd" => "1",
"nowatermark" => "1",
"candwnldpreview" => "1",
"cancmd" => "1",
"canadmin" => "1",
"actif" => "1",
"canreport" => "1",
"canpush" => "1",
"basusr_infousr" => "",
"canaddrecord" => "1",
"canmodifrecord" => "1",
"candeleterecord" => "1",
"chgstatus" => "1",
"imgtools" => "1",
"manage" => "1",
"modify_struct" => "1"
];
$this->app->getAclForUser($user)->update_rights_to_base($reference->getBaseId(), $rights);
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Alchemy\Phrasea\Collection\Factory;
use Alchemy\Phrasea\Collection\CollectionRepository;
use Alchemy\Phrasea\Collection\CollectionRepositoryFactory;
use Alchemy\Phrasea\Collection\Repository\ArrayCacheCollectionRepository;
class ArrayCachedCollectionRepositoryFactory implements CollectionRepositoryFactory
{
/**
* @var CollectionRepositoryFactory
*/
private $collectionRepositoryFactory;
/**
* @param CollectionRepositoryFactory $collectionRepositoryFactory
*/
public function __construct(CollectionRepositoryFactory $collectionRepositoryFactory)
{
$this->collectionRepositoryFactory = $collectionRepositoryFactory;
}
/**
* @param int $databoxId
* @return CollectionRepository
*/
public function createRepositoryForDatabox($databoxId)
{
$repository = $this->collectionRepositoryFactory->createRepositoryForDatabox($databoxId);
return new ArrayCacheCollectionRepository($repository);
}
}

View File

@@ -0,0 +1,66 @@
<?php
namespace Alchemy\Phrasea\Collection\Factory;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Collection\CollectionRepository;
use Alchemy\Phrasea\Collection\CollectionRepositoryFactory;
use Alchemy\Phrasea\Collection\Repository\CachedCollectionRepository;
use Doctrine\Common\Cache\Cache;
class CachedCollectionRepositoryFactory implements CollectionRepositoryFactory
{
/**
* @var Application
*/
private $application;
/**
* @var CollectionRepositoryFactory
*/
private $collectionRepositoryFactory;
/**
* @var Cache
*/
private $cache;
/**
* @var string
*/
private $baseCacheKey;
/**
* @param Application $application
* @param CollectionRepositoryFactory $collectionRepositoryFactory
* @param Cache $cache
* @param string $baseCacheKey
*/
public function __construct(
Application $application,
CollectionRepositoryFactory $collectionRepositoryFactory,
Cache $cache,
$baseCacheKey
) {
$this->application = $application;
$this->collectionRepositoryFactory = $collectionRepositoryFactory;
$this->cache = $cache;
$this->baseCacheKey = (string)$baseCacheKey;
}
/**
* @param int $databoxId
* @return CollectionRepository
*/
public function createRepositoryForDatabox($databoxId)
{
$repository = $this->collectionRepositoryFactory->createRepositoryForDatabox($databoxId);
return new CachedCollectionRepository(
$this->application,
$repository,
$this->cache,
$this->baseCacheKey . '.' . $databoxId
);
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace Alchemy\Phrasea\Collection\Factory;
use Alchemy\Phrasea\Collection\CollectionFactory;
use Alchemy\Phrasea\Collection\CollectionRepository;
use Alchemy\Phrasea\Collection\CollectionRepositoryFactory;
use Alchemy\Phrasea\Collection\Reference\CollectionReferenceRepository;
use Alchemy\Phrasea\Collection\Repository\DbalCollectionRepository;
use Alchemy\Phrasea\Databox\DataboxConnectionProvider;
class DbalCollectionRepositoryFactory implements CollectionRepositoryFactory
{
/**
* @var CollectionReferenceRepository
*/
private $collectionReferenceRepository;
/**
* @var DataboxConnectionProvider
*/
private $databoxConnectionProvider;
/**
* @var CollectionFactory
*/
private $collectionFactory;
/**
* @param DataboxConnectionProvider $connectionProvider
* @param CollectionFactory $collectionFactory
* @param CollectionReferenceRepository $referenceRepository
*/
public function __construct(
DataboxConnectionProvider $connectionProvider,
CollectionFactory $collectionFactory,
CollectionReferenceRepository $referenceRepository
) {
$this->databoxConnectionProvider = $connectionProvider;
$this->collectionFactory = $collectionFactory;
$this->collectionReferenceRepository = $referenceRepository;
}
/**
* @param int $databoxId
* @return CollectionRepository
*/
public function createRepositoryForDatabox($databoxId)
{
$databoxConnection = $this->databoxConnectionProvider->getConnection($databoxId);
return new DbalCollectionRepository(
$databoxId,
$databoxConnection,
$this->collectionReferenceRepository,
$this->collectionFactory
);
}
}

View File

@@ -0,0 +1,110 @@
<?php
namespace Alchemy\Phrasea\Collection\Reference;
class ArrayCacheCollectionReferenceRepository implements CollectionReferenceRepository
{
/**
* @var CollectionReferenceRepository
*/
private $repository;
/**
* @var null|array
*/
private $referenceCache = null;
public function __construct(CollectionReferenceRepository $referenceRepository)
{
$this->repository = $referenceRepository;
}
/**
* @return CollectionReference[]
*/
public function findAll()
{
if ($this->referenceCache === null) {
$this->referenceCache = $this->repository->findAll();
}
return $this->referenceCache;
}
/**
* @param int $databoxId
* @return CollectionReference[]
*/
public function findAllByDatabox($databoxId)
{
$references = $this->findAll();
$found = array();
foreach ($references as $reference) {
if ($reference->getDataboxId() == $databoxId) {
$found[$reference->getBaseId()] = $reference;
}
}
return $found;
}
/**
* @param int $baseId
* @return CollectionReference|null
*/
public function find($baseId)
{
$references = $this->findAll();
if (isset($references[$baseId])) {
return $references[$baseId];
}
return null;
}
/**
* @param int $databoxId
* @param int $collectionId
* @return CollectionReference|null
*/
public function findByCollectionId($databoxId, $collectionId)
{
$references = $this->findAll();
foreach ($references as $reference) {
if ($reference->getDataboxId() == $databoxId && $reference->getCollectionId() == $collectionId) {
return $reference;
}
}
return null;
}
/**
* @param CollectionReference $reference
* @return void
*/
public function save(CollectionReference $reference)
{
$this->repository->save($reference);
if ($this->referenceCache !== null) {
$this->referenceCache[$reference->getBaseId()] = $reference;
}
}
/**
* @param CollectionReference $reference
* @return void
*/
public function delete(CollectionReference $reference)
{
$this->repository->delete($reference);
if ($this->referenceCache !== null) {
unset($this->referenceCache[$reference->getBaseId()]);
}
}
}

View File

@@ -0,0 +1,156 @@
<?php
namespace Alchemy\Phrasea\Collection\Reference;
class CollectionReference
{
/**
* @var int
*/
private $baseId;
/**
* @var int
*/
private $databoxId;
/**
* @var int
*/
private $collectionId;
/**
* @var int
*/
private $displayIndex;
/**
* @var bool
*/
private $isActive;
/**
* @var string
*/
private $alias;
/**
* @param int $baseId
* @param int $databoxId
* @param int $collectionId
* @param int $displayIndex
* @param bool $isActive
* @param string $alias
*/
public function __construct($baseId, $databoxId, $collectionId, $displayIndex, $isActive, $alias)
{
$this->baseId = (int) $baseId;
$this->databoxId = (int) $databoxId;
$this->collectionId = (int) $collectionId;
$this->displayIndex = (int) $displayIndex;
$this->isActive = (bool) $isActive;
$this->alias = (string) $alias;
}
/**
* @return int
*/
public function getDataboxId()
{
return $this->databoxId;
}
/**
* @return int
*/
public function getBaseId()
{
return $this->baseId;
}
/**
* @param int $baseId
*/
public function setBaseId($baseId)
{
if ($this->baseId > 0) {
throw new \LogicException('Cannot change the baseId of an existing collection reference.');
}
$this->baseId = $baseId;
}
/**
* @return int
*/
public function getCollectionId()
{
return $this->collectionId;
}
/**
* @return int
*/
public function getDisplayIndex()
{
return $this->displayIndex;
}
/**
* @param int $index
* @return $this
*/
public function setDisplayIndex($index)
{
$this->displayIndex = (int) $index;
return $this;
}
/**
* @return boolean
*/
public function isActive()
{
return $this->isActive;
}
/**
* @return $this
*/
public function disable()
{
$this->isActive = false;
return $this;
}
/**
* @return $this
*/
public function enable()
{
$this->isActive = true;
return $this;
}
/**
* @return string
*/
public function getAlias()
{
return $this->alias;
}
/**
* @param string $alias
* @return $this
*/
public function setAlias($alias)
{
$this->alias = (string) $alias;
return $this;
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace Alchemy\Phrasea\Collection\Reference;
interface CollectionReferenceRepository
{
/**
* @return CollectionReference[]
*/
public function findAll();
/**
* @param int $databoxId
* @return CollectionReference[]
*/
public function findAllByDatabox($databoxId);
/**
* @param int $baseId
* @return CollectionReference|null
*/
public function find($baseId);
/**
* @param int $databoxId
* @param int $collectionId
* @return CollectionReference|null
*/
public function findByCollectionId($databoxId, $collectionId);
/**
* @param CollectionReference $reference
* @return void
*/
public function save(CollectionReference $reference);
/**
* @param CollectionReference $reference
* @return void
*/
public function delete(CollectionReference $reference);
}

View File

@@ -0,0 +1,174 @@
<?php
namespace Alchemy\Phrasea\Collection\Reference;
use Alchemy\Phrasea\Core\Database\QueryBuilder;
use Doctrine\DBAL\Connection;
class DbalCollectionReferenceRepository implements CollectionReferenceRepository
{
private static $table = 'bas';
private static $columns = [
'base_id' => 'baseId',
'sbas_id' => 'databoxId',
'server_coll_id' => 'collectionId',
'ord' => 'displayIndex',
'active' => 'isActive',
'aliases' => 'alias'
];
private static $selectQuery = 'SELECT base_id AS baseId, sbas_id AS databoxId, server_coll_id AS collectionId,
ord AS displayIndex, active AS isActive, aliases AS alias
FROM bas';
private static $insertQuery = 'INSERT INTO bas (sbas_id, server_coll_id, ord, active, aliases)
VALUES (:databoxId, :collectionId,
(SELECT COALESCE(MAX(b.ord), 0) + 1 AS ord FROM bas b WHERE b.sbas_id = :databoxId),
:isActive, :alias)';
private static $updateQuery = 'UPDATE bas SET ord = :displayIndex, active = :isActive, aliases = :alias
WHERE base_id = :baseId';
private static $deleteQuery = 'DELETE FROM bas WHERE base_id = :baseId';
/**
* @var Connection
*/
private $connection;
/**
* @param Connection $connection
*/
public function __construct(Connection $connection)
{
$this->connection = $connection;
}
/**
* @return CollectionReference[]
*/
public function findAll()
{
return $this->createManyReferences($this->connection->fetchAll(self::$selectQuery));
}
/**
* @param int $databoxId
* @return CollectionReference[]
*/
public function findAllByDatabox($databoxId)
{
$query = self::$selectQuery . ' WHERE sbas_id = :databoxId';
$rows = $this->connection->fetchAll($query, [ ':databoxId' => $databoxId ]);
return $this->createManyReferences($rows);
}
/**
* @param int $baseId
* @return CollectionReference|null
*/
public function find($baseId)
{
$query = self::$selectQuery . ' WHERE base_id = :baseId';
$row = $this->connection->fetchAssoc($query, [ ':baseId' => $baseId ]);
if ($row !== false) {
return $this->createReference($row);
}
return null;
}
/**
* @param int $databoxId
* @param int $collectionId
* @return CollectionReference|null
*/
public function findByCollectionId($databoxId, $collectionId)
{
$query = self::$selectQuery . ' WHERE sbas_id = :databoxId AND server_coll_id = :collectionId';
$row = $this->connection->fetchAssoc($query, [ ':databoxId' => $databoxId, ':collectionId' => $collectionId ]);
if ($row !== false) {
return $this->createReference($row);
}
return null;
}
public function save(CollectionReference $collectionReference)
{
$query = self::$insertQuery;
$isInsert = true;
$parameters = [
'isActive' => $collectionReference->isActive(),
'alias' => $collectionReference->getAlias()
];
if ($collectionReference->getBaseId() > 0) {
$query = self::$updateQuery;
$isInsert = false;
$parameters['baseId'] = $collectionReference->getBaseId();
$parameters['displayIndex'] = $collectionReference->getDisplayIndex();
}
else {
$parameters['databoxId'] = $collectionReference->getDataboxId();
$parameters['collectionId'] = $collectionReference->getCollectionId();
}
$this->connection->executeQuery($query, $parameters);
if ($isInsert) {
$collectionReference->setBaseId($this->connection->lastInsertId());
}
}
/**
* @param CollectionReference $collectionReference
* @throws \Doctrine\DBAL\DBALException
*/
public function delete(CollectionReference $collectionReference)
{
$parameters = [
'baseId' => $collectionReference->getBaseId()
];
$this->connection->executeQuery(self::$deleteQuery, $parameters);
}
/**
* @param array $row
* @return CollectionReference
*/
private function createReference(array $row)
{
return new CollectionReference(
$row['baseId'],
$row['databoxId'],
$row['collectionId'],
$row['displayIndex'],
$row['isActive'],
$row['alias']
);
}
/**
* @param $rows
* @return array
*/
private function createManyReferences($rows)
{
$references = [];
foreach ($rows as $row) {
$references[$row['baseId']] = $this->createReference($row);
}
return $references;
}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace Alchemy\Phrasea\Collection\Repository;
use Alchemy\Phrasea\Collection\Collection;
use Alchemy\Phrasea\Collection\CollectionRepository;
class ArrayCacheCollectionRepository implements CollectionRepository
{
/**
* @var CollectionRepository
*/
private $collectionRepository;
/**
* @var \collection[]
*/
private $collectionCache = null;
public function __construct(CollectionRepository $collectionRepository)
{
$this->collectionRepository = $collectionRepository;
}
/**
* @return \collection[]
*/
public function findAll()
{
if ($this->collectionCache === null) {
$this->collectionCache = $this->collectionRepository->findAll();
}
return $this->collectionCache;
}
/**
* @param int $collectionId
* @return \collection|null
*/
public function find($collectionId)
{
$collections = $this->findAll();
if (isset($collections[$collectionId])) {
return $collections[$collectionId];
}
return null;
}
public function save(Collection $collection)
{
$this->collectionRepository->save($collection);
if ($this->collectionCache !== null) {
$this->collectionCache = null;
}
}
public function delete(Collection $collection)
{
$this->collectionRepository->delete($collection);
if (isset($this->collectionCache[$collection->getCollectionId()])) {
unset($this->collectionCache[$collection->getCollectionId()]);
}
}
}

View File

@@ -0,0 +1,122 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2015 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Collection\Repository;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Collection\Collection;
use Alchemy\Phrasea\Collection\CollectionRepository;
use Doctrine\Common\Cache\Cache;
final class CachedCollectionRepository implements CollectionRepository
{
/**
* @var Application
*/
private $app;
/**
* @var CollectionRepository
*/
private $repository;
/**
* @var Cache
*/
private $cache;
/**
* @var string
*/
private $cacheKey;
/**
* @param Application $application
* @param CollectionRepository $repository
* @param Cache $cache
* @param $cacheKey
*/
public function __construct(Application $application, CollectionRepository $repository, Cache $cache, $cacheKey)
{
$this->app = $application;
$this->repository = $repository;
$this->cache = $cache;
$this->cacheKey = $cacheKey;
}
/**
* @return \collection[]
*/
public function findAll()
{
$cacheKey = $this->getCacheKey();
/** @var \collection[] $collections */
$collections = $this->cache->fetch($cacheKey);
if ($collections === false) {
$collections = $this->repository->findAll();
$this->putInCache($cacheKey, $collections);
} else {
foreach ($collections as $collection) {
$collection->hydrate($this->app);
}
}
return $collections;
}
/**
* @param int $collectionId
* @return \collection|null
*/
public function find($collectionId)
{
$collections = $this->findAll();
if (isset($collections[$collectionId])) {
return $collections[$collectionId];
}
return null;
}
public function save(Collection $collection)
{
$this->repository->save($collection);
$cacheKey = $this->getCacheKey();
$this->cache->delete($cacheKey);
}
public function delete(Collection $collection)
{
$this->repository->delete($collection);
$cacheKey = $this->getCacheKey();
$this->cache->delete($cacheKey);
}
private function putInCache($key, $value)
{
$this->cache->save($key, $value);
}
/**
* @return string
*/
private function getCacheKey()
{
$cacheKey = 'collections:' . hash('sha256', $this->cacheKey);
return $cacheKey;
}
}

View File

@@ -0,0 +1,172 @@
<?php
namespace Alchemy\Phrasea\Collection\Repository;
use Alchemy\Phrasea\Collection\Collection;
use Alchemy\Phrasea\Collection\CollectionFactory;
use Alchemy\Phrasea\Collection\CollectionRepository;
use Alchemy\Phrasea\Collection\Reference\CollectionReferenceRepository;
use Doctrine\DBAL\Connection;
class DbalCollectionRepository implements CollectionRepository
{
private static $selectQuery = 'SELECT coll_id, asciiname, label_en, label_fr, label_de, label_nl, prefs, logo, majLogo, pub_wm
FROM coll';
private static $insertQuery = 'INSERT INTO coll (asciiname, prefs, logo) VALUES (:name, :preferences, :logo)';
private static $updateQuery = 'UPDATE coll SET asciiname = :name, label_en = :labelEn, label_fr = :labelFr,
label_de = :labelDe, label_nl = :labelNl, prefs = :preferences, logo = :logo,
majLogo = :logoTimestamp, pub_wm = :publicWatermark WHERE coll_id = :collectionId';
private static $deleteQuery = 'DELETE FROM coll WHERE coll_id = :collectionId';
/**
* @var int
*/
private $databoxId;
/**
* @var CollectionReferenceRepository
*/
private $referenceRepository;
/**
* @var Connection
*/
private $databoxConnection;
/**
* @var CollectionFactory
*/
private $collectionFactory;
/**
* @param $databoxId
* @param Connection $databoxConnection
* @param CollectionReferenceRepository $referenceRepository
* @param CollectionFactory $collectionFactory
*/
public function __construct(
$databoxId,
Connection $databoxConnection,
CollectionReferenceRepository $referenceRepository,
CollectionFactory $collectionFactory
) {
$this->databoxId = (int) $databoxId;
$this->databoxConnection = $databoxConnection;
$this->referenceRepository = $referenceRepository;
$this->collectionFactory = $collectionFactory;
}
/**
* @return \collection[]
*/
public function findAll()
{
$references = $this->referenceRepository->findAllByDatabox($this->databoxId);
if (empty($references)) {
return [];
}
$parameters = [];
foreach ($references as $reference) {
$parameters[] = $reference->getCollectionId();
}
$query = self::$selectQuery . ' WHERE coll_id IN (:collectionIds)';
$parameters = [ 'collectionIds' => $parameters ];
$parameterTypes = [ 'collectionIds' => Connection::PARAM_INT_ARRAY ];
$rows = $this->databoxConnection->fetchAll($query, $parameters, $parameterTypes);
return $this->collectionFactory->createMany($this->databoxId, $references, $rows);
}
/**
* @param int $baseId
* @return \collection|null
*/
public function find($baseId)
{
$reference = $this->referenceRepository->find($baseId);
if ($reference === null) {
return null;
}
$query = self::$selectQuery . ' WHERE coll_id = :collectionId';
$row = $this->databoxConnection->fetchAssoc($query, [ ':collectionId' => $reference->getCollectionId() ]);
if ($row !== false) {
return $this->collectionFactory->create($this->databoxId, $reference, $row);
}
return null;
}
/**
* @param int $databoxId
* @param int $collectionId
* @return \collection|null
*/
public function findByCollectionId($databoxId, $collectionId)
{
$reference = $this->referenceRepository->findByCollectionId($databoxId, $collectionId);
if ($reference === null) {
return null;
}
$query = self::$selectQuery . ' WHERE coll_id = :collectionId';
$row = $this->databoxConnection->fetchAssoc($query, [ ':collectionId' => $reference->getCollectionId() ]);
if ($row !== false) {
return $this->collectionFactory->create($this->databoxId, $reference, $row);
}
return null;
}
public function save(Collection $collection)
{
$isInsert = true;
$query = self::$insertQuery;
$parameters = array(
'name' => $collection->getName(),
'preferences' => $collection->getPreferences(),
'logo' => $collection->getLogo()
);
if ($collection->getCollectionId() > 0) {
$parameters['collectionId'] = $collection->getCollectionId();
$parameters['labelEn'] = $collection->getLabel('en', false);
$parameters['labelFr'] = $collection->getLabel('fr', false);
$parameters['labelDe'] = $collection->getLabel('de', false);
$parameters['labelNl'] = $collection->getLabel('nl', false);
$parameters['logoTimestamp'] = $collection->getLogoUpdatedAt();
$parameters['publicWatermark'] = $collection->getPublicWatermark();
$query = self::$updateQuery;
$isInsert = false;
}
$this->databoxConnection->executeQuery($query, $parameters);
if ($isInsert) {
$collection->setCollectionId($this->databoxConnection->lastInsertId());
}
}
public function delete(Collection $collection)
{
$parameters = [
'collectionId' => $collection->getCollectionId()
];
$this->databoxConnection->executeQuery(self::$deleteQuery, $parameters);
}
}

View File

@@ -1,5 +1,4 @@
<?php <?php
/* /*
* This file is part of Phraseanet * This file is part of Phraseanet
* *
@@ -18,8 +17,6 @@ use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Process\ExecutableFinder;
use Symfony\Component\Yaml\Yaml;
use Symfony\Component\Process\Process; use Symfony\Component\Process\Process;
use vierbergenlars\SemVer\version as SemVer; use vierbergenlars\SemVer\version as SemVer;
@@ -65,7 +62,7 @@ class IniReset extends Command
$dialog = $this->getHelperSet()->get('dialog'); $dialog = $this->getHelperSet()->get('dialog');
$dbName = $dialog->ask( $dbName = $dialog->ask(
$output, $output,
_('Please enter the databox name to reset or create') $this->container['translator']->trans('Please enter the databox name to reset or create')
); );
} }
} else if ($input->getOption('db-name')) { } else if ($input->getOption('db-name')) {
@@ -75,7 +72,7 @@ class IniReset extends Command
} }
$continue = 'y'; $continue = 'y';
if (count($dbs['dbs']) > 1 && in_array($dbName, array_map(function($db) { return $db->get_dbname();}, $dbs['dbs']))) { if (count($dbs['dbs']) > 1 && in_array($dbName, array_map(function(\base $db) { return $db->get_dbname();}, $dbs['dbs']))) {
if ($interactive) { if ($interactive) {
do { do {
$continue = mb_strtolower($dialog->ask($output, '<question>' .$dbName.' database is going to be truncated, do you want to continue ? (Y/n)</question>', 'Y')); $continue = mb_strtolower($dialog->ask($output, '<question>' .$dbName.' database is going to be truncated, do you want to continue ? (Y/n)</question>', 'Y'));
@@ -87,7 +84,7 @@ class IniReset extends Command
return; return;
} }
$unmountedDbs = $dbToMount = array_diff(array_map(function($db) { return $db->get_dbname();}, $dbs['dbs']), array($dbName)); $unmountedDbs = $dbToMount = array_diff(array_map(function(\base $db) { return $db->get_dbname();}, $dbs['dbs']), array($dbName));
if (count($unmountedDbs) > 1 && $interactive) { if (count($unmountedDbs) > 1 && $interactive) {
array_unshift($unmountedDbs, 'all'); array_unshift($unmountedDbs, 'all');

View File

@@ -31,60 +31,45 @@ class Uninstaller extends Command
protected function doExecute(InputInterface $input, OutputInterface $output) protected function doExecute(InputInterface $input, OutputInterface $output)
{ {
$root = $this->container['root.path']; $root = $this->container['root.path'];
$path = $this->container['cache.path'];
foreach ([ $paths = [
$root.'/config/configuration.yml', $root . '/config/configuration.yml',
$root.'/config/services.yml', $root . '/config/services.yml',
$root.'/config/connexions.yml', $root . '/config/connexions.yml',
$root.'/config/config.yml', $root . '/config/config.yml',
$root.'/config/config.inc', $root . '/config/config.inc',
$root.'/config/connexion.inc', $root . '/config/connexion.inc',
$root.'/config/_GV.php', $root . '/config/_GV.php',
$root.'/config/_GV.php.old', $root . '/config/_GV.php.old',
$root.'/config/configuration-compiled.php', $root . '/config/configuration-compiled.php',
] as $file) {
if ($this->container['filesystem']->exists($file)) {
unlink($file);
}
}
foreach ([
$this->container['tmp.download.path'], $this->container['tmp.download.path'],
$this->container['tmp.lazaret.path'], $this->container['tmp.lazaret.path'],
$this->container['tmp.caption.path'], $this->container['tmp.caption.path'],
$this->container['tmp.path'].'/sessions', $this->container['tmp.path'] . '/sessions',
$this->container['tmp.path'].'/locks', $this->container['tmp.path'] . '/locks',
] as $resource) { $path . '/cache_registry.php',
if (is_dir($resource)) { $path . '/cache_registry.yml',
$finder = new Finder(); $path . '/serializer',
foreach ($finder->files()->in($resource) as $file) { $path . '/doctrine',
$this->container['filesystem']->remove($file); $path . '/twig',
} $path . '/translations',
} elseif (is_file($resource)) { $path . '/minify',
$this->container['filesystem']->remove($resource); $path . '/profiler',
];
$files = $directories = [];
foreach ($paths as $path) {
if (is_dir($path)) {
$directories[] = $path;
} elseif (is_file($path)) {
$files[] = $path;
} }
} }
$path = $this->container['cache.path']; $this->container['filesystem']->remove($files);
foreach ([ $this->container['filesystem']->remove(Finder::create()->in($directories));
$path.'/cache_registry.php',
$path.'/cache_registry.yml',
$path.'/serializer',
$path.'/doctrine',
$path.'/twig',
$path.'/translations',
$path.'/minify',
$path.'/profiler',
] as $resource) {
if (is_dir($resource)) {
$finder = new Finder();
foreach ($finder->files()->in($resource) as $file) {
$this->container['filesystem']->remove($file);
}
} elseif (is_file($resource)) {
$this->container['filesystem']->remove($resource);
}
}
return 0; return 0;
} }

View File

@@ -43,7 +43,7 @@ class RecordAdd extends Command
protected function doExecute(InputInterface $input, OutputInterface $output) protected function doExecute(InputInterface $input, OutputInterface $output)
{ {
try { try {
$collection = \collection::get_from_base_id($this->container, $input->getArgument('base_id')); $collection = \collection::getByBaseId($this->container, $input->getArgument('base_id'));
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \InvalidArgumentException(sprintf('Collection %s is invalid', $input->getArgument('base_id'))); throw new \InvalidArgumentException(sprintf('Collection %s is invalid', $input->getArgument('base_id')));
} }

View File

@@ -12,6 +12,7 @@
namespace Alchemy\Phrasea\Command\Setup; namespace Alchemy\Phrasea\Command\Setup;
use Alchemy\Phrasea\Command\Command; use Alchemy\Phrasea\Command\Command;
use Alchemy\Phrasea\Databox\DataboxPathExtractor;
use Alchemy\Phrasea\Http\H264PseudoStreaming\H264Factory; use Alchemy\Phrasea\Http\H264PseudoStreaming\H264Factory;
use Alchemy\Phrasea\Model\Manipulator\TokenManipulator; use Alchemy\Phrasea\Model\Manipulator\TokenManipulator;
use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputArgument;
@@ -36,7 +37,8 @@ class H264MappingGenerator extends Command
*/ */
protected function doExecute(InputInterface $input, OutputInterface $output) protected function doExecute(InputInterface $input, OutputInterface $output)
{ {
$paths = $this->extractPath($this->container->getApplicationBox()); $extractor = new DataboxPathExtractor($this->container->getApplicationBox());
$paths = $extractor->extractPaths();
foreach ($paths as $path) { foreach ($paths as $path) {
$this->container['filesystem']->mkdir($path); $this->container['filesystem']->mkdir($path);
} }
@@ -95,22 +97,4 @@ class H264MappingGenerator extends Command
return ['mount-point' => 'mp4-videos-'.$n, 'directory' => $path, 'passphrase' => $this->container['random.low']->generateString(32, TokenManipulator::LETTERS_AND_NUMBERS)]; return ['mount-point' => 'mp4-videos-'.$n, 'directory' => $path, 'passphrase' => $this->container['random.low']->generateString(32, TokenManipulator::LETTERS_AND_NUMBERS)];
} }
private function extractPath(\appbox $appbox)
{
$paths = [];
foreach ($appbox->get_databoxes() as $databox) {
foreach ($databox->get_subdef_structure() as $group => $subdefs) {
if ('video' !== $group) {
continue;
}
foreach ($subdefs as $subdef) {
$paths[] = $subdef->get_path();
}
}
}
return array_filter(array_unique($paths));
}
} }

View File

@@ -12,6 +12,7 @@
namespace Alchemy\Phrasea\Command\Setup; namespace Alchemy\Phrasea\Command\Setup;
use Alchemy\Phrasea\Command\Command; use Alchemy\Phrasea\Command\Command;
use Alchemy\Phrasea\Databox\DataboxPathExtractor;
use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
@@ -35,7 +36,8 @@ class XSendFileMappingGenerator extends Command
*/ */
protected function doExecute(InputInterface $input, OutputInterface $output) protected function doExecute(InputInterface $input, OutputInterface $output)
{ {
$paths = $this->extractPath($this->container->getApplicationBox()); $extractor = new DataboxPathExtractor($this->container->getApplicationBox());
$paths = $extractor->extractPaths();
foreach ($paths as $path) { foreach ($paths as $path) {
$this->container['filesystem']->mkdir($path); $this->container['filesystem']->mkdir($path);
} }
@@ -84,20 +86,4 @@ class XSendFileMappingGenerator extends Command
return ['mount-point' => 'protected_dir_'.$n, 'directory' => $path]; return ['mount-point' => 'protected_dir_'.$n, 'directory' => $path];
} }
private function extractPath(\appbox $appbox)
{
$paths = [];
foreach ($appbox->get_databoxes() as $databox) {
$paths[] = (string) $databox->get_sxml_structure()->path;
foreach ($databox->get_subdef_structure() as $group => $subdefs) {
foreach ($subdefs as $subdef) {
$paths[] = $subdef->get_path();
}
}
}
return array_filter(array_unique($paths));
}
} }

View File

@@ -125,7 +125,7 @@ class Step31 implements DatasUpgraderInterface
$uuid = Uuid::uuid4(); $uuid = Uuid::uuid4();
try { try {
$media = $this->app->getMediaFromUri($pathfile); $media = $this->app->getMediaFromUri($pathfile);
$collection = \collection::get_from_coll_id($this->$app, $databox, (int) $record['coll_id']); $collection = \collection::getByCollectionId($this->$app, $databox, (int) $record['coll_id']);
$file = new File($this->app, $media, $collection); $file = new File($this->app, $media, $collection);
$uuid = $file->getUUID(true, true); $uuid = $file->getUUID(true, true);

View File

@@ -16,7 +16,6 @@ use Alchemy\Phrasea\Application\Helper\DataboxLoggerAware;
use Alchemy\Phrasea\Application\Helper\DelivererAware; use Alchemy\Phrasea\Application\Helper\DelivererAware;
use Alchemy\Phrasea\Http\DeliverDataInterface; use Alchemy\Phrasea\Http\DeliverDataInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
abstract class AbstractDelivery abstract class AbstractDelivery
{ {
@@ -33,26 +32,20 @@ abstract class AbstractDelivery
public function deliverContent(Request $request, \record_adapter $record, $subdef, $watermark, $stamp) public function deliverContent(Request $request, \record_adapter $record, $subdef, $watermark, $stamp)
{ {
$file = $record->get_subdef($subdef); $mediaSubdefinition = $record->get_subdef($subdef);
$pathOut = $file->get_pathfile();
if ($watermark === true && $file->get_type() === \media_subdef::TYPE_IMAGE) { $pathOut = $this->tamperProofSubDefinition($mediaSubdefinition, $watermark, $stamp);
$pathOut = \recordutils_image::watermark($this->app, $file);
} elseif ($stamp === true && $file->get_type() === \media_subdef::TYPE_IMAGE) {
$pathOut = \recordutils_image::stamp($this->app, $file);
}
$disposition = $request->query->get('download') ? DeliverDataInterface::DISPOSITION_ATTACHMENT : DeliverDataInterface::DISPOSITION_INLINE; $disposition = $request->query->get('download') ? DeliverDataInterface::DISPOSITION_ATTACHMENT : DeliverDataInterface::DISPOSITION_INLINE;
/** @var Response $response */ $response = $this->deliverFile($pathOut, $mediaSubdefinition->get_file(), $disposition, $mediaSubdefinition->get_mime());
$response = $this->deliverFile($pathOut, $file->get_file(), $disposition, $file->get_mime());
if (in_array($subdef, array('document', 'preview'))) { if (in_array($subdef, array('document', 'preview'))) {
$response->setPrivate(); $response->setPrivate();
$this->logView($record, $request); $this->logView($record, $request);
} elseif ($subdef !== 'thumbnail') { } elseif ($subdef !== 'thumbnail') {
try { try {
if ($file->getDataboxSubdef()->get_class() != \databox_subdef::CLASS_THUMBNAIL) { if ($mediaSubdefinition->getDataboxSubdef()->get_class() != \databox_subdef::CLASS_THUMBNAIL) {
$response->setPrivate(); $response->setPrivate();
$this->logView($record, $request); $this->logView($record, $request);
} }
@@ -81,4 +74,23 @@ abstract class AbstractDelivery
// Ignore exception // Ignore exception
} }
} }
/**
* @param \media_subdef $mediaSubdefinition
* @param bool $watermark
* @param bool $stamp
* @return string
*/
private function tamperProofSubDefinition(\media_subdef $mediaSubdefinition, $watermark, $stamp)
{
$pathOut = $mediaSubdefinition->getRealPath();
if ($watermark === true && $mediaSubdefinition->get_type() === \media_subdef::TYPE_IMAGE) {
$pathOut = \recordutils_image::watermark($this->app, $mediaSubdefinition);
} elseif ($stamp === true && $mediaSubdefinition->get_type() === \media_subdef::TYPE_IMAGE) {
$pathOut = \recordutils_image::stamp($this->app, $mediaSubdefinition);
}
return $pathOut;
}
} }

View File

@@ -33,7 +33,7 @@ class CollectionController extends Controller
*/ */
public function getCollection(Request $request, $bas_id) public function getCollection(Request $request, $bas_id)
{ {
$collection = \collection::get_from_base_id($this->app, $bas_id); $collection = \collection::getByBaseId($this->app, $bas_id);
$admins = []; $admins = [];
@@ -144,7 +144,7 @@ class CollectionController extends Controller
$success = false; $success = false;
$msg = $this->app->trans('An error occurred'); $msg = $this->app->trans('An error occurred');
$collection = \collection::get_from_base_id($this->app, $bas_id); $collection = \collection::getByBaseId($this->app, $bas_id);
try { try {
if ($collection->get_record_amount() <= 500) { if ($collection->get_record_amount() <= 500) {
$collection->empty_collection(500); $collection->empty_collection(500);
@@ -184,7 +184,7 @@ class CollectionController extends Controller
{ {
$success = false; $success = false;
$collection = \collection::get_from_base_id($this->app, $bas_id); $collection = \collection::getByBaseId($this->app, $bas_id);
try { try {
$this->app->getApplicationBox()->write_collection_pic( $this->app->getApplicationBox()->write_collection_pic(
@@ -224,7 +224,7 @@ class CollectionController extends Controller
{ {
$success = false; $success = false;
$collection = \collection::get_from_base_id($this->app, $bas_id); $collection = \collection::getByBaseId($this->app, $bas_id);
try { try {
$this->app->getApplicationBox()->write_collection_pic( $this->app->getApplicationBox()->write_collection_pic(
@@ -264,7 +264,7 @@ class CollectionController extends Controller
{ {
$success = false; $success = false;
$collection = \collection::get_from_base_id($this->app, $bas_id); $collection = \collection::getByBaseId($this->app, $bas_id);
try { try {
$collection->update_logo(null); $collection->update_logo(null);
@@ -323,7 +323,7 @@ class CollectionController extends Controller
]); ]);
} }
$collection = \collection::get_from_base_id($this->app, $bas_id); $collection = \collection::getByBaseId($this->app, $bas_id);
try { try {
$this->app->getApplicationBox()->write_collection_pic( $this->app->getApplicationBox()->write_collection_pic(
@@ -378,7 +378,7 @@ class CollectionController extends Controller
]); ]);
} }
$collection = \collection::get_from_base_id($this->app, $bas_id); $collection = \collection::getByBaseId($this->app, $bas_id);
try { try {
$this->app->getApplicationBox()->write_collection_pic( $this->app->getApplicationBox()->write_collection_pic(
@@ -432,7 +432,7 @@ class CollectionController extends Controller
]); ]);
} }
$collection = \collection::get_from_base_id($this->app, $bas_id); $collection = \collection::getByBaseId($this->app, $bas_id);
try { try {
$this->app->getApplicationBox()->write_collection_pic( $this->app->getApplicationBox()->write_collection_pic(
@@ -468,13 +468,13 @@ class CollectionController extends Controller
$success = false; $success = false;
$msg = $this->app->trans('An error occured'); $msg = $this->app->trans('An error occured');
$collection = \collection::get_from_base_id($this->app, $bas_id); $collection = \collection::getByBaseId($this->app, $bas_id);
try { try {
if ($collection->get_record_amount() > 0) { if ($collection->get_record_amount() > 0) {
$msg = $this->app->trans('Empty the collection before removing'); $msg = $this->app->trans('Empty the collection before removing');
} else { } else {
$collection->unmount_collection($this->app); $collection->unmount();
$collection->delete(); $collection->delete();
$success = true; $success = true;
$msg = $this->app->trans('Successful removal'); $msg = $this->app->trans('Successful removal');
@@ -522,10 +522,10 @@ class CollectionController extends Controller
{ {
$success = false; $success = false;
$collection = \collection::get_from_base_id($this->app, $bas_id); $collection = \collection::getByBaseId($this->app, $bas_id);
try { try {
$collection->unmount_collection($this->app); $collection->unmount();
$success = true; $success = true;
} catch (\Exception $e) { } catch (\Exception $e) {
@@ -562,7 +562,7 @@ class CollectionController extends Controller
$success = false; $success = false;
$collection = \collection::get_from_base_id($this->app, $bas_id); $collection = \collection::getByBaseId($this->app, $bas_id);
try { try {
$collection->set_name($name); $collection->set_name($name);
@@ -594,7 +594,7 @@ class CollectionController extends Controller
$this->app->abort(400, $this->app->trans('Invalid labels parameter')); $this->app->abort(400, $this->app->trans('Invalid labels parameter'));
} }
$collection = \collection::get_from_base_id($this->app, $bas_id); $collection = \collection::getByBaseId($this->app, $bas_id);
$success = true; $success = true;
try { try {
@@ -638,7 +638,7 @@ class CollectionController extends Controller
$success = false; $success = false;
$collection = \collection::get_from_base_id($this->app, $bas_id); $collection = \collection::getByBaseId($this->app, $bas_id);
try { try {
$collection->set_public_presentation($watermark); $collection->set_public_presentation($watermark);
@@ -671,7 +671,7 @@ class CollectionController extends Controller
{ {
$success = false; $success = false;
$collection = \collection::get_from_base_id($this->app, $bas_id); $collection = \collection::getByBaseId($this->app, $bas_id);
try { try {
$collection->enable($this->app->getApplicationBox()); $collection->enable($this->app->getApplicationBox());
@@ -704,7 +704,7 @@ class CollectionController extends Controller
{ {
$success = false; $success = false;
$collection = \collection::get_from_base_id($this->app, $bas_id); $collection = \collection::getByBaseId($this->app, $bas_id);
try { try {
$collection->disable($this->app->getApplicationBox()); $collection->disable($this->app->getApplicationBox());
@@ -736,7 +736,7 @@ class CollectionController extends Controller
{ {
/** @var \databox $databox */ /** @var \databox $databox */
$databox = $this->app->findDataboxById(\phrasea::sbasFromBas($this->app, $bas_id)); $databox = $this->app->findDataboxById(\phrasea::sbasFromBas($this->app, $bas_id));
$collection = \collection::get_from_base_id($this->app, $bas_id); $collection = \collection::getByBaseId($this->app, $bas_id);
$structFields = $suggestedValues = $basePrefs = []; $structFields = $suggestedValues = $basePrefs = [];
/** @var \databox_field $meta */ /** @var \databox_field $meta */
@@ -806,7 +806,7 @@ class CollectionController extends Controller
{ {
$success = false; $success = false;
$collection = \collection::get_from_base_id($this->app, $bas_id); $collection = \collection::getByBaseId($this->app, $bas_id);
$prefs = $request->request->get('str'); $prefs = $request->request->get('str');
try { try {
@@ -843,7 +843,7 @@ class CollectionController extends Controller
*/ */
public function getDetails($bas_id) public function getDetails($bas_id)
{ {
$collection = \collection::get_from_base_id($this->app, $bas_id); $collection = \collection::getByBaseId($this->app, $bas_id);
$out = ['total' => ['totobj' => 0, 'totsiz' => 0, 'mega' => '0', 'giga' => '0'], 'result' => []]; $out = ['total' => ['totobj' => 0, 'totsiz' => 0, 'mega' => '0', 'giga' => '0'], 'result' => []];

View File

@@ -124,6 +124,10 @@ class DashboardController extends Controller
public function addAdmins(Request $request) public function addAdmins(Request $request)
{ {
$admins = $request->request->get('admins', []); $admins = $request->request->get('admins', []);
// Remove empty values
$admins = array_filter($admins);
if (!is_array($admins) || count($admins) === 0) { if (!is_array($admins) || count($admins) === 0) {
$this->app->abort(400, '"admins" parameter must contains at least one value.'); $this->app->abort(400, '"admins" parameter must contains at least one value.');
} }
@@ -134,6 +138,15 @@ class DashboardController extends Controller
} }
$userRepository = $this->getUserRepository(); $userRepository = $this->getUserRepository();
$demotedAdmins = [];
foreach ($userRepository->findAdmins() as $admin) {
if (!in_array($admin->getId(), $admins)) {
$demotedAdmins[$admin->getId()] = $admin;
}
}
$userRepository->findBy(['id' => $admins]); $userRepository->findBy(['id' => $admins]);
$admins = array_map(function ($usrId) use ($userRepository) { $admins = array_map(function ($usrId) use ($userRepository) {
if (null === $user = $userRepository->find($usrId)) { if (null === $user = $userRepository->find($usrId)) {
@@ -145,7 +158,10 @@ class DashboardController extends Controller
/** @var UserManipulator $userManipulator */ /** @var UserManipulator $userManipulator */
$userManipulator = $this->app['manipulator.user']; $userManipulator = $this->app['manipulator.user'];
$userManipulator->demote($demotedAdmins);
$userManipulator->promote($admins); $userManipulator->promote($admins);
/** @var ACLManipulator $aclManipulator */ /** @var ACLManipulator $aclManipulator */
$aclManipulator = $this->app['manipulator.acl']; $aclManipulator = $this->app['manipulator.acl'];
$aclManipulator->resetAdminRights($admins); $aclManipulator->resetAdminRights($admins);

View File

@@ -633,7 +633,7 @@ class DataboxController extends Controller
{ {
try { try {
foreach ($request->request->get('order', []) as $data) { foreach ($request->request->get('order', []) as $data) {
$collection = \collection::get_from_base_id($this->app, $data['id']); $collection = \collection::getByBaseId($this->app, $data['id']);
$collection->set_ord($data['offset']); $collection->set_ord($data['offset']);
} }
$success = true; $success = true;
@@ -712,7 +712,7 @@ class DataboxController extends Controller
} catch (\Exception $e) { } catch (\Exception $e) {
return $this->app->redirectPath('admin_database_submit_collection', [ return $this->app->redirectPath('admin_database_submit_collection', [
'databox_id' => $databox_id, 'databox_id' => $databox_id,
'error' => 'error', 'error' => $e->getMessage(),
]); ]);
} }
} }

View File

@@ -56,7 +56,7 @@ class FeedController extends Controller
if ($request->request->get('public') == '1') { if ($request->request->get('public') == '1') {
$feed->setIsPublic(true); $feed->setIsPublic(true);
} elseif ($request->request->get('base_id')) { } elseif ($request->request->get('base_id')) {
$feed->setCollection(\collection::get_from_base_id($this->app, $request->request->get('base_id'))); $feed->setCollection(\collection::getByBaseId($this->app, $request->request->get('base_id')));
} }
$publisher->setFeed($feed); $publisher->setFeed($feed);
@@ -106,7 +106,7 @@ class FeedController extends Controller
} }
try { try {
$collection = \collection::get_from_base_id($this->app, $request->request->get('base_id')); $collection = \collection::getByBaseId($this->app, $request->request->get('base_id'));
} catch (\Exception $e) { } catch (\Exception $e) {
$collection = null; $collection = null;
} }

View File

@@ -32,8 +32,7 @@ class RootController extends Controller
'module' => 'admin', 'module' => 'admin',
'events' => $this->app['events-manager'], 'events' => $this->app['events-manager'],
'module_name' => 'Admin', 'module_name' => 'Admin',
'notice' => $request->query->get("notice"), 'notice' => $request->query->get("notice")
'tree' => $this->render('admin/tree.html.twig', $params),
], $params)); ], $params));
} }

View File

@@ -455,7 +455,7 @@ class UserController extends Controller
$registrationRepository->getUserRegistrations( $registrationRepository->getUserRegistrations(
$user, $user,
array_map(function ($baseId) { array_map(function ($baseId) {
return \collection::get_from_base_id($this->app, $baseId); return \collection::getByBaseId($this->app, $baseId);
}, $bases) }, $bases)
) as $registration) { ) as $registration) {
$registrationManipulator->rejectRegistration($registration); $registrationManipulator->rejectRegistration($registration);
@@ -473,7 +473,7 @@ class UserController extends Controller
foreach ($registrationRepository->getUserRegistrations( foreach ($registrationRepository->getUserRegistrations(
$user, $user,
array_map(function ($baseId) { array_map(function ($baseId) {
return \collection::get_from_base_id($this->app, $baseId); return \collection::getByBaseId($this->app, $baseId);
}, $bases) }, $bases)
) as $registration) { ) as $registration) {
$done[$usr][$registration->getBaseId()] = true; $done[$usr][$registration->getBaseId()] = true;
@@ -503,7 +503,7 @@ class UserController extends Controller
]; ];
foreach ($bases as $bas => $isok) { foreach ($bases as $bas => $isok) {
$collection = \collection::get_from_base_id($this->app, $bas); $collection = \collection::getByBaseId($this->app, $bas);
$label = $collection->get_label($this->app['locale']); $label = $collection->get_label($this->app['locale']);
if ($isok) { if ($isok) {

View File

@@ -837,7 +837,7 @@ class V1Controller extends Controller
return $this->getBadRequestAction($request, 'Missing base_id parameter'); return $this->getBadRequestAction($request, 'Missing base_id parameter');
} }
$collection = \collection::get_from_base_id($this->app, $request->get('base_id')); $collection = \collection::getByBaseId($this->app, $request->get('base_id'));
if (!$this->getAclForUser()->has_right_on_base($request->get('base_id'), 'canaddrecord')) { if (!$this->getAclForUser()->has_right_on_base($request->get('base_id'), 'canaddrecord')) {
return Result::createError($request, 403, sprintf( return Result::createError($request, 403, sprintf(
@@ -935,7 +935,7 @@ class V1Controller extends Controller
$media = $this->app->getMediaFromUri($file->getPathname()); $media = $this->app->getMediaFromUri($file->getPathname());
$record = $this->findDataboxById($request->get('databox_id'))->get_record($request->get('record_id')); $record = $this->findDataboxById($request->get('databox_id'))->get_record($request->get('record_id'));
$base_id = $record->getBaseId(); $base_id = $record->getBaseId();
$collection = \collection::get_from_base_id($this->app, $base_id); $collection = \collection::getByBaseId($this->app, $base_id);
if (!$this->getAclForUser()->has_right_on_base($base_id, 'canaddrecord')) { if (!$this->getAclForUser()->has_right_on_base($base_id, 'canaddrecord')) {
return Result::createError($request, 403, sprintf( return Result::createError($request, 403, sprintf(
'You do not have access to collection %s', $collection->get_label($this->app['locale.I18n']) 'You do not have access to collection %s', $collection->get_label($this->app['locale.I18n'])
@@ -943,7 +943,7 @@ class V1Controller extends Controller
} }
$adapt = ($request->get('adapt')===null || !(\p4field::isno($request->get('adapt')))); $adapt = ($request->get('adapt')===null || !(\p4field::isno($request->get('adapt'))));
$ret['adapt'] = $adapt; $ret['adapt'] = $adapt;
$record->substitute_subdef($request->get('name'), $media, $this->app, $adapt); $this->getSubdefSubstituer()->substitute($record, $request->get('name'), $media, $adapt);
foreach ($record->get_embedable_medias() as $name => $media) { foreach ($record->get_embedable_medias() as $name => $media) {
if ($name == $request->get('name') && if ($name == $request->get('name') &&
null !== ($subdef = $this->listEmbeddableMedia($request, $record, $media))) { null !== ($subdef = $this->listEmbeddableMedia($request, $record, $media))) {
@@ -1611,7 +1611,7 @@ class V1Controller extends Controller
$record = $databox->get_record($record_id); $record = $databox->get_record($record_id);
try { try {
$collection = \collection::get_from_base_id($this->app, $request->get('base_id')); $collection = \collection::getByBaseId($this->app, $request->get('base_id'));
$record->move_to_collection($collection, $this->getApplicationBox()); $record->move_to_collection($collection, $this->getApplicationBox());
return Result::create($request, ["record" => $this->listRecord($request, $record)])->createResponse(); return Result::create($request, ["record" => $this->listRecord($request, $record)])->createResponse();
@@ -2067,7 +2067,7 @@ class V1Controller extends Controller
*/ */
protected function createStory($data) protected function createStory($data)
{ {
$collection = \collection::get_from_base_id($this->app, $data->{'base_id'}); $collection = \collection::getByBaseId($this->app, $data->{'base_id'});
if (!$this->getAclForUser()->has_right_on_base($collection->get_base_id(), 'canaddrecord')) { if (!$this->getAclForUser()->has_right_on_base($collection->get_base_id(), 'canaddrecord')) {
$this->app->abort(403, sprintf('You can not create a story on this collection %s', $collection->get_base_id())); $this->app->abort(403, sprintf('You can not create a story on this collection %s', $collection->get_base_id()));
@@ -2235,8 +2235,8 @@ class V1Controller extends Controller
if (!in_array($name, array('thumbnail', 'preview'))) { if (!in_array($name, array('thumbnail', 'preview'))) {
continue; continue;
} }
$media = $this->app->getMediaFromUri($value->get_pathfile()); $media = $this->app->getMediaFromUri($value->getRealPath());
$story->substitute_subdef($name, $media, $this->app); $this->getSubdefSubstituer()->substitute($story, $name, $media);
$this->getDataboxLogger($story->getDatabox())->log( $this->getDataboxLogger($story->getDatabox())->log(
$story, $story,
\Session_Logger::EVENT_SUBSTITUTE, \Session_Logger::EVENT_SUBSTITUTE,
@@ -2304,7 +2304,7 @@ class V1Controller extends Controller
$ret = [ 'success' => true ]; $ret = [ 'success' => true ];
} }
catch (AccountException $exception) { catch (AccountException $exception) {
$ret = [ 'success' => false, 'message' => _($exception->getMessage()) ]; $ret = [ 'success' => false, 'message' => $this->app->trans($exception->getMessage()) ];
} }
return Result::create($request, $ret)->createResponse(); return Result::create($request, $ret)->createResponse();
@@ -2327,7 +2327,7 @@ class V1Controller extends Controller
$service->updatePassword($command, null); $service->updatePassword($command, null);
$ret = ['success' => true]; $ret = ['success' => true];
} catch (AccountException $exception) { } catch (AccountException $exception) {
$ret = [ 'success' => false, 'message' => _($exception->getMessage()) ]; $ret = [ 'success' => false, 'message' => $this->app->trans($exception->getMessage()) ];
} }
} else { } else {
$ret = [ 'success' => false, 'message' => (string) $form->getErrorsAsString() ]; $ret = [ 'success' => false, 'message' => (string) $form->getErrorsAsString() ];
@@ -2567,4 +2567,12 @@ class V1Controller extends Controller
{ {
return $this->app['phraseanet.SE.logger']; return $this->app['phraseanet.SE.logger'];
} }
/**
* @return \Alchemy\Phrasea\Media\SubdefSubstituer
*/
private function getSubdefSubstituer()
{
return $this->app['subdef.substituer'];
}
} }

View File

@@ -52,18 +52,7 @@ class MediaAccessorController extends Controller
public function showAction(Request $request, $token) public function showAction(Request $request, $token)
{ {
try { list($sbas_id, $record_id, $subdef) = $this->validateToken($token);
$token = JWT::decode($token, $this->keyStorage, $this->allowedAlgorithms);
} catch (\UnexpectedValueException $exception) {
throw new NotFoundHttpException('Resource not found', $exception);
} catch (\Exception $exception) {
throw new BadRequestHttpException('Invalid token', $exception);
}
if (! isset($token->sdef) || !is_array($token->sdef) || count($token->sdef) !== 3) {
throw new BadRequestHttpException('sdef should be a sub-definition identifier.');
}
list ($sbas_id, $record_id, $subdef) = $token->sdef;
try { try {
$databox = $this->findDataboxById($sbas_id); $databox = $this->findDataboxById($sbas_id);
@@ -93,4 +82,39 @@ class MediaAccessorController extends Controller
return $response; return $response;
} }
/**
* @param string $token
* @return object
*/
public function decodeToken($token)
{
try {
return JWT::decode($token, $this->keyStorage, $this->allowedAlgorithms);
} catch (\UnexpectedValueException $exception) {
throw new NotFoundHttpException('Resource not found', $exception);
} catch (\Exception $exception) {
throw new BadRequestHttpException('Invalid token', $exception);
}
}
/**
* Validate token and returns triplet containing sbas_id, record_id and subdef.
*
* @param string|object $token
* @return array
*/
public function validateToken($token)
{
if (is_string($token)) {
$token = $this->decodeToken($token);
}
if (!isset($token->sdef) || !is_array($token->sdef) || count($token->sdef) !== 3) {
throw new BadRequestHttpException('sdef should be a sub-definition identifier.');
}
list ($sbas_id, $record_id, $subdef) = $token->sdef;
return array($sbas_id, $record_id, $subdef);
}
} }

View File

@@ -11,11 +11,12 @@
namespace Alchemy\Phrasea\Controller; namespace Alchemy\Phrasea\Controller;
use Alchemy\Embed\Media\Media; use Alchemy\Embed\Media\Media;
use Alchemy\Embed\Media\MediaInformation;
use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Application\Helper\ApplicationBoxAware;
use Alchemy\Phrasea\Authentication\ACLProvider; use Alchemy\Phrasea\Authentication\ACLProvider;
use Alchemy\Phrasea\Authentication\Authenticator; use Alchemy\Phrasea\Authentication\Authenticator;
use Alchemy\Phrasea\Model\Repositories\BasketElementRepository; use Alchemy\Phrasea\Model\Repositories\BasketElementRepository;
use Alchemy\Phrasea\Model\Repositories\FeedItemRepository;
use Alchemy\Phrasea\Model\Serializer\CaptionSerializer; use Alchemy\Phrasea\Model\Serializer\CaptionSerializer;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
@@ -23,20 +24,19 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class PermalinkController extends AbstractDelivery class PermalinkController extends AbstractDelivery
{ {
use ApplicationBoxAware;
/** @var ACLProvider */ /** @var ACLProvider */
private $acl; private $acl;
/** @var \appbox */
private $appbox;
/** @var Authenticator */ /** @var Authenticator */
private $authentication; private $authentication;
/** @var Media */ /** @var Media */
private $mediaService; private $mediaService;
public function __construct(Application $app, \appbox $appbox, ACLProvider $acl, Authenticator $authenticator, Media $mediaService) public function __construct(Application $app, ACLProvider $acl, Authenticator $authenticator, Media $mediaService)
{ {
parent::__construct($app); parent::__construct($app);
$this->appbox = $appbox;
$this->acl = $acl; $this->acl = $acl;
$this->authentication = $authenticator; $this->authentication = $authenticator;
$this->mediaService = $mediaService; $this->mediaService = $mediaService;
@@ -44,9 +44,9 @@ class PermalinkController extends AbstractDelivery
public function getOptionsResponse(Request $request, $sbas_id, $record_id) public function getOptionsResponse(Request $request, $sbas_id, $record_id)
{ {
$databox = $this->mediaService->getDatabox($sbas_id); $databox = $this->findDataboxById($sbas_id);
$token = $request->query->get('token'); $token = $request->query->get('token');
$record = $this->mediaService->retrieveRecord($databox, $token, $record_id, $request->get('subdef', 'thumbnail')); $record = $this->retrieveRecord($databox, $token, $record_id, $request->get('subdef', 'thumbnail'));
if (null === $record) { if (null === $record) {
throw new NotFoundHttpException("Record not found"); throw new NotFoundHttpException("Record not found");
@@ -57,9 +57,9 @@ class PermalinkController extends AbstractDelivery
public function deliverCaption(Request $request, $sbas_id, $record_id) public function deliverCaption(Request $request, $sbas_id, $record_id)
{ {
$databox = $this->mediaService->getDatabox($sbas_id); $databox = $this->findDataboxById($sbas_id);
$token = $request->query->get('token'); $token = $request->query->get('token');
$record = $this->mediaService->retrieveRecord($databox, $token, $record_id, \databox_subdef::CLASS_THUMBNAIL); $record = $this->retrieveRecord($databox, $token, $record_id, \databox_subdef::CLASS_THUMBNAIL);
if (null === $record) { if (null === $record) {
throw new NotFoundHttpException("Caption not found"); throw new NotFoundHttpException("Caption not found");
@@ -74,7 +74,38 @@ class PermalinkController extends AbstractDelivery
return $this->doDeliverPermaview($sbas_id, $record_id, $request->query->get('token'), $subdef); return $this->doDeliverPermaview($sbas_id, $record_id, $request->query->get('token'), $subdef);
} }
public function deliverPermaviewOldWay($sbas_id, $record_id, $token, $subdef) private function doDeliverPermaview($sbas_id, $record_id, $token, $subdefName)
{
$databox = $this->findDataboxById($sbas_id);
$record = $this->retrieveRecord($databox, $token, $record_id, $subdefName);
$subdef = $record->get_subdef($subdefName);
$information = $this->mediaService->createMediaInformationFromResourceAndRoute(
$subdef,
'permalinks_permalink',
[
'sbas_id' => $sbas_id,
'record_id' => $record_id,
'subdef' => $subdefName,
'label' => $record->get_title(),
'token' => $token,
]
);
$metaData = $this->mediaService->getMetaData($information);
return $this->app['twig']->render('overview.html.twig', [
'ogMetaData' => $metaData['ogMetaData'],
'subdef' => $subdef,
'module_name' => 'overview',
'module' => 'overview',
'view' => 'overview',
'token' => $token,
'record' => $record,
'recordUrl' => $information->getUrl(),
]);
}
public function deliverPermaviewOldWay(Request $request, $sbas_id, $record_id, $token, $subdef)
{ {
return $this->doDeliverPermaview($sbas_id, $record_id, $token, $subdef); return $this->doDeliverPermaview($sbas_id, $record_id, $token, $subdef);
} }
@@ -84,35 +115,10 @@ class PermalinkController extends AbstractDelivery
return $this->doDeliverPermalink($request, $sbas_id, $record_id, $request->query->get('token'), $subdef); return $this->doDeliverPermalink($request, $sbas_id, $record_id, $request->query->get('token'), $subdef);
} }
public function deliverPermalinkOldWay(Request $request, $sbas_id, $record_id, $token, $subdef)
{
return $this->doDeliverPermalink($request, $sbas_id, $record_id, $token, $subdef);
}
private function doDeliverPermaview($sbas_id, $record_id, $token, $subdefName)
{
$databox = $this->mediaService->getDatabox($sbas_id);
$record = $this->mediaService->retrieveRecord($databox, $token, $record_id, $subdefName);
$metaDatas = $this->mediaService->getMetaDatas($record, $subdefName);
$subdef = $record->get_subdef($subdefName);
return $this->app['twig']->render('overview.html.twig', [
'ogMetaDatas' => $metaDatas['ogMetaDatas'],
'subdef' => $subdef,
'module_name' => 'overview',
'module' => 'overview',
'view' => 'overview',
'token' => $token,
'record' => $record,
]);
}
private function doDeliverPermalink(Request $request, $sbas_id, $record_id, $token, $subdef) private function doDeliverPermalink(Request $request, $sbas_id, $record_id, $token, $subdef)
{ {
$databox = $this->mediaService->getDatabox($sbas_id); $databox = $this->findDataboxById($sbas_id);
// $record = $this->retrieveRecord($databox, $token, $record_id, $subdef); $record = $this->retrieveRecord($databox, $token, $record_id, $subdef);
$record = $this->mediaService->retrieveRecord($databox, $token, $record_id, $subdef);
$watermark = $stamp = false; $watermark = $stamp = false;
if ($this->authentication->isAuthenticated()) { if ($this->authentication->isAuthenticated()) {
@@ -132,7 +138,7 @@ class PermalinkController extends AbstractDelivery
return $this->deliverContentWithCaptionLink($request, $record, $subdef, $watermark, $stamp, $token); return $this->deliverContentWithCaptionLink($request, $record, $subdef, $watermark, $stamp, $token);
} }
$collection = \collection::get_from_base_id($this->app, $record->get_base_id()); $collection = \collection::getByBaseId($this->app, $record->get_base_id());
switch ($collection->get_pub_wm()) { switch ($collection->get_pub_wm()) {
default: default:
case 'none': case 'none':
@@ -170,4 +176,42 @@ class PermalinkController extends AbstractDelivery
return $response; return $response;
} }
public function deliverPermalinkOldWay(Request $request, $sbas_id, $record_id, $token, $subdef)
{
return $this->doDeliverPermalink($request, $sbas_id, $record_id, $token, $subdef);
}
/**
* @param \databox $databox
* @param string $token
* @param int $record_id
* @param string $subdef
* @return \record_adapter
*/
private function retrieveRecord(\databox $databox, $token, $record_id, $subdef)
{
try {
$record = $databox->get_record($record_id);
$subDefinition = $record->get_subdef($subdef);
$permalink = $subDefinition->get_permalink();
} catch (\Exception $exception) {
throw new NotFoundHttpException('Wrong token.', $exception);
}
if (null === $permalink || !$permalink->get_is_activated()) {
throw new NotFoundHttpException('This token has been disabled.');
}
$feedItemsRepository = $this->app['repo.feed-items'];
if (in_array($subdef, [\databox_subdef::CLASS_PREVIEW, \databox_subdef::CLASS_THUMBNAIL])
&& $feedItemsRepository->isRecordInPublicFeed($databox->get_sbas_id(), $record_id)
) {
return $record;
} elseif ($permalink->get_token() == (string)$token) {
return $record;
}
throw new NotFoundHttpException('Wrong token.');
}
} }

View File

@@ -297,7 +297,7 @@ class EditController extends Controller
continue; continue;
} }
$media = $this->app->getMediaFromUri($value->get_pathfile()); $media = $this->app->getMediaFromUri($value->getRealPath());
$this->getSubDefinitionSubstituer()->substitute($reg_record, $name, $media); $this->getSubDefinitionSubstituer()->substitute($reg_record, $name, $media);
$this->getDispatcher()->dispatch(PhraseaEvents::RECORD_EDIT, new RecordEdit($reg_record)); $this->getDispatcher()->dispatch(PhraseaEvents::RECORD_EDIT, new RecordEdit($reg_record));
$this->getDataboxLogger($reg_record->get_databox())->log( $this->getDataboxLogger($reg_record->get_databox())->log(

View File

@@ -58,7 +58,7 @@ class MoveCollectionController extends Controller
} }
try { try {
$collection = \collection::get_from_base_id($this->app, $request->request->get('base_id')); $collection = \collection::getByBaseId($this->app, $request->request->get('base_id'));
} catch (\Exception_Databox_CollectionNotFound $e) { } catch (\Exception_Databox_CollectionNotFound $e) {
$datas['message'] = $this->app->trans('Invalid target collection'); $datas['message'] = $this->app->trans('Invalid target collection');

View File

@@ -30,13 +30,14 @@ class PropertyController extends Controller
$records = RecordsRequest::fromRequest($this->app, $request, false, ['chgstatus']); $records = RecordsRequest::fromRequest($this->app, $request, false, ['chgstatus']);
if (count($records->databoxes()) > 1) { $databoxes = $records->databoxes();
if (count($databoxes) > 1) {
return new Response($this->render('prod/actions/Property/index.html.twig', [ return new Response($this->render('prod/actions/Property/index.html.twig', [
'records' => $records, 'records' => $records,
])); ]));
} }
$databox = current($records->databoxes()); $databox = reset($databoxes);
$statusStructure = $databox->getStatusStructure(); $statusStructure = $databox->getStatusStructure();
$recordsStatuses = []; $recordsStatuses = [];

View File

@@ -156,7 +156,11 @@ class QueryController extends Controller
. $this->app->trans('%total% reponses', ['%total%' => '<span>'.$result->getTotal().'</span>']) . '</a>'; . $this->app->trans('%total% reponses', ['%total%' => '<span>'.$result->getTotal().'</span>']) . '</a>';
$json['infos'] = $infoResult; $json['infos'] = $infoResult;
$json['navigation'] = $string; $json['navigationTpl'] = $string;
$json['navigation'] = [
'page' => $page,
'perPage' => $perPage
];
$prop = null; $prop = null;

View File

@@ -41,35 +41,13 @@ class ShareController extends Controller
$preview = $record->get_preview(); $preview = $record->get_preview();
if ($preview->get_permalink() !== null) { if (null !== $previewLink = $preview->get_permalink()) {
$permalinkUrl = $previewLink->get_url();
$permaviewUrl = $previewLink->get_page();
$previewWidth = $preview->get_width();
$previewHeight = $preview->get_height();
$embedUrl = $this->app->url('alchemy_embed_view', ['url' => (string)$permalinkUrl]);
$subdefName = $preview->get_name();
$subdef = $record->get_subdef($subdefName);
switch ($record->getType()) {
case 'flexpaper':
case 'document':
case 'audio':
case 'video':
default:
$token = $preview->get_permalink()->get_token();
$permalinkUrl = $preview->get_permalink()->get_url();
$permaviewUrl = $preview->get_permalink()->get_page();
$previewWidth = $preview->get_width();
$previewHeight = $preview->get_height();
break;
}
$sbas_id = $record->getDataboxId();
$embedUrl = $this->app->url('alchemy_embed_view', [
'sbas_id' => $sbas_id,
'record_id' => $record_id,
'subdefName' => $subdefName,
'token' => $token,
]);
$outputVars = [ $outputVars = [
'isAvailable' => true, 'isAvailable' => true,

View File

@@ -33,7 +33,7 @@ class StoryController extends Controller
public function postCreateFormAction(Request $request) public function postCreateFormAction(Request $request)
{ {
$collection = \collection::get_from_base_id($this->app, $request->request->get('base_id')); $collection = \collection::getByBaseId($this->app, $request->request->get('base_id'));
if (!$this->getAclForUser()->has_right_on_base($collection->get_base_id(), 'canaddrecord')) { if (!$this->getAclForUser()->has_right_on_base($collection->get_base_id(), 'canaddrecord')) {
throw new AccessDeniedHttpException('You can not create a story on this collection'); throw new AccessDeniedHttpException('You can not create a story on this collection');

View File

@@ -83,7 +83,7 @@ class ToolsController extends Controller
if (!$record->isStory()) { if (!$record->isStory()) {
try { try {
$metadata = $this->getExifToolReader() $metadata = $this->getExifToolReader()
->files($record->get_subdef('document')->get_pathfile()) ->files($record->get_subdef('document')->getRealPath())
->first()->getMetadatas(); ->first()->getMetadatas();
} catch (PHPExiftoolException $e) { } catch (PHPExiftoolException $e) {
// ignore // ignore

View File

@@ -133,7 +133,7 @@ class UploadController extends Controller
$this->getFilesystem()->rename($uploadedFilename, $renamedFilename); $this->getFilesystem()->rename($uploadedFilename, $renamedFilename);
$media = $this->app->getMediaFromUri($renamedFilename); $media = $this->app->getMediaFromUri($renamedFilename);
$collection = \collection::get_from_base_id($this->app, $base_id); $collection = \collection::getByBaseId($this->app, $base_id);
$lazaretSession = new LazaretSession(); $lazaretSession = new LazaretSession();
$lazaretSession->setUser($this->getAuthenticatedUser()); $lazaretSession->setUser($this->getAuthenticatedUser());

View File

@@ -316,7 +316,7 @@ class AccountController extends Controller
if (0 !== count($registrations)) { if (0 !== count($registrations)) {
foreach ($registrations as $baseId) { foreach ($registrations as $baseId) {
$this->getRegistrationManipulator() $this->getRegistrationManipulator()
->createRegistration($user, \collection::get_from_base_id($this->app, $baseId)); ->createRegistration($user, \collection::getByBaseId($this->app, $baseId));
} }
$this->app->addFlash('success', $this->app->trans('Your registration requests have been taken into account.')); $this->app->addFlash('success', $this->app->trans('Your registration requests have been taken into account.'));
} }

View File

@@ -82,7 +82,7 @@ class SessionController extends Controller
if (in_array($this->getSession()->get('phraseanet.message'), ['1', null])) { if (in_array($this->getSession()->get('phraseanet.message'), ['1', null])) {
if ($this->app['phraseanet.configuration']['main']['maintenance']) { if ($this->app['phraseanet.configuration']['main']['maintenance']) {
$ret['message'] .= _('The application is going down for maintenance, please logout.'); $ret['message'] .= $this->app->trans('The application is going down for maintenance, please logout.');
} }
if ($this->getConf()->get(['registry', 'maintenance', 'enabled'], false)) { if ($this->getConf()->get(['registry', 'maintenance', 'enabled'], false)) {

View File

@@ -0,0 +1,106 @@
<?php
namespace Alchemy\Phrasea\ControllerProvider;
use Alchemy\EmbedProvider\EmbedServiceProvider;
use Silex\Application;
use Silex\ServiceProviderInterface;
class ControllerProviderServiceProvider implements ServiceProviderInterface
{
private $controllerProviders = [];
/**
* Registers services on the given app.
*
* This method should only be used to configure services and parameters.
* It should not get services.
*/
public function register(Application $app)
{
$this->loadProviders();
foreach ($this->controllerProviders as $class => $values) {
$app->register(new $class, $values);
}
}
/**
* Bootstraps the application.
*
* This method is called after all services are registered
* and should be used for "dynamic" configuration (whenever
* a service must be requested).
*/
public function boot(Application $app)
{
// Nothing to do here
}
public function loadProviders()
{
$this->controllerProviders = [
Admin\Collection::class => [],
Admin\ConnectedUsers::class => [],
Admin\Dashboard::class => [],
Admin\Databox::class => [],
Admin\Databoxes::class => [],
Admin\Feeds::class => [],
Admin\Fields::class => [],
Admin\Plugins::class => [],
Admin\Root::class => [],
Admin\SearchEngine::class => [],
Admin\Setup::class => [],
Admin\Subdefs::class => [],
Admin\TaskManager::class => [],
Admin\Users::class => [],
Client\Root::class => [],
Datafiles::class => [],
Lightbox::class => [],
MediaAccessor::class => [],
Minifier::class => [],
Permalink::class => [],
Prod\BasketProvider::class => [],
Prod\Bridge::class => [],
Prod\DoDownload::class => [],
Prod\Download::class => [],
Prod\Edit::class => [],
Prod\Export::class => [],
Prod\Feed::class => [],
Prod\Language::class => [],
Prod\Lazaret::class => [],
Prod\MoveCollection::class => [],
Prod\Order::class => [],
Prod\Printer::class => [],
Prod\Property::class => [],
Prod\Push::class => [],
Prod\Query::class => [],
Prod\Record::class => [],
Prod\Root::class => [],
Prod\Share::class => [],
Prod\Story::class => [],
Prod\Tools::class => [],
Prod\Tooltip::class => [],
Prod\TOU::class => [],
Prod\Upload::class => [],
Prod\UsrLists::class => [],
Prod\WorkZone::class => [],
Report\Activity::class => [],
Report\Information::class => [],
Report\Root::class => [],
Root\Account::class => [],
Root\Developers::class => [],
Root\Login::class => [],
Root\Root::class => [],
Root\RSSFeeds::class => [],
Root\Session::class => [],
Setup::class => [],
Thesaurus\Thesaurus::class => [],
Thesaurus\Xmlhttp::class => [],
User\Notifications::class => [],
User\Preferences::class => [],
EmbedServiceProvider::class => [],
];
}
}

View File

@@ -24,9 +24,15 @@ class Permalink implements ControllerProviderInterface, ServiceProviderInterface
public function register(Application $app) public function register(Application $app)
{ {
$app['controller.permalink'] = $app->share(function (PhraseaApplication $app) { $app['controller.permalink'] = $app->share(function (PhraseaApplication $app) {
return (new PermalinkController($app, $app->getApplicationBox(), $app['acl'], $app->getAuthenticator(), $app['alchemy_embed.service.media'])) return (new PermalinkController(
$app,
$app['acl'],
$app->getAuthenticator(),
$app['alchemy_embed.service.media']
))
->setDataboxLoggerLocator($app['phraseanet.logger']) ->setDataboxLoggerLocator($app['phraseanet.logger'])
->setDelivererLocator(new LazyLocator($app, 'phraseanet.file-serve')) ->setDelivererLocator(new LazyLocator($app, 'phraseanet.file-serve'))
->setApplicationBox($app['phraseanet.appbox'])
; ;
}); });
} }

View File

@@ -1,9 +1,8 @@
<?php <?php
/**
/*
* This file is part of Phraseanet * This file is part of Phraseanet
* *
* (c) 2005-2014 Alchemy * (c) 2005-2016 Alchemy
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@@ -11,37 +10,63 @@
namespace Alchemy\Phrasea\Core\Configuration; namespace Alchemy\Phrasea\Core\Configuration;
use Alchemy\Phrasea\Cache\Cache;
use Alchemy\Phrasea\Model\Entities\Collection;
use Alchemy\Phrasea\Model\Entities\Databox;
use Assert\Assertion; use Assert\Assertion;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
class AccessRestriction class AccessRestriction
{ {
private $conf; /**
private $appbox; * @var PropertyAccess
private $logger; */
private $cache; private $propertyAccess;
public function __construct(Cache $cache, PropertyAccess $conf, \appbox $appbox, LoggerInterface $logger) /**
* @var \appbox
*/
private $appbox;
/**
* @var LoggerInterface
*/
private $logger;
/**
* @var bool
*/
private $loaded = false;
/**
* @var bool
*/
private $restricted = false;
/**
* @var array
*/
private $availableDataboxes = [];
/**
* @var array
*/
private $availableCollections = [];
public function __construct(PropertyAccess $propertyAccess, \appbox $appbox, LoggerInterface $logger)
{ {
$this->conf = $conf; $this->propertyAccess = $propertyAccess;
$this->appbox = $appbox; $this->appbox = $appbox;
$this->logger = $logger; $this->logger = $logger;
$this->cache = $cache;
} }
/** /**
* Returns true if a configuration is set. * Returns true if a configuration is set.
* *
* @return Boolean * @return bool
*/ */
public function isRestricted() public function isRestricted()
{ {
$this->load(); $this->load();
return $this->cache->fetch('restricted'); return $this->restricted;
} }
/** /**
@@ -49,7 +74,7 @@ class AccessRestriction
* *
* @param \databox $databox * @param \databox $databox
* *
* @return Boolean * @return bool
*/ */
public function isDataboxAvailable(\databox $databox) public function isDataboxAvailable(\databox $databox)
{ {
@@ -57,7 +82,7 @@ class AccessRestriction
return true; return true;
} }
return in_array($databox->get_sbas_id(), $this->cache->fetch('available_databoxes'), true); return in_array($databox->get_sbas_id(), $this->availableDataboxes, true);
} }
/** /**
@@ -72,7 +97,7 @@ class AccessRestriction
return $databoxes; return $databoxes;
} }
$available = array_flip($this->cache->fetch('available_databoxes')); $available = array_flip($this->availableDataboxes);
return array_filter($databoxes, function (\databox $databox) use ($available) { return array_filter($databoxes, function (\databox $databox) use ($available) {
return isset($available[$databox->get_sbas_id()]); return isset($available[$databox->get_sbas_id()]);
@@ -84,7 +109,7 @@ class AccessRestriction
* *
* @param \collection $collection * @param \collection $collection
* *
* @return Boolean * @return bool
*/ */
public function isCollectionAvailable(\collection $collection) public function isCollectionAvailable(\collection $collection)
{ {
@@ -92,30 +117,31 @@ class AccessRestriction
return true; return true;
} }
$availableCollections = $this->cache->fetch('available_collections_'.$collection->get_databox()->get_sbas_id()) ?: []; $availableCollections = isset($this->availableCollections[$collection->get_sbas_id()])
? $this->availableCollections[$collection->get_sbas_id()] : [];
return in_array($collection->get_base_id(), $availableCollections, true); return in_array($collection->get_base_id(), $availableCollections, true);
} }
private function load() private function load()
{ {
if ($this->cache->fetch('loaded')) { if ($this->loaded) {
return; return;
} }
$this->cache->save('loaded', true); $this->loaded = true;
$allowedDataboxIds = array_map(function ($dbConf) { $allowedDataboxIds = array_map(function ($dbConf) {
return $dbConf['id']; return $dbConf['id'];
}, $this->conf->get('databoxes', [])); }, $this->propertyAccess->get('databoxes', []));
if (count($allowedDataboxIds) === 0) { if (count($allowedDataboxIds) === 0) {
$this->cache->save('restricted', false); $this->restricted = false;
return; return;
} }
$this->cache->save('restricted', true); $this->restricted = true;
$databoxIds = array_map(function (\databox $databox) { return $databox->get_sbas_id(); }, $this->appbox->get_databoxes()); $databoxIds = array_map(function (\databox $databox) { return $databox->get_sbas_id(); }, $this->appbox->get_databoxes());
$errors = array_diff($allowedDataboxIds, $databoxIds); $errors = array_diff($allowedDataboxIds, $databoxIds);
@@ -124,18 +150,15 @@ class AccessRestriction
$this->logger->error(sprintf('Misconfiguration for allowed databoxes : ids %s do not exist', implode(', ', $errors))); $this->logger->error(sprintf('Misconfiguration for allowed databoxes : ids %s do not exist', implode(', ', $errors)));
} }
$allowedDataboxIds = array_intersect($allowedDataboxIds, $databoxIds); $this->availableDataboxes = array_intersect($allowedDataboxIds, $databoxIds);
$this->cache->save('available_databoxes', $allowedDataboxIds);
$this->loadCollections(); $this->loadCollections();
} }
private function loadCollections() private function loadCollections()
{ {
$allowedDataboxIds = $this->cache->fetch('available_databoxes'); foreach ($this->propertyAccess->get('databoxes') as $databox) {
if (!in_array($databox['id'], $this->availableDataboxes, true)) {
foreach ($this->conf->get('databoxes') as $databox) {
if (!in_array($databox['id'], $allowedDataboxIds, true)) {
continue; continue;
} }
@@ -148,9 +171,7 @@ class AccessRestriction
$this->logger->error(sprintf('Misconfiguration for allowed collections : ids %s do not exist', implode(', ', $errors))); $this->logger->error(sprintf('Misconfiguration for allowed collections : ids %s do not exist', implode(', ', $errors)));
} }
$collections = array_intersect($collections, $availableBaseIds); $this->availableCollections[$databox['id']] = array_intersect($collections, $availableBaseIds);
$this->cache->save('available_collections_'.$databox['id'], $collections);
} }
} }
} }

View File

@@ -33,7 +33,7 @@ class DisplaySettingService
'warning_on_delete_story' => 'true', 'warning_on_delete_story' => 'true',
'client_basket_status' => '1', 'client_basket_status' => '1',
'css' => '000000', 'css' => '000000',
'start_page_query' => 'last', 'start_page_query' => '',
'start_page' => 'QUERY', 'start_page' => 'QUERY',
'rollover_thumbnail' => 'caption', 'rollover_thumbnail' => 'caption',
'technical_display' => '1', 'technical_display' => '1',

View File

@@ -0,0 +1,120 @@
<?php
namespace Alchemy\Phrasea\Core\Event\Subscriber;
use Alchemy\Phrasea\Cache\Cache;
use Alchemy\Phrasea\Core\Profiler\TraceableCache;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;
class CacheStatisticsSubscriber implements EventSubscriberInterface
{
/**
* @var Cache
*/
private $cache;
/**
* @var string
*/
private $cacheType = '';
/**
* @var array
*/
private $stats = [];
/**
* @param Cache $cache
*/
public function __construct(Cache $cache)
{
$this->cache = $cache;
$this->cacheType = $cache->getName();
}
public function getCacheNamespace()
{
if ($this->cache instanceof TraceableCache) {
return $this->cache->getNamespace();
}
return '[ root ]';
}
public function getCallSummary()
{
if ($this->cache instanceof TraceableCache) {
return $this->cache->getSummary();
}
return [
'calls' => 0,
'hits' => 0,
'misses' => 0,
'calls_by_type' => [],
'calls_by_key' => []
];
}
public function getCalls()
{
if ($this->cache instanceof TraceableCache) {
return $this->cache->getCalls();
}
return [];
}
public function getTimeSpent()
{
if ($this->cache instanceof TraceableCache) {
return $this->cache->getTotalTime();
}
return 0;
}
public function getCacheType()
{
return $this->cacheType;
}
public function getInitialStats()
{
return $this->stats;
}
public function getCurrentStats()
{
return $this->cache->getStats();
}
public function onKernelRequest()
{
$this->stats = $this->cache->getStats();
}
/**
* Returns an array of event names this subscriber wants to listen to.
*
* The array keys are event names and the value can be:
*
* * The method name to call (priority defaults to 0)
* * An array composed of the method name to call and the priority
* * An array of arrays composed of the method names to call and respective
* priorities, or 0 if unset
*
* For instance:
*
* * array('eventName' => 'methodName')
* * array('eventName' => array('methodName', $priority))
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
*
* @return array The event names to listen to
*/
public static function getSubscribedEvents()
{
return [ KernelEvents::REQUEST => [ 'onKernelRequest', 2048 ] ];
}
}

View File

@@ -37,10 +37,6 @@ class DebuggerSubscriber implements EventSubscriberInterface
public function checkIp(GetResponseEvent $event) public function checkIp(GetResponseEvent $event)
{ {
if (Application::ENV_DEV !== $this->app->getEnvironment()) {
return;
}
if ($this->app['configuration.store']->isSetup() && $this->app['conf']->has(['debugger', 'allowed-ips'])) { if ($this->app['configuration.store']->isSetup() && $this->app['conf']->has(['debugger', 'allowed-ips'])) {
$allowedIps = $this->app['conf']->get(['debugger', 'allowed-ips']); $allowedIps = $this->app['conf']->get(['debugger', 'allowed-ips']);
$allowedIps = is_array($allowedIps) ? $allowedIps : [$allowedIps]; $allowedIps = is_array($allowedIps) ? $allowedIps : [$allowedIps];

View File

@@ -1,9 +1,8 @@
<?php <?php
/* /*
* This file is part of Phraseanet * This file is part of Phraseanet
* *
* (c) 2005-2014 Alchemy * (c) 2005-2016 Alchemy
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@@ -107,9 +106,9 @@ class RegistrationSubscriber extends AbstractNotificationSubscriber
{ {
$body = ''; $body = '';
$body .= sprintf("Login : %s\n", $registeredUser->getLogin()); $body .= sprintf("Login : %s\n", $registeredUser->getLogin());
$body .= sprintf("%s : %s\n", _('admin::compte-utilisateur nom'), $registeredUser->getFirstName()); $body .= sprintf("%s : %s\n", $this->app->trans('admin::compte-utilisateur nom'), $registeredUser->getFirstName());
$body .= sprintf("%s : %s\n", _('admin::compte-utilisateur prenom'), $registeredUser->getLastName()); $body .= sprintf("%s : %s\n", $this->app->trans('admin::compte-utilisateur prenom'), $registeredUser->getLastName());
$body .= sprintf("%s : %s\n", _('admin::compte-utilisateur email'), $registeredUser->getEmail()); $body .= sprintf("%s : %s\n", $this->app->trans('admin::compte-utilisateur email'), $registeredUser->getEmail());
$body .= sprintf("%s/%s\n", $registeredUser->get_job(), $registeredUser->getCompany()); $body .= sprintf("%s/%s\n", $registeredUser->get_job(), $registeredUser->getCompany());
$readyToSend = false; $readyToSend = false;

View File

@@ -29,7 +29,7 @@ class TrustedProxySubscriber implements EventSubscriberInterface
public static function getSubscribedEvents() public static function getSubscribedEvents()
{ {
return [ return [
KernelEvents::REQUEST => ['setProxyConf', 0], KernelEvents::REQUEST => ['setProxyConf', 1024],
]; ];
} }

View File

@@ -0,0 +1,102 @@
<?php
namespace Alchemy\Phrasea\Core\MetaProvider;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Cache\Manager;
use Alchemy\Phrasea\Core\Provider\ORMServiceProvider;
use Dflydev\Silex\Provider\DoctrineOrm\DoctrineOrmServiceProvider;
use Doctrine\DBAL\Events;
use Doctrine\ORM\Configuration;
use Gedmo\DoctrineExtensions as GedmoExtension;
use Silex\Application;
use Silex\Provider\DoctrineServiceProvider;
use Silex\ServiceProviderInterface;
class DatabaseMetaProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$app->register(new DoctrineServiceProvider());
$this->setupDBAL($app);
$app->register(new DoctrineOrmServiceProvider());
$this->setupOrms($app);
$app->register(new ORMServiceProvider());
}
private function setupDBAL(PhraseaApplication $app)
{
$app['dbs.config'] = $app->share($app->extend('dbs.config', function ($configs, $app) {
if (! $app->isDebug()) {
return $configs;
}
foreach($configs->keys() as $service) {
$app['dbal.config.register.loggers']($configs[$service]);
}
return $configs;
}));
$app['dbs.event_manager'] = $app->share($app->extend('dbs.event_manager', function ($eventManagers, $app) {
foreach ($eventManagers->keys() as $name) {
/** @var EventManager $eventManager */
$eventManager = $eventManagers[$name];
$app['dbal.evm.register.listeners']($eventManager);
$eventManager->addEventListener(Events::postConnect, $app);
}
return $eventManagers;
}));
}
private function setupOrms(PhraseaApplication $app)
{
// Override "orm.cache.configurer" service provided for benefiting
// of "phraseanet.cache-service"
$app['orm.cache.configurer'] = $app->protect(function($name, Configuration $config, $options) use ($app) {
/** @var Manager $service */
$service = $app['phraseanet.cache-service'];
$config->setMetadataCacheImpl(
$service->factory('ORM_metadata', $app['orm.cache.driver'], $app['orm.cache.options'])
);
$config->setQueryCacheImpl(
$service->factory('ORM_query', $app['orm.cache.driver'], $app['orm.cache.options'])
);
$config->setResultCacheImpl(
$service->factory('ORM_result', $app['orm.cache.driver'], $app['orm.cache.options'])
);
$config->setHydrationCacheImpl(
$service->factory('ORM_hydration', $app['orm.cache.driver'], $app['orm.cache.options'])
);
});
$app['orm.proxies_dir'] = $app['root.path'].'/resources/proxies';
$app['orm.auto_generate_proxies'] = $app['debug'];
$app['orm.proxies_namespace'] = 'Alchemy\Phrasea\Model\Proxies';
$app['orm.ems'] = $app->share($app->extend('orm.ems', function (\Pimple $ems, $app) {
GedmoExtension::registerAnnotations();
foreach ($ems->keys() as $key) {
$app['orm.annotation.register']($key);
$connection = $ems[$key]->getConnection();
$app['connection.pool.manager']->add($connection);
$types = $app['orm.ems.options'][$key]['types'];
$app['dbal.type.register']($connection, $types);
}
return $ems;
}));
}
public function boot(Application $app)
{
// no-op
}
}

View File

@@ -0,0 +1,107 @@
<?php
namespace Alchemy\Phrasea\Core\MetaProvider;
use Alchemy\Cors\Options\DefaultProvider;
use Alchemy\CorsProvider\CorsServiceProvider;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderServiceProvider;
use Alchemy\Phrasea\Core\Provider\ContentNegotiationServiceProvider;
use Alchemy\Phrasea\Core\Provider\SessionHandlerServiceProvider;
use Silex\Application;
use Silex\Provider\HttpFragmentServiceProvider;
use Silex\Provider\SessionServiceProvider;
use Silex\Provider\UrlGeneratorServiceProvider;
use Silex\ServiceProviderInterface;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Component\Routing\RequestContext;
class HttpStackMetaProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
if (! $app instanceof PhraseaApplication) {
throw new \LogicException('Expected an instance Alchemy\Phrasea\Application');
}
$app->register(new HttpFragmentServiceProvider());
$app->register(new UrlGeneratorServiceProvider());
$this->setupRequestContext($app);
$app->register(new SessionHandlerServiceProvider());
$app->register(new SessionServiceProvider(), [
'session.test' => $app->getEnvironment() === PhraseaApplication::ENV_TEST,
'session.storage.options' => ['cookie_lifetime' => 0]
]);
$app['session.storage.test'] = $app->share(function () {
return new MockArraySessionStorage();
});
$app['session.storage.handler'] = $app->share(function (Application $app) {
if (!$app['phraseanet.configuration-tester']->isInstalled()) {
return new NullSessionHandler();
}
return $app['session.storage.handler.factory']->create($app['conf']);
});
$app->register(new ControllerProviderServiceProvider());
$this->registerCors($app);
}
public function setupRequestContext(Application $app)
{
$app['request_context'] = $app->share($app->extend('request_context', function (RequestContext $context, Application $app) {
if ($app['configuration.store']->isSetup()) {
$data = parse_url($app['conf']->get('servername'));
if (isset($data['scheme'])) {
$context->setScheme($data['scheme']);
}
if (isset($data['host'])) {
$context->setHost($data['host']);
}
}
return $context;
}));
}
public function registerCors(Application $app)
{
$app->register(new ContentNegotiationServiceProvider());
$app->register(new CorsServiceProvider(), [
'alchemy_cors.debug' => $app['debug'],
'alchemy_cors.cache_path' => function (Application $app) {
return rtrim($app['cache.path'], '/\\') . '/alchemy_cors.cache.php';
},
]);
$app['phraseanet.api_cors.options_provider'] = function (Application $app) {
$paths = [];
if (isset($app['phraseanet.configuration']['api_cors'])) {
$config = $app['phraseanet.configuration']['api_cors'];
if (isset($config['enabled']) && $config['enabled']) {
unset($config['enabled']);
$paths['/api/v\d+/'] = $config;
}
}
return new DefaultProvider($paths, []);
};
$app['alchemy_cors.options_providers'][] = 'phraseanet.api_cors.options_provider';
}
public function boot(Application $app)
{
// no-op
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace Alchemy\Phrasea\Core\MetaProvider;
use Alchemy\Phrasea\Core\Provider\MediaAlchemystServiceProvider as PhraseanetMediaAlchemystServiceProvider;
use FFMpeg\FFMpegServiceProvider;
use MediaAlchemyst\MediaAlchemystServiceProvider;
use MediaVorus\MediaVorusServiceProvider;
use MP4Box\MP4BoxServiceProvider;
use Neutron\Silex\Provider\ImagineServiceProvider;
use PHPExiftool\PHPExiftoolServiceProvider;
use Silex\Application;
use Silex\ServiceProviderInterface;
class MediaUtilitiesMetaServiceProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$app->register(new ImagineServiceProvider());
$app->register(new FFMpegServiceProvider());
$app->register(new MediaAlchemystServiceProvider());
$app->register(new PhraseanetMediaAlchemystServiceProvider());
$app->register(new MediaVorusServiceProvider());
$app->register(new MP4BoxServiceProvider());
$app->register(new PHPExiftoolServiceProvider());
$app['imagine.factory'] = $app->share(function (Application $app) {
if ($app['conf']->get(['registry', 'executables', 'imagine-driver']) != '') {
return $app['conf']->get(['registry', 'executables', 'imagine-driver']);
}
if (class_exists('\Gmagick')) {
return 'gmagick';
}
if (class_exists('\Imagick')) {
return 'imagick';
}
if (extension_loaded('gd')) {
return 'gd';
}
throw new \RuntimeException('No Imagine driver available');
});
}
public function boot(Application $app)
{
// no-op
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Alchemy\Phrasea\Core\MetaProvider;
use Alchemy\Phrasea\Core\Provider\TwigServiceProvider as PhraseanetTwigServiceProvider;
use Silex\Application;
use Silex\Provider\TwigServiceProvider;
use Silex\ServiceProviderInterface;
class TemplateEngineMetaProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$app->register(new TwigServiceProvider());
$app->register(new PhraseanetTwigServiceProvider());
}
public function boot(Application $app)
{
// no-op
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace Alchemy\Phrasea\Core\MetaProvider;
use Alchemy\Phrasea\Core\Provider\TranslationServiceProvider;
use Silex\Application;
use Silex\ServiceProviderInterface;
class TranslationMetaProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$app->register(new TranslationServiceProvider(), [
'locale_fallbacks' => ['fr'],
'translator.resources' => [
[ 'xlf', __DIR__.'/../../../../../resources/locales/messages.fr.xlf', 'fr', 'messages' ],
[ 'xlf', __DIR__.'/../../../../../resources/locales/validators.fr.xlf', 'fr', 'validators' ],
[ 'xlf', __DIR__.'/../../../../../resources/locales/messages.en.xlf', 'en', 'messages' ],
[ 'xlf', __DIR__.'/../../../../../resources/locales/validators.en.xlf', 'en', 'validators' ],
[ 'xlf', __DIR__.'/../../../../../resources/locales/messages.de.xlf', 'de', 'messages' ],
[ 'xlf', __DIR__.'/../../../../../resources/locales/validators.de.xlf', 'de', 'validators' ],
[ 'xlf', __DIR__.'/../../../../../resources/locales/messages.nl.xlf', 'nl', 'messages' ],
[ 'xlf', __DIR__.'/../../../../../resources/locales/validators.nl.xlf', 'nl', 'validators' ]
],
'translator.cache-options' => [
'debug' => $app['debug'],
'cache_dir' => $app->share(function($app) {
return $app['cache.path'] . '/translations';
}),
],
]);
}
public function boot(Application $app)
{
// no-op
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace Alchemy\Phrasea\Core\Middleware;
use Assert\Assertion;
use Silex\Application;
use Silex\ServiceProviderInterface;
use Symfony\Component\HttpFoundation\Request;
class SetupMiddlewareProvider implements ServiceProviderInterface
{
/**
* Registers services on the given app.
*
* This method should only be used to configure services and parameters.
* It should not get services.
* @param Application $app
*/
public function register(Application $app)
{
Assertion::isInstanceOf($app, \Alchemy\Phrasea\Application::class);
$app['setup.validate-config'] = $app->protect(function (Request $request) use ($app) {
if (0 === strpos($request->getPathInfo(), '/setup')) {
if (!$app['phraseanet.configuration-tester']->isInstalled()) {
if (!$app['phraseanet.configuration-tester']->isBlank()) {
if ('setup_upgrade_instructions' !== $app['request']->attributes->get('_route')) {
return $app->redirectPath('setup_upgrade_instructions');
}
}
} elseif (!$app['phraseanet.configuration-tester']->isBlank()) {
return $app->redirectPath('homepage');
}
} else {
if (false === strpos($request->getPathInfo(), '/include/minify')) {
$app['firewall']->requireSetup();
}
}
});
}
/**
* Bootstraps the application.
*
* This method is called after all services are registered
* and should be used for "dynamic" configuration (whenever
* a service must be requested).
*/
public function boot(Application $app)
{
// no-op
}
}

View File

@@ -0,0 +1,132 @@
<?php
namespace Alchemy\Phrasea\Core\Profiler;
use Alchemy\Phrasea\Core\Event\Subscriber\CacheStatisticsSubscriber;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface;
class CacheDataCollector implements DataCollectorInterface
{
/**
* @var CacheStatisticsSubscriber
*/
private $statsListener;
/**
* @var CacheProfile
*/
private $startProfile;
/**
* @var CacheProfile
*/
private $endProfile;
/**
* @var CacheProfileSummary
*/
private $summary;
/**
* @var int
*/
private $timeSpent = 0;
/**
* @var array
*/
private $calls = [];
/**
* @var array
*/
private $callSummary;
/**
* @param CacheStatisticsSubscriber $cacheStatisticsSubscriber
*/
public function __construct(CacheStatisticsSubscriber $cacheStatisticsSubscriber)
{
$this->statsListener = $cacheStatisticsSubscriber;
}
/**
* Returns the name of the collector.
*
* @return string The collector name
*/
public function getName()
{
return 'cache';
}
/**
* Collects data for the given Request and Response.
*
* @param Request $request A Request instance
* @param Response $response A Response instance
* @param \Exception $exception An Exception instance
*/
public function collect(Request $request, Response $response, \Exception $exception = null)
{
$this->startProfile = new CacheProfile($this->statsListener->getInitialStats() ?: []);
$this->endProfile = new CacheProfile($this->statsListener->getCurrentStats() ?: []);
$this->timeSpent = $this->statsListener->getTimeSpent();
$this->calls = $this->statsListener->getCalls();
$this->callSummary = $this->statsListener->getCallSummary();
$this->summary = new CacheProfileSummary(
$this->statsListener->getCacheType(),
$this->statsListener->getCacheNamespace(),
$this->startProfile,
$this->endProfile,
$this->callSummary
);
}
/**
* @return CacheProfile
*/
public function getInitialProfile()
{
return $this->startProfile;
}
/**
* @return CacheProfile
*/
public function getCurrentProfile()
{
return $this->endProfile;
}
/**
* @return int
*/
public function getTotalTime()
{
return $this->timeSpent;
}
public function getCalls()
{
return $this->calls;
}
public function getCallSummary()
{
return $this->callSummary;
}
/**
* @return CacheProfileSummary
*/
public function getSummary()
{
return $this->summary;
}
}

View File

@@ -0,0 +1,74 @@
<?php
namespace Alchemy\Phrasea\Core\Profiler;
class CacheProfile
{
/**
* @var array
*/
private $serverStats;
/**
* @param array $serverStats
*/
public function __construct(array $serverStats)
{
$this->serverStats = array_replace([
'hits' => 0,
'misses' => 0,
'uptime' => 0,
'memory_usage' => 0,
'memory_available' => 0
], $serverStats);
}
/**
* @return int
*/
public function getHits()
{
return (int) $this->serverStats['hits'];
}
/**
* @return int
*/
public function getMisses()
{
return (int) $this->serverStats['misses'];
}
/**
* @return int
*/
public function getUptime()
{
return (int) $this->serverStats['uptime'];
}
/**
* @return int
*/
public function getMemUsage()
{
return (int) $this->serverStats['memory_usage'];
}
/**
* @return int
*/
public function getMemAvailable()
{
return (int) $this->serverStats['memory_available'];
}
/**
* @return array
*/
public function getServerStats()
{
return $this->serverStats;
}
}

View File

@@ -0,0 +1,153 @@
<?php
namespace Alchemy\Phrasea\Core\Profiler;
class CacheProfileSummary
{
/**
* @var string
*/
private $cacheType;
/**
* @var string
*/
private $cacheNamespace;
/**
* @var CacheProfile
*/
private $initialProfile;
/**
* @var CacheProfile
*/
private $finalProfile;
/**
* @var array
*/
private $callSummaryData;
/**
* @param string $cacheType
* @param string $namespace
* @param CacheProfile $initialProfile
* @param CacheProfile $finalProfile
* @param array $callSummaryData
*/
public function __construct(
$cacheType,
$namespace,
CacheProfile $initialProfile,
CacheProfile $finalProfile,
array $callSummaryData
) {
$this->cacheType = (string)$cacheType;
$this->cacheNamespace = (string)$namespace;
$this->initialProfile = $initialProfile;
$this->finalProfile = $finalProfile;
$this->callSummaryData = $callSummaryData;
}
/**
* @return string
*/
public function getCacheType()
{
return $this->cacheType;
}
/**
* @return string
*/
public function getNamespace()
{
return $this->cacheNamespace;
}
/**
* @return int
*/
public function getHits()
{
if (isset($this->callSummaryData['hits'])) {
return (int) $this->callSummaryData['hits'];
}
return (int)max(0, $this->finalProfile->getHits() - $this->initialProfile->getHits());
}
/**
* @return int
*/
public function getMisses()
{
if (isset($this->callSummaryData['misses'])) {
return (int) $this->callSummaryData['misses'];
}
return (int)max(0, $this->finalProfile->getMisses() - $this->initialProfile->getMisses());
}
/**
* @return int
*/
public function getCalls()
{
if (isset($this->callSummaryData['calls'])) {
return (int) $this->callSummaryData['calls'];
}
return $this->getHits() + $this->getMisses();
}
/**
* @return float
*/
public function getHitRatio()
{
$calls = $this->getCalls();
if ($calls == 0) {
return (float)0;
}
return $this->getHits() / $calls;
}
/**
* @return float
*/
public function getMissRatio()
{
$calls = $this->getCalls();
if ($calls == 0) {
return (float)0;
}
return $this->getMisses() / $calls;
}
/**
* @return int
*/
public function getMemUsageDelta()
{
return $this->finalProfile->getMemUsage() - $this->initialProfile->getMemUsage();
}
/**
* @return int
*/
public function getMemAvailableDelta()
{
return $this->finalProfile->getMemAvailable() - $this->initialProfile->getMemAvailable();
}
public function getUptimeDelta()
{
return $this->finalProfile->getUptime() - $this->initialProfile->getUptime();
}
}

View File

@@ -0,0 +1,341 @@
<?php
namespace Alchemy\Phrasea\Core\Profiler;
use Alchemy\Phrasea\Cache\Cache as PhraseaCache;
use Alchemy\Phrasea\Cache\Exception;
use Doctrine\Common\Cache\Cache;
use Symfony\Component\Stopwatch\Stopwatch;
class TraceableCache implements Cache, PhraseaCache
{
/**
* @var PhraseaCache
*/
private $cache;
/**
* @var string
*/
private $namespace = '';
/**
* @var array
*/
private $calls = [];
private $summary = [
'calls' => 0,
'hits' => 0,
'misses' => 0,
'calls_by_type' => [],
'calls_by_key' => [],
];
private $stopWatch;
/*s*
* @param PhraseaCache $cache
*/
public function __construct(PhraseaCache $cache, Stopwatch $stopwatch = null)
{
$this->cache = $cache;
$this->stopWatch = $stopwatch ?: new Stopwatch();
}
private function collect($type, $id, $hit = true, $result = null)
{
$this->summary['calls']++;
$this->summary['hits'] += $hit ? 1 : 0;
$this->summary['misses'] += $hit ? 0 : 1;
if (! array_key_exists($type, $this->summary['calls_by_type'])) {
$this->summary['calls_by_type'][$type] = 0;
}
$this->summary['calls_by_type'][$type]++;
if (! array_key_exists($id, $this->summary['calls_by_key'])) {
$this->summary['calls_by_key'][$id] = [
'total' => 0,
'reads'=> 0,
'writes' => 0,
'hits' => 0,
'misses' => 0
];
}
if (! array_key_exists($type, $this->summary['calls_by_key'][$id])) {
$this->summary['calls_by_key'][$id][$type] = 0;
}
$this->summary['calls_by_key'][$id]['hits'] += $hit ? 1 : 0;
$this->summary['calls_by_key'][$id]['misses'] += $hit ? 0 : 1;
$this->summary['calls_by_key'][$id]['reads'] += ($type == 'fetch' || $type == 'contains') ? 1 : 0;
$this->summary['calls_by_key'][$id]['writes'] += ($type == 'fetch' || $type == 'contains') ? 0 : 1;
$this->summary['calls_by_key'][$id]['total']++;
$lastCall = end($this->calls);
$callData = [
'type' => $type,
'key' => $id,
'result' => $result,
'hit' => (bool) $hit,
'count' => 1
];
if (is_array($lastCall) && $this->compareCalls($lastCall, $callData)) {
$lastCall['count']++;
$callData = $lastCall;
array_pop($this->calls);
}
$this->calls[] = $callData;
}
private function compareCalls(array $previousCall, array $currentCall)
{
$keys = [ 'type', 'key', 'result', 'hit'];
foreach ($keys as $key) {
if ($previousCall[$key] != $currentCall[$key]) {
return false;
}
}
return true;
}
/**
* @return string
*/
public function getNamespace()
{
return $this->namespace;
}
/**
* @return int
*/
public function getTotalTime()
{
return $this->stopWatch->getEvent('cache')->getDuration();
}
/**
* @return array
*/
public function getCalls()
{
return $this->calls;
}
/**
* @return array
*/
public function getSummary()
{
return $this->summary;
}
/**
* Fetches an entry from the cache.
*
* @param string $id The id of the cache entry to fetch.
*
* @return mixed The cached data or FALSE, if no cache entry exists for the given id.
*/
public function fetch($id)
{
try {
$this->stopWatch->start('cache');
$value = $this->cache->fetch($id);
$this->stopWatch->stop('cache');
}
catch (\Exception $ex) {
$value = false;
}
$this->collect('fetch', $id, $value != false, $value);
return $value;
}
/**
* Tests if an entry exists in the cache.
*
* @param string $id The cache id of the entry to check for.
*
* @return bool TRUE if a cache entry exists for the given cache id, FALSE otherwise.
*/
public function contains($id)
{
$this->collect('contains', $id);
$this->stopWatch->start('cache');
$result = $this->cache->contains($id);
$this->stopWatch->stop('cache');
return $result;
}
/**
* Puts data into the cache.
*
* If a cache entry with the given id already exists, its data will be replaced.
*
* @param string $id The cache id.
* @param mixed $data The cache entry/data.
* @param int $lifeTime The lifetime in number of seconds for this cache entry.
* If zero (the default), the entry never expires (although it may be deleted from the cache
* to make place for other entries).
*
* @return bool TRUE if the entry was successfully stored in the cache, FALSE otherwise.
*/
public function save($id, $data, $lifeTime = 0)
{
$this->collect('save', $id);
$this->stopWatch->start('cache');
$result = $this->cache->save($id, $data, $lifeTime);
$this->stopWatch->stop('cache');
return $result;
}
/**
* Deletes a cache entry.
*
* @param string $id The cache id.
*
* @return bool TRUE if the cache entry was successfully deleted, FALSE otherwise.
* Deleting a non-existing entry is considered successful.
*/
public function delete($id)
{
$this->collect('delete', $id);
$this->stopWatch->start('cache');
$result = $this->cache->delete($id);
$this->stopWatch->stop('cache');
return $result;
}
/**
* Retrieves cached information from the data store.
*
* The server's statistics array has the following values:
*
* - <b>hits</b>
* Number of keys that have been requested and found present.
*
* - <b>misses</b>
* Number of items that have been requested and not found.
*
* - <b>uptime</b>
* Time that the server is running.
*
* - <b>memory_usage</b>
* Memory used by this server to store items.
*
* - <b>memory_available</b>
* Memory allowed to use for storage.
*
* @since 2.2
*
* @return array|null An associative array with server's statistics if available, NULL otherwise.
*/
public function getStats()
{
$this->stopWatch->start('cache');
$result = $this->cache->getStats();
$this->stopWatch->stop('cache');
return $result;
}
/**
* Sets the namespace
*
* @param string $namespace
*/
public function setNamespace($namespace)
{
$this->namespace = $namespace;
$this->cache->setNamespace($namespace);
}
/**
* Flushes all data contained in the adapter
*/
public function flushAll()
{
$this->collect('flush-all', null);
$this->stopWatch->start('cache');
$this->cache->flushAll();
$this->stopWatch->stop('cache');
}
/**
* Name of the cache driver
* @return string
*/
public function getName()
{
return 'traceable-' . $this->cache->getName();
}
/**
* Tell whether the caching system use a server or not
* @return boolean
*/
public function isServer()
{
return $this->cache->isServer();
}
/**
* Tell if the cache system is online
* @return boolean
*/
public function isOnline()
{
return $this->cache->isOnline();
}
/**
* Get an entry from the cache.
*
* @param string $key cache id The id of the cache entry to fetch.
*
* @return string The cached data.
* @return FALSE, if no cache entry exists for the given id.
*
* @throws Exception if provided key does not exist
*/
public function get($key)
{
if ( ! $this->contains($key)) {
throw new Exception('Unable to retrieve the value');
}
return $this->fetch($key);
}
/**
* Delete multi cache entries
*
* @param array $keys contains all keys to delete
* @return PhraseaCache
*/
public function deleteMulti(array $keys)
{
foreach ($keys as $key) {
$this->delete($key);
}
}
}

View File

@@ -70,7 +70,7 @@ class BorderManagerServiceProvider implements ServiceProviderInterface
$collections = []; $collections = [];
foreach ($checker['collections'] as $base_id) { foreach ($checker['collections'] as $base_id) {
try { try {
$collections[] = \collection::get_from_base_id($app, $base_id); $collections[] = \collection::getByBaseId($app, $base_id);
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \InvalidArgumentException('Invalid collection option'); throw new \InvalidArgumentException('Invalid collection option');
} }

View File

@@ -69,7 +69,7 @@ class ConfigurationServiceProvider implements ServiceProviderInterface
}); });
$app['conf.restrictions'] = $app->share(function (SilexApplication $app) { $app['conf.restrictions'] = $app->share(function (SilexApplication $app) {
return new AccessRestriction($app['cache'], $app['conf'], $app->getApplicationBox(), $app['monolog']); return new AccessRestriction($app['conf'], $app->getApplicationBox(), $app['monolog']);
}); });
} }

View File

@@ -15,6 +15,7 @@ use Alchemy\Phrasea\Setup\ConfigurationTester;
use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Setup\Version\PreSchemaUpgrade\PreSchemaUpgradeCollection; use Alchemy\Phrasea\Setup\Version\PreSchemaUpgrade\PreSchemaUpgradeCollection;
use Alchemy\Phrasea\Setup\Version\PreSchemaUpgrade\Upgrade39Feeds; use Alchemy\Phrasea\Setup\Version\PreSchemaUpgrade\Upgrade39Feeds;
use Alchemy\Phrasea\Setup\Version\PreSchemaUpgrade\Upgrade39Sessions;
use Alchemy\Phrasea\Setup\Version\PreSchemaUpgrade\Upgrade39Tokens; use Alchemy\Phrasea\Setup\Version\PreSchemaUpgrade\Upgrade39Tokens;
use Alchemy\Phrasea\Setup\Version\PreSchemaUpgrade\Upgrade39Users; use Alchemy\Phrasea\Setup\Version\PreSchemaUpgrade\Upgrade39Users;
use Silex\Application as SilexApplication; use Silex\Application as SilexApplication;
@@ -30,7 +31,7 @@ class ConfigurationTesterServiceProvider implements ServiceProviderInterface
}); });
$app['phraseanet.pre-schema-upgrader.upgrades'] = $app->share(function () { $app['phraseanet.pre-schema-upgrader.upgrades'] = $app->share(function () {
return [new Upgrade39Feeds(), new Upgrade39Users(), new Upgrade39Tokens()]; return [new Upgrade39Feeds(), new Upgrade39Users(), new Upgrade39Tokens(), new Upgrade39Sessions()];
}); });
$app['phraseanet.pre-schema-upgrader'] = $app->share(function (Application $app) { $app['phraseanet.pre-schema-upgrader'] = $app->share(function (Application $app) {

View File

@@ -14,12 +14,11 @@ namespace Alchemy\Phrasea\Core\Provider;
use Alchemy\Phrasea\Core\Event\Subscriber\XSendFileSubscriber; use Alchemy\Phrasea\Core\Event\Subscriber\XSendFileSubscriber;
use Alchemy\Phrasea\Http\H264PseudoStreaming\H264Factory; use Alchemy\Phrasea\Http\H264PseudoStreaming\H264Factory;
use Alchemy\Phrasea\Http\ServeFileResponseFactory; use Alchemy\Phrasea\Http\ServeFileResponseFactory;
use Alchemy\Phrasea\Http\StaticFile\StaticFileFactory;
use Alchemy\Phrasea\Http\StaticFile\StaticMode; use Alchemy\Phrasea\Http\StaticFile\StaticMode;
use Alchemy\Phrasea\Http\StaticFile\Symlink\SymLinker;
use Alchemy\Phrasea\Http\XSendFile\XSendFileFactory; use Alchemy\Phrasea\Http\XSendFile\XSendFileFactory;
use Silex\Application; use Silex\Application;
use Silex\ServiceProviderInterface; use Silex\ServiceProviderInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class FileServeServiceProvider implements ServiceProviderInterface class FileServeServiceProvider implements ServiceProviderInterface
{ {
@@ -41,11 +40,11 @@ class FileServeServiceProvider implements ServiceProviderInterface
}); });
$app['phraseanet.static-file'] = $app->share(function (Application $app) { $app['phraseanet.static-file'] = $app->share(function (Application $app) {
return new StaticMode(SymLinker::create($app)); return new StaticMode($app['phraseanet.thumb-symlinker']);
}); });
$app['phraseanet.file-serve'] = $app->share(function (Application $app) { $app['phraseanet.file-serve'] = $app->share(function (Application $app) {
return ServeFileResponseFactory::create($app); return new ServeFileResponseFactory($app['unicode']);
}); });
} }
@@ -55,7 +54,7 @@ class FileServeServiceProvider implements ServiceProviderInterface
public function boot(Application $app) public function boot(Application $app)
{ {
$app['dispatcher'] = $app->share( $app['dispatcher'] = $app->share(
$app->extend('dispatcher', function ($dispatcher, Application $app) { $app->extend('dispatcher', function (EventDispatcherInterface $dispatcher, Application $app) {
$dispatcher->addSubscriber(new XSendFileSubscriber($app)); $dispatcher->addSubscriber(new XSendFileSubscriber($app));
return $dispatcher; return $dispatcher;

View File

@@ -0,0 +1,53 @@
<?php
namespace Alchemy\Phrasea\Core\Provider;
use Silex\Application;
use Silex\ServiceProviderInterface;
class MediaAlchemystServiceProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$app['media-alchemyst.configuration'] = $app->share(function (Application $app) {
$configuration = [];
$parameters = [
'swftools.pdf2swf.binaries' => 'pdf2swf_binary',
'swftools.swfrender.binaries' => 'swf_render_binary',
'swftools.swfextract.binaries' => 'swf_extract_binary',
'unoconv.binaries' => 'unoconv_binary',
'mp4box.binaries' => 'mp4box_binary',
'gs.binaries' => 'ghostscript_binary',
'ffmpeg.ffmpeg.binaries' => 'ffmpeg_binary',
'ffmpeg.ffprobe.binaries' => 'ffprobe_binary',
'ffmpeg.ffmpeg.timeout' => 'ffmpeg_timeout',
'ffmpeg.ffprobe.timeout' => 'ffprobe_timeout',
'gs.timeout' => 'gs_timeout',
'mp4box.timeout' => 'mp4box_timeout',
'swftools.timeout' => 'swftools_timeout',
'unoconv.timeout' => 'unoconv_timeout',
];
foreach ($parameters as $parameter => $key) {
if ($app['conf']->has(['main', 'binaries', $key])) {
$configuration[$parameter] = $app['conf']->get(['main', 'binaries', $key]);
}
}
$configuration['ffmpeg.threads'] = $app['conf']->get(['registry', 'executables', 'ffmpeg-threads']) ?: null;
$configuration['imagine.driver'] = $app['conf']->get(['registry', 'executables', 'imagine-driver']) ?: null;
return $configuration;
});
$app['media-alchemyst.logger'] = $app->share(function (Application $app) {
return $app['monolog'];
});
}
public function boot(Application $app)
{
// no-op
}
}

View File

@@ -41,11 +41,15 @@ class PhraseanetServiceProvider implements ServiceProviderInterface
}); });
$app['phraseanet.thumb-symlinker'] = $app->share(function (SilexApplication $app) { $app['phraseanet.thumb-symlinker'] = $app->share(function (SilexApplication $app) {
return SymLinker::create($app); return new SymLinker(
$app['phraseanet.thumb-symlinker-encoder'],
$app['filesystem'],
$app['thumbnail.path']
);
}); });
$app['phraseanet.thumb-symlinker-encoder'] = $app->share(function (SilexApplication $app) { $app['phraseanet.thumb-symlinker-encoder'] = $app->share(function (SilexApplication $app) {
return SymLinkerEncoder::create($app); return new SymLinkerEncoder($app['phraseanet.configuration']['main']['key']);
}); });
$app['acl'] = $app->share(function (SilexApplication $app) { $app['acl'] = $app->share(function (SilexApplication $app) {

View File

@@ -1,9 +1,8 @@
<?php <?php
/**
/*
* This file is part of Phraseanet * This file is part of Phraseanet
* *
* (c) 2005-2014 Alchemy * (c) 2005-2016 Alchemy
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
@@ -12,12 +11,22 @@
namespace Alchemy\Phrasea\Core\Provider; namespace Alchemy\Phrasea\Core\Provider;
use Alchemy\Phrasea\Application as PhraseaApplication; use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Collection\CollectionFactory;
use Alchemy\Phrasea\Collection\CollectionRepositoryRegistry;
use Alchemy\Phrasea\Collection\Factory\ArrayCachedCollectionRepositoryFactory;
use Alchemy\Phrasea\Collection\Factory\CachedCollectionRepositoryFactory;
use Alchemy\Phrasea\Collection\Factory\DbalCollectionRepositoryFactory;
use Alchemy\Phrasea\Collection\Reference\ArrayCacheCollectionReferenceRepository;
use Alchemy\Phrasea\Collection\Reference\DbalCollectionReferenceRepository;
use Alchemy\Phrasea\Databox\ArrayCacheDataboxRepository;
use Alchemy\Phrasea\Databox\CachingDataboxRepositoryDecorator; use Alchemy\Phrasea\Databox\CachingDataboxRepositoryDecorator;
use Alchemy\Phrasea\Databox\DataboxConnectionProvider;
use Alchemy\Phrasea\Databox\DataboxFactory; use Alchemy\Phrasea\Databox\DataboxFactory;
use Alchemy\Phrasea\Databox\DbalDataboxRepository; use Alchemy\Phrasea\Databox\DbalDataboxRepository;
use Alchemy\Phrasea\Databox\Field\DataboxFieldFactory; use Alchemy\Phrasea\Databox\Field\DataboxFieldFactory;
use Alchemy\Phrasea\Databox\Field\DbalDataboxFieldRepository; use Alchemy\Phrasea\Databox\Field\DbalDataboxFieldRepository;
use Alchemy\Phrasea\Databox\Record\LegacyRecordRepository; use Alchemy\Phrasea\Databox\Record\LegacyRecordRepository;
use Alchemy\Phrasea\Model\Repositories\BasketRepository;
use Silex\Application; use Silex\Application;
use Silex\ServiceProviderInterface; use Silex\ServiceProviderInterface;
@@ -45,7 +54,11 @@ class RepositoriesServiceProvider implements ServiceProviderInterface
return $app['orm.em']->getRepository('Phraseanet:Registration'); return $app['orm.em']->getRepository('Phraseanet:Registration');
}); });
$app['repo.baskets'] = $app->share(function (PhraseaApplication $app) { $app['repo.baskets'] = $app->share(function (PhraseaApplication $app) {
return $app['orm.em']->getRepository('Phraseanet:Basket'); /** @var BasketRepository $repository */
$repository = $app['orm.em']->getRepository('Phraseanet:Basket');
$repository->setTranslator($app['translator']);
return $repository;
}); });
$app['repo.basket-elements'] = $app->share(function (PhraseaApplication $app) { $app['repo.basket-elements'] = $app->share(function (PhraseaApplication $app) {
return $app['orm.em']->getRepository('Phraseanet:BasketElement'); return $app['orm.em']->getRepository('Phraseanet:BasketElement');
@@ -133,11 +146,21 @@ class RepositoriesServiceProvider implements ServiceProviderInterface
}); });
$app['repo.databoxes'] = $app->share(function (PhraseaApplication $app) { $app['repo.databoxes'] = $app->share(function (PhraseaApplication $app) {
$factory = new DataboxFactory($app);
$appbox = $app->getApplicationBox(); $appbox = $app->getApplicationBox();
$repository = new DbalDataboxRepository($appbox->get_connection(), $factory);
return new CachingDataboxRepositoryDecorator($repository, $app['cache'], $appbox->get_cache_key($appbox::CACHE_LIST_BASES), $factory); $factory = new DataboxFactory($app);
$repository = new CachingDataboxRepositoryDecorator(
new DbalDataboxRepository($appbox->get_connection(), $factory),
$app['cache'],
$appbox->get_cache_key($appbox::CACHE_LIST_BASES),
$factory
);
$repository = new ArrayCacheDataboxRepository($repository);
$factory->setDataboxRepository($repository);
return $repository;
}); });
$app['repo.fields.factory'] = $app->protect(function (\databox $databox) use ($app) { $app['repo.fields.factory'] = $app->protect(function (\databox $databox) use ($app) {
@@ -147,9 +170,37 @@ class RepositoriesServiceProvider implements ServiceProviderInterface
$app['repo.records.factory'] = $app->protect(function (\databox $databox) use ($app) { $app['repo.records.factory'] = $app->protect(function (\databox $databox) use ($app) {
return new LegacyRecordRepository($app, $databox); return new LegacyRecordRepository($app, $databox);
}); });
$app['repo.collection-references'] = $app->share(function (PhraseaApplication $app) {
$repository = new DbalCollectionReferenceRepository($app->getApplicationBox()->get_connection());
return new ArrayCacheCollectionReferenceRepository($repository);
});
$app['repo.collections-registry'] = $app->share(function (PhraseaApplication $app) {
$factory = new CollectionFactory($app);
$connectionProvider = new DataboxConnectionProvider($app->getApplicationBox());
$repositoryFactory = new DbalCollectionRepositoryFactory(
$connectionProvider,
$factory,
$app['repo.collection-references']
);
$repositoryFactory = new CachedCollectionRepositoryFactory(
$app,
$repositoryFactory,
$app['cache'],
'phrasea.collections'
);
$repositoryFactory = new ArrayCachedCollectionRepositoryFactory($repositoryFactory);
return new CollectionRepositoryRegistry($app, $repositoryFactory, $app['repo.collection-references']);
});
} }
public function boot(Application $app) public function boot(Application $app)
{ {
// no-op
} }
} }

View File

@@ -21,11 +21,14 @@ class SubdefServiceProvider implements ServiceProviderInterface
{ {
public function register(SilexApplication $app) public function register(SilexApplication $app)
{ {
$app['subdef.generator'] = $app->share(function (SilexApplication $app) { $app['subdef.generator'] = $app->share(function (Application $app) {
return new SubdefGenerator($app, $app['media-alchemyst'], $app['filesystem'], $app['mediavorus'], isset($app['task-manager.logger']) ? $app['task-manager.logger'] : $app['monolog']); $generator = new SubdefGenerator($app, $app['media-alchemyst'], $app['phraseanet.filesystem'], $app['mediavorus'], isset($app['task-manager.logger']) ? $app['task-manager.logger'] : $app['monolog']);
$generator->setDispatcher($app['dispatcher']);
return $generator;
}); });
$app['subdef.substituer'] = $app->share(function (SilexApplication $app) { $app['subdef.substituer'] = $app->share(function (Application $app) {
return new SubdefSubstituer($app, $app['filesystem'], $app['media-alchemyst'], $app['mediavorus'], $app['dispatcher']); return new SubdefSubstituer($app, $app['phraseanet.filesystem'], $app['media-alchemyst'], $app['mediavorus'], $app['dispatcher']);
}); });
} }

View File

@@ -5,6 +5,7 @@ namespace Alchemy\Phrasea\Core\Provider;
use Alchemy\Phrasea\Utilities\CachedTranslator; use Alchemy\Phrasea\Utilities\CachedTranslator;
use Silex\Application; use Silex\Application;
use Silex\ServiceProviderInterface; use Silex\ServiceProviderInterface;
use Symfony\Component\Translation\Loader\PoFileLoader;
use Symfony\Component\Translation\MessageSelector; use Symfony\Component\Translation\MessageSelector;
use Symfony\Component\Translation\Loader\ArrayLoader; use Symfony\Component\Translation\Loader\ArrayLoader;
use JMS\TranslationBundle\Translation\Loader\Symfony\XliffLoader; use JMS\TranslationBundle\Translation\Loader\Symfony\XliffLoader;
@@ -36,6 +37,7 @@ class TranslationServiceProvider implements ServiceProviderInterface
$translator->addLoader('xliff', new XliffLoader()); $translator->addLoader('xliff', new XliffLoader());
// to load Phraseanet resources // to load Phraseanet resources
$translator->addLoader('xlf', new XliffLoader()); $translator->addLoader('xlf', new XliffLoader());
$translator->addLoader('po', new PoFileLoader());
foreach ($app['translator.domains'] as $domain => $data) { foreach ($app['translator.domains'] as $domain => $data) {
foreach ($data as $locale => $messages) { foreach ($data as $locale => $messages) {
@@ -43,6 +45,15 @@ class TranslationServiceProvider implements ServiceProviderInterface
} }
} }
foreach ($app['translator.resources'] as $resource) {
$translator->addResource(
$resource[0],
$resource[1],
$resource[2],
isset($resource[3]) ? $resource[3] : null
);
}
return $translator; return $translator;
}); });

View File

@@ -0,0 +1,159 @@
<?php
/**
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Core\Provider;
use Alchemy\Phrasea\Twig\BytesConverter;
use Alchemy\Phrasea\Twig\Camelize;
use Alchemy\Phrasea\Twig\Fit;
use Alchemy\Phrasea\Twig\JSUniqueID;
use Alchemy\Phrasea\Twig\PhraseanetExtension;
use Silex\Application;
use Silex\ServiceProviderInterface;
use Symfony\Bridge\Twig\Extension\TranslationExtension;
class TwigServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given app.
*
* This method should only be used to configure services and parameters.
* It should not get services.
*/
public function register(Application $app)
{
$app['twig'] = $app->share($app->extend('twig', function (\Twig_Environment $twig, $app) {
$twig->setCache($app['cache.path'] . '/twig');
$paths = [];
if (file_exists($app['plugin.path'] . '/twig-paths.php')) {
$paths = require $app['plugin.path'] . '/twig-paths.php';
}
if ($app['browser']->isTablet() || $app['browser']->isMobile()) {
$paths[] = $app['root.path'] . '/config/templates/mobile';
$paths[] = $app['root.path'] . '/templates/mobile';
$paths['phraseanet'] = $app['root.path'] . '/config/templates/mobile';
$paths['phraseanet'] = $app['root.path'] . '/templates/mobile';
}
$paths[] = $app['root.path'] . '/config/templates/web';
$paths[] = $app['root.path'] . '/templates/web';
$paths['phraseanet'] = $app['root.path'] . '/config/templates/web';
$paths['phraseanet'] = $app['root.path'] . '/templates/web';
foreach ($paths as $namespace => $path) {
if (!is_int($namespace)) {
$app['twig.loader.filesystem']->addPath($path, $namespace);
} else {
$app['twig.loader.filesystem']->addPath($path);
}
}
$twig->addGlobal('current_date', new \DateTime());
$this->registerExtensions($twig, $app);
$this->registerFilters($twig, $app);
return $twig;
}));
}
private function registerExtensions(\Twig_Environment $twig, Application $app)
{
$twig->addExtension(new \Twig_Extension_Core());
$twig->addExtension(new \Twig_Extension_Optimizer());
$twig->addExtension(new \Twig_Extension_Escaper());
if ($app['debug']) {
$twig->addExtension(new \Twig_Extension_Debug());
}
// add filter trans
$twig->addExtension(new TranslationExtension($app['translator']));
// add filter localizeddate
$twig->addExtension(new \Twig_Extensions_Extension_Intl());
// add filters truncate, wordwrap, nl2br
$twig->addExtension(new \Twig_Extensions_Extension_Text());
$twig->addExtension(new JSUniqueID());
$twig->addExtension(new Fit());
$twig->addExtension(new Camelize());
$twig->addExtension(new BytesConverter());
$twig->addExtension(new PhraseanetExtension($app));
}
private function registerFilters(\Twig_Environment $twig, Application $app)
{
$twig->addFilter('serialize', new \Twig_Filter_Function('serialize'));
$twig->addFilter('stristr', new \Twig_Filter_Function('stristr'));
$twig->addFilter('get_class', new \Twig_Filter_Function('get_class'));
$twig->addFilter('stripdoublequotes', new \Twig_Filter_Function('stripdoublequotes'));
$twig->addFilter('get_collection_logo', new \Twig_Filter_Function('collection::getLogo'));
$twig->addFilter('floor', new \Twig_Filter_Function('floor'));
$twig->addFilter('ceil', new \Twig_Filter_Function('ceil'));
$twig->addFilter('max', new \Twig_Filter_Function('max'));
$twig->addFilter('min', new \Twig_Filter_Function('min'));
$twig->addFilter('bas_labels', new \Twig_Filter_Function('phrasea::bas_labels'));
$twig->addFilter('sbas_names', new \Twig_Filter_Function('phrasea::sbas_names'));
$twig->addFilter('sbas_labels', new \Twig_Filter_Function('phrasea::sbas_labels'));
$twig->addFilter('sbas_from_bas', new \Twig_Filter_Function('phrasea::sbasFromBas'));
$twig->addFilter('key_exists', new \Twig_Filter_Function('array_key_exists'));
$twig->addFilter('round', new \Twig_Filter_Function('round'));
$twig->addFilter('count', new \Twig_Filter_Function('count'));
$twig->addFilter('formatOctets', new \Twig_Filter_Function('p4string::format_octets'));
$twig->addFilter('base_from_coll', new \Twig_Filter_Function('phrasea::baseFromColl'));
$twig->addFilter(new \Twig_SimpleFilter('escapeSimpleQuote', function ($value) {
return str_replace("'", "\\'", $value);
}));
$twig->addFilter(new \Twig_SimpleFilter('highlight', function (\Twig_Environment $twig, $string) {
return str_replace(['[[em]]', '[[/em]]'], ['<em>', '</em>'], $string);
}, ['needs_environment' => true, 'is_safe' => ['html']]));
$twig->addFilter(new \Twig_SimpleFilter('linkify', function (\Twig_Environment $twig, $string) use ($app) {
return preg_replace(
"(([^']{1})((https?|file):((/{2,4})|(\\{2,4}))[\w:#%/;$()~_?/\-=\\\.&]*)([^']{1}))"
,
'$1 $2 <a title="' . $app['translator']->trans('Open the URL in a new window') . '" class="ui-icon ui-icon-extlink" href="$2" style="display:inline;padding:2px 5px;margin:0 4px 0 2px;" target="_blank"> &nbsp;</a>$7'
, $string
);
}, ['needs_environment' => true, 'is_safe' => ['html']]));
$twig->addFilter(new \Twig_SimpleFilter('bounce',
function (\Twig_Environment $twig, $fieldValue, $fieldName, $searchRequest, $sbasId) {
// bounce value if it is present in thesaurus as well
return "<a class=\"bounce\" onclick=\"bounce('" . $sbasId . "','"
. str_replace("'", "\\'", $searchRequest)
. "', '"
. str_replace("'", "\\'", $fieldName)
. "');return(false);\">"
. $fieldValue
. "</a>";
}, ['needs_environment' => true, 'is_safe' => ['html']]));
$twig->addFilter(new \Twig_SimpleFilter('escapeDoubleQuote', function ($value) {
return str_replace('"', '\"', $value);
}));
}
/**
* Bootstraps the application.
*
* This method is called after all services are registered
* and should be used for "dynamic" configuration (whenever
* a service must be requested).
*/
public function boot(Application $app)
{
// no-op
}
}

View File

@@ -0,0 +1,133 @@
<?php
namespace Alchemy\Phrasea\Core\Provider;
use Alchemy\Phrasea\Core\Event\Subscriber\CacheStatisticsSubscriber;
use Alchemy\Phrasea\Core\Profiler\CacheDataCollector;
use Alchemy\Phrasea\Core\Profiler\TraceableCache;
use Doctrine\Common\Cache\Cache;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Logging\DebugStack;
use Doctrine\DBAL\Logging\LoggerChain;
use Silex\Application;
use Silex\ServiceProviderInterface;
use Sorien\DataCollector\DoctrineDataCollector;
use Sorien\Logger\DbalLogger;
use Symfony\Bundle\FrameworkBundle\DataCollector\AjaxDataCollector;
use Symfony\Bundle\WebProfilerBundle\EventListener\WebDebugToolbarListener;
class WebProfilerServiceProvider implements ServiceProviderInterface
{
/**
* Registers services on the given app.
*
* This method should only be used to configure services and parameters.
* It should not get services.
*/
public function register(Application $app)
{
// Required because the Silex provider is not up to date with Symfony Debug Toolbar
$app['web_profiler.toolbar.listener'] = $app->share(
$app->extend('web_profiler.toolbar.listener', function () use ($app) {
return new WebDebugToolbarListener(
$app['twig'],
$app['web_profiler.debug_toolbar.intercept_redirects'],
2,
$app['web_profiler.debug_toolbar.position'],
$app['url_generator']
);
})
);
if (class_exists(AjaxDataCollector::class)) {
$app['data_collector.templates'] = $app->share($app->extend('data_collector.templates', function (array $templates) {
$templates[] = array('ajax', '@WebProfiler/Collector/ajax.html.twig');
return $templates;
}));
$app['data_collectors'] = $app->share($app->extend('data_collectors', function ($collectors) use ($app) {
$collectors['ajax'] = function () {
return new AjaxDataCollector();
};
return $collectors;
}));
}
$app['data_collectors.doctrine'] = $app->share(function ($app) {
/** @var Connection $db */
$db = $app['db'];
return new DoctrineDataCollector($db);
});
$app['cache'] = $app->share($app->extend('cache', function (Cache $cache, $app) {
$namespace = $app['conf']->get(['main', 'cache', 'options', 'namespace']);
$cache = new TraceableCache($cache);
$cache->setNamespace($namespace);
return $cache;
}));
$app['data_collector.cache_subscriber'] = $app->share(function ($app) {
return new CacheStatisticsSubscriber($app['cache']);
});
$app['data_collectors'] = $app->share($app->extend('data_collectors', function ($collectors) use ($app) {
$collectors['db'] = $app->share(function ($app) {
/** @var DoctrineDataCollector $collector */
$collector = $app['data_collectors.doctrine'];
$loggerChain = new LoggerChain();
$logger = new DebugStack();
$loggerChain->addLogger($logger);
$loggerChain->addLogger(new DbalLogger($app['logger'], $app['stopwatch']));
/** @var Connection $db */
$db = $app['db'];
$db->getConfiguration()->setSQLLogger($loggerChain);
$collector->addLogger($logger);
return $collector;
});
$collectors['cache'] = $app->share(function ($app) {
return new CacheDataCollector($app['data_collector.cache_subscriber']);
});
return $collectors;
}));
$app['data_collector.templates'] = $app->share($app->extend('data_collector.templates', function (array $templates) {
$templates[] = array('db', '@DoctrineBundle/Collector/db.html.twig');
$templates[] = array('cache', '@PhraseaProfiler/cache.html.twig');
return $templates;
}));
$app['twig.loader.filesystem'] = $app->share($app->extend('twig.loader.filesystem', function ($loader, $app) {
$loader->addPath(
$app['root.path'] . '/vendor/sorien/silex-dbal-profiler/src/Sorien/Resources/views',
'DoctrineBundle'
);
$loader->addPath($app['root.path'] . '/templates-profiler/', 'PhraseaProfiler');
return $loader;
}));
}
/**
* Bootstraps the application.
*
* This method is called after all services are registered
* and should be used for "dynamic" configuration (whenever
* a service must be requested).
*/
public function boot(Application $app)
{
$app['dispatcher']->addSubscriber($app['data_collector.cache_subscriber']);
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Alchemy\Phrasea\Core\Provider;
use Alchemy\Phrasea\Webhook\EventProcessorFactory;
use Silex\Application;
use Silex\ServiceProviderInterface;
class WebhookServiceProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$app['webhook.processor_factory'] = $app->share(function ($app) {
return new EventProcessorFactory($app);
});
}
public function boot(Application $app)
{
// no-op
}
}

View File

@@ -0,0 +1,136 @@
<?php
namespace Alchemy\Phrasea\Databox;
class ArrayCacheDataboxRepository implements DataboxRepository
{
/**
* @var DataboxRepository
*/
private $repository;
/**
* @var bool
*/
private $loaded = false;
/**
* @var \databox[]
*/
private $databoxes = [];
/**
* @param DataboxRepository $repository
*/
public function __construct(DataboxRepository $repository)
{
$this->repository = $repository;
}
/**
* @param int $id
* @return \databox
*/
public function find($id)
{
$this->load();
if (! isset($this->databoxes[$id])) {
return null;
}
return $this->databoxes[$id];
}
/**
* @return \databox[]
*/
public function findAll()
{
$this->load();
return $this->databoxes;
}
/**
* @param \databox $databox
*/
public function save(\databox $databox)
{
$this->clear();
return $this->repository->save($databox);
}
/**
* @param \databox $databox
*/
public function delete(\databox $databox)
{
$this->clear();
return $this->repository->delete($databox);
}
/**
* @param \databox $databox
*/
public function unmount(\databox $databox)
{
$this->clear();
return $this->repository->unmount($databox);
}
/**
* @param $host
* @param $port
* @param $user
* @param $password
* @param $dbname
*
* @return \databox
*/
public function mount($host, $port, $user, $password, $dbname)
{
$this->clear();
return $this->repository->mount($host, $port, $user, $password, $dbname);
}
/**
* @param $host
* @param $port
* @param $user
* @param $password
* @param $dbname
*
* @return \databox
*/
public function create($host, $port, $user, $password, $dbname)
{
$this->clear();
return $this->repository->create($host, $port, $user, $password, $dbname);
}
/**
* Initializes the memory cache if needed.
*/
private function load()
{
if (! $this->loaded) {
$this->databoxes = $this->repository->findAll();
$this->loaded = true;
}
}
/**
* Clears the memory cache.
*/
private function clear()
{
$this->loaded = false;
$this->databoxes = [];
}
}

View File

@@ -22,6 +22,12 @@ final class CachingDataboxRepositoryDecorator implements DataboxRepository
/** @var DataboxFactory */ /** @var DataboxFactory */
private $factory; private $factory;
/**
* @param DataboxRepository $repository
* @param Cache $cache
* @param string $cacheKey
* @param DataboxFactory $factory
*/
public function __construct(DataboxRepository $repository, Cache $cache, $cacheKey, DataboxFactory $factory) public function __construct(DataboxRepository $repository, Cache $cache, $cacheKey, DataboxFactory $factory)
{ {
$this->repository = $repository; $this->repository = $repository;
@@ -56,6 +62,63 @@ final class CachingDataboxRepositoryDecorator implements DataboxRepository
return $databoxes; return $databoxes;
} }
public function save(\databox $databox)
{
$this->clearCache();
return $this->repository->save($databox);
}
public function delete(\databox $databox)
{
$this->clearCache();
return $this->repository->delete($databox);
}
public function unmount(\databox $databox)
{
$this->clearCache();
return $this->repository->unmount($databox);
}
/**
* @param $host
* @param $port
* @param $user
* @param $password
* @param $dbname
*
* @return \databox
*/
public function mount($host, $port, $user, $password, $dbname)
{
$databox = $this->repository->mount($host, $port, $user, $password, $dbname);
$this->clearCache();
return $databox;
}
/**
* @param $host
* @param $port
* @param $user
* @param $password
* @param $dbname
*
* @return \databox
*/
public function create($host, $port, $user, $password, $dbname)
{
$databox = $this->repository->create($host, $port, $user, $password, $dbname);
$this->clearCache();
return $databox;
}
/** /**
* @param \databox[] $databoxes * @param \databox[] $databoxes
*/ */
@@ -69,4 +132,9 @@ final class CachingDataboxRepositoryDecorator implements DataboxRepository
$this->cache->save($this->cacheKey, $rows); $this->cache->save($this->cacheKey, $rows);
} }
private function clearCache()
{
$this->cache->delete($this->cacheKey);
}
} }

View File

@@ -0,0 +1,23 @@
<?php
namespace Alchemy\Phrasea\Databox;
class DataboxConnectionProvider
{
private $applicationBox;
public function __construct(\appbox $applicationBox)
{
$this->applicationBox = $applicationBox;
}
/**
* @param $databoxId
* @return \Doctrine\DBAL\Connection
*/
public function getConnection($databoxId)
{
return $this->applicationBox->get_databox($databoxId)->get_connection();
}
}

View File

@@ -17,20 +17,33 @@ class DataboxFactory
/** @var Application */ /** @var Application */
private $app; private $app;
/** @var DataboxRepository */
private $databoxRepository;
/**
* @param Application $app
*/
public function __construct(Application $app) public function __construct(Application $app)
{ {
$this->app = $app; $this->app = $app;
} }
/** /**
* @param int $id * @param DataboxRepository $databoxRepository
*/
public function setDataboxRepository(DataboxRepository $databoxRepository)
{
$this->databoxRepository = $databoxRepository;
}
/**
* @param int $id
* @param array $raw * @param array $raw
* @throws NotFoundHttpException when Databox could not be retrieved from Persistence layer * @return \databox when Databox could not be retrieved from Persistence layer
* @return \databox
*/ */
public function create($id, array $raw) public function create($id, array $raw)
{ {
return new \databox($this->app, $id, $raw); return new \databox($this->app, $id, $this->databoxRepository, $raw);
} }
/** /**
@@ -43,7 +56,7 @@ class DataboxFactory
$databoxes = []; $databoxes = [];
foreach ($rows as $id => $raw) { foreach ($rows as $id => $raw) {
$databoxes[$id] = new \databox($this->app, $id, $raw); $databoxes[$id] = new \databox($this->app, $id, $this->databoxRepository, $raw);
} }
return $databoxes; return $databoxes;

View File

@@ -0,0 +1,37 @@
<?php
/**
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Databox;
class DataboxPathExtractor
{
/**
* @var \appbox
*/
private $appbox;
public function __construct(\appbox $appbox)
{
$this->appbox = $appbox;
}
public function extractPaths()
{
$paths = [];
foreach ($this->appbox->get_databoxes() as $databox) {
foreach ($databox->get_subdef_structure()->getSubdefGroup('video') as $subdef) {
$paths[] = $subdef->get_path();
}
}
return array_filter(array_unique($paths));
}
}

View File

@@ -21,4 +21,41 @@ interface DataboxRepository
* @return \databox[] * @return \databox[]
*/ */
public function findAll(); public function findAll();
/**
* @param \databox $databox
*/
public function save(\databox $databox);
/**
* @param \databox $databox
*/
public function delete(\databox $databox);
/**
* @param \databox $databox
*/
public function unmount(\databox $databox);
/**
* @param $host
* @param $port
* @param $user
* @param $password
* @param $dbname
*
* @return \databox
*/
public function mount($host, $port, $user, $password, $dbname);
/**
* @param $host
* @param $port
* @param $user
* @param $password
* @param $dbname
*
* @return \databox
*/
public function create($host, $port, $user, $password, $dbname);
} }

View File

@@ -47,6 +47,25 @@ final class DbalDataboxRepository implements DataboxRepository
return $this->factory->createMany($this->fetchRows()); return $this->factory->createMany($this->fetchRows());
} }
/**
* @param \databox $databox
* @return bool
*/
public function save(\databox $databox)
{
return true;
}
public function delete(\databox $databox)
{
return true;
}
public function unmount(\databox $databox)
{
return true;
}
/** /**
* @param int $id * @param int $id
* @return false|array * @return false|array
@@ -82,4 +101,73 @@ final class DbalDataboxRepository implements DataboxRepository
return $rows; return $rows;
} }
/**
* @param $host
* @param $port
* @param $user
* @param $password
* @param $dbname
*
* @return \databox
*/
public function mount($host, $port, $user, $password, $dbname)
{
$query = 'INSERT INTO sbas (ord, host, port, dbname, sqlengine, user, pwd)
SELECT COALESCE(MAX(ord), 0) + 1 AS ord, :host AS host, :port AS port, :dbname AS dbname,
"MYSQL" AS sqlengine, :user AS user, :password AS pwd FROM sbas';
$statement = $this->connection->prepare($query);
$statement->execute([
':host' => $host,
':port' => $port,
':dbname' => $dbname,
':user' => $user,
':password' => $password
]);
$statement->closeCursor();
return $this->find((int) $this->connection->lastInsertId());
}
/**
* @param $host
* @param $port
* @param $user
* @param $password
* @param $dbname
*
* @return \databox
*/
public function create($host, $port, $user, $password, $dbname)
{
$params = [
':host' => $host,
':port' => $port,
':user' => $user,
':password' => $password,
':dbname' => $dbname
];
$query = 'SELECT sbas_id FROM sbas
WHERE host = :host AND port = :port AND `user` = :user AND pwd = :password AND dbname = :dbname';
$statement = $this->connection->executeQuery($query, $params);
if ($row = $statement->fetch(\PDO::FETCH_ASSOC)) {
return $this->find((int) $row['sbas_id']);
}
$query = 'INSERT INTO sbas (ord, host, port, dbname, sqlengine, user, pwd)
SELECT COALESCE(MAX(ord), 0) + 1 AS ord, :host AS host, :port AS port, :dbname AS dbname,
"MYSQL" AS sqlengine, :user AS user, :password AS pwd FROM sbas';
$stmt = $this->connection->prepare($query);
$stmt->execute($params);
$stmt->closeCursor();
return $this->find((int) $this->connection->lastInsertId());
}
} }

View File

@@ -0,0 +1,38 @@
<?php
/**
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Filesystem;
use Alchemy\Phrasea\Application;
class ApplicationPathServiceGenerator
{
public function createDefinition(array $key, callable $default)
{
return function(Application $app) use ($key, $default) {
static $path;
if (null === $path) {
$path = ($app['phraseanet.configuration']->isSetup())
? $app['conf']->get($key)
: null;
if (null === $path) {
$path = $default($app);
}
// ensure path is created
$app['filesystem']->mkdir($path);
}
return $path;
};
}
}

View File

@@ -0,0 +1,208 @@
<?php
/**
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Filesystem;
use MediaAlchemyst\Specification\SpecificationInterface;
class FilesystemService
{
/**
* @var \Symfony\Component\Filesystem\Filesystem
*/
private $filesystem;
public function __construct(\Symfony\Component\Filesystem\Filesystem $filesystem)
{
$this->filesystem = $filesystem;
}
/**
* @param string $repository_path
* @return string
*/
public function directorySpread($repository_path)
{
$repository_path = \p4string::addEndSlash($repository_path);
$timestamp = strtotime(date('Y-m-d'));
$year = date('Y', $timestamp);
$month = date('m', $timestamp);
$day = date('d', $timestamp);
$comp = $year . DIRECTORY_SEPARATOR . $month . DIRECTORY_SEPARATOR . $day . DIRECTORY_SEPARATOR;
$n = 0;
do {
$pathout = sprintf('%s%s%05d', $repository_path, $comp, $n++);
} while (is_dir($pathout) && iterator_count(new \DirectoryIterator($pathout)) > 100);
$this->filesystem->mkdir($pathout, 0750);
return $pathout . DIRECTORY_SEPARATOR;
}
public function exists($path)
{
return $this->filesystem->exists($path);
}
public function generateSubdefPathname(\record_adapter $record, \databox_subdef $subdef, $oldVersion)
{
if ($oldVersion) {
$pathdest = \p4string::addEndSlash(pathinfo($oldVersion, PATHINFO_DIRNAME));
} else {
$pathdest = $this->directorySpread($subdef->get_path());
}
return $pathdest . $this->generateSubdefFilename($record, $subdef);
}
/**
* @param \record_adapter $record
* @param string|\SplFileInfo $source
* @return string
*/
public function generateDocumentFilename(\record_adapter $record, $source)
{
if (!$source instanceof \SplFileInfo) {
$source = new \SplFileInfo($source);
}
return $record->getRecordId() . '_document' . strtolower($source->getExtension());
}
/**
* @param \record_adapter $record
* @param \databox_subdef $subdef
* @param string $marker
* @return string
*/
public function generateSubdefFilename(\record_adapter $record, \databox_subdef $subdef, $marker = '')
{
return $record->getRecordId() . '_' . $marker . $subdef->get_name() . '.' . $this->getExtensionFromSpec($subdef->getSpecs());
}
public function generateSubdefSubstitutionPathname(\record_adapter $record, \databox_subdef $subdef)
{
$pathdest = $this->directorySpread($subdef->get_path());
return $pathdest . $this->generateSubdefFilename($record, $subdef, '0_');
}
/**
* @param \databox $databox
* @return string
*/
public function generateDataboxDocumentBasePath(\databox $databox)
{
$baseprefs = $databox->get_sxml_structure();
return $this->directorySpread(\p4string::addEndSlash((string)($baseprefs->path)));
}
/**
* Write Media source file with given filename
*
* @param \databox $databox
* @param string $source
* @param string $filename
*/
public function writeMediaSourceFile(\databox $databox, $source, $filename)
{
$realPath = $this->generateDataboxDocumentBasePath($databox) . $filename;
$this->filesystem->copy($source, $realPath, true);
$this->filesystem->chmod($realPath, 0760);
}
/**
* Copy file from source to target
*
* @param string $source
* @param string $target
*/
public function copy($source, $target)
{
$this->filesystem->copy($source, $target, true);
}
public function chmod($files, $mode, $umask = 0000, $recursive = false)
{
$this->filesystem->chmod($files, $mode, $umask, $recursive);
}
/**
* Get the extension from MediaAlchemyst specs
*
* @param SpecificationInterface $spec
*
* @return string
*/
private function getExtensionFromSpec(SpecificationInterface $spec)
{
switch ($spec->getType()) {
case SpecificationInterface::TYPE_IMAGE:
return 'jpg';
case SpecificationInterface::TYPE_ANIMATION:
return 'gif';
case SpecificationInterface::TYPE_AUDIO:
return $this->getExtensionFromAudioCodec($spec->getAudioCodec());
case SpecificationInterface::TYPE_VIDEO:
return $this->getExtensionFromVideoCodec($spec->getVideoCodec());
case SpecificationInterface::TYPE_SWF:
return 'swf';
}
return null;
}
/**
* Get the extension from audiocodec
*
* @param string $audioCodec
*
* @return string
*/
private function getExtensionFromAudioCodec($audioCodec)
{
switch ($audioCodec) {
case 'flac':
return 'flac';
case 'libvorbis':
return 'ogg';
case 'libmp3lame':
return 'mp3';
}
return null;
}
/**
* Get the extension from videocodec
*
* @param string $videoCodec
*
* @return string
*/
private function getExtensionFromVideoCodec($videoCodec)
{
switch ($videoCodec) {
case 'libtheora':
return 'ogv';
case 'libvpx':
return 'webm';
case 'libx264':
return 'mp4';
}
return null;
}
}

View File

@@ -1,6 +1,5 @@
<?php <?php
/**
/*
* This file is part of Phraseanet * This file is part of Phraseanet
* *
* (c) 2005-2016 Alchemy * (c) 2005-2016 Alchemy
@@ -9,26 +8,40 @@
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
namespace Alchemy\Phrasea\Core\Provider; namespace Alchemy\Phrasea\Filesystem;
use Neutron\TemporaryFilesystem\TemporaryFilesystem;
use Neutron\TemporaryFilesystem\Manager; use Neutron\TemporaryFilesystem\Manager;
use Neutron\TemporaryFilesystem\TemporaryFilesystem;
use Silex\Application; use Silex\Application;
use Silex\ServiceProviderInterface; use Silex\ServiceProviderInterface;
use Symfony\Component\Filesystem\Filesystem;
class TemporaryFilesystemServiceProvider implements ServiceProviderInterface class FilesystemServiceProvider implements ServiceProviderInterface
{ {
public function register(Application $app) public function register(Application $app)
{ {
$app['filesystem'] = $app->share(function () {
return new Filesystem();
});
$app['temporary-filesystem.temporary-fs'] = $app->share(function (Application $app) { $app['temporary-filesystem.temporary-fs'] = $app->share(function (Application $app) {
return new TemporaryFilesystem($app['filesystem']); return new TemporaryFilesystem($app['filesystem']);
}); });
$app['temporary-filesystem'] = $app->share(function (Application $app) { $app['temporary-filesystem'] = $app->share(function (Application $app) {
return new Manager($app['temporary-filesystem.temporary-fs'], $app['filesystem']); return new Manager($app['temporary-filesystem.temporary-fs'], $app['filesystem']);
}); });
$app['phraseanet.filesystem'] = $app->share(function (Application $app) {
return new FilesystemService($app['filesystem']);
});
$app['phraseanet.lazaret_filesystem'] = $app->share(function (Application $app) {
return new LazaretFilesystemService($app['filesystem'], $app['tmp.lazaret.path'], $app['media-alchemyst']);
});
} }
public function boot(Application $app) public function boot(Application $app)
{ {
// no-op
} }
} }

Some files were not shown because too many files have changed in this diff Show More