Browse Source

Merge branch 'master' into 3.next

mark_story 8 years ago
parent
commit
956ddb2265

+ 1 - 1
appveyor.yml

@@ -27,7 +27,7 @@ init:
 
 install:
   - cd c:\
-  - curl -fsS https://windows.php.net/downloads/releases/php-5.6.35-nts-Win32-VC11-x86.zip -o php.zip
+  - curl -fsS https://windows.php.net/downloads/releases/php-5.6.36-nts-Win32-VC11-x86.zip -o php.zip
   - 7z x php.zip -oc:\php > nul
   - curl -fsS https://dl.dropboxusercontent.com/s/euip490d9183jkr/SQLSRV32.cab -o sqlsrv.cab
   - 7z x sqlsrv.cab -oc:\php\ext php*_56_nts.dll > nul

+ 1 - 1
src/Database/Schema/TableSchema.php

@@ -440,7 +440,7 @@ class TableSchema implements TableSchemaInterface, SqlGeneratorInterface
             return null;
         }
 
-        if (Type::map($type)) {
+        if (Type::getMap($type)) {
             $type = Type::build($type)->getBaseType();
         }
 

+ 57 - 2
src/Database/Type.php

@@ -145,8 +145,12 @@ class Type implements TypeInterface
      * If called with no arguments it will return current types map array
      * If $className is omitted it will return mapped class for $type
      *
-     * Deprecated: The usage of $type as \Cake\Database\Type[] is deprecated. Please always use string[] if you pass an array
-     * as first argument.
+     * Deprecated 3.6.2:
+     * - The usage of $type as string[]|\Cake\Database\Type[] is deprecated.
+     *   Use Type::setMap() with string[] instead.
+     * - Passing $className as \Cake\Database\Type instance is deprecated, use
+     *   class name string only.
+     * - Using this method as getter is deprecated. Use Type::getMap() instead.
      *
      * @param string|string[]|\Cake\Database\Type[]|null $type If string name of type to map, if array list of arrays to be mapped
      * @param string|\Cake\Database\Type|null $className The classname or object instance of it to register.
@@ -156,22 +160,73 @@ class Type implements TypeInterface
     public static function map($type = null, $className = null)
     {
         if ($type === null) {
+            deprecationWarning(
+                'Using `Type::map()` as getter is deprecated. ' .
+                'Use `Type::getMap()` instead.'
+            );
+
             return static::$_types;
         }
         if (is_array($type)) {
+            deprecationWarning(
+                'Using `Type::map()` to set complete types map is deprecated. ' .
+                'Use `Type::setMap()` instead.'
+            );
+
             static::$_types = $type;
 
             return null;
         }
         if ($className === null) {
+            deprecationWarning(
+                'Using `Type::map()` as getter is deprecated. ' .
+                'Use `Type::getMap()` instead.'
+            );
+
             return isset(static::$_types[$type]) ? static::$_types[$type] : null;
         }
 
+        if (!is_string($className)) {
+            deprecationWarning(
+                'Passing $className as object to Type::map() is deprecated. ' .
+                'Use Type::set() instead.'
+            );
+        }
+
         static::$_types[$type] = $className;
         unset(static::$_builtTypes[$type]);
     }
 
     /**
+     * Set type to classname mapping.
+     *
+     * @param string[] $map List of types to be mapped.
+     * @return void
+     * @since 3.6.2
+     */
+    public static function setMap(array $map)
+    {
+        static::$_types = $map;
+        static::$_builtTypes = [];
+    }
+
+    /**
+     * Get mapped class name or instance for type(s).
+     *
+     * @param string|null $type Type name to get mapped class for or null to get map array.
+     * @return array|string|\Cake\Database\TypeInterface|null Configured class name or instance for give $type or map array.
+     * @since 3.6.2
+     */
+    public static function getMap($type = null)
+    {
+        if ($type === null) {
+            return static::$_types;
+        }
+
+        return isset(static::$_types[$type]) ? static::$_types[$type] : null;
+    }
+
+    /**
      * Clears out all created instances and mapped types classes, useful for testing
      *
      * @return void

+ 2 - 15
src/Error/ExceptionRenderer.php

@@ -29,7 +29,6 @@ use Cake\Utility\Inflector;
 use Cake\View\Exception\MissingTemplateException;
 use Exception;
 use PDOException;
-use Psr\Http\Message\ServerRequestInterface;
 
 /**
  * Exception Renderer.
@@ -80,25 +79,15 @@ class ExceptionRenderer implements ExceptionRendererInterface
     public $method = '';
 
     /**
-     * If set, this will be request used to create the controller that will render
-     * the error.
-     *
-     * @var \Psr\Http\Message\ServerRequestInterface|null
-     */
-    protected $request = null;
-
-    /**
      * Creates the controller to perform rendering on the error response.
      * If the error is a Cake\Core\Exception\Exception it will be converted to either a 400 or a 500
      * code error depending on the code used to construct the error.
      *
      * @param \Exception $exception Exception.
-     * @param \Psr\Http\Message\ServerRequestInterface $request The request - if this is set it will be used instead of creating a new one
      */
-    public function __construct(Exception $exception, ServerRequestInterface $request = null)
+    public function __construct(Exception $exception)
     {
         $this->error = $exception;
-        $this->request = $request;
         $this->controller = $this->_getController();
     }
 
@@ -125,11 +114,9 @@ class ExceptionRenderer implements ExceptionRendererInterface
      */
     protected function _getController()
     {
-        $request = $this->request ?: Router::getRequest(true);
-        if ($request === null) {
+        if (!$request = Router::getRequest(true)) {
             $request = ServerRequestFactory::fromGlobals();
         }
-
         $response = new Response();
         $controller = null;
 

+ 4 - 5
src/Error/Middleware/ErrorHandlerMiddleware.php

@@ -113,7 +113,7 @@ class ErrorHandlerMiddleware
      */
     public function handleException($exception, $request, $response)
     {
-        $renderer = $this->getRenderer($exception, $request);
+        $renderer = $this->getRenderer($exception);
         try {
             $res = $renderer->render();
             $this->logException($request, $exception);
@@ -148,11 +148,10 @@ class ErrorHandlerMiddleware
      * Get a renderer instance
      *
      * @param \Exception $exception The exception being rendered.
-     * @param \Psr\Http\Message\ServerRequestInterface $request The request.
      * @return \Cake\Error\ExceptionRendererInterface The exception renderer.
      * @throws \Exception When the renderer class cannot be found.
      */
-    protected function getRenderer($exception, $request)
+    protected function getRenderer($exception)
     {
         if (!$this->exceptionRenderer) {
             $this->exceptionRenderer = $this->getConfig('exceptionRenderer') ?: ExceptionRenderer::class;
@@ -172,11 +171,11 @@ class ErrorHandlerMiddleware
                 ));
             }
 
-            return new $class($exception, $request);
+            return new $class($exception);
         }
         $factory = $this->exceptionRenderer;
 
-        return $factory($exception, $request);
+        return $factory($exception);
     }
 
     /**

+ 0 - 3
src/TestSuite/IntegrationTestCase.php

@@ -23,7 +23,6 @@ if (class_exists('PHPUnit_Runner_Version', false) && !interface_exists('PHPUnit\
 use Cake\Core\Configure;
 use Cake\Database\Exception as DatabaseException;
 use Cake\Http\ServerRequest;
-use Cake\Http\ServerRequestFactory;
 use Cake\Http\Session;
 use Cake\Routing\Router;
 use Cake\TestSuite\Stub\TestExceptionRenderer;
@@ -482,7 +481,6 @@ abstract class IntegrationTestCase extends TestCase
     protected function _sendRequest($url, $method, $data = [])
     {
         $dispatcher = $this->_makeDispatcher();
-        $psrRequest = null;
         try {
             $request = $this->_buildRequest($url, $method, $data);
             $response = $dispatcher->execute($request);
@@ -499,7 +497,6 @@ abstract class IntegrationTestCase extends TestCase
             throw $e;
         } catch (Exception $e) {
             $this->_exception = $e;
-            // Simulate the global exception handler being invoked.
             $this->_handleError($e);
         }
     }

+ 32 - 31
src/TestSuite/MiddlewareDispatcher.php

@@ -67,10 +67,41 @@ class MiddlewareDispatcher
     }
 
     /**
+     * Run a request and get the response.
+     *
+     * @param \Cake\Http\ServerRequest $request The request to execute.
+     * @return \Psr\Http\Message\ResponseInterface The generated response.
+     */
+    public function execute($request)
+    {
+        try {
+            $reflect = new ReflectionClass($this->_class);
+            $app = $reflect->newInstanceArgs($this->_constructorArgs);
+        } catch (ReflectionException $e) {
+            throw new LogicException(sprintf(
+                'Cannot load "%s" for use in integration testing.',
+                $this->_class
+            ));
+        }
+
+        // Spy on the controller using the initialize hook instead
+        // of the dispatcher hooks as those will be going away one day.
+        EventManager::instance()->on(
+            'Controller.initialize',
+            [$this->_test, 'controllerSpy']
+        );
+
+        $server = new Server($app);
+        $psrRequest = $this->_createRequest($request);
+
+        return $server->run($psrRequest);
+    }
+
+    /**
      * Create a PSR7 request from the request spec.
      *
      * @param array $spec The request spec.
-     * @return \Psr\Http\Message\ServerRequestInterface
+     * @return \Psr\Http\Message\RequestInterface
      */
     protected function _createRequest($spec)
     {
@@ -94,34 +125,4 @@ class MiddlewareDispatcher
 
         return $request;
     }
-
-    /**
-     * Run a request and get the response.
-     *
-     * @param array $requestSpec The request spec to execute.
-     * @return \Psr\Http\Message\ResponseInterface The generated response.
-     */
-    public function execute($requestSpec)
-    {
-        try {
-            $reflect = new ReflectionClass($this->_class);
-            $app = $reflect->newInstanceArgs($this->_constructorArgs);
-        } catch (ReflectionException $e) {
-            throw new LogicException(sprintf(
-                'Cannot load "%s" for use in integration testing.',
-                $this->_class
-            ));
-        }
-
-        // Spy on the controller using the initialize hook instead
-        // of the dispatcher hooks as those will be going away one day.
-        EventManager::instance()->on(
-            'Controller.initialize',
-            [$this->_test, 'controllerSpy']
-        );
-
-        $server = new Server($app);
-
-        return $server->run($this->_createRequest($requestSpec));
-    }
 }

+ 8 - 10
src/Utility/Xml.php

@@ -157,18 +157,16 @@ class Xml
                 $xml = new DOMDocument();
                 $xml->loadXML($input, $flags);
             }
