Seditio Source
Root |
./othercms/croogo-4.0.7/vendor/cakephp/cakephp/src/Controller/Controller.php
<?php
/**
 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 * @link          https://cakephp.org CakePHP(tm) Project
 * @since         0.2.9
 * @license       https://opensource.org/licenses/mit-license.php MIT License
 */
namespace Cake\Controller;

use
Cake\Controller\Exception\MissingActionException;
use
Cake\Datasource\ModelAwareTrait;
use
Cake\Event\Event;
use
Cake\Event\EventDispatcherInterface;
use
Cake\Event\EventDispatcherTrait;
use
Cake\Event\EventListenerInterface;
use
Cake\Http\Response;
use
Cake\Http\ServerRequest;
use
Cake\Log\LogTrait;
use
Cake\ORM\Locator\LocatorAwareTrait;
use
Cake\Routing\RequestActionTrait;
use
Cake\Routing\Router;
use
Cake\Utility\MergeVariablesTrait;
use
Cake\View\ViewVarsTrait;
use
LogicException;
use
ReflectionClass;
use
ReflectionException;
use
ReflectionMethod;
use
RuntimeException;

/**
 * Application controller class for organization of business logic.
 * Provides basic functionality, such as rendering views inside layouts,
 * automatic model availability, redirection, callbacks, and more.
 *
 * Controllers should provide a number of 'action' methods. These are public
 * methods on a controller that are not inherited from `Controller`.
 * Each action serves as an endpoint for performing a specific action on a
 * resource or collection of resources. For example adding or editing a new
 * object, or listing a set of objects.
 *
 * You can access request parameters, using `$this->request`. The request object
 * contains all the POST, GET and FILES that were part of the request.
 *
 * After performing the required action, controllers are responsible for
 * creating a response. This usually takes the form of a generated `View`, or
 * possibly a redirection to another URL. In either case `$this->response`
 * allows you to manipulate all aspects of the response.
 *
 * Controllers are created by `Dispatcher` based on request parameters and
 * routing. By default controllers and actions use conventional names.
 * For example `/posts/index` maps to `PostsController::index()`. You can re-map
 * URLs using Router::connect() or RouterBuilder::connect().
 *
 * ### Life cycle callbacks
 *
 * CakePHP fires a number of life cycle callbacks during each request.
 * By implementing a method you can receive the related events. The available
 * callbacks are:
 *
 * - `beforeFilter(Event $event)`
 *   Called before each action. This is a good place to do general logic that
 *   applies to all actions.
 * - `beforeRender(Event $event)`
 *   Called before the view is rendered.
 * - `beforeRedirect(Event $event, $url, Response $response)`
 *    Called before a redirect is done.
 * - `afterFilter(Event $event)`
 *   Called after each action is complete and after the view is rendered.
 *
 * @property \Cake\Controller\Component\AuthComponent $Auth
 * @property \Cake\Controller\Component\CookieComponent $Cookie
 * @property \Cake\Controller\Component\CsrfComponent $Csrf
 * @property \Cake\Controller\Component\FlashComponent $Flash
 * @property \Cake\Controller\Component\PaginatorComponent $Paginator
 * @property \Cake\Controller\Component\RequestHandlerComponent $RequestHandler
 * @property \Cake\Controller\Component\SecurityComponent $Security
 * @method bool isAuthorized($user)
 * @link https://book.cakephp.org/3/en/controllers.html
 */
