1: <?php
2: /**
3: * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
4: * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
5: *
6: * Licensed under The MIT License
7: * For full copyright and license information, please see the LICENSE.txt
8: * Redistributions of files must retain the above copyright notice.
9: *
10: * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
11: * @link https://cakephp.org CakePHP(tm) Project
12: * @since 0.2.9
13: * @license https://opensource.org/licenses/mit-license.php MIT License
14: */
15: namespace Cake\Controller;
16:
17: use Cake\Controller\Exception\MissingActionException;
18: use Cake\Datasource\ModelAwareTrait;
19: use Cake\Event\Event;
20: use Cake\Event\EventDispatcherInterface;
21: use Cake\Event\EventDispatcherTrait;
22: use Cake\Event\EventListenerInterface;
23: use Cake\Http\Response;
24: use Cake\Http\ServerRequest;
25: use Cake\Log\LogTrait;
26: use Cake\ORM\Locator\LocatorAwareTrait;
27: use Cake\Routing\RequestActionTrait;
28: use Cake\Routing\Router;
29: use Cake\Utility\MergeVariablesTrait;
30: use Cake\View\ViewVarsTrait;
31: use LogicException;
32: use ReflectionClass;
33: use ReflectionException;
34: use ReflectionMethod;
35: use RuntimeException;
36:
37: /**
38: * Application controller class for organization of business logic.
39: * Provides basic functionality, such as rendering views inside layouts,
40: * automatic model availability, redirection, callbacks, and more.
41: *
42: * Controllers should provide a number of 'action' methods. These are public
43: * methods on a controller that are not inherited from `Controller`.
44: * Each action serves as an endpoint for performing a specific action on a
45: * resource or collection of resources. For example adding or editing a new
46: * object, or listing a set of objects.
47: *
48: * You can access request parameters, using `$this->request`. The request object
49: * contains all the POST, GET and FILES that were part of the request.
50: *
51: * After performing the required action, controllers are responsible for
52: * creating a response. This usually takes the form of a generated `View`, or
53: * possibly a redirection to another URL. In either case `$this->response`
54: * allows you to manipulate all aspects of the response.
55: *
56: * Controllers are created by `Dispatcher` based on request parameters and
57: * routing. By default controllers and actions use conventional names.
58: * For example `/posts/index` maps to `PostsController::index()`. You can re-map
59: * URLs using Router::connect() or RouterBuilder::connect().
60: *
61: * ### Life cycle callbacks
62: *
63: * CakePHP fires a number of life cycle callbacks during each request.
64: * By implementing a method you can receive the related events. The available
65: * callbacks are:
66: *
67: * - `beforeFilter(Event $event)`
68: * Called before each action. This is a good place to do general logic that
69: * applies to all actions.
70: * - `beforeRender(Event $event)`
71: * Called before the view is rendered.
72: * - `beforeRedirect(Event $event, $url, Response $response)`
73: * Called before a redirect is done.
74: * - `afterFilter(Event $event)`
75: * Called after each action is complete and after the view is rendered.
76: *
77: * @property \Cake\Controller\Component\AuthComponent $Auth
78: * @property \Cake\Controller\Component\CookieComponent $Cookie
79: * @property \Cake\Controller\Component\CsrfComponent $Csrf
80: * @property \Cake\Controller\Component\FlashComponent $Flash
81: * @property \Cake\Controller\Component\PaginatorComponent $Paginator
82: * @property \Cake\Controller\Component\RequestHandlerComponent $RequestHandler
83: * @property \Cake\Controller\Component\SecurityComponent $Security
84: * @method bool isAuthorized($user)
85: * @link https://book.cakephp.org/3.0/en/controllers.html
86: */
87: class Controller implements EventListenerInterface, EventDispatcherInterface
88: {
89:
90: use EventDispatcherTrait;
91: use LocatorAwareTrait;
92: use LogTrait;
93: use MergeVariablesTrait;
94: use ModelAwareTrait;
95: use RequestActionTrait;
96: use ViewVarsTrait;
97:
98: /**
99: * The name of this controller. Controller names are plural, named after the model they manipulate.
100: *
101: * Set automatically using conventions in Controller::__construct().
102: *
103: * @var string
104: */
105: protected $name;
106:
107: /**
108: * An array containing the names of helpers this controller uses. The array elements should
109: * not contain the "Helper" part of the class name.
110: *
111: * Example:
112: * ```
113: * public $helpers = ['Form', 'Html', 'Time'];
114: * ```
115: *
116: * @var array
117: * @link https://book.cakephp.org/3.0/en/controllers.html#configuring-helpers-to-load
118: *
119: * @deprecated 3.0.0 You should configure helpers in your AppView::initialize() method.
120: */
121: public $helpers = [];
122:
123: /**
124: * An instance of a \Cake\Http\ServerRequest object that contains information about the current request.
125: * This object contains all the information about a request and several methods for reading
126: * additional information about the request.
127: *
128: * Deprecated 3.6.0: The property will become protected in 4.0.0. Use getRequest()/setRequest instead.
129: *
130: * @var \Cake\Http\ServerRequest
131: * @link https://book.cakephp.org/3.0/en/controllers/request-response.html#request
132: */
133: public $request;
134:
135: /**
136: * An instance of a Response object that contains information about the impending response
137: *
138: * Deprecated 3.6.0: The property will become protected in 4.0.0. Use getResponse()/setResponse instead.
139:
140: * @var \Cake\Http\Response
141: * @link https://book.cakephp.org/3.0/en/controllers/request-response.html#response
142: */
143: public $response;
144:
145: /**
146: * The class name to use for creating the response object.
147: *
148: * @var string
149: */
150: protected $_responseClass = 'Cake\Http\Response';
151:
152: /**
153: * Settings for pagination.
154: *
155: * Used to pre-configure pagination preferences for the various
156: * tables your controller will be paginating.
157: *
158: * @var array
159: * @see \Cake\Controller\Component\PaginatorComponent
160: */
161: public $paginate = [];
162:
163: /**
164: * Set to true to automatically render the view
165: * after action logic.
166: *
167: * @var bool
168: */
169: protected $autoRender = true;
170:
171: /**
172: * Instance of ComponentRegistry used to create Components
173: *
174: * @var \Cake\Controller\ComponentRegistry
175: */
176: protected $_components;
177:
178: /**
179: * Array containing the names of components this controller uses. Component names
180: * should not contain the "Component" portion of the class name.
181: *
182: * Example:
183: * ```
184: * public $components = ['RequestHandler', 'Acl'];
185: * ```
186: *
187: * @var array
188: * @link https://book.cakephp.org/3.0/en/controllers/components.html
189: *
190: * @deprecated 3.0.0 You should configure components in your Controller::initialize() method.
191: */
192: public $components = [];
193:
194: /**
195: * Instance of the View created during rendering. Won't be set until after
196: * Controller::render() is called.
197: *
198: * @var \Cake\View\View
199: * @deprecated 3.1.0 Use viewBuilder() instead.
200: */
201: public $View;
202:
203: /**
204: * These Controller properties will be passed from the Controller to the View as options.
205: *
206: * @var array
207: * @see \Cake\View\View
208: * @deprecated 3.7.0 Use ViewBuilder::setOptions() or any one of it's setter methods instead.
209: */
210: protected $_validViewOptions = [
211: 'passedArgs'
212: ];
213:
214: /**
215: * Automatically set to the name of a plugin.
216: *
217: * @var string|null
218: */
219: protected $plugin;
220:
221: /**
222: * Holds all passed params.
223: *
224: * @var array
225: * @deprecated 3.1.0 Use `$this->request->getParam('pass')` instead.
226: */
227: public $passedArgs = [];
228:
229: /**
230: * Constructor.
231: *
232: * Sets a number of properties based on conventions if they are empty. To override the
233: * conventions CakePHP uses you can define properties in your class declaration.
234: *
235: * @param \Cake\Http\ServerRequest|null $request Request object for this controller. Can be null for testing,
236: * but expect that features that use the request parameters will not work.
237: * @param \Cake\Http\Response|null $response Response object for this controller.
238: * @param string|null $name Override the name useful in testing when using mocks.
239: * @param \Cake\Event\EventManager|null $eventManager The event manager. Defaults to a new instance.
240: * @param \Cake\Controller\ComponentRegistry|null $components The component registry. Defaults to a new instance.
241: */
242: public function __construct(ServerRequest $request = null, Response $response = null, $name = null, $eventManager = null, $components = null)
243: {
244: if ($name !== null) {
245: $this->name = $name;
246: }
247:
248: if ($this->name === null && $request && $request->getParam('controller')) {
249: $this->name = $request->getParam('controller');
250: }
251:
252: if ($this->name === null) {
253: list(, $name) = namespaceSplit(get_class($this));
254: $this->name = substr($name, 0, -10);
255: }
256:
257: $this->setRequest($request ?: new ServerRequest());
258: $this->response = $response ?: new Response();
259:
260: if ($eventManager !== null) {
261: $this->setEventManager($eventManager);
262: }
263:
264: $this->modelFactory('Table', [$this->getTableLocator(), 'get']);
265: $plugin = $this->request->getParam('plugin');
266: $modelClass = ($plugin ? $plugin . '.' : '') . $this->name;
267: $this->_setModelClass($modelClass);
268:
269: if ($components !== null) {
270: $this->components($components);
271: }
272:
273: $this->initialize();
274:
275: $this->_mergeControllerVars();
276: $this->_loadComponents();
277: $this->getEventManager()->on($this);
278: }
279:
280: /**
281: * Initialization hook method.
282: *
283: * Implement this method to avoid having to overwrite
284: * the constructor and call parent.
285: *
286: * @return void
287: */
288: public function initialize()
289: {
290: }
291:
292: /**
293: * Get the component registry for this controller.
294: *
295: * If called with the first parameter, it will be set as the controller $this->_components property
296: *
297: * @param \Cake\Controller\ComponentRegistry|null $components Component registry.
298: *
299: * @return \Cake\Controller\ComponentRegistry
300: */
301: public function components($components = null)
302: {
303: if ($components === null && $this->_components === null) {
304: $this->_components = new ComponentRegistry($this);
305: }
306: if ($components !== null) {
307: $components->setController($this);
308: $this->_components = $components;
309: }
310:
311: return $this->_components;
312: }
313:
314: /**
315: * Add a component to the controller's registry.
316: *
317: * This method will also set the component to a property.
318: * For example:
319: *
320: * ```
321: * $this->loadComponent('Acl.Acl');
322: * ```
323: *
324: * Will result in a `Toolbar` property being set.
325: *
326: * @param string $name The name of the component to load.
327: * @param array $config The config for the component.
328: * @return \Cake\Controller\Component
329: * @throws \Exception
330: */
331: public function loadComponent($name, array $config = [])
332: {
333: list(, $prop) = pluginSplit($name);
334:
335: return $this->{$prop} = $this->components()->load($name, $config);
336: }
337:
338: /**
339: * Magic accessor for model autoloading.
340: *
341: * @param string $name Property name
342: * @return bool|object The model instance or false
343: */
344: public function __get($name)
345: {
346: $deprecated = [
347: 'name' => 'getName',
348: 'plugin' => 'getPlugin',
349: 'autoRender' => 'isAutoRenderEnabled',
350: ];
351: if (isset($deprecated[$name])) {
352: $method = $deprecated[$name];
353: deprecationWarning(sprintf('Controller::$%s is deprecated. Use $this->%s() instead.', $name, $method));
354:
355: return $this->{$method}();
356: }
357:
358: $deprecated = [
359: 'layout' => 'getLayout',
360: 'view' => 'getTemplate',
361: 'theme' => 'getTheme',
362: 'autoLayout' => 'isAutoLayoutEnabled',
363: 'viewPath' => 'getTemplatePath',
364: 'layoutPath' => 'getLayoutPath',
365: ];
366: if (isset($deprecated[$name])) {
367: $method = $deprecated[$name];
368: deprecationWarning(sprintf('Controller::$%s is deprecated. Use $this->viewBuilder()->%s() instead.', $name, $method));
369:
370: return $this->viewBuilder()->{$method}();
371: }
372:
373: list($plugin, $class) = pluginSplit($this->modelClass, true);
374: if ($class === $name) {
375: return $this->loadModel($plugin . $class);
376: }
377:
378: $trace = debug_backtrace();
379: $parts = explode('\\', get_class($this));
380: trigger_error(
381: sprintf(
382: 'Undefined property: %s::$%s in %s on line %s',
383: array_pop($parts),
384: $name,
385: $trace[0]['file'],
386: $trace[0]['line']
387: ),
388: E_USER_NOTICE
389: );
390:
391: return false;
392: }
393:
394: /**
395: * Magic setter for removed properties.
396: *
397: * @param string $name Property name.
398: * @param mixed $value Value to set.
399: * @return void
400: */
401: public function __set($name, $value)
402: {
403: $deprecated = [
404: 'name' => 'setName',
405: 'plugin' => 'setPlugin'
406: ];
407: if (isset($deprecated[$name])) {
408: $method = $deprecated[$name];
409: deprecationWarning(sprintf('Controller::$%s is deprecated. Use $this->%s() instead.', $name, $method));
410: $this->{$method}($value);
411:
412: return;
413: }
414: if ($name === 'autoRender') {
415: $value ? $this->enableAutoRender() : $this->disableAutoRender();
416: deprecationWarning(sprintf('Controller::$%s is deprecated. Use $this->enableAutoRender/disableAutoRender() instead.', $name));
417:
418: return;
419: }
420: $deprecated = [
421: 'layout' => 'setLayout',
422: 'view' => 'setTemplate',
423: 'theme' => 'setTheme',
424: 'autoLayout' => 'enableAutoLayout',
425: 'viewPath' => 'setTemplatePath',
426: 'layoutPath' => 'setLayoutPath',
427: ];
428: if (isset($deprecated[$name])) {
429: $method = $deprecated[$name];
430: deprecationWarning(sprintf('Controller::$%s is deprecated. Use $this->viewBuilder()->%s() instead.', $name, $method));
431:
432: $this->viewBuilder()->{$method}($value);
433:
434: return;
435: }
436:
437: $this->{$name} = $value;
438: }
439:
440: /**
441: * Returns the controller name.
442: *
443: * @return string
444: * @since 3.6.0
445: */
446: public function getName()
447: {
448: return $this->name;
449: }
450:
451: /**
452: * Sets the controller name.
453: *
454: * @param string $name Controller name.
455: * @return $this
456: * @since 3.6.0
457: */
458: public function setName($name)
459: {
460: $this->name = $name;
461:
462: return $this;
463: }
464:
465: /**
466: * Returns the plugin name.
467: *
468: * @return string|null
469: * @since 3.6.0
470: */
471: public function getPlugin()
472: {
473: return $this->plugin;
474: }
475:
476: /**
477: * Sets the plugin name.
478: *
479: * @param string $name Plugin name.
480: * @return $this
481: * @since 3.6.0
482: */
483: public function setPlugin($name)
484: {
485: $this->plugin = $name;
486:
487: return $this;
488: }
489:
490: /**
491: * Returns true if an action should be rendered automatically.
492: *
493: * @return bool
494: * @since 3.6.0
495: */
496: public function isAutoRenderEnabled()
497: {
498: return $this->autoRender;
499: }
500:
501: /**
502: * Enable automatic action rendering.
503: *
504: * @return $this
505: * @since 3.6.0
506: */
507: public function enableAutoRender()
508: {
509: $this->autoRender = true;
510:
511: return $this;
512: }
513:
514: /**
515: * Disable automatic action rendering.
516: *
517: * @return $this
518: * @since 3.6.0
519: */
520: public function disableAutoRender()
521: {
522: $this->autoRender = false;
523:
524: return $this;
525: }
526:
527: /**
528: * Gets the request instance.
529: *
530: * @return \Cake\Http\ServerRequest
531: * @since 3.6.0
532: */
533: public function getRequest()
534: {
535: return $this->request;
536: }
537:
538: /**
539: * Sets the request objects and configures a number of controller properties
540: * based on the contents of the request. Controller acts as a proxy for certain View variables
541: * which must also be updated here. The properties that get set are:
542: *
543: * - $this->request - To the $request parameter
544: * - $this->passedArgs - Same as $request->params['pass]
545: *
546: * @param \Cake\Http\ServerRequest $request Request instance.
547: * @return $this
548: */
549: public function setRequest(ServerRequest $request)
550: {
551: $this->request = $request;
552: $this->plugin = $request->getParam('plugin') ?: null;
553:
554: if ($request->getParam('pass')) {
555: $this->passedArgs = $request->getParam('pass');
556: }
557:
558: return $this;
559: }
560:
561: /**
562: * Gets the response instance.
563: *
564: * @return \Cake\Http\Response
565: * @since 3.6.0
566: */
567: public function getResponse()
568: {
569: return $this->response;
570: }
571:
572: /**
573: * Sets the response instance.
574: *
575: * @param \Cake\Http\Response $response Response instance.
576: * @return $this
577: * @since 3.6.0
578: */
579: public function setResponse(Response $response)
580: {
581: $this->response = $response;
582:
583: return $this;
584: }
585:
586: /**
587: * Dispatches the controller action. Checks that the action
588: * exists and isn't private.
589: *
590: * @return mixed The resulting response.
591: * @throws \ReflectionException
592: */
593: public function invokeAction()
594: {
595: $request = $this->request;
596: if (!$request) {
597: throw new LogicException('No Request object configured. Cannot invoke action');
598: }
599: if (!$this->isAction($request->getParam('action'))) {
600: throw new MissingActionException([
601: 'controller' => $this->name . 'Controller',
602: 'action' => $request->getParam('action'),
603: 'prefix' => $request->getParam('prefix') ?: '',
604: 'plugin' => $request->getParam('plugin'),
605: ]);
606: }
607: /* @var callable $callable */
608: $callable = [$this, $request->getParam('action')];
609:
610: return $callable(...array_values($request->getParam('pass')));
611: }
612:
613: /**
614: * Merge components, helpers vars from
615: * parent classes.
616: *
617: * @return void
618: */
619: protected function _mergeControllerVars()
620: {
621: $this->_mergeVars(
622: ['components', 'helpers'],
623: ['associative' => ['components', 'helpers']]
624: );
625: }
626:
627: /**
628: * Returns a list of all events that will fire in the controller during its lifecycle.
629: * You can override this function to add your own listener callbacks
630: *
631: * @return array
632: */
633: public function implementedEvents()
634: {
635: return [
636: 'Controller.initialize' => 'beforeFilter',
637: 'Controller.beforeRender' => 'beforeRender',
638: 'Controller.beforeRedirect' => 'beforeRedirect',
639: 'Controller.shutdown' => 'afterFilter',
640: ];
641: }
642:
643: /**
644: * Loads the defined components using the Component factory.
645: *
646: * @return void
647: */
648: protected function _loadComponents()
649: {
650: if (empty($this->components)) {
651: return;
652: }
653: $registry = $this->components();
654: $components = $registry->normalizeArray($this->components);
655: foreach ($components as $properties) {
656: $this->loadComponent($properties['class'], $properties['config']);
657: }
658: }
659:
660: /**
661: * Perform the startup process for this controller.
662: * Fire the Components and Controller callbacks in the correct order.
663: *
664: * - Initializes components, which fires their `initialize` callback
665: * - Calls the controller `beforeFilter`.
666: * - triggers Component `startup` methods.
667: *
668: * @return \Cake\Http\Response|null
669: */
670: public function startupProcess()
671: {
672: $event = $this->dispatchEvent('Controller.initialize');
673: if ($event->getResult() instanceof Response) {
674: return $event->getResult();
675: }
676: $event = $this->dispatchEvent('Controller.startup');
677: if ($event->getResult() instanceof Response) {
678: return $event->getResult();
679: }
680:
681: return null;
682: }
683:
684: /**
685: * Perform the various shutdown processes for this controller.
686: * Fire the Components and Controller callbacks in the correct order.
687: *
688: * - triggers the component `shutdown` callback.
689: * - calls the Controller's `afterFilter` method.
690: *
691: * @return \Cake\Http\Response|null
692: */
693: public function shutdownProcess()
694: {
695: $event = $this->dispatchEvent('Controller.shutdown');
696: if ($event->getResult() instanceof Response) {
697: return $event->getResult();
698: }
699:
700: return null;
701: }
702:
703: /**
704: * Redirects to given $url, after turning off $this->autoRender.
705: *
706: * @param string|array $url A string or array-based URL pointing to another location within the app,
707: * or an absolute URL
708: * @param int $status HTTP status code (eg: 301)
709: * @return \Cake\Http\Response|null
710: * @link https://book.cakephp.org/3.0/en/controllers.html#Controller::redirect
711: */
712: public function redirect($url, $status = 302)
713: {
714: $this->autoRender = false;
715:
716: if ($status) {
717: $this->response = $this->response->withStatus($status);
718: }
719:
720: $event = $this->dispatchEvent('Controller.beforeRedirect', [$url, $this->response]);
721: if ($event->getResult() instanceof Response) {
722: return $this->response = $event->getResult();
723: }
724: if ($event->isStopped()) {
725: return null;
726: }
727: $response = $this->response;
728:
729: if (!$response->getHeaderLine('Location')) {
730: $response = $response->withLocation(Router::url($url, true));
731: }
732:
733: return $this->response = $response;
734: }
735:
736: /**
737: * Internally redirects one action to another. Does not perform another HTTP request unlike Controller::redirect()
738: *
739: * Examples:
740: *
741: * ```
742: * setAction('another_action');
743: * setAction('action_with_parameters', $parameter1);
744: * ```
745: *
746: * @param string $action The new action to be 'redirected' to.
747: * Any other parameters passed to this method will be passed as parameters to the new action.
748: * @param array ...$args Arguments passed to the action
749: * @return mixed Returns the return value of the called action
750: */
751: public function setAction($action, ...$args)
752: {
753: $this->setRequest($this->request->withParam('action', $action));
754:
755: return $this->$action(...$args);
756: }
757:
758: /**
759: * Instantiates the correct view class, hands it its data, and uses it to render the view output.
760: *
761: * @param string|null $view View to use for rendering
762: * @param string|null $layout Layout to use
763: * @return \Cake\Http\Response A response object containing the rendered view.
764: * @link https://book.cakephp.org/3.0/en/controllers.html#rendering-a-view
765: */
766: public function render($view = null, $layout = null)
767: {
768: $builder = $this->viewBuilder();
769: if (!$builder->getTemplatePath()) {
770: $builder->setTemplatePath($this->_viewPath());
771: }
772:
773: if ($this->request->getParam('bare')) {
774: $builder->disableAutoLayout();
775: }
776: $this->autoRender = false;
777:
778: $event = $this->dispatchEvent('Controller.beforeRender');
779: if ($event->getResult() instanceof Response) {
780: return $event->getResult();
781: }
782: if ($event->isStopped()) {
783: return $this->response;
784: }
785:
786: if ($builder->getTemplate() === null && $this->request->getParam('action')) {
787: $builder->setTemplate($this->request->getParam('action'));
788: }
789:
790: $this->View = $this->createView();
791: $contents = $this->View->render($view, $layout);
792: $this->setResponse($this->View->getResponse()->withStringBody($contents));
793:
794: return $this->response;
795: }
796:
797: /**
798: * Get the viewPath based on controller name and request prefix.
799: *
800: * @return string
801: */
802: protected function _viewPath()
803: {
804: $viewPath = $this->name;
805: if ($this->request->getParam('prefix')) {
806: $prefixes = array_map(
807: 'Cake\Utility\Inflector::camelize',
808: explode('/', $this->request->getParam('prefix'))
809: );
810: $viewPath = implode(DIRECTORY_SEPARATOR, $prefixes) . DIRECTORY_SEPARATOR . $viewPath;
811: }
812:
813: return $viewPath;
814: }
815:
816: /**
817: * Returns the referring URL for this request.
818: *
819: * @param string|array|null $default Default URL to use if HTTP_REFERER cannot be read from headers
820: * @param bool $local If true, restrict referring URLs to local server
821: * @return string Referring URL
822: */
823: public function referer($default = null, $local = false)
824: {
825: if (!$this->request) {
826: return Router::url($default, !$local);
827: }
828:
829: $referer = $this->request->referer($local);
830: if ($referer === '/' && $default && $default !== $referer) {
831: $url = Router::url($default, !$local);
832: $base = $this->request->getAttribute('base');
833: if ($local && $base && strpos($url, $base) === 0) {
834: $url = substr($url, strlen($base));
835: if ($url[0] !== '/') {
836: $url = '/' . $url;
837: }
838:
839: return $url;
840: }
841:
842: return $url;
843: }
844:
845: return $referer;
846: }
847:
848: /**
849: * Handles pagination of records in Table objects.
850: *
851: * Will load the referenced Table object, and have the PaginatorComponent
852: * paginate the query using the request date and settings defined in `$this->paginate`.
853: *
854: * This method will also make the PaginatorHelper available in the view.
855: *
856: * @param \Cake\ORM\Table|string|\Cake\ORM\Query|null $object Table to paginate
857: * (e.g: Table instance, 'TableName' or a Query object)
858: * @param array $settings The settings/configuration used for pagination.
859: * @return \Cake\ORM\ResultSet|\Cake\Datasource\ResultSetInterface Query results
860: * @link https://book.cakephp.org/3.0/en/controllers.html#paginating-a-model
861: * @throws \RuntimeException When no compatible table object can be found.
862: */
863: public function paginate($object = null, array $settings = [])
864: {
865: if (is_object($object)) {
866: $table = $object;
867: }
868:
869: if (is_string($object) || $object === null) {
870: $try = [$object, $this->modelClass];
871: foreach ($try as $tableName) {
872: if (empty($tableName)) {
873: continue;
874: }
875: $table = $this->loadModel($tableName);
876: break;
877: }
878: }
879:
880: $this->loadComponent('Paginator');
881: if (empty($table)) {
882: throw new RuntimeException('Unable to locate an object compatible with paginate.');
883: }
884: $settings += $this->paginate;
885:
886: return $this->Paginator->paginate($table, $settings);
887: }
888:
889: /**
890: * Method to check that an action is accessible from a URL.
891: *
892: * Override this method to change which controller methods can be reached.
893: * The default implementation disallows access to all methods defined on Cake\Controller\Controller,
894: * and allows all public methods on all subclasses of this class.
895: *
896: * @param string $action The action to check.
897: * @return bool Whether or not the method is accessible from a URL.
898: * @throws \ReflectionException
899: */
900: public function isAction($action)
901: {
902: $baseClass = new ReflectionClass('Cake\Controller\Controller');
903: if ($baseClass->hasMethod($action)) {
904: return false;
905: }
906: try {
907: $method = new ReflectionMethod($this, $action);
908: } catch (ReflectionException $e) {
909: return false;
910: }
911:
912: return $method->isPublic();
913: }
914:
915: /**
916: * Called before the controller action. You can use this method to configure and customize components
917: * or perform logic that needs to happen before each controller action.
918: *
919: * @param \Cake\Event\Event $event An Event instance
920: * @return \Cake\Http\Response|null
921: * @link https://book.cakephp.org/3.0/en/controllers.html#request-life-cycle-callbacks
922: */
923: public function beforeFilter(Event $event)
924: {
925: return null;
926: }
927:
928: /**
929: * Called after the controller action is run, but before the view is rendered. You can use this method
930: * to perform logic or set view variables that are required on every request.
931: *
932: * @param \Cake\Event\Event $event An Event instance
933: * @return \Cake\Http\Response|null
934: * @link https://book.cakephp.org/3.0/en/controllers.html#request-life-cycle-callbacks
935: */
936: public function beforeRender(Event $event)
937: {
938: return null;
939: }
940:
941: /**
942: * The beforeRedirect method is invoked when the controller's redirect method is called but before any
943: * further action.
944: *
945: * If the event is stopped the controller will not continue on to redirect the request.
946: * The $url and $status variables have same meaning as for the controller's method.
947: * You can set the event result to response instance or modify the redirect location
948: * using controller's response instance.
949: *
950: * @param \Cake\Event\Event $event An Event instance
951: * @param string|array $url A string or array-based URL pointing to another location within the app,
952: * or an absolute URL
953: * @param \Cake\Http\Response $response The response object.
954: * @return \Cake\Http\Response|null
955: * @link https://book.cakephp.org/3.0/en/controllers.html#request-life-cycle-callbacks
956: */
957: public function beforeRedirect(Event $event, $url, Response $response)
958: {
959: return null;
960: }
961:
962: /**
963: * Called after the controller action is run and rendered.
964: *
965: * @param \Cake\Event\Event $event An Event instance
966: * @return \Cake\Http\Response|null
967: * @link https://book.cakephp.org/3.0/en/controllers.html#request-life-cycle-callbacks
968: */
969: public function afterFilter(Event $event)
970: {
971: return null;
972: }
973: }
974: