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