class Controller implements EventListenerInterface, EventDispatcherInterface
{
    use
EventDispatcherTrait;
    use
LocatorAwareTrait;
    use
LogTrait;
    use
MergeVariablesTrait;
    use
ModelAwareTrait;
    use
RequestActionTrait;
    use
ViewVarsTrait;

   
/**
     * The name of this controller. Controller names are plural, named after the model they manipulate.
     *
     * Set automatically using conventions in Controller::__construct().
     *
     * @var string
     */
   
protected $name;

   
/**
     * An array containing the names of helpers this controller uses. The array elements should
     * not contain the "Helper" part of the class name.
     *
     * Example:
     * ```
     * public $helpers = ['Form', 'Html', 'Time'];
     * ```
     *
     * @var array
     * @link https://book.cakephp.org/3/en/controllers.html#configuring-helpers-to-load
     *
     * @deprecated 3.0.0 You should configure helpers in your AppView::initialize() method.
     */
   
public $helpers = [];

   
/**
     * An instance of a \Cake\Http\ServerRequest object that contains information about the current request.
     * This object contains all the information about a request and several methods for reading
     * additional information about the request.
     *
     * Deprecated 3.6.0: The property will become protected in 4.0.0. Use getRequest()/setRequest instead.
     *
     * @var \Cake\Http\ServerRequest
     * @link https://book.cakephp.org/3/en/controllers/request-response.html#request
     */
   
public $request;

   
/**
     * An instance of a Response object that contains information about the impending response
     *
     * Deprecated 3.6.0: The property will become protected in 4.0.0. Use getResponse()/setResponse instead.

     * @var \Cake\Http\Response
     * @link https://book.cakephp.org/3/en/controllers/request-response.html#response
     */
   
public $response;

   
/**
     * The class name to use for creating the response object.
     *
     * @var string
     */
   
protected $_responseClass = Response::class;

   
/**
     * Settings for pagination.
     *
     * Used to pre-configure pagination preferences for the various
     * tables your controller will be paginating.
     *
     * @var array
     * @see \Cake\Controller\Component\PaginatorComponent
     */
   
public $paginate = [];

   
/**
     * Set to true to automatically render the view
     * after action logic.
     *
     * @var bool
     */
   
protected $autoRender = true;

   
/**
     * Instance of ComponentRegistry used to create Components
     *
     * @var \Cake\Controller\ComponentRegistry
     */
   
protected $_components;

   
/**
     * Array containing the names of components this controller uses. Component names
     * should not contain the "Component" portion of the class name.
     *
     * Example:
     * ```
     * public $components = ['RequestHandler', 'Acl'];
     * ```
     *
     * @var array
     * @link https://book.cakephp.org/3/en/controllers/components.html
     *
     * @deprecated 3.0.0 You should configure components in your Controller::initialize() method.
     */
   
public $components = [];

   
/**
     * Instance of the View created during rendering. Won't be set until after
     * Controller::render() is called.
     *
     * @var \Cake\View\View
     * @deprecated 3.1.0 Use viewBuilder() instead.
     */
   
public $View;

   
/**
     * These Controller properties will be passed from the Controller to the View as options.
     *
     * @var array
     * @see \Cake\View\View
     * @deprecated 3.7.0 Use ViewBuilder::setOptions() or any one of it's setter methods instead.
     */
   
protected $_validViewOptions = [
       
'passedArgs',
    ];

   
/**
     * Automatically set to the name of a plugin.
     *
     * @var string|null
     */
   
protected $plugin;

   
/**
     * Holds all passed params.
     *
     * @var array
     * @deprecated 3.1.0 Use `$this->request->getParam('pass')` instead.
     */
   
public $passedArgs = [];

   
/**
     * Constructor.
     *
     * Sets a number of properties based on conventions if they are empty. To override the
     * conventions CakePHP uses you can define properties in your class declaration.
     *
     * @param \Cake\Http\ServerRequest|null $request Request object for this controller. Can be null for testing,
     *   but expect that features that use the request parameters will not work.
     * @param \Cake\Http\Response|null $response Response object for this controller.
     * @param string|null $name Override the name useful in testing when using mocks.
     * @param \Cake\Event\EventManager|null $eventManager The event manager. Defaults to a new instance.
     * @param \Cake\Controller\ComponentRegistry|null $components The component registry. Defaults to a new instance.
     */
   
public function __construct(ServerRequest $request = null, Response $response = null, $name = null, $eventManager = null, $components = null)
    {
        if (
$name !== null) {
           
$this->name = $name;
        }

        if (
$this->name === null && $request && $request->getParam('controller')) {
           
$this->name = $request->getParam('controller');
        }

        if (
$this->name === null) {
            list(,
$name) = namespaceSplit(get_class($this));
           
$this->name = substr($name, 0, -10);
        }

       
$this->setRequest($request ?: new ServerRequest());
       
$this->response = $response ?: new Response();

        if (
$eventManager !== null) {
           
$this->setEventManager($eventManager);
        }

       
$this->modelFactory('Table', [$this->getTableLocator(), 'get']);
       
$plugin = $this->request->getParam('plugin');
       
$modelClass = ($plugin ? $plugin . '.' : '') . $this->name;
       
$this->_setModelClass($modelClass);

        if (
$components !== null) {
           
$this->components($components);
        }

       
$this->initialize();

       
$this->_mergeControllerVars();
       
$this->_loadComponents();
       
$this->getEventManager()->on($this);
    }

   
/**
     * Initialization hook method.
     *
     * Implement this method to avoid having to overwrite
     * the constructor and call parent.
     *
     * @return void
     */
   
public function initialize()
    {
    }

   
/**
     * Get the component registry for this controller.
     *
     * If called with the first parameter, it will be set as the controller $this->_components property
     *
     * @param \Cake\Controller\ComponentRegistry|null $components Component registry.
     *
     * @return \Cake\Controller\ComponentRegistry
     */
   
public function components($components = null)
    {
        if (
$components === null && $this->_components === null) {
           
$this->_components = new ComponentRegistry($this);
        }
        if (
$components !== null) {
           
$components->setController($this);
           
$this->_components = $components;
        }

        return
$this->_components;
    }

   
/**
     * Add a component to the controller's registry.
     *
     * This method will also set the component to a property.
     * For example:
     *
     * ```
     * $this->loadComponent('Acl.Acl');
     * ```
     *
     * Will result in a `Toolbar` property being set.
     *
     * @param string $name The name of the component to load.
     * @param array $config The config for the component.
     * @return \Cake\Controller\Component
     * @throws \Exception
     */
   
public function loadComponent($name, array $config = [])
    {
        list(,
$prop) = pluginSplit($name);

        return
$this->{$prop} = $this->components()->load($name, $config);
    }

   
/**
     * Magic accessor for model autoloading.
     *
     * @param string $name Property name
     * @return bool|object The model instance or false
     */
   
public function __get($name)
    {
       
$deprecated = [
           
'name' => 'getName',
           
'plugin' => 'getPlugin',
           
'autoRender' => 'isAutoRenderEnabled',
        ];
        if (isset(
$deprecated[$name])) {
           
$method = $deprecated[$name];
           
deprecationWarning(sprintf('Controller::$%s is deprecated. Use $this->%s() instead.', $name, $method));

            return
$this->{$method}();
        }

       
$deprecated = [
           
'layout' => 'getLayout',
           
'view' => 'getTemplate',
           
'theme' => 'getTheme',
           
'autoLayout' => 'isAutoLayoutEnabled',
           
'viewPath' => 'getTemplatePath',
           
'layoutPath' => 'getLayoutPath',
        ];
        if (isset(
$deprecated[$name])) {
           
$method = $deprecated[$name];
           
deprecationWarning(sprintf('Controller::$%s is deprecated. Use $this->viewBuilder()->%s() instead.', $name, $method));

            return
$this->viewBuilder()->{$method}();
        }

        list(
$plugin, $class) = pluginSplit($this->modelClass, true);
        if (
$class === $name) {
            return
$this->loadModel($plugin . $class);
        }

       
$trace = debug_backtrace();
       
$parts = explode('\\', get_class($this));
       
trigger_error(
           
sprintf(
               
'Undefined property: %s::$%s in %s on line %s',
               
array_pop($parts),
               
$name,
               
$trace[0]['file'],
               
$trace[0]['line']
            ),
           
E_USER_NOTICE
       
);

        return
false;
    }

   
/**
     * Magic setter for removed properties.
     *
     * @param string $name Property name.
     * @param mixed $value Value to set.
     * @return void
     */
   
public function __set($name, $value)
    {
       
$deprecated = [
           
'name' => 'setName',
           
'plugin' => 'setPlugin',
        ];
        if (isset(
$deprecated[$name])) {
           
$method = $deprecated[$name];
           
deprecationWarning(sprintf('Controller::$%s is deprecated. Use $this->%s() instead.', $name, $method));
           
$this->{$method}($value);

            return;
        }
        if (
$name === 'autoRender') {
           
$value ? $this->enableAutoRender() : $this->disableAutoRender();
           
deprecationWarning(sprintf('Controller::$%s is deprecated. Use $this->enableAutoRender/disableAutoRender() instead.', $name));

            return;
        }
       
$deprecated = [
           
'layout' => 'setLayout',
           
'view' => 'setTemplate',
           
'theme' => 'setTheme',
           
'autoLayout' => 'enableAutoLayout',
           
'viewPath' => 'setTemplatePath',
           
'layoutPath' => 'setLayoutPath',
        ];
        if (isset(
$deprecated[$name])) {
           
$method = $deprecated[$name];
           
deprecationWarning(sprintf('Controller::$%s is deprecated. Use $this->viewBuilder()->%s() instead.', $name, $method));

           
$this->viewBuilder()->{$method}($value);

            return;
        }

       
$this->{$name} = $value;
    }

   
/**
     * Returns the controller name.
     *
     * @return string
     * @since 3.6.0
     */
   
public function getName()
    {
        return
$this->name;
    }

   
/**
     * Sets the controller name.
     *
     * @param string $name Controller name.
     * @return $this
     * @since 3.6.0
     */
   
public function setName($name)
    {
       
$this->name = $name;

        return
$this;
    }

   
/**
     * Returns the plugin name.
     *
     * @return string|null
     * @since 3.6.0
     */
   
public function getPlugin()
    {
        return
$this->plugin;
    }

   
/**
     * Sets the plugin name.
     *
     * @param string $name Plugin name.
     * @return $this
     * @since 3.6.0
     */
   
public function setPlugin($name)
    {
       
$this->plugin = $name;

        return
$this;
    }

   
/**
     * Returns true if an action should be rendered automatically.
     *
     * @return bool
     * @since 3.6.0
     */
   
public function isAutoRenderEnabled()
    {
        return
$this->autoRender;
    }

   
/**
     * Enable automatic action rendering.
     *
     * @return $this
     * @since 3.6.0
     */
   
public function enableAutoRender()
    {
       
$this->autoRender = true;

        return
$this;
    }

   
/**
     * Disable automatic action rendering.
     *
     * @return $this
     * @since 3.6.0
     */
   
public function disableAutoRender()
    {
       
$this->autoRender = false;

        return
$this;
    }

   
/**
     * Gets the request instance.
     *
     * @return \Cake\Http\ServerRequest
     * @since 3.6.0
     */
   
public function getRequest()
    {
        return
$this->request;
    }

   
/**
     * Sets the request objects and configures a number of controller properties
     * based on the contents of the request. Controller acts as a proxy for certain View variables
     * which must also be updated here. The properties that get set are:
     *
     * - $this->request - To the $request parameter
     * - $this->passedArgs - Same as $request->params['pass]
     *
     * @param \Cake\Http\ServerRequest $request Request instance.
     * @return $this
     */
   
public function setRequest(ServerRequest $request)
    {
       
$this->request = $request;
       
$this->plugin = $request->getParam('plugin') ?: null;

        if (
$request->getParam('pass')) {
           
$this->passedArgs = $request->getParam('pass');
        }

        return
$this;
    }

   
/**
     * Gets the response instance.
     *
     * @return \Cake\Http\Response
     * @since 3.6.0
     */
   
public function getResponse()
    {
        return
$this->response;
    }

   
/**
     * Sets the response instance.
     *
     * @param \Cake\Http\Response $response Response instance.
     * @return $this
     * @since 3.6.0
     */
   
public function setResponse(Response $response)
    {
       
$this->response = $response;

        return
$this;
    }

   
/**
     * Dispatches the controller action. Checks that the action
     * exists and isn't private.
     *
     * @return mixed The resulting response.
     * @throws \ReflectionException
     */
   
public function invokeAction()
    {
       
$request = $this->request;
        if (!
$request) {
            throw new
LogicException('No Request object configured. Cannot invoke action');
        }
        if (!
$this->isAction($request->getParam('action'))) {
            throw new
MissingActionException([
               
'controller' => $this->name . 'Controller',
               
'action' => $request->getParam('action'),
               
'prefix' => $request->getParam('prefix') ?: '',
               
'plugin' => $request->getParam('plugin'),
            ]);
        }
       
/** @var callable $callable */
       
$callable = [$this, $request->getParam('action')];

       
$result = $callable(...array_values($request->getParam('pass')));
        if (
$result instanceof Response) {
           
$this->response = $result;
        }

        return
$result;
    }

   
/**
     * Merge components, helpers vars from
     * parent classes.
     *
     * @return void
     */
   
protected function _mergeControllerVars()
    {
       
$this->_mergeVars(
            [
'components', 'helpers'],
            [
'associative' => ['components', 'helpers']]
        );
    }

   
/**
     * Returns a list of all events that will fire in the controller during its lifecycle.
     * You can override this function to add your own listener callbacks
     *
     * @return array
     */
   
public function implementedEvents()
    {
        return [
           
'Controller.initialize' => 'beforeFilter',
           
'Controller.beforeRender' => 'beforeRender',
           
'Controller.beforeRedirect' => 'beforeRedirect',
           
'Controller.shutdown' => 'afterFilter',
        ];
    }

   
/**
     * Loads the defined components using the Component factory.
     *
     * @return void
     */
   
protected function _loadComponents()
    {
        if (empty(
$this->components)) {
            return;
        }
       
$registry = $this->components();
       
$components = $registry->normalizeArray($this->components);
        foreach (
$components as $properties) {
           
$this->loadComponent($properties['class'], $properties['config']);
        }
    }

   
/**
     * Perform the startup process for this controller.
     * Fire the Components and Controller callbacks in the correct order.
     *
     * - Initializes components, which fires their `initialize` callback
     * - Calls the controller `beforeFilter`.
     * - triggers Component `startup` methods.
     *
     * @return \Cake\Http\Response|null
     */
   
public function startupProcess()
    {
       
$event = $this->dispatchEvent('Controller.initialize');
        if (
$event->getResult() instanceof Response) {
            return
$event->getResult();
        }
       
$event = $this->dispatchEvent('Controller.startup');
        if (
$event->getResult() instanceof Response) {
            return
$event->getResult();
        }

        return
null;
    }

   
/**
     * Perform the various shutdown processes for this controller.
     * Fire the Components and Controller callbacks in the correct order.
     *
     * - triggers the component `shutdown` callback.
     * - calls the Controller's `afterFilter` method.
     *
     * @return \Cake\Http\Response|null
     */
   
public function shutdownProcess()
    {
       
$event = $this->dispatchEvent('Controller.shutdown');
        if (
$event->getResult() instanceof Response) {
            return
$event->getResult();
        }

        return
null;
    }

   
/**
     * Redirects to given $url, after turning off $this->autoRender.
     *
     * @param string|array $url A string or array-based URL pointing to another location within the app,
     *     or an absolute URL
     * @param int $status HTTP status code (eg: 301)
     * @return \Cake\Http\Response|null
     * @link https://book.cakephp.org/3/en/controllers.html#Controller::redirect
     */
   
public function redirect($url, $status = 302)
    {
       
$this->autoRender = false;

        if (
$status) {
           
$this->response = $this->response->withStatus($status);
        }

       
$event = $this->dispatchEvent('Controller.beforeRedirect', [$url, $this->response]);
        if (
$event->getResult() instanceof Response) {
            return
$this->response = $event->getResult();
        }
        if (
$event->isStopped()) {
            return
null;
        }
       
$response = $this->response;

        if (!
$response->getHeaderLine('Location')) {
           
$response = $response->withLocation(Router::url($url, true));
        }

        return
$this->response = $response;
    }

   
/**
     * Internally redirects one action to another. Does not perform another HTTP request unlike Controller::redirect()
     *
     * Examples:
     *
     * ```
     * setAction('another_action');
     * setAction('action_with_parameters', $parameter1);
     * ```
     *
     * @param string $action The new action to be 'redirected' to.
     *   Any other parameters passed to this method will be passed as parameters to the new action.
     * @param array ...$args Arguments passed to the action
     * @return mixed Returns the return value of the called action
     */
   
public function setAction($action, ...$args)
    {
       
$this->setRequest($this->request->withParam('action', $action));

        return
$this->$action(...$args);
    }

   
/**
     * Instantiates the correct view class, hands it its data, and uses it to render the view output.
     *
     * @param string|null $view View to use for rendering
     * @param string|null $layout Layout to use
     * @return \Cake\Http\Response A response object containing the rendered view.
     * @link https://book.cakephp.org/3/en/controllers.html#rendering-a-view
     */
   
public function render($view = null, $layout = null)
    {
       
$builder = $this->viewBuilder();
        if (!
$builder->getTemplatePath()) {
           
$builder->setTemplatePath($this->_viewPath());
        }

        if (
$this->request->getParam('bare')) {
           
$builder->disableAutoLayout();
        }
       
$this->autoRender = false;

       
$event = $this->dispatchEvent('Controller.beforeRender');
        if (
$event->getResult() instanceof Response) {
            return
$event->getResult();
        }
        if (
$event->isStopped()) {
            return
$this->response;
        }

        if (
$builder->getTemplate() === null && $this->request->getParam('action')) {
           
$builder->setTemplate($this->request->getParam('action'));
        }

       
$this->View = $this->createView();
       
$contents = $this->View->render($view, $layout);
       
$this->setResponse($this->View->getResponse()->withStringBody($contents));

        return
$this->response;
    }

   
/**
     * Get the viewPath based on controller name and request prefix.
     *
     * @return string
     */
   
protected function _viewPath()
    {
       
$viewPath = $this->name;
        if (
$this->request->getParam('prefix')) {
           
$prefixes = array_map(
               
'Cake\Utility\Inflector::camelize',
               
explode('/', $this->request->getParam('prefix'))
            );
           
$viewPath = implode(DIRECTORY_SEPARATOR, $prefixes) . DIRECTORY_SEPARATOR . $viewPath;
        }

        return
$viewPath;
    }

   
/**
     * Returns the referring URL for this request.
     *
     * @param string|array|null $default Default URL to use if HTTP_REFERER cannot be read from headers
     * @param bool $local If true, restrict referring URLs to local server
     * @return string Referring URL
     */
   
public function referer($default = null, $local = false)
    {
        if (!
$this->request) {
            return
Router::url($default, !$local);
        }

       
$referer = $this->request->referer($local);
        if (
$referer === '/' && $default && $default !== $referer) {
           
$url = Router::url($default, !$local);
           
$base = $this->request->getAttribute('base');
            if (
$local && $base && strpos($url, $base) === 0) {
               
$url = substr($url, strlen($base));
                if (
$url[0] !== '/') {
                   
$url = '/' . $url;
                }

                return
$url;
            }

            return
$url;
        }

        return
$referer;
    }

   
/**
     * Handles pagination of records in Table objects.
     *
     * Will load the referenced Table object, and have the PaginatorComponent
     * paginate the query using the request date and settings defined in `$this->paginate`.
     *
     * This method will also make the PaginatorHelper available in the view.
     *
     * @param \Cake\ORM\Table|string|\Cake\ORM\Query|null $object Table to paginate
     * (e.g: Table instance, 'TableName' or a Query object)
     * @param array $settings The settings/configuration used for pagination.
     * @return \Cake\ORM\ResultSet|\Cake\Datasource\ResultSetInterface Query results
     * @link https://book.cakephp.org/3/en/controllers.html#paginating-a-model
     * @throws \RuntimeException When no compatible table object can be found.
     */
   
public function paginate($object = null, array $settings = [])
    {
        if (
is_object($object)) {
           
$table = $object;
        }

        if (
is_string($object) || $object === null) {
           
$try = [$object, $this->modelClass];
            foreach (
$try as $tableName) {
                if (empty(
$tableName)) {
                    continue;
                }
               
$table = $this->loadModel($tableName);
                break;
            }
        }

       
$this->loadComponent('Paginator');
        if (empty(
$table)) {
            throw new
RuntimeException('Unable to locate an object compatible with paginate.');
        }
       
$settings += $this->paginate;

        return
$this->Paginator->paginate($table, $settings);
    }

   
/**
     * Method to check that an action is accessible from a URL.
     *
     * Override this method to change which controller methods can be reached.
     * The default implementation disallows access to all methods defined on Cake\Controller\Controller,
     * and allows all public methods on all subclasses of this class.
     *
     * @param string $action The action to check.
     * @return bool Whether or not the method is accessible from a URL.
     * @throws \ReflectionException
     */
   
public function isAction($action)
    {
       
$baseClass = new ReflectionClass('Cake\Controller\Controller');
        if (
$baseClass->hasMethod($action)) {
            return
false;
        }
        try {
           
$method = new ReflectionMethod($this, $action);
        } catch (
ReflectionException $e) {
            return
false;
        }

        return
$method->isPublic();
    }

   
/**
     * Called before the controller action. You can use this method to configure and customize components
     * or perform logic that needs to happen before each controller action.
     *
     * @param \Cake\Event\Event $event An Event instance
     * @return \Cake\Http\Response|null
     * @link https://book.cakephp.org/3/en/controllers.html#request-life-cycle-callbacks
     */
   
public function beforeFilter(Event $event)
    {
        return
null;
    }

   
/**
     * Called after the controller action is run, but before the view is rendered. You can use this method
     * to perform logic or set view variables that are required on every request.
     *
     * @param \Cake\Event\Event $event An Event instance
     * @return \Cake\Http\Response|null
     * @link https://book.cakephp.org/3/en/controllers.html#request-life-cycle-callbacks
     */
   
public function beforeRender(Event $event)
    {
        return
null;
    }

   
/**
     * The beforeRedirect method is invoked when the controller's redirect method is called but before any
     * further action.
     *
     * If the event is stopped the controller will not continue on to redirect the request.
     * The $url and $status variables have same meaning as for the controller's method.
     * You can set the event result to response instance or modify the redirect location
     * using controller's response instance.
     *
     * @param \Cake\Event\Event $event An Event instance
     * @param string|array $url A string or array-based URL pointing to another location within the app,
     *     or an absolute URL
     * @param \Cake\Http\Response $response The response object.
     * @return \Cake\Http\Response|null
     * @link https://book.cakephp.org/3/en/controllers.html#request-life-cycle-callbacks
     */
   
public function beforeRedirect(Event $event, $url, Response $response)
    {
        return
null;
    }

   
/**
     * Called after the controller action is run and rendered.
     *
     * @param \Cake\Event\Event $event An Event instance
     * @return \Cake\Http\Response|null
     * @link https://book.cakephp.org/3/en/controllers.html#request-life-cycle-callbacks
     */
   
public function afterFilter(Event $event)
    {
        return
null;
    }
}