diff --git a/modules/backend/classes/BackendController.php b/modules/backend/classes/BackendController.php index 57ac5dff2..dcf590be2 100644 --- a/modules/backend/classes/BackendController.php +++ b/modules/backend/classes/BackendController.php @@ -55,6 +55,44 @@ class BackendController extends ControllerBase */ public function __construct() { + $this->middleware(function ($request, $next) { + // Process the request before retrieving controller middleware, to allow for the session and auth data + // to be made available to the controller's constructor. + $response = $next($request); + + // Find requested controller to determine if any middleware has been attached + $pathParts = explode('/', str_replace(Request::root() . '/', '', Request::url())); + if (count($pathParts)) { + // Drop off preceding backend URL part if needed + if (!empty(Config::get('cms.backendUri', 'backend'))) { + array_shift($pathParts); + } + $path = implode('/', $pathParts); + + $requestedController = $this->getRequestedController($path); + if ( + !is_null($requestedController) + && is_array($requestedController) + && count($requestedController['controller']->getMiddleware()) + ) { + $action = $requestedController['action']; + + // Collect applicable middleware and insert middleware into pipeline + $controllerMiddleware = collect($requestedController['controller']->getMiddleware()) + ->reject(function ($data) use ($action) { + return static::methodExcludedByOptions($action, $data['options']); + }) + ->pluck('middleware'); + + foreach ($controllerMiddleware as $middleware) { + $middleware->call($requestedController['controller'], $request, $response); + } + } + } + + return $response; + }); + $this->extendableConstruct(); } @@ -113,6 +151,34 @@ class BackendController extends ControllerBase : $this->passToCmsController($url); } + $controllerRequest = $this->getRequestedController($url); + if (!is_null($controllerRequest)) { + return $controllerRequest['controller']->run( + $controllerRequest['action'], + $controllerRequest['params'] + ); + } + + /* + * Fall back on Cms controller + */ + return $this->passToCmsController($url); + } + + /** + * Determines the controller and action to load in the backend via a provided URL. + * + * If a suitable controller is found, this will return an array with the controller class name as a string, the + * action to call as a string and an array of parameters. If a suitable controller and action cannot be found, + * this method will return null. + * + * @param string $url A URL to determine the requested controller and action for + * @return array|null A suitable controller, action and parameters in an array if found, otherwise null. + */ + protected function getRequestedController($url) + { + $params = RouterHelper::segmentizeUrl($url); + /* * Look for a Module controller */ @@ -126,7 +192,11 @@ class BackendController extends ControllerBase $action, base_path().'/modules' )) { - return $controllerObj->run($action, $controllerParams); + return [ + 'controller' => $controllerObj, + 'action' => $action, + 'params' => $controllerParams + ]; } /* @@ -149,14 +219,15 @@ class BackendController extends ControllerBase $action, plugins_path() )) { - return $controllerObj->run($action, $controllerParams); + return [ + 'controller' => $controllerObj, + 'action' => $action, + 'params' => $controllerParams + ]; } } - /* - * Fall back on Cms controller - */ - return $this->passToCmsController($url); + return null; } /** @@ -169,6 +240,10 @@ class BackendController extends ControllerBase */ protected function findController($controller, $action, $inPath) { + if (isset($this->requestedController)) { + return $this->requestedController; + } + /* * Workaround: Composer does not support case insensitivity. */ @@ -181,16 +256,16 @@ class BackendController extends ControllerBase } if (!class_exists($controller)) { - return false; + return $this->requestedController = null; } $controllerObj = App::make($controller); if ($controllerObj->actionExists($action)) { - return $controllerObj; + return $this->requestedController = $controllerObj; } - return false; + return $this->requestedController = null; } /** @@ -206,4 +281,17 @@ class BackendController extends ControllerBase return $actionName; } + + /** + * Determine if the given options exclude a particular method. + * + * @param string $method + * @param array $options + * @return bool + */ + protected static function methodExcludedByOptions($method, array $options) + { + return (isset($options['only']) && !in_array($method, (array) $options['only'])) || + (!empty($options['except']) && in_array($method, (array) $options['except'])); + } } diff --git a/modules/backend/classes/Controller.php b/modules/backend/classes/Controller.php index ff6177320..9d4dc7995 100644 --- a/modules/backend/classes/Controller.php +++ b/modules/backend/classes/Controller.php @@ -19,9 +19,9 @@ use October\Rain\Exception\AjaxException; use October\Rain\Exception\SystemException; use October\Rain\Exception\ValidationException; use October\Rain\Exception\ApplicationException; -use October\Rain\Extension\Extendable; use Illuminate\Database\Eloquent\MassAssignmentException; use Illuminate\Http\RedirectResponse; +use Illuminate\Routing\Controller as ControllerBase; /** * The Backend base controller class, used by Backend controllers. @@ -30,7 +30,7 @@ use Illuminate\Http\RedirectResponse; * @package october\backend * @author Alexey Bobkov, Samuel Georges */ -class Controller extends Extendable +class Controller extends ControllerBase { use \System\Traits\ViewMaker; use \System\Traits\AssetMaker; @@ -40,6 +40,12 @@ class Controller extends Extendable use \System\Traits\SecurityController; use \Backend\Traits\ErrorMaker; use \Backend\Traits\WidgetMaker; + use \October\Rain\Extension\ExtendableTrait; + + /** + * @var array Behaviors implemented by this controller. + */ + public $implement; /** * @var object Reference the logged in admin user. @@ -153,6 +159,32 @@ class Controller extends Extendable $manager = new MediaManager($this, 'ocmediamanager'); $manager->bindToController(); } + + $this->extendableConstruct(); + } + + /** + * Extend this object properties upon construction. + */ + public static function extend(Closure $callback) + { + self::extendableExtendCallback($callback); + } + public function __get($name) + { + return $this->extendableGet($name); + } + public function __set($name, $value) + { + $this->extendableSet($name, $value); + } + public function __call($name, $params) + { + return $this->extendableCall($name, $params); + } + public static function __callStatic($name, $params) + { + return self::extendableCallStatic($name, $params); } /**