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 3.3.0
13: * @license https://opensource.org/licenses/mit-license.php MIT License
14: */
15: namespace Cake\Http;
16:
17: use Cake\Core\HttpApplicationInterface;
18: use Cake\Core\PluginApplicationInterface;
19: use Cake\Event\EventDispatcherInterface;
20: use Cake\Event\EventDispatcherTrait;
21: use Cake\Event\EventManager;
22: use InvalidArgumentException;
23: use Psr\Http\Message\ResponseInterface;
24: use Psr\Http\Message\ServerRequestInterface;
25: use RuntimeException;
26: use Zend\Diactoros\Response\EmitterInterface;
27:
28: /**
29: * Runs an application invoking all the PSR7 middleware and the registered application.
30: */
31: class Server implements EventDispatcherInterface
32: {
33: /**
34: * Alias methods away so we can implement proxying methods.
35: */
36: use EventDispatcherTrait {
37: eventManager as private _eventManager;
38: getEventManager as private _getEventManager;
39: setEventManager as private _setEventManager;
40: }
41:
42: /**
43: * @var \Cake\Core\HttpApplicationInterface
44: */
45: protected $app;
46:
47: /**
48: * @var \Cake\Http\Runner
49: */
50: protected $runner;
51:
52: /**
53: * Constructor
54: *
55: * @param \Cake\Core\HttpApplicationInterface $app The application to use.
56: */
57: public function __construct(HttpApplicationInterface $app)
58: {
59: $this->app = $app;
60: $this->setRunner(new Runner());
61: }
62:
63: /**
64: * Run the request/response through the Application and its middleware.
65: *
66: * This will invoke the following methods:
67: *
68: * - App->bootstrap() - Perform any bootstrapping logic for your application here.
69: * - App->middleware() - Attach any application middleware here.
70: * - Trigger the 'Server.buildMiddleware' event. You can use this to modify the
71: * from event listeners.
72: * - Run the middleware queue including the application.
73: *
74: * @param \Psr\Http\Message\ServerRequestInterface|null $request The request to use or null.
75: * @param \Psr\Http\Message\ResponseInterface|null $response The response to use or null.
76: * @return \Psr\Http\Message\ResponseInterface
77: * @throws \RuntimeException When the application does not make a response.
78: */
79: public function run(ServerRequestInterface $request = null, ResponseInterface $response = null)
80: {
81: $this->bootstrap();
82:
83: $response = $response ?: new Response();
84: $request = $request ?: ServerRequestFactory::fromGlobals();
85:
86: $middleware = $this->app->middleware(new MiddlewareQueue());
87: if ($this->app instanceof PluginApplicationInterface) {
88: $middleware = $this->app->pluginMiddleware($middleware);
89: }
90:
91: if (!($middleware instanceof MiddlewareQueue)) {
92: throw new RuntimeException('The application `middleware` method did not return a middleware queue.');
93: }
94: $this->dispatchEvent('Server.buildMiddleware', ['middleware' => $middleware]);
95: $middleware->add($this->app);
96:
97: $response = $this->runner->run($middleware, $request, $response);
98:
99: if (!($response instanceof ResponseInterface)) {
100: throw new RuntimeException(sprintf(
101: 'Application did not create a response. Got "%s" instead.',
102: is_object($response) ? get_class($response) : $response
103: ));
104: }
105:
106: return $response;
107: }
108:
109: /**
110: * Application bootstrap wrapper.
111: *
112: * Calls `bootstrap()` and `events()` if application implements `EventApplicationInterface`.
113: * After the application is bootstrapped and events are attached, plugins are bootstrapped
114: * and have their events attached.
115: *
116: * @return void
117: */
118: protected function bootstrap()
119: {
120: $this->app->bootstrap();
121:
122: if ($this->app instanceof PluginApplicationInterface) {
123: $this->app->pluginBootstrap();
124: }
125: }
126:
127: /**
128: * Emit the response using the PHP SAPI.
129: *
130: * @param \Psr\Http\Message\ResponseInterface $response The response to emit
131: * @param \Zend\Diactoros\Response\EmitterInterface|null $emitter The emitter to use.
132: * When null, a SAPI Stream Emitter will be used.
133: * @return void
134: */
135: public function emit(ResponseInterface $response, EmitterInterface $emitter = null)
136: {
137: if (!$emitter) {
138: $emitter = new ResponseEmitter();
139: }
140: $emitter->emit($response);
141: }
142:
143: /**
144: * Get the current application.
145: *
146: * @return \Cake\Core\HttpApplicationInterface The application that will be run.
147: */
148: public function getApp()
149: {
150: return $this->app;
151: }
152:
153: /**
154: * Set the runner
155: *
156: * @param \Cake\Http\Runner $runner The runner to use.
157: * @return $this
158: */
159: public function setRunner(Runner $runner)
160: {
161: $this->runner = $runner;
162:
163: return $this;
164: }
165:
166: /**
167: * Get the application's event manager or the global one.
168: *
169: * @return \Cake\Event\EventManager
170: */
171: public function getEventManager()
172: {
173: if ($this->app instanceof PluginApplicationInterface) {
174: return $this->app->getEventManager();
175: }
176:
177: return EventManager::instance();
178: }
179:
180: /**
181: * Get/set the application's event manager.
182: *
183: * If the application does not support events and this method is used as
184: * a setter, an exception will be raised.
185: *
186: * @param \Cake\Event\EventManager|null $events The event manager to set.
187: * @return \Cake\Event\EventManager|$this
188: * @deprecated 3.6.0 Will be removed in 4.0
189: */
190: public function eventManager(EventManager $events = null)
191: {
192: deprecationWarning('eventManager() is deprecated. Use getEventManager()/setEventManager() instead.');
193: if ($events === null) {
194: return $this->getEventManager();
195: }
196:
197: return $this->setEventManager($events);
198: }
199:
200: /**
201: * Get/set the application's event manager.
202: *
203: * If the application does not support events and this method is used as
204: * a setter, an exception will be raised.
205: *
206: * @param \Cake\Event\EventManager $events The event manager to set.
207: * @return $this
208: */
209: public function setEventManager(EventManager $events)
210: {
211: if ($this->app instanceof PluginApplicationInterface) {
212: $this->app->setEventManager($events);
213:
214: return $this;
215: }
216:
217: throw new InvalidArgumentException('Cannot set the event manager, the application does not support events.');
218: }
219: }
220: