reverted: --- b/core/vendor/composer/autoload_namespaces.php +++ a/core/vendor/composer/autoload_namespaces.php @@ -7,15 +7,16 @@ return array( 'Twig_' => $vendorDir . '/twig/twig/lib/', + 'Symfony\\Component\\Yaml' => $vendorDir . '/symfony/yaml/', + 'Symfony\\Component\\Serializer' => $vendorDir . '/symfony/serializer/', + 'Symfony\\Component\\Routing' => $vendorDir . '/symfony/routing/', - 'Symfony\\Component\\Yaml\\' => $vendorDir . '/symfony/yaml/', - 'Symfony\\Component\\Serializer\\' => $vendorDir . '/symfony/serializer/', - 'Symfony\\Component\\Routing\\' => $vendorDir . '/symfony/routing/', 'Symfony\\Component\\Process' => $vendorDir . '/symfony/process/', 'Symfony\\Component\\HttpKernel' => $vendorDir . '/symfony/http-kernel/', + 'Symfony\\Component\\HttpFoundation' => $vendorDir . '/symfony/http-foundation/', - 'Symfony\\Component\\HttpFoundation\\' => $vendorDir . '/symfony/http-foundation/', 'Symfony\\Component\\EventDispatcher' => $vendorDir . '/symfony/event-dispatcher/', + 'Symfony\\Component\\DependencyInjection' => $vendorDir . '/symfony/dependency-injection/', + 'Symfony\\Component\\ClassLoader' => $vendorDir . '/symfony/class-loader/', + 'SessionHandlerInterface' => $vendorDir . '/symfony/http-foundation/Symfony/Component/HttpFoundation/Resources/stubs', - 'Symfony\\Component\\DependencyInjection\\' => $vendorDir . '/symfony/dependency-injection/', - 'Symfony\\Component\\ClassLoader\\' => $vendorDir . '/symfony/class-loader/', 'Guzzle\\Stream' => $vendorDir . '/guzzle/stream/', 'Guzzle\\Parser' => $vendorDir . '/guzzle/parser/', 'Guzzle\\Http' => $vendorDir . '/guzzle/http/', diff -u b/core/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Controller/ControllerResolver.php b/core/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Controller/ControllerResolver.php --- b/core/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Controller/ControllerResolver.php +++ b/core/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Controller/ControllerResolver.php @@ -68,8 +68,12 @@ return $controller; } - if (false === strpos($controller, ':') && method_exists($controller, '__invoke')) { - return new $controller; + if (false === strpos($controller, ':')) { + if (method_exists($controller, '__invoke')) { + return new $controller; + } elseif (function_exists($controller)) { + return $controller; + } } list($controller, $method) = $this->createController($controller); reverted: --- /dev/null +++ a/core/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Event/PostResponseEvent.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Event; + +use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; + +/** + * Allows to execute logic after a response was sent + * + * @author Jordi Boggiano + */ +class PostResponseEvent extends Event +{ + /** + * The kernel in which this event was thrown + * @var HttpKernelInterface + */ + private $kernel; + + private $request; + + private $response; + + public function __construct(HttpKernelInterface $kernel, Request $request, Response $response) + { + $this->kernel = $kernel; + $this->request = $request; + $this->response = $response; + } + + /** + * Returns the kernel in which this event was thrown. + * + * @return HttpKernelInterface + */ + public function getKernel() + { + return $this->kernel; + } + + /** + * Returns the request for which this event was thrown. + * + * @return Request + */ + public function getRequest() + { + return $this->request; + } + + /** + * Returns the response for which this event was thrown. + * + * @return Response + */ + public function getResponse() + { + return $this->response; + } +} reverted: --- /dev/null +++ a/core/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/EventListener/RouterListener.php @@ -0,0 +1,116 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\EventListener; + +use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\Routing\Exception\MethodNotAllowedException; +use Symfony\Component\Routing\Exception\ResourceNotFoundException; +use Symfony\Component\Routing\Matcher\UrlMatcherInterface; +use Symfony\Component\Routing\Matcher\RequestMatcherInterface; +use Symfony\Component\Routing\RequestContext; +use Symfony\Component\Routing\RequestContextAwareInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +/** + * Initializes the context from the request and sets request attributes based on a matching route. + * + * @author Fabien Potencier + */ +class RouterListener implements EventSubscriberInterface +{ + private $matcher; + private $context; + private $logger; + + /** + * Constructor. + * + * @param UrlMatcherInterface|RequestMatcherInterface $matcher The Url or Request matcher + * @param RequestContext|null $context The RequestContext (can be null when $matcher implements RequestContextAwareInterface) + * @param LoggerInterface|null $logger The logger + */ + public function __construct($matcher, RequestContext $context = null, LoggerInterface $logger = null) + { + if (!$matcher instanceof UrlMatcherInterface && !$matcher instanceof RequestMatcherInterface) { + throw new \InvalidArgumentException('Matcher must either implement UrlMatcherInterface or RequestMatcherInterface.'); + } + + if (null === $context && !$matcher instanceof RequestContextAwareInterface) { + throw new \InvalidArgumentException('You must either pass a RequestContext or the matcher must implement RequestContextAwareInterface.'); + } + + $this->matcher = $matcher; + $this->context = $context ?: $matcher->getContext(); + $this->logger = $logger; + } + + public function onKernelRequest(GetResponseEvent $event) + { + $request = $event->getRequest(); + + // initialize the context that is also used by the generator (assuming matcher and generator share the same context instance) + $this->context->fromRequest($request); + + if ($request->attributes->has('_controller')) { + // routing is already done + return; + } + + // add attributes based on the request (routing) + try { + // matching a request is more powerful than matching a URL path + context, so try that first + if ($this->matcher instanceof RequestMatcherInterface) { + $parameters = $this->matcher->matchRequest($request); + } else { + $parameters = $this->matcher->match($request->getPathInfo()); + } + + if (null !== $this->logger) { + $this->logger->info(sprintf('Matched route "%s" (parameters: %s)', $parameters['_route'], $this->parametersToString($parameters))); + } + + $request->attributes->add($parameters); + unset($parameters['_route']); + unset($parameters['_controller']); + $request->attributes->set('_route_params', $parameters); + } catch (ResourceNotFoundException $e) { + $message = sprintf('No route found for "%s %s"', $request->getMethod(), $request->getPathInfo()); + + throw new NotFoundHttpException($message, $e); + } catch (MethodNotAllowedException $e) { + $message = sprintf('No route found for "%s %s": Method Not Allowed (Allow: %s)', $request->getMethod(), $request->getPathInfo(), strtoupper(implode(', ', $e->getAllowedMethods()))); + + throw new MethodNotAllowedHttpException($e->getAllowedMethods(), $message, $e); + } + } + + private function parametersToString(array $parameters) + { + $pieces = array(); + foreach ($parameters as $key => $val) { + $pieces[] = sprintf('"%s": "%s"', $key, (is_string($val) ? $val : json_encode($val))); + } + + return implode(', ', $pieces); + } + + public static function getSubscribedEvents() + { + return array( + KernelEvents::REQUEST => array(array('onKernelRequest', 32)), + ); + } +} diff -u b/core/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Exception/FlattenException.php b/core/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Exception/FlattenException.php --- b/core/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Exception/FlattenException.php +++ b/core/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Exception/FlattenException.php @@ -33,6 +33,16 @@ $e = new static(); $e->setMessage($exception->getMessage()); $e->setCode($exception->getCode()); + + if ($exception instanceof HttpExceptionInterface) { + $statusCode = $exception->getStatusCode(); + $headers = array_merge($headers, $exception->getHeaders()); + } + + if (null === $statusCode) { + $statusCode = 500; + } + $e->setStatusCode($statusCode); $e->setHeaders($headers); $e->setTrace($exception->getTrace(), $exception->getFile(), $exception->getLine()); only in patch2: unchanged: --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -190,6 +190,14 @@ public function registerBundles() { } /** + * @todo Symfony used to implement this in HttpKernel, but moved it somewhere. + * Figure out where. + */ + public function terminate(\Symfony\Component\HttpFoundation\Request $request, \Symfony\Component\HttpFoundation\Response $response) { + $this->container->get('dispatcher')->dispatch('terminate', new \Symfony\Component\HttpKernel\Event\PostResponseEvent($this, $request, $response)); + } + + /** * Returns module data on the filesystem. * * @param $module only in patch2: unchanged: --- a/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php @@ -126,7 +126,7 @@ static function getSubscribedEvents() { $events[KernelEvents::REQUEST][] = array('onKernelRequestLanguageResolve', 150); $events[KernelEvents::REQUEST][] = array('onKernelRequestFrontPageResolve', 101); $events[KernelEvents::REQUEST][] = array('onKernelRequestPathResolve', 100); - $events[KernelEvents::TERMINATE][] = array('onKernelTerminate', 200); + $events['terminate'][] = array('onKernelTerminate', 200); return $events; } only in patch2: unchanged: --- a/core/lib/Drupal/Core/EventSubscriber/RequestCloseSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/RequestCloseSubscriber.php @@ -40,7 +40,7 @@ public function onTerminate(PostResponseEvent $event) { * An array of event listener definitions. */ static function getSubscribedEvents() { - $events[KernelEvents::TERMINATE][] = array('onTerminate', 100); + $events['terminate'][] = array('onTerminate', 100); return $events; } only in patch2: unchanged: --- a/core/lib/Drupal/Core/ExceptionController.php +++ b/core/lib/Drupal/Core/ExceptionController.php @@ -336,7 +336,7 @@ protected function decodeException(FlattenException $exception) { // This value is missing from the stack for some reason in the // FlattenException version of the backtrace. - $backtrace[0]['line'] = $exception->getLine(); + //$backtrace[0]['line'] = $exception->getLine(); // For database errors, we try to return the initial caller, // skipping internal functions of the database layer. @@ -345,7 +345,7 @@ protected function decodeException(FlattenException $exception) { // the original PDOException. It's the stack trace from that exception // that we care about. $backtrace = $exception->getPrevious()->getTrace(); - $backtrace[0]['line'] = $exception->getLine(); + //$backtrace[0]['line'] = $exception->getLine(); // The first element in the stack is the call, the second element gives us the caller. // We skip calls that occurred in one of the classes of the database layer