* @package tao * @example * * $bootStrap = new BootStrap('tao'); //create the Bootstrap instance * $bootStrap->start(); //start all the services * $bootStrap->dispatch(); //dispatch the http request into the control loop * */ class Bootstrap implements ServiceManagerAwareInterface { use ServiceManagerAwareTrait; const CONFIG_SESSION_HANDLER = 'session'; /** * @var boolean if the context has been started */ protected static $isStarted = false; /** * @var boolean if the context has been dispatched */ protected static $isDispatched = false; /** * Bootstrap constructor. * * Initialize the context * * @param $configuration * @throws \common_Exception If config file is not readable */ public function __construct($configuration) { new DotEnvReader(); if (! is_string($configuration) || ! is_readable($configuration)) { throw new PreConditionException('TAO platform seems to be not installed.'); } require_once $configuration; $serviceManager = new ServiceManager( (new ServiceConfigDriver())->connect('config', [ 'dir' => dirname($configuration), 'humanReadable' => true ]) ); $this->setServiceLocator($serviceManager); // To be removed when getServiceManager will disappear ServiceManager::setServiceManager($serviceManager); if (PHP_SAPI === 'cli') { tao_helpers_Context::load('SCRIPT_MODE'); } else { tao_helpers_Context::load('APP_MODE'); } } /** * Check if the current context has been started * @return boolean */ public static function isStarted() { return self::$isStarted; } /** * Check if the current context has been dispatched * @return boolean */ public static function isDispatched() { return self::$isDispatched; } /** * Check if the platform is ready * * @return boolean Return true if the application is ready */ protected function isReady() { return $this->getMaintenanceService()->isPlatformReady(); } /** * Start all the services: * 1. Start the session * 2. Update the include path * 3. Include the global helpers * 4. Connect the current user to the generis API * 5. Initialize the internationalization * 6. Check the application' state */ public function start() { if (!self::$isStarted) { $this->session(); $this->setDefaultTimezone(); $this->registerErrorhandler(); self::$isStarted = true; } } protected function dispatchHttp() { $isAjax = tao_helpers_Request::isAjax(); if (tao_helpers_Context::check('APP_MODE')) { if (!$isAjax) { $this->scripts(); } } //Catch all exceptions try { //the app is ready, process mvc if ($this->isReady()) { $this->mvc(); } //the app is not ready, put platform on maintenance else { $this->displayMaintenancePage(); } } catch (Exception $e) { $this->catchError($e); } // explicitly close session session_write_close(); } /** * Put the platform on maintenance * Redirect to maintenance page if http call is not ajax * Otherwise throw common_exception_SystemUnderMaintenance * * @throws MaintenanceException */ protected function displayMaintenancePage() { //the request is not an ajax request, redirect the user to the maintenance page if (! tao_helpers_Request::isAjax()) { require_once Template::getTemplate('error/maintenance.tpl', 'tao'); //else throw an exception, this exception will be send to the client properly } else { throw new MaintenanceException(); } } protected function dispatchCli() { $params = $_SERVER['argv']; array_shift($params); if (count($params) < 1) { $report = new Report(Report::TYPE_ERROR, __('No action specified')); } else { $actionIdentifier = array_shift($params); $cliController = new CliController(); $this->propagate($cliController); $report = $cliController->runAction($actionIdentifier, $params); } echo ReportHelper::renderToCommandline($report); } /** * Dispatch the current http request into the control loop: * 1. Load the ressources * 2. Start the MVC Loop from the ClearFW * manage Exception: */ public function dispatch() { if (!self::$isDispatched) { if (PHP_SAPI === 'cli') { $this->dispatchCli(); } else { $this->dispatchHttp(); } $this->getServiceManager()->get(EventAggregator::SERVICE_ID)->triggerAggregatedEvents(); self::$isDispatched = true; } } /** * Catch any errors * return a http response in function of client accepted mime type * * @param Exception $exception */ protected function catchError(Exception $exception) { $exceptionInterpreterService = $this->getServiceLocator()->get(ExceptionInterpreterService::SERVICE_ID); $interpretor = $exceptionInterpreterService->getExceptionInterpreter($exception); $interpretor->getResponse()->send(); } /** * Start the session */ protected function session() { if (PHP_SAPI === 'cli') { return; } if (tao_helpers_Context::check('APP_MODE')) { // Set a specific ID to the session. $request = new Request(); if ($request->hasParameter('session_id')) { session_id($request->getParameter('session_id')); } } // set the session cookie to HTTP only. $this->configureSessionHandler(); $this->getSessionCookieService()->initializeSessionCookie(); } private function configureSessionHandler() { $sessionHandler = common_ext_ExtensionsManager::singleton()->getExtensionById('tao')->getConfig(self::CONFIG_SESSION_HANDLER); if ($sessionHandler !== false) { session_set_save_handler( [$sessionHandler, 'open'], [$sessionHandler, 'close'], [$sessionHandler, 'read'], [$sessionHandler, 'write'], [$sessionHandler, 'destroy'], [$sessionHandler, 'gc'] ); } } /** * register a custom Errorhandler */ protected function registerErrorhandler() { // register the logger as erorhandler common_Logger::singleton()->register(); } /** * Set Timezone quickfix */ protected function setDefaultTimezone() { if (function_exists("date_default_timezone_set") && defined('TIME_ZONE')) { date_default_timezone_set(TIME_ZONE); } } /** * Start the MVC Loop from the ClearFW * @throws \ActionEnforcingException in case of wrong module or action * @throws \tao_models_classes_UserException when a request try to acces a protected area */ protected function mvc() { $request = $this->buildRequest(); $response = new Response(); $frontController = $this->propagate(new TaoFrontController()); $frontController($request, $response); } /** * Load external resources for the current context * @see \tao_helpers_Scriptloader */ protected function scripts() { $assetService = $this->getServiceLocator()->get(AssetService::SERVICE_ID); $cssFiles = [ $assetService->getAsset('css/layout.css', 'tao'), $assetService->getAsset('css/tao-main-style.css', 'tao'), $assetService->getAsset('css/tao-3.css', 'tao') ]; //stylesheets to load ScriptLoader::addCssFiles($cssFiles); if (SessionManager::isAnonymous()) { ScriptLoader::addCssFile( $assetService->getAsset('css/portal.css', 'tao') ); } } protected function getMaintenanceService(): Maintenance { /** @noinspection PhpIncompatibleReturnTypeInspection */ return $this->getServiceLocator()->get(Maintenance::SERVICE_ID); } private function getSessionCookieService(): SessionCookieServiceInterface { /** @noinspection PhpIncompatibleReturnTypeInspection */ return $this->getServiceLocator()->get(SessionCookieServiceInterface::class); } private function buildRequest(): RequestInterface { $request = ServerRequest::fromGlobals(); return (new RequestRebuilder())->rebuild($request); } }