ConfigLoader::class, 'log' => LogLoader::class, 'fileManager' => FileManagerLoader::class, 'dataManager' => DataManagerLoader::class, 'metadata' => MetadataLoader::class, ]; public function __construct() { date_default_timezone_set('UTC'); $this->initContainer(); $this->initAutoloads(); $this->initPreloads(); } protected function initContainer() { $this->container = new Container(ContainerConfiguration::class, $this->loaderClassNames); } /** * Run REST API. */ public function runApi() { $slim = $this->createSlimApp(); $slim->addRoutingMiddleware(); $crudList = array_keys($this->getConfig()->get('crud')); $routeList = $this->getRouteList(); foreach ($routeList as $item) { $method = strtolower($item['method']); $route = $item['route']; if (!in_array($method, $crudList) && $method !== 'options') { $GLOBALS['log']->error("Route: Method '{$method}' does not exist. Check the route '{$route}'."); continue; } $slim->$method( $route, function (Request $request, Response $response, array $args) use ($item, $slim) { $requestWrapped = new RequestWrapper($request, $slim->getBasePath()); $responseWrapped = new ResponseWrapper($response); try { $authRequired = !($item['noAuth'] ?? false); $apiAuth = new ApiAuth($this->createAuth($requestWrapped), $authRequired); $apiAuth->process($requestWrapped, $responseWrapped); if (!$apiAuth->isResolved()) { return $responseWrapped->getResponse(); } if ($apiAuth->isResolvedUseNoAuth()) { $this->setupSystemUser(); } $routeProcessor = $this->getInjectableFactory()->create(RouteProcessor::class); $routeProcessor->process($item['route'], $item['params'], $requestWrapped, $responseWrapped, $args); } catch (\Exception $exception) { (new ApiErrorOutput($requestWrapped))->process( $responseWrapped, $exception, false, $item, $args ); } return $responseWrapped->getResponse(); } ); } $slim->addErrorMiddleware(false, true, true); $slim->run(); } /** * Display the main HTML page. */ public function runClient() { $this->getClientMaanger()->display(); exit; } /** * Run entryPoint. */ public function runEntryPoint(string $entryPoint, array $data = [], bool $final = false) { if (empty($entryPoint)) { throw new Error(); } $slim = $this->createSlimApp(); $entryPointManager = $this->getInjectableFactory()->create(EntryPointManager::class); $authRequired = $entryPointManager->checkAuthRequired($entryPoint); $authNotStrict = $entryPointManager->checkNotStrictAuth($entryPoint); if ($authRequired && !$authNotStrict) { if (!$final && $portalId = $this->detectPortalId()) { $app = new PortalApplication($portalId); $app->setClientBasePath($this->getClientBasePath()); $app->runEntryPoint($entryPoint, $data, true); exit; } } $slim->add( function (Request $request, RequestHandler $handler) use ( $entryPointManager, $entryPoint, $data, $authRequired, $authNotStrict, $slim ) { $requestWrapped = new RequestWrapper($request, $slim->getBasePath()); $responseWrapped = new ResponseWrapper($handler->handle($request)); try { $auth = $this->createAuth($requestWrapped, $authNotStrict); $apiAuth = new ApiAuth($auth, $authRequired, true, true); $apiAuth->process($requestWrapped, $responseWrapped); if (!$apiAuth->isResolved()) { $requestWrapped->getResponse(); } if ($apiAuth->isResolvedUseNoAuth()) { $this->setupSystemUser(); } ob_start(); $entryPointManager->run($entryPoint, $requestWrapped, $responseWrapped, $data); $contents = ob_get_clean(); if ($contents) { $responseWrapped->writeBody($contents); } } catch (\Exception $e) { (new ApiErrorOutput($requestWrapped))->process($responseWrapped, $e, true); } return $responseWrapped->getResponse(); } ); $slim->get('/', function (Request $request, Response $response) { return $response; }); $slim->run(); } /** * Run cron. */ public function runCron() { if ($this->getConfig()->get('cronDisabled')) { $GLOBALS['log']->warning("Cron is not run because it's disabled with 'cronDisabled' param."); return; } $this->setupSystemUser(); $this->getCronManager()->run(); } /** * Run daemon. */ public function runDaemon() { $maxProcessNumber = $this->getConfig()->get('daemonMaxProcessNumber'); $interval = $this->getConfig()->get('daemonInterval'); $timeout = $this->getConfig()->get('daemonProcessTimeout'); $phpExecutablePath = $this->getConfig()->get('phpExecutablePath'); if (!$phpExecutablePath) { $phpExecutablePath = (new \Symfony\Component\Process\PhpExecutableFinder)->find(); } if (!$maxProcessNumber || !$interval) { $GLOBALS['log']->error("Daemon config params are not set."); return; } $processList = []; while (true) { $toSkip = false; $runningCount = 0; foreach ($processList as $i => $process) { if ($process->isRunning()) { $runningCount++; } else { unset($processList[$i]); } } $processList = array_values($processList); if ($runningCount >= $maxProcessNumber) { $toSkip = true; } if (!$toSkip) { $process = new \Symfony\Component\Process\Process([$phpExecutablePath, 'cron.php']); $process->setTimeout($timeout); $process->run(); $processList[] = $process; } sleep($interval); } } /** * Run a job by ID. A job record should exist in database. */ public function runJob(string $id) { $this->setupSystemUser(); $this->getCronManager()->runJobById($id); } /** * Rebuild application. */ public function runRebuild() { $this->getDataManager()->rebuild(); } /** * Clear application cache. */ public function runClearCache() { $this->getDataManager()->clearCache(); } /** * Run command in Console Command framework. */ public function runCommand(string $command) { $this->setupSystemUser(); $consoleCommandManager = $this->getInjectableFactory()->create(ConsoleCommandManager::class); return $consoleCommandManager->run($command); } /** * Whether the application is installed. */ public function isInstalled() : bool { $config = $this->getConfig(); if (file_exists($config->getConfigPath()) && $config->get('isInstalled')) { return true; } return false; } /** * Get the service container. */ public function getContainer() : Container { return $this->container; } protected function getInjectableFactory() : InjectableFactory { return $this->container->get('injectableFactory'); } protected function getClientMaanger() : ClientManager { return $this->container->get('clientManager'); } protected function getMetadata() : Metadata { return $this->container->get('metadata'); } protected function getConfig() : Config { return $this->container->get('config'); } protected function getDataManager() : DataManager { return $this->container->get('dataManager'); } protected function getCronManager() : CronManager { return $this->container->get('cronManager'); } protected function getEntityManager() : EntityManager { return $this->container->get('entityManager'); } protected function createSlimApp() : SlimApp { $slim = SlimAppFactory::create(); $slim->setBasePath(Route::detectBasePath()); return $slim; } protected function createAuth(RequestWrapper $request, bool $allowAnyAccess = false) : Auth { return $this->getInjectableFactory()->createWith(Auth::class, [ 'request' => $request, 'allowAnyAccess' => $allowAnyAccess, ]); } protected function initAutoloads() { $autoload = $this->getInjectableFactory()->create(Autoload::class); $autoload->register(); } /** * Initialize services that has the 'preload' parameter. */ protected function initPreloads() { foreach ($this->getMetadata()->get(['app', 'containerServices']) ?? [] as $name => $defs) { if ($defs['preload'] ?? false) { $this->container->get($name); } } } protected function getRouteList() : array { return $this->getInjectableFactory()->create(Route::class)->getFullList(); } /** * Set a base path of an index file related to the application directory. Used for a portal. */ public function setClientBasePath(string $basePath) { $this->getClientMaanger()->setBasePath($basePath); } /** * Get a base path of an index file related to the application directory. Used for a portal. */ public function getClientBasePath() : string { return $this->getClientMaanger()->getBasePath(); } public function detectPortalId() : ?string { if (!empty($_GET['portalId'])) { return $_GET['portalId']; } if (!empty($_COOKIE['auth-token'])) { $token = $this->getEntityManager()->getRepository('AuthToken') ->where(['token' => $_COOKIE['auth-token']])->findOne(); if ($token && $token->get('portalId')) { return $token->get('portalId'); } } return null; } /** * Setup the system user. The system user is used when no user is logged in. */ public function setupSystemUser() { $user = $this->getEntityManager()->getEntity('User', 'system'); if (!$user) { throw new Error("System user is not found"); } $user->set('ipAddress', $_SERVER['REMOTE_ADDR'] ?? null); $user->set('type', 'system'); $this->container->set('user', $user); } }