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: * Redistributions of files must retain the above copyright notice.
8: *
9: * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
10: * @link https://cakephp.org CakePHP(tm) Project
11: * @since 3.0.0
12: * @license https://opensource.org/licenses/mit-license.php MIT License
13: */
14: namespace Cake\Routing;
15:
16: use Cake\Core\Configure;
17: use Cake\Http\Response;
18: use Cake\Http\ServerRequest;
19: use Cake\Http\Session;
20: use Cake\Routing\Filter\ControllerFactoryFilter;
21: use Cake\Routing\Filter\RoutingFilter;
22:
23: /**
24: * Provides the requestAction() method for doing sub-requests
25: *
26: * @deprecated 3.3.0 Use view cells instead.
27: */
28: trait RequestActionTrait
29: {
30: /**
31: * Calls a controller's method from any location. Can be used to connect controllers together
32: * or tie plugins into a main application. requestAction can be used to return rendered views
33: * or fetch the return value from controller actions.
34: *
35: * Under the hood this method uses Router::reverse() to convert the $url parameter into a string
36: * URL. You should use URL formats that are compatible with Router::reverse()
37: *
38: * ### Examples
39: *
40: * A basic example getting the return value of the controller action:
41: *
42: * ```
43: * $variables = $this->requestAction('/articles/popular');
44: * ```
45: *
46: * A basic example of request action to fetch a rendered page without the layout.
47: *
48: * ```
49: * $viewHtml = $this->requestAction('/articles/popular', ['return']);
50: * ```
51: *
52: * You can also pass the URL as an array:
53: *
54: * ```
55: * $vars = $this->requestAction(['controller' => 'articles', 'action' => 'popular']);
56: * ```
57: *
58: * ### Passing other request data
59: *
60: * You can pass POST, GET, COOKIE and other data into the request using the appropriate keys.
61: * Cookies can be passed using the `cookies` key. Get parameters can be set with `query` and post
62: * data can be sent using the `post` key.
63: *
64: * ```
65: * $vars = $this->requestAction('/articles/popular', [
66: * 'query' => ['page' => 1],
67: * 'cookies' => ['remember_me' => 1],
68: * ]);
69: * ```
70: *
71: * ### Sending environment or header values
72: *
73: * By default actions dispatched with this method will use the global $_SERVER and $_ENV
74: * values. If you want to override those values for a request action, you can specify the values:
75: *
76: * ```
77: * $vars = $this->requestAction('/articles/popular', [
78: * 'environment' => ['CONTENT_TYPE' => 'application/json']
79: * ]);
80: * ```
81: *
82: * ### Transmitting the session
83: *
84: * By default actions dispatched with this method will use the standard session object.
85: * If you want a particular session instance to be used, you need to specify it.
86: *
87: * ```
88: * $vars = $this->requestAction('/articles/popular', [
89: * 'session' => new Session($someSessionConfig)
90: * ]);
91: * ```
92: *
93: * @param string|array $url String or array-based url. Unlike other url arrays in CakePHP, this
94: * url will not automatically handle passed arguments in the $url parameter.
95: * @param array $extra if array includes the key "return" it sets the autoRender to true. Can
96: * also be used to submit GET/POST data, and passed arguments.
97: * @return mixed Boolean true or false on success/failure, or contents
98: * of rendered action if 'return' is set in $extra.
99: * @deprecated 3.3.0 You should refactor your code to use View Cells instead of this method.
100: */
101: public function requestAction($url, array $extra = [])
102: {
103: deprecationWarning(
104: 'RequestActionTrait::requestAction() is deprecated. ' .
105: 'You should refactor to use View Cells or Components instead.'
106: );
107: if (empty($url)) {
108: return false;
109: }
110: $isReturn = array_search('return', $extra, true);
111: if ($isReturn !== false) {
112: $extra['return'] = 0;
113: $extra['autoRender'] = 1;
114: unset($extra[$isReturn]);
115: }
116: $extra += ['autoRender' => 0, 'return' => 1, 'bare' => 1, 'requested' => 1];
117:
118: $baseUrl = Configure::read('App.fullBaseUrl');
119: if (is_string($url) && strpos($url, $baseUrl) === 0) {
120: $url = Router::normalize(str_replace($baseUrl, '', $url));
121: }
122: if (is_string($url)) {
123: $params = [
124: 'url' => $url
125: ];
126: } elseif (is_array($url)) {
127: $defaultParams = ['plugin' => null, 'controller' => null, 'action' => null];
128: $params = [
129: 'params' => $url + $defaultParams,
130: 'base' => false,
131: 'url' => Router::reverse($url)
132: ];
133: if (empty($params['params']['pass'])) {
134: $params['params']['pass'] = [];
135: }
136: }
137: $current = Router::getRequest();
138: if ($current) {
139: $params['base'] = $current->getAttribute('base');
140: $params['webroot'] = $current->getAttribute('webroot');
141: }
142:
143: $params['post'] = $params['query'] = [];
144: if (isset($extra['post'])) {
145: $params['post'] = $extra['post'];
146: }
147: if (isset($extra['query'])) {
148: $params['query'] = $extra['query'];
149: }
150: if (isset($extra['cookies'])) {
151: $params['cookies'] = $extra['cookies'];
152: }
153: if (isset($extra['environment'])) {
154: $params['environment'] = $extra['environment'] + $_SERVER + $_ENV;
155: }
156: unset($extra['environment'], $extra['post'], $extra['query']);
157:
158: $params['session'] = isset($extra['session']) ? $extra['session'] : new Session();
159:
160: $request = new ServerRequest($params);
161: $request->addParams($extra);
162: $dispatcher = DispatcherFactory::create();
163:
164: // If an application is using PSR7 middleware,
165: // we need to 'fix' their missing dispatcher filters.
166: $needed = [
167: 'routing' => RoutingFilter::class,
168: 'controller' => ControllerFactoryFilter::class
169: ];
170: foreach ($dispatcher->filters() as $filter) {
171: if ($filter instanceof RoutingFilter) {
172: unset($needed['routing']);
173: }
174: if ($filter instanceof ControllerFactoryFilter) {
175: unset($needed['controller']);
176: }
177: }
178: foreach ($needed as $class) {
179: $dispatcher->addFilter(new $class());
180: }
181: $result = $dispatcher->dispatch($request, new Response());
182: Router::popRequest();
183:
184: return $result;
185: }
186: }
187: