From 450adb0847ae3122d3e28eccd1758d0aa162fa4e Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Thu, 21 Jan 2016 13:28:17 +0100 Subject: [PATCH] Application bootstrap refactor - Extract environment properties in Environment class - Replaces initialisation closure by ApplicationLoader class - Removes undesirable error handling/PHP settings modifications --- lib/Alchemy/Phrasea/Application.php | 231 ++++-------------- .../Phrasea/Application/ApplicationLoader.php | 56 +++++ .../Phrasea/Application/Environment.php | 42 ++++ lib/Alchemy/Phrasea/Application/Root.php | 64 +---- .../Phrasea/Application/RouteLoader.php | 155 ++++++++++++ .../ControllerProviderServiceProvider.php | 106 ++++++++ .../Event/Subscriber/DebuggerSubscriber.php | 4 - .../Middleware/SetupMiddlewareProvider.php | 53 ++++ .../Phrasea/Application/RouteLoaderTest.php | 48 ++++ .../Subscriber/DebuggerSubscriberTest.php | 6 +- www/index.php | 3 +- 11 files changed, 522 insertions(+), 246 deletions(-) create mode 100644 lib/Alchemy/Phrasea/Application/ApplicationLoader.php create mode 100644 lib/Alchemy/Phrasea/Application/Environment.php create mode 100644 lib/Alchemy/Phrasea/Application/RouteLoader.php create mode 100644 lib/Alchemy/Phrasea/ControllerProvider/ControllerProviderServiceProvider.php create mode 100644 lib/Alchemy/Phrasea/Core/Middleware/SetupMiddlewareProvider.php create mode 100644 tests/Alchemy/Tests/Phrasea/Application/RouteLoaderTest.php diff --git a/lib/Alchemy/Phrasea/Application.php b/lib/Alchemy/Phrasea/Application.php index b2b01317c1..a28f8b0ac1 100644 --- a/lib/Alchemy/Phrasea/Application.php +++ b/lib/Alchemy/Phrasea/Application.php @@ -14,10 +14,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\ControllerProvider\ControllerProviderServiceProvider; use Alchemy\Phrasea\Core\Event\Subscriber\BasketSubscriber; use Alchemy\Phrasea\Core\Event\Subscriber\BridgeSubscriber; use Alchemy\Phrasea\Core\Event\Subscriber\ExportSubscriber; @@ -142,6 +145,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', @@ -150,38 +157,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()); } @@ -287,6 +287,7 @@ class Application extends SilexApplication return rtrim($app['cache.path'], '/\\') . '/alchemy_cors.cache.php'; }, ]); + $this['phraseanet.api_cors.options_provider'] = function (Application $app) { $paths = []; @@ -307,78 +308,16 @@ class Application extends SilexApplication $this->register(new LocaleServiceProvider()); $this->setupEventDispatcher(); $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' => [], - ]; - foreach ($providers as $class => $values) { - $this->register(new $class, $values); - } + $this->register(new ControllerProviderServiceProvider()); $resolvers = $this['alchemy_embed.resource_resolvers']; $resolvers['datafile'] = $resolvers->share(function () { @@ -411,6 +350,11 @@ class Application extends SilexApplication } } + public function getEnvironment() + { + return $this->environment->getName(); + } + /** * Loads Phraseanet plugins */ @@ -475,6 +419,7 @@ class Application extends SilexApplication $twig->setCache($app['cache.path'].'/twig'); $paths = []; + if (file_exists($app['plugin.path'] . '/twig-paths.php')) { $paths = require $app['plugin.path'] . '/twig-paths.php'; } @@ -651,6 +596,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 * @@ -706,75 +659,12 @@ 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', - '/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); - $this->bindPluginRoutes('plugin.controller_providers.root'); + $loader->bindRoutes($this); + $loader->bindPluginRoutes($this, 'plugin.controller_providers.root'); } /** @@ -928,12 +818,15 @@ class Application extends SilexApplication 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'; } @@ -980,6 +873,7 @@ class Application extends SilexApplication $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'; @@ -1014,6 +908,7 @@ class Application extends SilexApplication return $this['session.storage.handler.factory']->create($app['conf']); }); } + private function setupRecaptacha() { $this['recaptcha.public-key'] = $this->share(function (Application $app) { @@ -1105,6 +1000,7 @@ class Application extends SilexApplication return $configuration; }); + $this['media-alchemyst.logger'] = $this->share(function (Application $app) { return $app['monolog']; }); @@ -1220,12 +1116,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); } @@ -1242,30 +1141,6 @@ class Application extends SilexApplication */ public function bindPluginRoutes($routeParameter) { - foreach ($this[$routeParameter] as $provider) { - $prefix = ''; - 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); - } } } diff --git a/lib/Alchemy/Phrasea/Application/ApplicationLoader.php b/lib/Alchemy/Phrasea/Application/ApplicationLoader.php new file mode 100644 index 0000000000..6664bf044a --- /dev/null +++ b/lib/Alchemy/Phrasea/Application/ApplicationLoader.php @@ -0,0 +1,56 @@ +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; + } +} diff --git a/lib/Alchemy/Phrasea/Application/Environment.php b/lib/Alchemy/Phrasea/Application/Environment.php new file mode 100644 index 0000000000..6c3825c368 --- /dev/null +++ b/lib/Alchemy/Phrasea/Application/Environment.php @@ -0,0 +1,42 @@ +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; + } +} diff --git a/lib/Alchemy/Phrasea/Application/Root.php b/lib/Alchemy/Phrasea/Application/Root.php index 90564a1eaf..619dcae2e0 100644 --- a/lib/Alchemy/Phrasea/Application/Root.php +++ b/lib/Alchemy/Phrasea/Application/Root.php @@ -9,65 +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 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(); - - $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 +); diff --git a/lib/Alchemy/Phrasea/Application/RouteLoader.php b/lib/Alchemy/Phrasea/Application/RouteLoader.php new file mode 100644 index 0000000000..2d891d2529 --- /dev/null +++ b/lib/Alchemy/Phrasea/Application/RouteLoader.php @@ -0,0 +1,155 @@ + 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 $provider) { + $prefix = ''; + $providerKey = $provider; + + if (is_array($provider)) { + list($prefix, $providerKey) = $provider; + } + + if (! $this->isValidProviderDefinition($app, $prefix, $provider)) { + 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; + } +} diff --git a/lib/Alchemy/Phrasea/ControllerProvider/ControllerProviderServiceProvider.php b/lib/Alchemy/Phrasea/ControllerProvider/ControllerProviderServiceProvider.php new file mode 100644 index 0000000000..92e35853ab --- /dev/null +++ b/lib/Alchemy/Phrasea/ControllerProvider/ControllerProviderServiceProvider.php @@ -0,0 +1,106 @@ +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 => [], + ]; + } +} diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/DebuggerSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/DebuggerSubscriber.php index 1a13e6fccf..696546f7dd 100644 --- a/lib/Alchemy/Phrasea/Core/Event/Subscriber/DebuggerSubscriber.php +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/DebuggerSubscriber.php @@ -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]; diff --git a/lib/Alchemy/Phrasea/Core/Middleware/SetupMiddlewareProvider.php b/lib/Alchemy/Phrasea/Core/Middleware/SetupMiddlewareProvider.php new file mode 100644 index 0000000000..44c7e4c547 --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Middleware/SetupMiddlewareProvider.php @@ -0,0 +1,53 @@ +share($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 + } +} diff --git a/tests/Alchemy/Tests/Phrasea/Application/RouteLoaderTest.php b/tests/Alchemy/Tests/Phrasea/Application/RouteLoaderTest.php new file mode 100644 index 0000000000..850a647caf --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Application/RouteLoaderTest.php @@ -0,0 +1,48 @@ +registerProvider('test_invalid_class', '\Alchemy\Tests\Phrasea\Application\UndefinedClass'); + } + + public function testRegisteredProvidersAreMountedInApplication() + { + $application = $this->prophesize(Application::class); + $application->offsetGet(Argument::any()) + ->shouldBeCalled(); + $application->mount(Argument::any(), Argument::type(ControllerProviderInterface::class)) + ->shouldBeCalled(); + $application->mount(Argument::exact('mount_prefix'), Argument::type(MockControllerProvider::class)) + ->shouldBeCalled(); + + $routeLoader = new RouteLoader(); + $routeLoader->registerProvider('mount_prefix', MockControllerProvider::class); + + $routeLoader->bindRoutes($application->reveal()); + } +} + +class MockControllerProvider implements ControllerProviderInterface +{ + public function connect(\Silex\Application $app) + { + return new ControllerCollection(new Route('/')); + } +} diff --git a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/DebuggerSubscriberTest.php b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/DebuggerSubscriberTest.php index 658dbec25a..938207cdf1 100644 --- a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/DebuggerSubscriberTest.php +++ b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/DebuggerSubscriberTest.php @@ -37,9 +37,11 @@ class DebuggerSubscriberTest extends \PhraseanetTestCase $app['conf']->set(['debugger', 'allowed-ips'], $authorized); $app['dispatcher']->addSubscriber(new DebuggerSubscriber($app)); + $app->get('/', function () { return 'success'; }); + $app->boot(); if ($exceptionThrown) { @@ -53,12 +55,12 @@ class DebuggerSubscriberTest extends \PhraseanetTestCase { return [ [false, Application::ENV_PROD, '127.0.0.1', []], - [false, Application::ENV_PROD, '192.168.0.1', []], + [true, Application::ENV_PROD, '192.168.0.1', []], [false, Application::ENV_DEV, '127.0.0.1', []], [true, Application::ENV_DEV, '192.168.0.1', []], [false, Application::ENV_DEV, '192.168.0.1', ['192.168.0.1']], [false, Application::ENV_TEST, '127.0.0.1', []], - [false, Application::ENV_TEST, '192.168.0.1', []], + [true, Application::ENV_TEST, '192.168.0.1', []], ]; } } diff --git a/www/index.php b/www/index.php index 6f06ad2009..bd58a183cf 100644 --- a/www/index.php +++ b/www/index.php @@ -12,9 +12,8 @@ use Alchemy\Phrasea\Application; use Symfony\Component\Debug\ErrorHandler; -require_once __DIR__ . "/../lib/autoload.php"; -error_reporting(0); +require_once __DIR__ . "/../lib/autoload.php"; ErrorHandler::register();