+
+            return $xml;
         } catch (Exception $e) {
-            $xml = null;
-        }
-        if ($hasDisable && !$options['loadEntities']) {
-            libxml_disable_entity_loader(false);
-        }
-        libxml_use_internal_errors($internalErrors);
-        if ($xml === null) {
-            throw new XmlException('Xml cannot be read.');
+            throw new XmlException('Xml cannot be read. ' . $e->getMessage(), null, $e);
+        } finally {
+            if ($hasDisable && !$options['loadEntities']) {
+                libxml_disable_entity_loader(false);
+            }
+            libxml_use_internal_errors($internalErrors);
         }
-
-        return $xml;
     }
 
     /**

+ 1 - 1
tests/TestCase/Database/ExpressionTypeCastingTest.php

@@ -49,7 +49,7 @@ class ExpressionTypeCastingTest extends TestCase
     public function setUp()
     {
         parent::setUp();
-        Type::map('test', new TestType);
+        Type::set('test', new TestType);
     }
 
     /**

+ 2 - 2
tests/TestCase/Database/Schema/TableSchemaTest.php

@@ -49,7 +49,7 @@ class TableTest extends TestCase
 
     public function setUp()
     {
-        $this->_map = Type::map();
+        $this->_map = Type::getMap();
         parent::setUp();
     }
 
@@ -57,7 +57,7 @@ class TableTest extends TestCase
     {
         $this->getTableLocator()->clear();
         Type::clear();
-        Type::map($this->_map);
+        Type::setMap($this->_map);
         parent::tearDown();
     }
 

+ 43 - 18
tests/TestCase/Database/TypeTest.php

@@ -15,8 +15,6 @@
 namespace Cake\Test\TestCase\Database;
 
 use Cake\Database\Type;
-use Cake\Database\Type\BoolType;
-use Cake\Database\Type\IntegerType;
 use Cake\Database\Type\UuidType;
 use Cake\TestSuite\TestCase;
 use PDO;
@@ -43,7 +41,7 @@ class TypeTest extends TestCase
      */
     public function setUp()
     {
-        $this->_originalMap = Type::map();
+        $this->_originalMap = Type::getMap();
         parent::setUp();
     }
 
@@ -56,7 +54,7 @@ class TypeTest extends TestCase
     {
         parent::tearDown();
 
-        Type::map($this->_originalMap);
+        Type::setMap($this->_originalMap);
     }
 
     /**
@@ -120,15 +118,19 @@ class TypeTest extends TestCase
      */
     public function testMapAndBuild()
     {
-        $map = Type::map();
-        $this->assertNotEmpty($map);
-        $this->assertArrayNotHasKey('foo', $map);
+        $this->deprecated(function () {
+            $map = Type::map();
+            $this->assertNotEmpty($map);
+            $this->assertArrayNotHasKey('foo', $map);
+        });
 
         $fooType = FooType::class;
         Type::map('foo', $fooType);
-        $map = Type::map();
+        $map = Type::getMap();
         $this->assertEquals($fooType, $map['foo']);
-        $this->assertEquals($fooType, Type::map('foo'));
+        $this->deprecated(function () use ($fooType) {
+            $this->assertEquals($fooType, Type::map('foo'));
+        });
 
         $type = Type::build('foo');
         $this->assertInstanceOf($fooType, $type);
@@ -136,9 +138,9 @@ class TypeTest extends TestCase
         $this->assertEquals('text', $type->getBaseType());
 
         Type::map('foo2', $fooType);
-        $map = Type::map();
+        $map = Type::getMap();
         $this->assertSame($fooType, $map['foo2']);
-        $this->assertSame($fooType, Type::map('foo2'));
+        $this->assertSame($fooType, Type::getMap('foo2'));
 
         $type = Type::build('foo2');
         $this->assertInstanceOf($fooType, $type);
@@ -169,14 +171,37 @@ class TypeTest extends TestCase
      */
     public function testMapAndBuildWithObjects()
     {
-        $map = Type::map();
+        $map = Type::getMap();
         Type::clear();
 
         $uuidType = new UuidType('uuid');
-        Type::map('uuid', $uuidType);
+        $this->deprecated(function () use ($uuidType) {
+            Type::map('uuid', $uuidType);
+        });
 
         $this->assertSame($uuidType, Type::build('uuid'));
-        Type::map($map);
+        Type::setMap($map);
+    }
+
+    /**
+     * testGetMapAndSetMap
+     *
+     * @return void
+     */
+    public function testGetMapAndSetMap()
+    {
+        $map = Type::getMap();
+        $this->assertNotEmpty($map);
+        $this->assertArrayNotHasKey('foo', $map);
+
+        $expected = [
+            'foo' => 'bar',
+            'ping' => 'pong',
+        ];
+        Type::setMap($expected);
+
+        $this->assertEquals($expected, Type::getMap());
+        $this->assertEquals('bar', Type::getMap('foo'));
     }
 
     /**
@@ -186,15 +211,15 @@ class TypeTest extends TestCase
      */
     public function testClear()
     {
-        $map = Type::map();
+        $map = Type::getMap();
         $this->assertNotEmpty($map);
 
         $type = Type::build('float');
         Type::clear();
 
-        $this->assertEmpty(Type::map());
-        Type::map($map);
-        $newMap = Type::map();
+        $this->assertEmpty(Type::getMap());
+        Type::setMap($map);
+        $newMap = Type::getMap();
 
         $this->assertEquals(array_keys($map), array_keys($newMap));
         $this->assertEquals($map['integer'], $newMap['integer']);

+ 23 - 0
tests/TestCase/Error/Middleware/ErrorHandlerMiddlewareTest.php

@@ -148,6 +148,29 @@ class ErrorHandlerMiddlewareTest extends TestCase
     }
 
     /**
+     * Test rendering an error page holds onto the original request.
+     *
+     * @return void
+     */
+    public function testHandleExceptionPreserveRequest()
+    {
+        $request = ServerRequestFactory::fromGlobals();
+        $request = $request->withHeader('Accept', 'application/json');
+
+        $response = new Response();
+        $middleware = new ErrorHandlerMiddleware();
+        $next = function ($req, $res) {
+            throw new \Cake\Http\Exception\NotFoundException('whoops');
+        };
+        $result = $middleware($request, $response, $next);
+        $this->assertInstanceOf('Cake\Http\Response', $result);
+        $this->assertNotSame($result, $response);
+        $this->assertEquals(404, $result->getStatusCode());
+        $this->assertContains('"message": "whoops"', '' . $result->getBody());
+        $this->assertEquals('application/json; charset=UTF-8', $result->getHeaderLine('Content-type'));
+    }
+
+    /**
      * Test handling PHP 7's Error instance.
      *
      * @return void

+ 0 - 19
tests/TestCase/TestSuite/IntegrationTestCaseTest.php

@@ -18,7 +18,6 @@ use Cake\Core\Configure;
 use Cake\Event\EventManager;
 use Cake\Http\Response;
 use Cake\Routing\DispatcherFactory;
-use Cake\Routing\RouteBuilder;
 use Cake\Routing\Router;
 use Cake\Routing\Route\InflectedRoute;
 use Cake\TestSuite\IntegrationTestCase;
@@ -230,24 +229,6 @@ class IntegrationTestCaseTest extends IntegrationTestCase
         $this->assertEquals('5', $this->_getBodyAsString());
     }
 
-    public function testExceptionsInMiddlewareJsonView()
-    {
-        Router::reload();
-        Router::connect('/json_response/api_get_data', [
-            'controller' => 'JsonResponse',
-            'action' => 'apiGetData'
-        ]);
-
-        $this->configApplication(Configure::read('App.namespace') . '\ApplicationWithExceptionsInMiddleware', null);
-
-        $this->_request['headers'] = [ "Accept" => "application/json" ];
-        $this->get('/json_response/api_get_data');
-        $this->assertResponseCode(403);
-        $this->assertHeader('Content-Type', 'application/json; charset=UTF-8');
-        $this->assertResponseContains('"message": "Sample Message"');
-        $this->assertResponseContains('"code": 403');
-    }
-
     /**
      * Test sending head requests.
      *

+ 14 - 0
tests/TestCase/Utility/XmlTest.php

@@ -18,6 +18,7 @@ use Cake\Collection\Collection;
 use Cake\Core\Configure;
 use Cake\ORM\Entity;
 use Cake\TestSuite\TestCase;
+use Cake\Utility\Exception\XmlException;
 use Cake\Utility\Xml;
 
 /**
@@ -64,6 +65,19 @@ class XmlTest extends TestCase
         Configure::write('App.encoding', $this->_appEncoding);
     }
 
+    public function testExceptionChainingForInvalidInput()
+    {
+        try {
+            $value = "invalid-xml-input<<";
+            Xml::build($value);
+            $this->fail('This line should not be executed because of exception above.');
+        } catch (XmlException $exception) {
+            $cause = $exception->getPrevious();
+            $this->assertNotNull($cause);
+            $this->assertInstanceOf(\Exception::class, $cause);
+        }
+    }
+
     /**
      * testBuild method
      *

+ 0 - 54
tests/test_app/TestApp/ApplicationWithExceptionsInMiddleware.php

@@ -1,54 +0,0 @@
-<?php
-/**
- * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
- * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the LICENSE.txt
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- * @link          https://cakephp.org CakePHP(tm) Project
- * @since         3.6.2
- * @license       https://opensource.org/licenses/mit-license.php MIT License
- */
-namespace TestApp;
-
-use Cake\Error\Middleware\ErrorHandlerMiddleware;
-use Cake\Http\BaseApplication;
-use Cake\Routing\Middleware\RoutingMiddleware;
-use TestApp\Middleware\ThrowsExceptionMiddleware;
-
-/**
- * Simple Application class doing nothing that:
- */
-class ApplicationWithExceptionsInMiddleware extends BaseApplication
-{
-    /**
-     * Bootstrap hook.
-     *
-     * Nerfed as this is for IntegrationTestCase testing.
-     *
-     * @return void
-     */
-    public function bootstrap()
-    {
-        // Do nothing.
-    }
-
-    public function middleware($middlewareQueue)
-    {
-        $middlewareQueue
-            // Catch any exceptions in the lower layers,
-            // and make an error page/response
-            ->add(ErrorHandlerMiddleware::class)
-
-            // Throw an error
-            ->add(ThrowsExceptionMiddleware::class)
-
-            // Add routing middleware.
-            ->add(new RoutingMiddleware($this));
-
-        return $middlewareQueue;
-    }
-}

+ 1 - 2
tests/test_app/TestApp/Error/TestAppsExceptionRenderer.php

@@ -17,8 +17,7 @@ class TestAppsExceptionRenderer extends ExceptionRenderer
      */
     protected function _getController()
     {
-        $request = $this->request ?: Router::getRequest(true);
-        if ($request === null) {
+        if (!$request = Router::getRequest(true)) {
             $request = new ServerRequest();
         }
         $response = new Response();

+ 0 - 28
tests/test_app/TestApp/Middleware/ThrowsExceptionMiddleware.php

@@ -1,28 +0,0 @@
-<?php
-/**
- * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
- * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- * @link          https://cakephp.org CakePHP(tm) Project
- * @since         3.6.2
- * @license       https://opensource.org/licenses/mit-license.php MIT License
- */
-namespace TestApp\Middleware;
-
-use Cake\Http\Exception\ForbiddenException;
-
-/**
- * Testing stub for middleware tests.
- */
-class ThrowsExceptionMiddleware
-{
-    public function __invoke($req, $res, $next)
-    {
-        throw new ForbiddenException("Sample Message");
-    }
-}