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: /**
32: * Calls a controller's method from any location. Can be used to connect controllers together
33: * or tie plugins into a main application. requestAction can be used to return rendered views
34: * or fetch the return value from controller actions.
35: *
36: * Under the hood this method uses Router::reverse() to convert the $url parameter into a string
37: * URL. You should use URL formats that are compatible with Router::reverse()
38: *
39: * ### Examples
40: *
41: * A basic example getting the return value of the controller action:
42: *
43: * ```
44: * $variables = $this->requestAction('/articles/popular');
45: * ```
46: *
47: * A basic example of request action to fetch a rendered page without the layout.
48: *
49: * ```
50: * $viewHtml = $this->requestAction('/articles/popular', ['return']);
51: * ```
52: *
53: * You can also pass the URL as an array:
54: *
55: * ```
56: * $vars = $this->requestAction(['controller' => 'articles', 'action' => 'popular']);
57: * ```
58: *
59: * ### Passing other request data
60: *
61: * You can pass POST, GET, COOKIE and other data into the request using the appropriate keys.
62: * Cookies can be passed using the `cookies` key. Get parameters can be set with `query` and post
63: * data can be sent using the `post` key.
64: *
65: * ```
66: * $vars = $this->requestAction('/articles/popular', [
67: * 'query' => ['page' => 1],
68: * 'cookies' => ['remember_me' => 1],
69: * ]);
70: * ```
71: *
72: * ### Sending environment or header values
73: *
74: * By default actions dispatched with this method will use the global $_SERVER and $_ENV
75: * values. If you want to override those values for a request action, you can specify the values:
76: *
77: * ```
78: * $vars = $this->requestAction('/articles/popular', [
79: * 'environment' => ['CONTENT_TYPE' => 'application/json']
80: * ]);
81: * ```
82: *
83: * ### Transmitting the session
84: *
85: * By default actions dispatched with this method will use the standard session object.
86: * If you want a particular session instance to be used, you need to specify it.
87: *
88: * ```
89: * $vars = $this->requestAction('/articles/popular', [
90: * 'session' => new Session($someSessionConfig)
91: * ]);
92: * ```
93: *
94: * @param string|array $url String or array-based url. Unlike other url arrays in CakePHP, this
95: * url will not automatically handle passed arguments in the $url parameter.
96: * @param array $extra if array includes the key "return" it sets the autoRender to true. Can
97: * also be used to submit GET/POST data, and passed arguments.
98: * @return mixed Boolean true or false on success/failure, or contents
99: * of rendered action if 'return' is set in $extra.
100: * @deprecated 3.3.0 You should refactor your code to use View Cells instead of this method.
101: */
102: public function requestAction($url, array $extra = [])
103: {
104: deprecationWarning(
105: 'RequestActionTrait::requestAction() is deprecated. ' .
106: 'You should refactor to use View Cells or Components instead.'
107: );
108: if (empty($url)) {
109: return false;
110: }
111: if (($index = array_search('return', $extra)) !== false) {
112: $extra['return'] = 0;
113: $extra['autoRender'] = 1;
114: unset($extra[$index]);
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: