16use InvalidArgumentException;
55 const VERSION =
'3.11.0';
79 if (!
$container instanceof ContainerInterface) {
80 throw new InvalidArgumentException(
'Expected a ContainerInterface');
90 public function getContainer()
104 public function add($callable)
106 return $this->
addMiddleware(
new DeferredCallable($callable, $this->container));
117 public function __call($method, $args)
119 if ($this->container->has($method)) {
120 $obj = $this->container->get($method);
121 if (is_callable($obj)) {
122 return call_user_func_array($obj, $args);
126 throw new \BadMethodCallException(
"Method $method is not a valid method");
141 public function get($pattern, $callable)
143 return $this->map([
'GET'], $pattern, $callable);
154 public function post($pattern, $callable)
156 return $this->map([
'POST'], $pattern, $callable);
167 public function put($pattern, $callable)
169 return $this->map([
'PUT'], $pattern, $callable);
180 public function patch($pattern, $callable)
182 return $this->map([
'PATCH'], $pattern, $callable);
193 public function delete($pattern, $callable)
195 return $this->map([
'DELETE'], $pattern, $callable);
206 public function options($pattern, $callable)
208 return $this->map([
'OPTIONS'], $pattern, $callable);
219 public function any($pattern, $callable)
221 return $this->map([
'GET',
'POST',
'PUT',
'PATCH',
'DELETE',
'OPTIONS'], $pattern, $callable);
233 public function map(array $methods, $pattern, $callable)
235 if ($callable instanceof Closure) {
236 $callable = $callable->bindTo($this->container);
239 $route = $this->container->get(
'router')->map($methods, $pattern, $callable);
240 if (is_callable([$route,
'setContainer'])) {
241 $route->setContainer($this->container);
244 if (is_callable([$route,
'setOutputBuffering'])) {
245 $route->setOutputBuffering($this->container->get(
'settings')[
'outputBuffering']);
260 public function redirect(
$from, $to, $status = 302)
263 return $response->withHeader(
'Location', (
string)$to)->withStatus($status);
281 public function group($pattern, $callable)
284 $group = $this->container->get(
'router')->pushGroup($pattern, $callable);
285 $group->setContainer($this->container);
287 $this->container->get(
'router')->popGroup();
308 public function run($silent =
false)
310 $response = $this->container->get(
'response');
315 }
catch (InvalidMethodException $e) {
322 $outputBuffering = $this->container->get(
'settings')[
'outputBuffering'];
323 if ($outputBuffering ===
'prepend') {
325 $body =
new Http\Body(fopen(
'php://temp',
'r+'));
328 } elseif ($outputBuffering ===
'append') {
355 protected function processInvalidMethod(ServerRequestInterface
$request, ResponseInterface
$response)
357 $router = $this->container->get(
'router');
358 if (is_callable([
$request->getUri(),
'getBasePath']) && is_callable([$router,
'setBasePath'])) {
359 $router->setBasePath(
$request->getUri()->getBasePath());
363 $routeInfo =
$request->getAttribute(
'routeInfo', [RouterInterface::DISPATCH_STATUS => Dispatcher::NOT_FOUND]);
365 if ($routeInfo[RouterInterface::DISPATCH_STATUS] === Dispatcher::METHOD_NOT_ALLOWED) {
366 return $this->handleException(
367 new MethodNotAllowedException(
$request,
$response, $routeInfo[RouterInterface::ALLOWED_METHODS]),
390 public function process(ServerRequestInterface
$request, ResponseInterface
$response)
393 $router = $this->container->get(
'router');
394 if (is_callable([
$request->getUri(),
'getBasePath']) && is_callable([$router,
'setBasePath'])) {
395 $router->setBasePath(
$request->getUri()->getBasePath());
399 if ($this->container->get(
'settings')[
'determineRouteBeforeAppMiddleware'] ===
true) {
407 }
catch (Exception $e) {
409 }
catch (Throwable $e) {
421 public function respond(ResponseInterface
$response)
424 if (!headers_sent()) {
427 $first = stripos(
$name,
'Set-Cookie') === 0 ? false :
true;
429 header(sprintf(
'%s: %s',
$name, $value), $first);
447 if (!$this->isEmptyResponse(
$response)) {
449 if ($body->isSeekable()) {
452 $settings = $this->container->get(
'settings');
453 $chunkSize = $settings[
'responseChunkSize'];
463 while ($amountToRead > 0 && !$body->eof()) {
464 $data = $body->read(min($chunkSize, $amountToRead));
467 $amountToRead -= strlen(
$data);
469 if (connection_status() != CONNECTION_NORMAL) {
474 while (!$body->eof()) {
475 echo $body->read($chunkSize);
476 if (connection_status() != CONNECTION_NORMAL) {
499 public function __invoke(ServerRequestInterface
$request, ResponseInterface
$response)
502 $routeInfo =
$request->getAttribute(
'routeInfo');
505 $router = $this->container->get(
'router');
508 if (
null === $routeInfo || ($routeInfo[
'request'] !== [
$request->getMethod(), (
string)
$request->getUri()])) {
510 $routeInfo =
$request->getAttribute(
'routeInfo');
513 if ($routeInfo[0] === Dispatcher::FOUND) {
514 $route = $router->lookupRoute($routeInfo[1]);
516 } elseif ($routeInfo[0] === Dispatcher::METHOD_NOT_ALLOWED) {
517 if (!$this->container->has(
'notAllowedHandler')) {
521 $notAllowedHandler = $this->container->get(
'notAllowedHandler');
525 if (!$this->container->has(
'notFoundHandler')) {
529 $notFoundHandler = $this->container->get(
'notFoundHandler');
551 public function subRequest(
560 $env = $this->container->get(
'environment');
561 $uri = Uri::createFromEnvironment(
$env)->withPath(
$path)->withQuery(
$query);
562 $headers =
new Headers($headers);
563 $serverParams =
$env->all();
564 $body =
new Body(fopen(
'php://temp',
'r+'));
565 $body->write($bodyContent);
567 $request =
new Request($method, $uri, $headers, $cookies, $serverParams, $body);
570 $response = $this->container->get(
'response');
583 protected function dispatchRouterAndPrepareRoute(ServerRequestInterface
$request, RouterInterface $router)
585 $routeInfo = $router->dispatch(
$request);
587 if ($routeInfo[0] === Dispatcher::FOUND) {
588 $routeArguments = [];
589 foreach ($routeInfo[2] as $k => $v) {
590 $routeArguments[$k] = urldecode($v);
593 $route = $router->lookupRoute($routeInfo[1]);
594 $route->prepare(
$request, $routeArguments);
600 $routeInfo[
'request'] = [
$request->getMethod(), (string)
$request->getUri()];
602 return $request->withAttribute(
'routeInfo', $routeInfo);
611 protected function finalize(ResponseInterface
$response)
614 ini_set(
'default_mimetype',
'');
617 return $response->withoutHeader(
'Content-Type')->withoutHeader(
'Content-Length');
621 if (isset($this->container->get(
'settings')[
'addContentLengthHeader']) &&
622 $this->container->get(
'settings')[
'addContentLengthHeader'] ==
true) {
623 if (ob_get_length() > 0) {
624 throw new \RuntimeException(
"Unexpected data in output buffer. " .
625 "Maybe you have characters before an opening <?php tag?");
645 protected function isEmptyResponse(ResponseInterface
$response)
647 if (method_exists(
$response,
'isEmpty')) {
651 return in_array(
$response->getStatusCode(), [204, 205, 304]);
665 protected function handleException(Exception $e, ServerRequestInterface
$request, ResponseInterface
$response)
667 if ($e instanceof MethodNotAllowedException) {
669 $params = [$e->getRequest(), $e->getResponse(), $e->getAllowedMethods()];
670 } elseif ($e instanceof NotFoundException) {
672 $params = [$e->getRequest(), $e->getResponse(), $e];
673 } elseif ($e instanceof SlimException) {
675 return $e->getResponse();
682 if ($this->container->has(
$handler)) {
683 $callable = $this->container->get(
$handler);
685 return call_user_func_array($callable,
$params);
702 protected function handlePhpError(Throwable $e, ServerRequestInterface
$request, ResponseInterface
$response)
707 if ($this->container->has(
$handler)) {
708 $callable = $this->container->get(
$handler);
710 return call_user_func_array($callable,
$params);
foreach($paths as $path) $request
An exception for terminatinating execution or to throw for unit testing.
Value object representing a URI.
Describes the interface of a container that exposes methods to read its entries.
Representation of an outgoing, client-side request.
Representation of an outgoing, server-side response.
Representation of an incoming, server-side HTTP request.
if(preg_match('#\.( $contentLength[^/\.]+) $#D', $path, $type)) if($contentType===null)
__call($method, array $arguments)
Plugins pass-through.
Slim Framework (https://slimframework.com)
trait MiddlewareAwareTrait
Middleware.
addMiddleware(callable $callable)
Add middleware.