/** * Handles dependencies for ExtendedClass instances * * @final * @access protected * @param mixed $Instance * @param array $Options (Optional) Array with options * @return void */ protected final function HandleDependencies(&$Instance, array $Options = []) { /* ------------------------------------------------------------------------------------------------------ GET DEPENDENCIES ------------------------------------------------------------------------------------------------------ */ $Dependencies = new Dependencies(); // Load environment $Environment = $this->InjectionContainer->Retrieve('Environment'); // Call the "Dependencies" method on the instance // $Dependencies which we created above, is injected as a reference, so any actions taken // to it, are automatically applied on this very object $Instance->Dependencies($Dependencies, $Environment, ['Method' => (string) $Options['Method']]); /* ------------------------------------------------------------------------------------------------------ REQUIREMENTS ------------------------------------------------------------------------------------------------------ */ // List the requirements defined in the Dependencies method $Requirements = $Dependencies->ListRequirements(); // Work on groups foreach ($Requirements['Groups'] as $X => $Group) { foreach ($this->Implementations as $Y => $Implementation) { if (!is_array($Implementation['Groups'])) { continue; } if (in_array($Group['Group'], $Implementation['Groups'])) { $Requirements['Implementations'][] = ['Name' => basename($Implementation['Location']), 'StrictRequirement' => False, 'Extra' => ['Groups' => $Implementation['Groups']]]; } } } /* -------------------------------------------------------------------------------------------------- INSTANTIATE -------------------------------------------------------------------------------------------------- */ // Iterate over the required implementations foreach ($Requirements['Implementations'] as $I => $ImplementationData) { // Set name $Implementation = $ImplementationData['Name']; // If the implementation is not registered, we cannot safely assume its location and we'll // fail to load it. So let's throw an Exception if (!array_key_exists($Implementation, $this->Implementations)) { if (!$ImplementationData['StrictRequirement']) { continue; } // Let the developer know the implementation has not been registered throw new \Bytes\ComponentException(sprintf('%s has required the implementation %s. But it does not occur in the application registry.', get_class($Instance), $Implementation)); } // If the implementation has been registered, we'll create it via the CreateImplementation // method, and then attach it to the InjectionContainer $this->InjectionContainer->Attach($Implementation, $this->CreateImplementation($this->Implementations[$Implementation]['Location']), isset($ImplementationData['Extra']) ? $ImplementationData['Extra'] : []); } /* ------------------------------------------------------------------------------------------------------ ADD INJECTION CONTAINER ------------------------------------------------------------------------------------------------------ */ $Instance->SetInjectionContainer($this->InjectionContainer); }
/** * Starts the application * * @access public * @param string $URI URI for the router to compare against * @param callable $Callback * @return mixed Whatever comes out of $Callback */ public function Start(string $URI, callable $Callback) { /* ------------------------------------------------------------------------------------------------------ INITIALIZE ------------------------------------------------------------------------------------------------------ */ $InjectionContainer = new InjectionContainer(); $ObjectBuilder = new ObjectBuilder(); $InjectionContainer->Attach('Environment', $this->Environment); $InjectionContainer->Attach('Header', $this->Header); $ObjectBuilder->SetInjectionContainer($InjectionContainer); $ObjectBuilder->SetHooksContainer($this->HooksContainer); $ObjectBuilder->SetImplementations($this->Implementations); // Populate triggers/hook for the application object $this->__Options->PopulateTriggers($this->HooksContainer, $ObjectBuilder); /* ------------------------------------------------------------------------------------------------------ LOAD COMPONENTS ------------------------------------------------------------------------------------------------------ */ // Iterate over all preloaded components foreach ($this->Components as $I => $ComponentName) { // Use the object builder to create the component and work with the router and environment $Component = $ObjectBuilder->CreateImplementation($ComponentName, 'Component'); // Initialize the component (create its routes, etc.) $Component->Initialize($this->Router); // Store the component for later reference $this->Components[basename($ComponentName)] = $Component; } /* ------------------------------------------------------------------------------------------------------ FIND ROUTE + EXECUTE CONTROLLER ------------------------------------------------------------------------------------------------------ */ try { // Find information on controller and method, using the Router's Match method $Route = $this->Router->Match($URI); // If no route is found, we'll invoke a 404 error if (!$Route) { throw new Exception('Not Found', 404); } // Retrieve output from the controller's requested method $ComponentId = basename($Route['Component']); $Output = $this->Components[$ComponentId]->Controller((string) $Route['Controller'], (string) $Route['Method'], ['Route' => $URI]); // If we successfully get to this point, we store the output // This enables us to use it both inside the custom callback method, as well as // in other methods, such as Application::Render $this->ControllerOutput = $Output; } catch (\Exception $E) { // Load environment $Env = $this->Environment(); // In case of exception, we'll look to the router, and see if it requests to use // a custom error handle if ($this->AssignedErrorHandler) { $Handle = 'ERROR/' . (string) $Route['ErrorHandle']; $ErrorHandlerComponent = basename($this->AssignedErrorHandler['Location']); $ErrorHandler = $this->Components[$ErrorHandlerComponent]; $ErrorRoute = $this->Router->Match($Handle); $ErrorController = (string) $ErrorRoute['Controller']; $ErrorMethod = (string) $ErrorRoute['Method']; if (!$ErrorRoute) { $ErrorController = 'Index'; $ErrorMethod = 'Default'; } $Output = $ErrorHandler->Controller($ErrorController, $ErrorMethod, ['ErrorHandler' => True, 'Exception' => $E]); $this->ControllerOutput = $Output; } else { // If there's no custom error handle and no default, we'll do a fallback to a simple JSON message // (JSON applied, if Application::Render is used) $this->ControllerOutput = ['Error' => $E->getMessage()]; } } /* ------------------------------------------------------------------------------------------------------ RETURN ------------------------------------------------------------------------------------------------------ */ return $Callback($this, $this->ControllerOutput); }