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:
- 5.5
- 5.6
- 7.0
matrix:
fast_finish: true
allow_failures:
- php: 7.0
services:
- mysql
- memcached

View File

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

View File

@@ -36,14 +36,14 @@ database:
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;';
post:
- "./bin/developer system:uninstall"
- "./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/developer ini:setup-tests-dbs"
- "./bin/console searchengine:index:create"
- "./bin/developer phraseanet:regenerate-sqlite"
- "./bin/developer phraseanet:generate-js-fixtures"
- "./bin/developer system:uninstall -v"
- "./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 -v"
- "./bin/console searchengine:index:create -v"
- "./bin/developer phraseanet:regenerate-sqlite -v"
- "./bin/developer phraseanet:generate-js-fixtures -v"
test:
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

View File

@@ -22,10 +22,6 @@
"type": "vcs",
"url": "https://github.com/alchemy-fr/JMSTranslationBundle"
},
{
"type": "git",
"url": "https://github.com/alchemy-fr/symfony-cors"
},
{
"type": "vcs",
"url": "https://github.com/alchemy-fr/embed-bundle.git"
@@ -34,7 +30,7 @@
"require": {
"php": ">=5.5",
"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/google-plus-api-client": "~0.6.2",
"alchemy/mediavorus": "^0.4.4",
@@ -68,6 +64,8 @@
"jms/serializer": "~0.10",
"jms/translation-bundle": "dev-rebase-2015-10-20",
"justinrainbow/json-schema": "~1.3",
"league/flysystem": "^1.0",
"league/flysystem-aws-s3-v2": "^1.0",
"media-alchemyst/media-alchemyst": "~0.4",
"monolog/monolog": "~1.3",
"mrclay/minify": "~2.1.6",
@@ -113,7 +111,7 @@
"include-path": ["vendor/zend/gdata/library"],
"extra": {
"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;
use Alchemy\Cors\Options\DefaultProvider;
use Alchemy\CorsProvider\CorsServiceProvider;
use Alchemy\Geonames\GeonamesServiceProvider;
use Alchemy\Phrasea\Application\Environment;
use Alchemy\Phrasea\Application\Helper\AclAware;
use Alchemy\Phrasea\Application\Helper\ApplicationBoxAware;
use Alchemy\Phrasea\Application\Helper\AuthenticatorAware;
use Alchemy\Phrasea\Application\RouteLoader;
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\BridgeSubscriber;
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\RegistrationSubscriber;
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\BasketMiddlewareProvider;
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\ConfigurationServiceProvider;
use Alchemy\Phrasea\Core\Provider\ConfigurationTesterServiceProvider;
use Alchemy\Phrasea\Core\Provider\ContentNegotiationServiceProvider;
use Alchemy\Phrasea\Core\Provider\ConvertersServiceProvider;
use Alchemy\Phrasea\Core\Provider\CSVServiceProvider;
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\ManipulatorServiceProvider;
use Alchemy\Phrasea\Core\Provider\NotificationDelivererServiceProvider;
use Alchemy\Phrasea\Core\Provider\ORMServiceProvider;
use Alchemy\Phrasea\Core\Provider\PhraseaEventServiceProvider;
use Alchemy\Phrasea\Core\Provider\PhraseanetServiceProvider;
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\SearchEngineServiceProvider;
use Alchemy\Phrasea\Core\Provider\SerializerServiceProvider;
use Alchemy\Phrasea\Core\Provider\SessionHandlerServiceProvider;
use Alchemy\Phrasea\Core\Provider\StatusServiceProvider;
use Alchemy\Phrasea\Core\Provider\SubdefServiceProvider;
use Alchemy\Phrasea\Core\Provider\TasksServiceProvider;
use Alchemy\Phrasea\Core\Provider\TemporaryFilesystemServiceProvider;
use Alchemy\Phrasea\Core\Provider\TokensServiceProvider;
use Alchemy\Phrasea\Core\Provider\TranslationServiceProvider;
use Alchemy\Phrasea\Core\Provider\UnicodeServiceProvider;
use Alchemy\Phrasea\Core\Provider\WebhookServiceProvider;
use Alchemy\Phrasea\Core\Provider\ZippyServiceProvider;
use Alchemy\Phrasea\Core\Provider\WebProfilerServiceProvider as PhraseaWebProfilerServiceProvider;
use Alchemy\Phrasea\Exception\InvalidArgumentException;
use Alchemy\Phrasea\Filesystem\FilesystemServiceProvider;
use Alchemy\Phrasea\Filesystem\ApplicationPathServiceGenerator;
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\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\Events;
use Doctrine\ORM\Configuration;
use FFMpeg\FFMpegServiceProvider;
use Gedmo\DoctrineExtensions as GedmoExtension;
use MediaAlchemyst\MediaAlchemystServiceProvider;
use MediaVorus\Media\MediaInterface;
use MediaVorus\MediaVorus;
use MediaVorus\MediaVorusServiceProvider;
use Monolog\Handler\NullHandler;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Handler\SyslogHandler;
use Monolog\Logger;
use Monolog\Processor\IntrospectionProcessor;
use MP4Box\MP4BoxServiceProvider;
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\TranslationTrait;
use Silex\Application\UrlGeneratorTrait;
use Silex\ControllerProviderInterface;
use Silex\Provider\DoctrineServiceProvider;
use Silex\Provider\FormServiceProvider;
use Silex\Provider\HttpFragmentServiceProvider;
use Silex\Provider\MonologServiceProvider;
use Silex\Provider\ServiceControllerServiceProvider;
use Silex\Provider\SessionServiceProvider;
use Silex\Provider\SwiftmailerServiceProvider;
use Silex\Provider\TwigServiceProvider;
use Silex\Provider\UrlGeneratorServiceProvider;
use Silex\Provider\ValidatorServiceProvider;
use Silex\Provider\WebProfilerServiceProvider;
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\FormException;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormTypeInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Unoconv\UnoconvServiceProvider;
use XPDF\PdfToText;
use XPDF\XPDFServiceProvider;
@@ -139,6 +116,10 @@ class Application extends SilexApplication
use UrlGeneratorTrait;
use TranslationTrait;
const ENV_DEV = 'dev';
const ENV_PROD = 'prod';
const ENV_TEST = 'test';
protected static $availableLanguages = [
'de' => 'Deutsch',
'en' => 'English',
@@ -147,38 +128,31 @@ class Application extends SilexApplication
];
private static $flashTypes = ['warning', 'info', 'success', 'error'];
/**
* @var Environment
*/
private $environment;
const ENV_DEV = 'dev';
const ENV_PROD = 'prod';
const ENV_TEST = 'test';
public function getEnvironment()
/**
* @param Environment|string $environment
*/
public function __construct($environment = null)
{
return $this->environment;
}
if (is_string($environment)) {
$environment = new Environment($environment, false);
}
public function __construct($environment = self::ENV_PROD)
{
parent::__construct();
$this->environment = $environment ?: new Environment(self::ENV_PROD, false);
error_reporting(-1);
$this->environment = $environment;
parent::__construct([
'debug' => $this->environment->isDebug()
]);
$this->setupCharset();
$this->setupApplicationPaths();
$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')) {
$this->register(new PimpleDumpProvider());
}
@@ -191,11 +165,9 @@ class Application extends SilexApplication
$this->register(new CacheConnectionServiceProvider());
$this->register(new PhraseanetServiceProvider());
$this->register(new ConfigurationTesterServiceProvider());
$this->register(new DoctrineServiceProvider());
$this->setupDBAL();
$this->register(new DoctrineOrmServiceProvider());
$this->setupOrms();
$this->register(new ORMServiceProvider());
$this->register(new DatabaseMetaProvider());
$this->register(new BasketMiddlewareProvider());
$this->register(new TokenMiddlewareProvider());
$this->register(new AccountServiceProvider());
@@ -208,25 +180,19 @@ class Application extends SilexApplication
$this->register(new ConvertersServiceProvider());
$this->register(new CSVServiceProvider());
$this->register(new RegistrationServiceProvider());
$this->register(new ImagineServiceProvider());
$this->setUpImagine();
$this->register(new JMSSerializerServiceProvider());
$this->register(new FFMpegServiceProvider());
$this->register(new FeedServiceProvider());
$this->register(new FtpServiceProvider());
$this->register(new GeonamesServiceProvider());
$this->register(new StatusServiceProvider());
$this->setupGeonames();
$this->register(new MediaAlchemystServiceProvider());
$this->setupMediaAlchemyst();
$this->register(new MediaVorusServiceProvider());
$this->register(new MP4BoxServiceProvider());
$this->register(new NotificationDelivererServiceProvider());
$this->register(new RepositoriesServiceProvider());
$this->register(new ManipulatorServiceProvider());
$this->register(new InstallerServiceProvider());
$this->register(new PhraseaVersionServiceProvider());
$this->register(new PHPExiftoolServiceProvider());
$this->register(new RandomGeneratorServiceProvider());
$this->register(new ReCaptchaServiceProvider());
$this->register(new SubdefServiceProvider());
@@ -238,37 +204,23 @@ class Application extends SilexApplication
$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 ServiceControllerServiceProvider());
$this->register(new SwiftmailerServiceProvider());
$this->setupSwiftMailer();
$this->register(new TasksServiceProvider());
$this->register(new TemporaryFilesystemServiceProvider());
$this->register(new TokensServiceProvider());
$this->register(new HttpFragmentServiceProvider());
$this->register(new TwigServiceProvider());
$this->setupTwig();
$this->register(new TranslationServiceProvider(), [
'locale_fallbacks' => ['fr'],
'translator.cache-options' => [
'debug' => $this['debug'],
'cache_dir' => $this->share(function($app) {
return $app['cache.path'].'/translations';
}),
],
]);
$this->setupTranslation();
$this->register(new TemplateEngineMetaProvider());
$this->register(new HttpStackMetaProvider());
$this->register(new MediaUtilitiesMetaServiceProvider());
$this->register(new TranslationMetaProvider());
$this->register(new FormServiceProvider());
$this->setupForm();
$this->register(new UnoconvServiceProvider());
$this->register(new UrlGeneratorServiceProvider());
$this->setupUrlGenerator();
$this->register(new UnicodeServiceProvider());
$this->register(new ValidatorServiceProvider());
$this->register(new XPDFServiceProvider());
@@ -277,108 +229,58 @@ class Application extends SilexApplication
$this->register(new ManipulatorServiceProvider());
$this->register(new PluginServiceProvider());
$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->setupEventDispatcher();
$this->register(new WebhookServiceProvider());
$this['phraseanet.exception_handler'] = $this->share(function ($app) {
/** @var PhraseaExceptionHandler $handler */
$handler = PhraseaExceptionHandler::register($app['debug']);
$handler->setTranslator($app['translator']);
$handler->setLogger($app['monolog']);
return $handler;
});
$providers = [
'Alchemy\Phrasea\ControllerProvider\Admin\Collection' => [],
'Alchemy\Phrasea\ControllerProvider\Admin\ConnectedUsers' => [],
'Alchemy\Phrasea\ControllerProvider\Admin\Dashboard' => [],
'Alchemy\Phrasea\ControllerProvider\Admin\Databox' => [],
'Alchemy\Phrasea\ControllerProvider\Admin\Databoxes' => [],
'Alchemy\Phrasea\ControllerProvider\Admin\Feeds' => [],
'Alchemy\Phrasea\ControllerProvider\Admin\Fields' => [],
'Alchemy\Phrasea\ControllerProvider\Admin\Plugins' => [],
'Alchemy\Phrasea\ControllerProvider\Admin\Root' => [],
'Alchemy\Phrasea\ControllerProvider\Admin\SearchEngine' => [],
'Alchemy\Phrasea\ControllerProvider\Admin\Setup' => [],
'Alchemy\Phrasea\ControllerProvider\Admin\Subdefs' => [],
'Alchemy\Phrasea\ControllerProvider\Admin\TaskManager' => [],
'Alchemy\Phrasea\ControllerProvider\Admin\Users' => [],
'Alchemy\Phrasea\ControllerProvider\Client\Root' => [],
'Alchemy\Phrasea\ControllerProvider\Datafiles' => [],
'Alchemy\Phrasea\ControllerProvider\Lightbox' => [],
'Alchemy\Phrasea\ControllerProvider\MediaAccessor' => [],
'Alchemy\Phrasea\ControllerProvider\Minifier' => [],
'Alchemy\Phrasea\ControllerProvider\Permalink' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\BasketProvider' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\Bridge' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\DoDownload' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\Download' => [],
'Alchemy\Phrasea\ControllerProvider\Prod\Edit' => [],
'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);
$resolvers = $this['alchemy_embed.resource_resolvers'];
$resolvers['datafile'] = $resolvers->share(function () {
return new DatafilesResolver($this->getApplicationBox());
});
$resolvers['permalinks_permalink'] = $resolvers->share(function () {
return new PermalinkMediaResolver($this->getApplicationBox());
});
$resolvers['media_accessor'] = $resolvers->share(function () {
return new MediaAccessorResolver(
$this->getApplicationBox(), $this['controller.media_accessor']
);
});
if (self::ENV_DEV === $this->getEnvironment()) {
$this->register($p = new WebProfilerServiceProvider(), [
'profiler.cache_dir' => $this['cache.path'].'/profiler',
]);
$this->register(new PhraseaWebProfilerServiceProvider());
$this->mount('/_profiler', $p);
if ($this['phraseanet.configuration-tester']->isInstalled()) {
$this['db'] = $this->share(function (self $app) {
return $app['orm.em']->getConnection();
});
}
}
}
public function getEnvironment()
{
return $this->environment->getName();
}
/**
* Loads Phraseanet plugins
*/
@@ -436,113 +338,6 @@ class Application extends SilexApplication
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.
*
@@ -619,6 +414,14 @@ class Application extends SilexApplication
return $this;
}
/**
* @return bool
*/
public function isDebug()
{
return $this->environment->isDebug();
}
/**
* Returns true if a captcha is required for next authentication
*
@@ -674,75 +477,11 @@ class Application extends SilexApplication
*/
public function bindRoutes()
{
$providers = [
'/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',
];
$loader = new RouteLoader();
// controllers with routes referenced by api
$providers[$this['controller.media_accessor.route_prefix']] = 'Alchemy\Phrasea\ControllerProvider\MediaAccessor';
foreach ($providers as $prefix => $class) {
$this->mount($prefix, new $class);
}
$loader->registerProviders(RouteLoader::$defaultProviders);
$loader->bindRoutes($this);
$this->bindPluginRoutes('plugin.controller_providers.root');
}
@@ -786,86 +525,53 @@ class Application extends SilexApplication
// app root path
$this['root.path'] = realpath(__DIR__ . '/../../..');
// 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
$this['plugin.path'] = $dir = $this['root.path'].'/plugins';
$this['plugin.path'] = $this['root.path'].'/plugins';
// 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 ...)
$this['cache.path'] = $this->share(function() {
$defaultPath = $path = $this['root.path'].'/cache';
if ($this['phraseanet.configuration']->isSetup()) {
$path = $this['conf']->get(['main', 'storage', 'cache'], $path);
$factory = new ApplicationPathServiceGenerator();
$this['cache.path'] = $factory->createDefinition(
['main', 'storage', 'cache'],
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) {
return new \ArrayObject([
$app['cache.path'],
]);
};
// log path
$this['log.path'] = $this->share(function() {
$defaultPath = $path = $this['root.path'].'/logs';
if ($this['phraseanet.configuration']->isSetup()) {
return $this['conf']->get(['main', 'storage', 'log'], $path);
$this['log.path'] = $factory->createDefinition(
['main', 'storage', 'log'],
function (Application $app) {
return $app['root.path'].'/logs';
}
$path = $path ?: $defaultPath;
);
// ensure path is created
$this['filesystem']->mkdir($path);
return $path;
});
// 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);
$this['tmp.download.path'] = $factory->createDefinition(
['main', 'storage', 'download'],
function (Application $app) {
return $app['tmp.path'].'/download';
}
$path = $path ?: $defaultPath;
);
// ensure path is created
$this['filesystem']->mkdir($path);
return $path;
});
// 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);
$this['tmp.lazaret.path'] = $factory->createDefinition(
['main', 'storage', 'quarantine'],
function (Application $app) {
return $app['tmp.path'].'/lazaret';
}
$path = $path ?: $defaultPath;
);
// ensure path is created
$this['filesystem']->mkdir($path);
return $path;
});
// 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);
$this['tmp.caption.path'] = $factory->createDefinition(
['main', 'storage', 'caption'],
function (Application $app) {
return $app['tmp.path'].'/caption';
}
$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()
{
$this['recaptcha.public-key'] = $this->share(function (Application $app) {
@@ -1000,38 +614,10 @@ class Application extends SilexApplication
private function setupGeonames()
{
$this['geonames.server-uri'] = $this->share(function (Application $app) {
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
* @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()
{
$this['swiftmailer.transport'] = $this->share(function (Application $app) {
@@ -1161,8 +693,7 @@ class Application extends SilexApplication
private function setupEventDispatcher()
{
$this['dispatcher'] = $this->share(
$this->extend('dispatcher', function ($dispatcher, Application $app) {
//$dispatcher->addListener(KernelEvents::RESPONSE, [$app, 'addUTF8Charset'], -128);
$this->extend('dispatcher', function (EventDispatcherInterface $dispatcher, Application $app) {
$dispatcher->addSubscriber($app['phraseanet.logout-subscriber']);
$dispatcher->addSubscriber($app['phraseanet.locale-subscriber']);
$dispatcher->addSubscriber($app['phraseanet.content-negotiation-subscriber']);
@@ -1190,12 +721,15 @@ class Application extends SilexApplication
if (!defined('JETON_MAKE_SUBDEF')) {
define('JETON_MAKE_SUBDEF', 0x01);
}
if (!defined('JETON_WRITE_META_DOC')) {
define('JETON_WRITE_META_DOC', 0x02);
}
if (!defined('JETON_WRITE_META_SUBDEF')) {
define('JETON_WRITE_META_SUBDEF', 0x04);
}
if (!defined('JETON_WRITE_META')) {
define('JETON_WRITE_META', 0x06);
}
@@ -1212,30 +746,8 @@ class Application extends SilexApplication
*/
public function bindPluginRoutes($routeParameter)
{
foreach ($this[$routeParameter] as $provider) {
$prefix = '';
$loader = new RouteLoader();
if (is_array($provider)) {
$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);
}
$loader->bindPluginRoutes($this, $routeParameter);
}
}

View File

@@ -52,10 +52,10 @@ return call_user_func(function ($environment = PhraseaApplication::ENV_PROD) {
}));
$app['phraseanet.content-negotiation.priorities'] = array_merge(
['application/json', 'application/yaml', 'text/yaml', 'text/javascript', 'application/javascript'],
V1::$extendedContentTypes['json'],
V1::$extendedContentTypes['jsonp'],
V1::$extendedContentTypes['yaml'],
['application/json', 'application/yaml', 'text/yaml', 'text/javascript', 'application/javascript']
V1::$extendedContentTypes['yaml']
);
$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;
use Alchemy\Phrasea\Collection\CollectionService;
trait ApplicationBoxAware
{
/** @var \appbox|callable */
@@ -61,6 +63,14 @@ trait ApplicationBoxAware
return $this->applicationBox;
}
/**
* @return CollectionService
*/
public function getCollectionService()
{
return $this['services.collection'];
}
/**
* Find a registered Databoxes.
*

View File

@@ -10,6 +10,7 @@
namespace Alchemy\Phrasea\Application\Helper;
use Alchemy\Phrasea\Http\DeliverDataInterface;
use Symfony\Component\HttpFoundation\Response;
trait DelivererAware
{
@@ -57,28 +58,15 @@ trait DelivererAware
/**
* Returns a HTTP Response ready to deliver a binary file
*
* @param string $file
* @param string $filename
* @param string $disposition
* @param string $file
* @param string $filename
* @param string $disposition
* @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)
{
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;
use Neutron\TemporaryFilesystem\Manager;
use Neutron\TemporaryFilesystem\TemporaryFilesystemInterface;
use Symfony\Component\Filesystem\Filesystem;
trait FilesystemAware

View File

@@ -9,80 +9,9 @@
* 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\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) {
$app = new PhraseaApplication($environment);
$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(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);
return (new Application\ApplicationLoader())->buildWebApplication(
isset($environment) ? $environment : Application::ENV_PROD,
isset($forceDebug) ? $forceDebug : false
);

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;
}
$collection = \collection::get_from_base_id($this->app, $baseId);
$collection = \collection::getByBaseId($this->app, $baseId);
$registrationManipulator->createRegistration($user, $collection);
$successfulRegistrations[$baseId] = $collection;
});

View File

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

View File

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

View File

@@ -11,6 +11,7 @@
namespace Alchemy\Phrasea\Border;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Border\Checker\CheckerInterface;
use Alchemy\Phrasea\Border\Attribute\AttributeInterface;
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\LazaretFile;
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\Value\Mono as MonoValue;
use PHPExiftool\Driver\Value\Multi;
use Silex\Application;
use Symfony\Component\Filesystem\Exception\IOException;
/**
@@ -44,6 +42,9 @@ use Symfony\Component\Filesystem\Exception\IOException;
*/
class Manager
{
/**
* @var CheckerInterface[]
*/
protected $checkers = [];
protected $app;
protected $filesystem;
@@ -159,7 +160,9 @@ class Manager
}
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;
@@ -242,42 +245,11 @@ class Manager
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
*
* @param File $file The package file
* @return \record_adater
* @return \record_adapter
*/
protected function createRecord(File $file, $nosubdef=false)
{
@@ -384,21 +356,8 @@ class Manager
)
);
$lazaretPathname = $this->bookLazaretPathfile($file->getOriginalName());
$lazaretPathnameThumb = $this->bookLazaretPathfile($file->getOriginalName(), 'thumb');
$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) {
}
$lazaretFilesystemService = $this->app['phraseanet.lazaret_filesystem'];
$persistedLazaret = $lazaretFilesystemService->writeLazaret($file);
$lazaretFile = new LazaretFile();
$lazaretFile->setBaseId($file->getCollection()->get_base_id());
@@ -408,8 +367,8 @@ class Manager
$lazaretFile->setForced($forced);
$lazaretFile->setFilename(pathinfo($lazaretPathname, PATHINFO_BASENAME));
$lazaretFile->setThumbFileName(pathinfo($lazaretPathnameThumb, PATHINFO_BASENAME));
$lazaretFile->setFilename($persistedLazaret->getFilename());
$lazaretFile->setThumbFileName($persistedLazaret->getThumbnailFilename());
$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
/*
* 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\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Process\ExecutableFinder;
use Symfony\Component\Yaml\Yaml;
use Symfony\Component\Process\Process;
use vierbergenlars\SemVer\version as SemVer;
@@ -65,7 +62,7 @@ class IniReset extends Command
$dialog = $this->getHelperSet()->get('dialog');
$dbName = $dialog->ask(
$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')) {
@@ -75,7 +72,7 @@ class IniReset extends Command
}
$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) {
do {
$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;
}
$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) {
array_unshift($unmountedDbs, 'all');

View File

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

View File

@@ -43,7 +43,7 @@ class RecordAdd extends Command
protected function doExecute(InputInterface $input, OutputInterface $output)
{
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) {
throw new \InvalidArgumentException(sprintf('Collection %s is invalid', $input->getArgument('base_id')));
}

View File

@@ -12,6 +12,7 @@
namespace Alchemy\Phrasea\Command\Setup;
use Alchemy\Phrasea\Command\Command;
use Alchemy\Phrasea\Databox\DataboxPathExtractor;
use Alchemy\Phrasea\Http\H264PseudoStreaming\H264Factory;
use Alchemy\Phrasea\Model\Manipulator\TokenManipulator;
use Symfony\Component\Console\Input\InputArgument;
@@ -36,7 +37,8 @@ class H264MappingGenerator extends Command
*/
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) {
$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)];
}
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;
use Alchemy\Phrasea\Command\Command;
use Alchemy\Phrasea\Databox\DataboxPathExtractor;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
@@ -35,7 +36,8 @@ class XSendFileMappingGenerator extends Command
*/
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) {
$this->container['filesystem']->mkdir($path);
}
@@ -84,20 +86,4 @@ class XSendFileMappingGenerator extends Command
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();
try {
$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);
$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\Http\DeliverDataInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
abstract class AbstractDelivery
{
@@ -33,26 +32,20 @@ abstract class AbstractDelivery
public function deliverContent(Request $request, \record_adapter $record, $subdef, $watermark, $stamp)
{
$file = $record->get_subdef($subdef);
$pathOut = $file->get_pathfile();
$mediaSubdefinition = $record->get_subdef($subdef);
if ($watermark === true && $file->get_type() === \media_subdef::TYPE_IMAGE) {
$pathOut = \recordutils_image::watermark($this->app, $file);
} elseif ($stamp === true && $file->get_type() === \media_subdef::TYPE_IMAGE) {
$pathOut = \recordutils_image::stamp($this->app, $file);
}
$pathOut = $this->tamperProofSubDefinition($mediaSubdefinition, $watermark, $stamp);
$disposition = $request->query->get('download') ? DeliverDataInterface::DISPOSITION_ATTACHMENT : DeliverDataInterface::DISPOSITION_INLINE;
/** @var Response $response */
$response = $this->deliverFile($pathOut, $file->get_file(), $disposition, $file->get_mime());
$response = $this->deliverFile($pathOut, $mediaSubdefinition->get_file(), $disposition, $mediaSubdefinition->get_mime());
if (in_array($subdef, array('document', 'preview'))) {
$response->setPrivate();
$this->logView($record, $request);
} elseif ($subdef !== 'thumbnail') {
try {
if ($file->getDataboxSubdef()->get_class() != \databox_subdef::CLASS_THUMBNAIL) {
if ($mediaSubdefinition->getDataboxSubdef()->get_class() != \databox_subdef::CLASS_THUMBNAIL) {
$response->setPrivate();
$this->logView($record, $request);
}
@@ -81,4 +74,23 @@ abstract class AbstractDelivery
// 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)
{
$collection = \collection::get_from_base_id($this->app, $bas_id);
$collection = \collection::getByBaseId($this->app, $bas_id);
$admins = [];
@@ -144,7 +144,7 @@ class CollectionController extends Controller
$success = false;
$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 {
if ($collection->get_record_amount() <= 500) {
$collection->empty_collection(500);
@@ -184,7 +184,7 @@ class CollectionController extends Controller
{
$success = false;
$collection = \collection::get_from_base_id($this->app, $bas_id);
$collection = \collection::getByBaseId($this->app, $bas_id);
try {
$this->app->getApplicationBox()->write_collection_pic(
@@ -224,7 +224,7 @@ class CollectionController extends Controller
{
$success = false;
$collection = \collection::get_from_base_id($this->app, $bas_id);
$collection = \collection::getByBaseId($this->app, $bas_id);
try {
$this->app->getApplicationBox()->write_collection_pic(
@@ -264,7 +264,7 @@ class CollectionController extends Controller
{
$success = false;
$collection = \collection::get_from_base_id($this->app, $bas_id);
$collection = \collection::getByBaseId($this->app, $bas_id);
try {
$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 {
$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 {
$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 {
$this->app->getApplicationBox()->write_collection_pic(
@@ -468,13 +468,13 @@ class CollectionController extends Controller
$success = false;
$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 {
if ($collection->get_record_amount() > 0) {
$msg = $this->app->trans('Empty the collection before removing');
} else {
$collection->unmount_collection($this->app);
$collection->unmount();
$collection->delete();
$success = true;
$msg = $this->app->trans('Successful removal');
@@ -522,10 +522,10 @@ class CollectionController extends Controller
{
$success = false;
$collection = \collection::get_from_base_id($this->app, $bas_id);
$collection = \collection::getByBaseId($this->app, $bas_id);
try {
$collection->unmount_collection($this->app);
$collection->unmount();
$success = true;
} catch (\Exception $e) {
@@ -562,7 +562,7 @@ class CollectionController extends Controller
$success = false;
$collection = \collection::get_from_base_id($this->app, $bas_id);
$collection = \collection::getByBaseId($this->app, $bas_id);
try {
$collection->set_name($name);
@@ -594,7 +594,7 @@ class CollectionController extends Controller
$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;
try {
@@ -638,7 +638,7 @@ class CollectionController extends Controller
$success = false;
$collection = \collection::get_from_base_id($this->app, $bas_id);
$collection = \collection::getByBaseId($this->app, $bas_id);
try {
$collection->set_public_presentation($watermark);
@@ -671,7 +671,7 @@ class CollectionController extends Controller
{
$success = false;
$collection = \collection::get_from_base_id($this->app, $bas_id);
$collection = \collection::getByBaseId($this->app, $bas_id);
try {
$collection->enable($this->app->getApplicationBox());
@@ -704,7 +704,7 @@ class CollectionController extends Controller
{
$success = false;
$collection = \collection::get_from_base_id($this->app, $bas_id);
$collection = \collection::getByBaseId($this->app, $bas_id);
try {
$collection->disable($this->app->getApplicationBox());
@@ -736,7 +736,7 @@ class CollectionController extends Controller
{
/** @var \databox $databox */
$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 = [];
/** @var \databox_field $meta */
@@ -806,7 +806,7 @@ class CollectionController extends Controller
{
$success = false;
$collection = \collection::get_from_base_id($this->app, $bas_id);
$collection = \collection::getByBaseId($this->app, $bas_id);
$prefs = $request->request->get('str');
try {
@@ -843,7 +843,7 @@ class CollectionController extends Controller
*/
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' => []];

View File

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

View File

@@ -633,7 +633,7 @@ class DataboxController extends Controller
{
try {
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']);
}
$success = true;
@@ -712,7 +712,7 @@ class DataboxController extends Controller
} catch (\Exception $e) {
return $this->app->redirectPath('admin_database_submit_collection', [
'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') {
$feed->setIsPublic(true);
} 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);
@@ -106,7 +106,7 @@ class FeedController extends Controller
}
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) {
$collection = null;
}

View File

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

View File

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

View File

@@ -837,7 +837,7 @@ class V1Controller extends Controller
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')) {
return Result::createError($request, 403, sprintf(
@@ -935,7 +935,7 @@ class V1Controller extends Controller
$media = $this->app->getMediaFromUri($file->getPathname());
$record = $this->findDataboxById($request->get('databox_id'))->get_record($request->get('record_id'));
$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')) {
return Result::createError($request, 403, sprintf(
'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'))));
$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) {
if ($name == $request->get('name') &&
null !== ($subdef = $this->listEmbeddableMedia($request, $record, $media))) {
@@ -1611,7 +1611,7 @@ class V1Controller extends Controller
$record = $databox->get_record($record_id);
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());
return Result::create($request, ["record" => $this->listRecord($request, $record)])->createResponse();
@@ -2067,7 +2067,7 @@ class V1Controller extends Controller
*/
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')) {
$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'))) {
continue;
}
$media = $this->app->getMediaFromUri($value->get_pathfile());
$story->substitute_subdef($name, $media, $this->app);
$media = $this->app->getMediaFromUri($value->getRealPath());
$this->getSubdefSubstituer()->substitute($story, $name, $media);
$this->getDataboxLogger($story->getDatabox())->log(
$story,
\Session_Logger::EVENT_SUBSTITUTE,
@@ -2304,7 +2304,7 @@ class V1Controller extends Controller
$ret = [ 'success' => true ];
}
catch (AccountException $exception) {
$ret = [ 'success' => false, 'message' => _($exception->getMessage()) ];
$ret = [ 'success' => false, 'message' => $this->app->trans($exception->getMessage()) ];
}
return Result::create($request, $ret)->createResponse();
@@ -2327,7 +2327,7 @@ class V1Controller extends Controller
$service->updatePassword($command, null);
$ret = ['success' => true];
} catch (AccountException $exception) {
$ret = [ 'success' => false, 'message' => _($exception->getMessage()) ];
$ret = [ 'success' => false, 'message' => $this->app->trans($exception->getMessage()) ];
}
} else {
$ret = [ 'success' => false, 'message' => (string) $form->getErrorsAsString() ];
@@ -2567,4 +2567,12 @@ class V1Controller extends Controller
{
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)
{
try {
$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;
list($sbas_id, $record_id, $subdef) = $this->validateToken($token);
try {
$databox = $this->findDataboxById($sbas_id);
@@ -93,4 +82,39 @@ class MediaAccessorController extends Controller
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;
use Alchemy\Embed\Media\Media;
use Alchemy\Embed\Media\MediaInformation;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Application\Helper\ApplicationBoxAware;
use Alchemy\Phrasea\Authentication\ACLProvider;
use Alchemy\Phrasea\Authentication\Authenticator;
use Alchemy\Phrasea\Model\Repositories\BasketElementRepository;
use Alchemy\Phrasea\Model\Repositories\FeedItemRepository;
use Alchemy\Phrasea\Model\Serializer\CaptionSerializer;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@@ -23,20 +24,19 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class PermalinkController extends AbstractDelivery
{
use ApplicationBoxAware;
/** @var ACLProvider */
private $acl;
/** @var \appbox */
private $appbox;
/** @var Authenticator */
private $authentication;
/** @var Media */
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);
$this->appbox = $appbox;
$this->acl = $acl;
$this->authentication = $authenticator;
$this->mediaService = $mediaService;
@@ -44,9 +44,9 @@ class PermalinkController extends AbstractDelivery
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');
$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) {
throw new NotFoundHttpException("Record not found");
@@ -57,9 +57,9 @@ class PermalinkController extends AbstractDelivery
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');
$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) {
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);
}
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);
}
@@ -84,35 +115,10 @@ class PermalinkController extends AbstractDelivery
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)
{
$databox = $this->mediaService->getDatabox($sbas_id);
// $record = $this->retrieveRecord($databox, $token, $record_id, $subdef);
$record = $this->mediaService->retrieveRecord($databox, $token, $record_id, $subdef);
$databox = $this->findDataboxById($sbas_id);
$record = $this->retrieveRecord($databox, $token, $record_id, $subdef);
$watermark = $stamp = false;
if ($this->authentication->isAuthenticated()) {
@@ -132,7 +138,7 @@ class PermalinkController extends AbstractDelivery
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()) {
default:
case 'none':
@@ -170,4 +176,42 @@ class PermalinkController extends AbstractDelivery
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;
}
$media = $this->app->getMediaFromUri($value->get_pathfile());
$media = $this->app->getMediaFromUri($value->getRealPath());
$this->getSubDefinitionSubstituer()->substitute($reg_record, $name, $media);
$this->getDispatcher()->dispatch(PhraseaEvents::RECORD_EDIT, new RecordEdit($reg_record));
$this->getDataboxLogger($reg_record->get_databox())->log(

View File

@@ -58,7 +58,7 @@ class MoveCollectionController extends Controller
}
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) {
$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']);
if (count($records->databoxes()) > 1) {
$databoxes = $records->databoxes();
if (count($databoxes) > 1) {
return new Response($this->render('prod/actions/Property/index.html.twig', [
'records' => $records,
]));
}
$databox = current($records->databoxes());
$databox = reset($databoxes);
$statusStructure = $databox->getStatusStructure();
$recordsStatuses = [];

View File

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

View File

@@ -41,35 +41,13 @@ class ShareController extends Controller
$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();
$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,
]);
$embedUrl = $this->app->url('alchemy_embed_view', ['url' => (string)$permalinkUrl]);
$outputVars = [
'isAvailable' => true,

View File

@@ -33,7 +33,7 @@ class StoryController extends Controller
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')) {
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()) {
try {
$metadata = $this->getExifToolReader()
->files($record->get_subdef('document')->get_pathfile())
->files($record->get_subdef('document')->getRealPath())
->first()->getMetadatas();
} catch (PHPExiftoolException $e) {
// ignore

View File

@@ -133,7 +133,7 @@ class UploadController extends Controller
$this->getFilesystem()->rename($uploadedFilename, $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->setUser($this->getAuthenticatedUser());

View File

@@ -316,7 +316,7 @@ class AccountController extends Controller
if (0 !== count($registrations)) {
foreach ($registrations as $baseId) {
$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.'));
}

View File

@@ -82,7 +82,7 @@ class SessionController extends Controller
if (in_array($this->getSession()->get('phraseanet.message'), ['1', null])) {
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)) {

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)
{
$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'])
->setDelivererLocator(new LazyLocator($app, 'phraseanet.file-serve'))
->setApplicationBox($app['phraseanet.appbox'])
;
});
}

View File

@@ -1,9 +1,8 @@
<?php
/*
/**
* 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
* file that was distributed with this source code.
@@ -11,37 +10,63 @@
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 Psr\Log\LoggerInterface;
class AccessRestriction
{
private $conf;
private $appbox;
private $logger;
private $cache;
/**
* @var PropertyAccess
*/
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->logger = $logger;
$this->cache = $cache;
}
/**
* Returns true if a configuration is set.
*
* @return Boolean
* @return bool
*/
public function isRestricted()
{
$this->load();
return $this->cache->fetch('restricted');
return $this->restricted;
}
/**
@@ -49,7 +74,7 @@ class AccessRestriction
*
* @param \databox $databox
*
* @return Boolean
* @return bool
*/
public function isDataboxAvailable(\databox $databox)
{
@@ -57,7 +82,7 @@ class AccessRestriction
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;
}
$available = array_flip($this->cache->fetch('available_databoxes'));
$available = array_flip($this->availableDataboxes);
return array_filter($databoxes, function (\databox $databox) use ($available) {
return isset($available[$databox->get_sbas_id()]);
@@ -84,7 +109,7 @@ class AccessRestriction
*
* @param \collection $collection
*
* @return Boolean
* @return bool
*/
public function isCollectionAvailable(\collection $collection)
{
@@ -92,30 +117,31 @@ class AccessRestriction
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);
}
private function load()
{
if ($this->cache->fetch('loaded')) {
if ($this->loaded) {
return;
}
$this->cache->save('loaded', true);
$this->loaded = true;
$allowedDataboxIds = array_map(function ($dbConf) {
return $dbConf['id'];
}, $this->conf->get('databoxes', []));
}, $this->propertyAccess->get('databoxes', []));
if (count($allowedDataboxIds) === 0) {
$this->cache->save('restricted', false);
$this->restricted = false;
return;
}
$this->cache->save('restricted', true);
$this->restricted = true;
$databoxIds = array_map(function (\databox $databox) { return $databox->get_sbas_id(); }, $this->appbox->get_databoxes());
$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)));
}
$allowedDataboxIds = array_intersect($allowedDataboxIds, $databoxIds);
$this->cache->save('available_databoxes', $allowedDataboxIds);
$this->availableDataboxes = array_intersect($allowedDataboxIds, $databoxIds);
$this->loadCollections();
}
private function loadCollections()
{
$allowedDataboxIds = $this->cache->fetch('available_databoxes');
foreach ($this->conf->get('databoxes') as $databox) {
if (!in_array($databox['id'], $allowedDataboxIds, true)) {
foreach ($this->propertyAccess->get('databoxes') as $databox) {
if (!in_array($databox['id'], $this->availableDataboxes, true)) {
continue;
}
@@ -148,9 +171,7 @@ class AccessRestriction
$this->logger->error(sprintf('Misconfiguration for allowed collections : ids %s do not exist', implode(', ', $errors)));
}
$collections = array_intersect($collections, $availableBaseIds);
$this->cache->save('available_collections_'.$databox['id'], $collections);
$this->availableCollections[$databox['id']] = array_intersect($collections, $availableBaseIds);
}
}
}

View File

@@ -33,7 +33,7 @@ class DisplaySettingService
'warning_on_delete_story' => 'true',
'client_basket_status' => '1',
'css' => '000000',
'start_page_query' => 'last',
'start_page_query' => '',
'start_page' => 'QUERY',
'rollover_thumbnail' => 'caption',
'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)
{
if (Application::ENV_DEV !== $this->app->getEnvironment()) {
return;
}
if ($this->app['configuration.store']->isSetup() && $this->app['conf']->has(['debugger', 'allowed-ips'])) {
$allowedIps = $this->app['conf']->get(['debugger', 'allowed-ips']);
$allowedIps = is_array($allowedIps) ? $allowedIps : [$allowedIps];

View File

@@ -1,9 +1,8 @@
<?php
/*
* 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
* file that was distributed with this source code.
@@ -107,9 +106,9 @@ class RegistrationSubscriber extends AbstractNotificationSubscriber
{
$body = '';
$body .= sprintf("Login : %s\n", $registeredUser->getLogin());
$body .= sprintf("%s : %s\n", _('admin::compte-utilisateur nom'), $registeredUser->getFirstName());
$body .= sprintf("%s : %s\n", _('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 nom'), $registeredUser->getFirstName());
$body .= sprintf("%s : %s\n", $this->app->trans('admin::compte-utilisateur prenom'), $registeredUser->getLastName());
$body .= sprintf("%s : %s\n", $this->app->trans('admin::compte-utilisateur email'), $registeredUser->getEmail());
$body .= sprintf("%s/%s\n", $registeredUser->get_job(), $registeredUser->getCompany());
$readyToSend = false;

View File

@@ -29,7 +29,7 @@ class TrustedProxySubscriber implements EventSubscriberInterface
public static function getSubscribedEvents()
{
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 = [];
foreach ($checker['collections'] as $base_id) {
try {
$collections[] = \collection::get_from_base_id($app, $base_id);
$collections[] = \collection::getByBaseId($app, $base_id);
} catch (\Exception $e) {
throw new \InvalidArgumentException('Invalid collection option');
}

View File

@@ -69,7 +69,7 @@ class ConfigurationServiceProvider implements ServiceProviderInterface
});
$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\Setup\Version\PreSchemaUpgrade\PreSchemaUpgradeCollection;
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\Upgrade39Users;
use Silex\Application as SilexApplication;
@@ -30,7 +31,7 @@ class ConfigurationTesterServiceProvider implements ServiceProviderInterface
});
$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) {

View File

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

View File

@@ -1,9 +1,8 @@
<?php
/*
/**
* 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
* file that was distributed with this source code.
@@ -12,12 +11,22 @@
namespace Alchemy\Phrasea\Core\Provider;
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\DataboxConnectionProvider;
use Alchemy\Phrasea\Databox\DataboxFactory;
use Alchemy\Phrasea\Databox\DbalDataboxRepository;
use Alchemy\Phrasea\Databox\Field\DataboxFieldFactory;
use Alchemy\Phrasea\Databox\Field\DbalDataboxFieldRepository;
use Alchemy\Phrasea\Databox\Record\LegacyRecordRepository;
use Alchemy\Phrasea\Model\Repositories\BasketRepository;
use Silex\Application;
use Silex\ServiceProviderInterface;
@@ -45,7 +54,11 @@ class RepositoriesServiceProvider implements ServiceProviderInterface
return $app['orm.em']->getRepository('Phraseanet:Registration');
});
$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) {
return $app['orm.em']->getRepository('Phraseanet:BasketElement');
@@ -133,11 +146,21 @@ class RepositoriesServiceProvider implements ServiceProviderInterface
});
$app['repo.databoxes'] = $app->share(function (PhraseaApplication $app) {
$factory = new DataboxFactory($app);
$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) {
@@ -147,9 +170,37 @@ class RepositoriesServiceProvider implements ServiceProviderInterface
$app['repo.records.factory'] = $app->protect(function (\databox $databox) use ($app) {
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)
{
// no-op
}
}

View File

@@ -21,11 +21,14 @@ class SubdefServiceProvider implements ServiceProviderInterface
{
public function register(SilexApplication $app)
{
$app['subdef.generator'] = $app->share(function (SilexApplication $app) {
return new SubdefGenerator($app, $app['media-alchemyst'], $app['filesystem'], $app['mediavorus'], isset($app['task-manager.logger']) ? $app['task-manager.logger'] : $app['monolog']);
$app['subdef.generator'] = $app->share(function (Application $app) {
$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) {
return new SubdefSubstituer($app, $app['filesystem'], $app['media-alchemyst'], $app['mediavorus'], $app['dispatcher']);
$app['subdef.substituer'] = $app->share(function (Application $app) {
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 Silex\Application;
use Silex\ServiceProviderInterface;
use Symfony\Component\Translation\Loader\PoFileLoader;
use Symfony\Component\Translation\MessageSelector;
use Symfony\Component\Translation\Loader\ArrayLoader;
use JMS\TranslationBundle\Translation\Loader\Symfony\XliffLoader;
@@ -36,6 +37,7 @@ class TranslationServiceProvider implements ServiceProviderInterface
$translator->addLoader('xliff', new XliffLoader());
// to load Phraseanet resources
$translator->addLoader('xlf', new XliffLoader());
$translator->addLoader('po', new PoFileLoader());
foreach ($app['translator.domains'] as $domain => $data) {
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;
});

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 */
private $factory;
/**
* @param DataboxRepository $repository
* @param Cache $cache
* @param string $cacheKey
* @param DataboxFactory $factory
*/
public function __construct(DataboxRepository $repository, Cache $cache, $cacheKey, DataboxFactory $factory)
{
$this->repository = $repository;
@@ -56,6 +62,63 @@ final class CachingDataboxRepositoryDecorator implements DataboxRepository
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
*/
@@ -69,4 +132,9 @@ final class CachingDataboxRepositoryDecorator implements DataboxRepository
$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 */
private $app;
/** @var DataboxRepository */
private $databoxRepository;
/**
* @param Application $app
*/
public function __construct(Application $app)
{
$this->app = $app;
}
/**
* @param int $id
* @param DataboxRepository $databoxRepository
*/
public function setDataboxRepository(DataboxRepository $databoxRepository)
{
$this->databoxRepository = $databoxRepository;
}
/**
* @param int $id
* @param array $raw
* @throws NotFoundHttpException when Databox could not be retrieved from Persistence layer
* @return \databox
* @return \databox when Databox could not be retrieved from Persistence layer
*/
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 = [];
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;

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[]
*/
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());
}
/**
* @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
* @return false|array
@@ -82,4 +101,73 @@ final class DbalDataboxRepository implements DataboxRepository
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
/*
/**
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
@@ -9,26 +8,40 @@
* 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\TemporaryFilesystem;
use Silex\Application;
use Silex\ServiceProviderInterface;
use Symfony\Component\Filesystem\Filesystem;
class TemporaryFilesystemServiceProvider implements ServiceProviderInterface
class FilesystemServiceProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$app['filesystem'] = $app->share(function () {
return new Filesystem();
});
$app['temporary-filesystem.temporary-fs'] = $app->share(function (Application $app) {
return new TemporaryFilesystem($app['filesystem']);
});
$app['temporary-filesystem'] = $app->share(function (Application $app) {
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)
{
// no-op
}
}

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