Browse Source

Merge pull request #13897 from cakephp/4.x-merge3.next

Forward port 3.next into 4.x.
Mark Story 6 years ago
parent
commit
16379dd63a

+ 3 - 0
.editorconfig

@@ -16,3 +16,6 @@ end_of_line = crlf
 [*.yml]
 indent_style = space
 indent_size = 2
+
+[Makefile]
+indent_style = tab

+ 1 - 1
src/Cache/Cache.php

@@ -71,7 +71,7 @@ class Cache
      * An array mapping url schemes to fully qualified caching engine
      * class names.
      *
-     * @var array
+     * @var string[]
      */
     protected static $_dsnClassMap = [
         'array' => Engine\ArrayEngine::class,

+ 1 - 1
src/Core/App.php

@@ -181,7 +181,7 @@ class App
      * @param string $type type of path
      * @param string|null $plugin This argument is deprecated.
      *   Use \Cake\Core\Plugin::classPath()/templatePath() instead for plugin paths.
-     * @return array
+     * @return string[]
      * @link https://book.cakephp.org/4/en/core-libraries/app.html#finding-paths-to-namespaces
      */
     public static function path(string $type, ?string $plugin = null): array

+ 1 - 1
src/Core/StaticConfigTrait.php

@@ -68,7 +68,7 @@ trait StaticConfigTrait
      * ```
      *
      * @param string|array $key The name of the configuration, or an array of multiple configs.
-     * @param array|object $config An array of name => configuration data for adapter.
+     * @param array|object|null $config An array of name => configuration data for adapter.
      * @throws \BadMethodCallException When trying to modify an existing config.
      * @throws \LogicException When trying to store an invalid structured config array.
      * @return void

+ 3 - 3
src/Database/Query.php

@@ -883,8 +883,8 @@ class Query implements ExpressionInterface, IteratorAggregate
      * $query
      *   ->where(['title !=' => 'Hello World'])
      *   ->where(function ($exp, $query) {
-     *     $or = $exp->or_(['id' => 1]);
-     *     $and = $exp->and_(['id >' => 2, 'id <' => 10]);
+     *     $or = $exp->or(['id' => 1]);
+     *     $and = $exp->and(['id >' => 2, 'id <' => 10]);
      *    return $or->add($and);
      *   });
      * ```
@@ -1071,7 +1071,7 @@ class Query implements ExpressionInterface, IteratorAggregate
      *   ->where(['title' => 'Foo'])
      *   ->andWhere(function ($exp, $query) {
      *     return $exp
-     *       ->or_(['author_id' => 1])
+     *       ->or(['author_id' => 1])
      *       ->add(['author_id' => 2]);
      *   });
      * ```

+ 1 - 1
src/Database/README.md

@@ -270,7 +270,7 @@ Combining expressions is also possible:
 
 ```php
 $query->where(function ($exp) {
-        $orConditions = $exp->or_(['author_id' => 2])
+        $orConditions = $exp->or(['author_id' => 2])
             ->eq('author_id', 5);
         return $exp
             ->not($orConditions)

+ 4 - 4
src/Database/Schema/BaseSchema.php

@@ -220,10 +220,10 @@ abstract class BaseSchema
      * Generate the SQL to create a table.
      *
      * @param \Cake\Database\Schema\TableSchema $schema Table instance.
-     * @param array $columns The columns to go inside the table.
-     * @param array $constraints The constraints for the table.
-     * @param array $indexes The indexes for the table.
-     * @return array SQL statements to create a table.
+     * @param string[] $columns The columns to go inside the table.
+     * @param string[] $constraints The constraints for the table.
+     * @param string[] $indexes The indexes for the table.
+     * @return string[] SQL statements to create a table.
      */
     abstract public function createTableSql(
         TableSchema $schema,

+ 1 - 1
src/Datasource/ConnectionManager.php

@@ -50,7 +50,7 @@ class ConnectionManager
     /**
      * An array mapping url schemes to fully qualified driver class names
      *
-     * @var string[]
+     * @return string[]
      */
     protected static $_dsnClassMap = [
         'mysql' => Mysql::class,

+ 2 - 2
src/Datasource/EntityInterface.php

@@ -217,7 +217,7 @@ interface EntityInterface extends ArrayAccess, JsonSerializable
      * Returns whether this entity contains a field named $field
      * regardless of if it is empty.
      *
-     * @param string|array $field The field to check.
+     * @param string|string[] $field The field to check.
      * @return bool
      */
     public function has($field): bool;
@@ -225,7 +225,7 @@ interface EntityInterface extends ArrayAccess, JsonSerializable
     /**
      * Removes a field or list of fields from this entity
      *
-     * @param string|array $field The field to unset.
+     * @param string|string[] $field The field to unset.
      * @return $this
      */
     public function unset($field);

+ 4 - 4
src/Datasource/EntityTrait.php

@@ -302,7 +302,7 @@ trait EntityTrait
      */
     public function getOriginal(string $field)
     {
-        if (!strlen((string)$field)) {
+        if (!strlen($field)) {
             throw new InvalidArgumentException('Cannot get an empty field');
         }
         if (array_key_exists($field, $this->_original)) {
@@ -354,7 +354,7 @@ trait EntityTrait
      * When checking multiple fields. All fields must not be null
      * in order for true to be returned.
      *
-     * @param string|array $field The field or fields to check.
+     * @param string|string[] $field The field or fields to check.
      * @return bool
      */
     public function has($field): bool
@@ -434,7 +434,7 @@ trait EntityTrait
      * $entity->unset(['name', 'last_name']);
      * ```
      *
-     * @param string|array $field The field to unset.
+     * @param string|string[] $field The field to unset.
      * @return $this
      */
     public function unset($field)
@@ -451,7 +451,7 @@ trait EntityTrait
      * Removes a field or list of fields from this entity
      *
      * @deprecated 4.0.0 Use unset() instead. Will be removed in 5.0.
-     * @param string|array $field The field to unset.
+     * @param string|string[] $field The field to unset.
      * @return $this
      */
     public function unsetProperty($field)

+ 2 - 2
src/Datasource/QueryInterface.php

@@ -365,8 +365,8 @@ interface QueryInterface
      *  $query
      *  ->where(['title !=' => 'Hello World'])
      *  ->where(function ($exp, $query) {
-     *      $or = $exp->or_(['id' => 1]);
-     *      $and = $exp->and_(['id >' => 2, 'id <' => 10]);
+     *      $or = $exp->or(['id' => 1]);
+     *      $and = $exp->and(['id >' => 2, 'id <' => 10]);
      *  return $or->add($and);
      *  });
      * ```

+ 1 - 1
src/Http/Client.php

@@ -553,7 +553,7 @@ class Client implements ClientInterface
      * or full mime-type.
      *
      * @param string $type short type alias or full mimetype.
-     * @return array Headers to set on the request.
+     * @return string[] Headers to set on the request.
      * @throws \Cake\Core\Exception\Exception When an unknown type alias is used.
      * @psalm-return array{Accept: string, Content-Type: string}
      */

+ 1 - 1
src/Mailer/TransportFactory.php

@@ -36,7 +36,7 @@ class TransportFactory
     /**
      * An array mapping url schemes to fully qualified Transport class names
      *
-     * @var array
+     * @var string[]
      */
     protected static $_dsnClassMap = [
         'debug' => Transport\DebugTransport::class,

+ 3 - 2
src/ORM/Association/BelongsToMany.php

@@ -19,6 +19,7 @@ namespace Cake\ORM\Association;
 use Cake\Core\App;
 use Cake\Database\Expression\IdentifierExpression;
 use Cake\Database\ExpressionInterface;
+use Cake\Database\Expression\QueryExpression;
 use Cake\Datasource\EntityInterface;
 use Cake\ORM\Association;
 use Cake\ORM\Association\Loader\SelectWithPivotLoader;
@@ -472,7 +473,7 @@ class BelongsToMany extends Association
         $subquery = $this->_appendJunctionJoin($subquery);
 
         $query
-            ->andWhere(function ($exp) use ($subquery, $conds) {
+            ->andWhere(function (QueryExpression $exp) use ($subquery, $conds) {
                 $identifiers = [];
                 foreach (array_keys($conds) as $field) {
                     $identifiers[] = new IdentifierExpression($field);
@@ -481,7 +482,7 @@ class BelongsToMany extends Association
                 $nullExp = clone $exp;
 
                 return $exp
-                    ->or_([
+                    ->or([
                         $exp->notIn($identifiers, $subquery),
                         $nullExp->and(array_map([$nullExp, 'isNull'], array_keys($conds))),
                     ]);

+ 1 - 1
src/Routing/Route/Route.php

@@ -195,7 +195,7 @@ class Route
         if (mb_strlen($patternValues) < strlen($patternValues)) {
             $this->options['multibytePattern'] = true;
         }
-        $this->options = array_merge($this->options, $patterns);
+        $this->options = $patterns + $this->options;
 
         return $this;
     }

+ 3 - 2
src/Routing/RouteBuilder.php

@@ -107,7 +107,7 @@ class RouteBuilder
      * The list of middleware that routes in this builder get
      * added during construction.
      *
-     * @var array
+     * @var string[]
      */
     protected $middleware = [];
 
@@ -197,7 +197,7 @@ class RouteBuilder
     /**
      * Add additional extensions to what is already in current scope
      *
-     * @param string|array $extensions One or more extensions to add
+     * @param string|string[] $extensions One or more extensions to add
      * @return $this
      */
     public function addExtensions($extensions)
@@ -979,6 +979,7 @@ class RouteBuilder
      *
      * @param string ...$names The names of the middleware to apply to the current scope.
      * @return $this
+     * @throws \RuntimeException
      * @see \Cake\Routing\RouteCollection::addMiddlewareToScope()
      */
     public function applyMiddleware(string ...$names)

+ 20 - 1
src/TestSuite/IntegrationTestTrait.php

@@ -821,7 +821,7 @@ trait IntegrationTestTrait
     }
 
     /**
-     * Asserts that the Location header is correct.
+     * Asserts that the Location header is correct. Comparison is made against a full URL.
      *
      * @param string|array|null $url The URL you expected the client to go to. This
      *   can either be a string URL or an array compatible with Router::url(). Use null to
@@ -844,6 +844,25 @@ trait IntegrationTestTrait
     }
 
     /**
+     * Asserts that the Location header is correct. Comparison is made against exactly the URL provided.
+     *
+     * @param string|array|null $url The URL you expected the client to go to. This
+     *   can either be a string URL or an array compatible with Router::url(). Use null to
+     *   simply check for the existence of this header.
+     * @param string $message The failure message that will be appended to the generated message.
+     * @return void
+     */
+    public function assertRedirectEquals($url = null, $message = '')
+    {
+        $verboseMessage = $this->extractVerboseMessage($message);
+        $this->assertThat(null, new HeaderSet($this->_response, 'Location'), $verboseMessage);
+
+        if ($url) {
+            $this->assertThat(Router::url($url), new HeaderEquals($this->_response, 'Location'), $verboseMessage);
+        }
+    }
+
+    /**
      * Asserts that the Location header contains a substring
      *
      * @param string $url The URL you expected the client to go to.

+ 2 - 2
src/Utility/CookieCryptTrait.php

@@ -30,7 +30,7 @@ trait CookieCryptTrait
     /**
      * Valid cipher names for encrypted cookies.
      *
-     * @var array
+     * @var string[]
      */
     protected $_validCiphers = ['aes'];
 
@@ -92,7 +92,7 @@ trait CookieCryptTrait
     /**
      * Decrypts $value using public $type method in Security class
      *
-     * @param array|string $values Values to decrypt
+     * @param string[]|string $values Values to decrypt
      * @param string|false $mode Encryption mode
      * @param string|null $key Used as the security salt if specified.
      * @return string|array Decrypted values

+ 3 - 3
src/Validation/Validation.php

@@ -330,12 +330,12 @@ class Validation
                 }
                 break;
             case static::COMPARE_EQUAL:
-                if ($check1 === $check2) {
+                if ($check1 == $check2) {
                     return true;
                 }
                 break;
             case static::COMPARE_NOT_EQUAL:
-                if ($check1 !== $check2) {
+                if ($check1 != $check2) {
                     return true;
                 }
                 break;
@@ -385,7 +385,7 @@ class Validation
      */
     public static function compareFields($check, string $field, string $operator, array $context): bool
     {
-        if (!isset($context['data'][$field])) {
+        if (!isset($context['data']) || !array_key_exists($field, $context['data'])) {
             return false;
         }
 

+ 1 - 1
src/View/StringTemplate.php

@@ -309,7 +309,7 @@ class StringTemplate
      * Works with minimized attributes that have the same value as their name such as 'disabled' and 'checked'
      *
      * @param string $key The name of the attribute to create
-     * @param string|array $value The value of the attribute to create.
+     * @param string|string[] $value The value of the attribute to create.
      * @param bool $escape Define if the value must be escaped
      * @return string The composed attribute.
      */

+ 2 - 2
src/View/Widget/SelectBoxWidget.php

@@ -306,7 +306,7 @@ class SelectBoxWidget extends BasicWidget
      * Helper method for deciding what options are selected.
      *
      * @param string $key The key to test.
-     * @param array|string|false|null $selected The selected values.
+     * @param  string[]|string|false|null $selected The selected values.
      * @return bool
      */
     protected function _isSelected(string $key, $selected): bool
@@ -328,7 +328,7 @@ class SelectBoxWidget extends BasicWidget
      * Helper method for deciding what options are disabled.
      *
      * @param string $key The key to test.
-     * @param array|null $disabled The disabled values.
+     * @param string[]|null $disabled The disabled values.
      * @return bool
      */
     protected function _isDisabled(string $key, ?array $disabled): bool

+ 8 - 8
tests/TestCase/Database/QueryTest.php

@@ -1537,7 +1537,7 @@ class QueryTest extends TestCase
             ->select(['id'])
             ->from('comments')
             ->where(function ($exp) {
-                $and = $exp->and_(['id' => 2, 'id >' => 1]);
+                $and = $exp->and(['id' => 2, 'id >' => 1]);
 
                 return $exp->add($and);
             })
@@ -1551,7 +1551,7 @@ class QueryTest extends TestCase
             ->select(['id'])
             ->from('comments')
             ->where(function ($exp) {
-                $and = $exp->and_(['id' => 2, 'id <' => 2]);
+                $and = $exp->and(['id' => 2, 'id <' => 2]);
 
                 return $exp->add($and);
             })
@@ -1564,7 +1564,7 @@ class QueryTest extends TestCase
             ->select(['id'])
             ->from('comments')
             ->where(function ($exp) {
-                $and = $exp->and_(function ($and) {
+                $and = $exp->and(function ($and) {
                     return $and->eq('id', 1)->gt('id', 0);
                 });
 
@@ -1580,8 +1580,8 @@ class QueryTest extends TestCase
             ->select(['id'])
             ->from('comments')
             ->where(function ($exp) {
-                $or = $exp->or_(['id' => 1]);
-                $and = $exp->and_(['id >' => 2, 'id <' => 4]);
+                $or = $exp->or(['id' => 1]);
+                $and = $exp->and(['id >' => 2, 'id <' => 4]);
 
                 return $or->add($and);
             })
@@ -1596,7 +1596,7 @@ class QueryTest extends TestCase
             ->select(['id'])
             ->from('comments')
             ->where(function ($exp) {
-                $or = $exp->or_(function ($or) {
+                $or = $exp->or(function ($or) {
                     return $or->eq('id', 1)->eq('id', 2);
                 });
 
@@ -1624,7 +1624,7 @@ class QueryTest extends TestCase
             ->from('comments')
             ->where(function ($exp) {
                 return $exp->not(
-                    $exp->and_(['id' => 2, 'created' => new \DateTime('2007-03-18 10:47:23')], ['created' => 'datetime'])
+                    $exp->and(['id' => 2, 'created' => new \DateTime('2007-03-18 10:47:23')], ['created' => 'datetime'])
                 );
             })
             ->execute();
@@ -1639,7 +1639,7 @@ class QueryTest extends TestCase
             ->from('comments')
             ->where(function ($exp) {
                 return $exp->not(
-                    $exp->and_(['id' => 2, 'created' => new \DateTime('2012-12-21 12:00')], ['created' => 'datetime'])
+                    $exp->and(['id' => 2, 'created' => new \DateTime('2012-12-21 12:00')], ['created' => 'datetime'])
                 );
             })
             ->execute();

+ 14 - 0
tests/TestCase/Mailer/EmailTest.php

@@ -2332,6 +2332,20 @@ class EmailTest extends TestCase
     }
 
     /**
+     * Tests headerCharset on reset
+     *
+     * @return void
+     */
+    public function testHeaderCharsetReset()
+    {
+        $email = new Email(['headerCharset' => 'ISO-2022-JP']);
+        $email->reset();
+
+        $this->assertSame('utf-8', $email->getCharset());
+        $this->assertSame('utf-8', $email->getHeaderCharset());
+    }
+
+    /**
      * Test transferEncoding
      *
      * @return void

+ 3 - 0
tests/TestCase/Routing/Route/RouteTest.php

@@ -1523,6 +1523,9 @@ class RouteTest extends TestCase
         $route = new Route('/{controller}/{action}');
         $this->assertSame('_controller:_action', $route->getName());
 
+        $route = new Route('/{controller}/{action}');
+        $this->assertSame('_controller:_action', $route->getName());
+
         $route = new Route('/articles/:action', ['controller' => 'posts']);
         $this->assertSame('posts:_action', $route->getName());
 

+ 17 - 0
tests/TestCase/TestSuite/IntegrationTestTraitTest.php

@@ -1036,6 +1036,23 @@ class IntegrationTestTraitTest extends TestCase
     }
 
     /**
+     * Test the location header assertion.
+     *
+     * @return void
+     */
+    public function testAssertRedirectEquals()
+    {
+        $this->_response = new Response();
+        $this->_response = $this->_response->withHeader('Location', '/get/tasks/index');
+
+        $this->assertRedirect();
+        $this->assertRedirectEquals('/get/tasks/index');
+        $this->assertRedirectEquals(['controller' => 'Tasks', 'action' => 'index']);
+
+        $this->assertResponseEmpty();
+    }
+
+    /**
      * Test the location header assertion string not contains
      *
      * @return void

+ 9 - 0
tests/TestCase/Validation/ValidationTest.php

@@ -2965,6 +2965,15 @@ class ValidationTest extends TestCase
 
         $context = [];
         $this->assertFalse(Validation::compareFields('a value', 'other', Validation::COMPARE_EQUAL, $context));
+
+        $context = [
+            'data' => ['other' => null],
+        ];
+        $this->assertFalse(Validation::compareFields('a value', 'other', Validation::COMPARE_EQUAL, $context));
+        $this->assertFalse(Validation::compareFields(false, 'other', Validation::COMPARE_SAME, $context));
+        $this->assertTrue(Validation::compareFields(false, 'other', Validation::COMPARE_EQUAL, $context));
+        $this->assertTrue(Validation::compareFields(null, 'other', Validation::COMPARE_SAME, $context));
+        $this->assertFalse(Validation::compareFields(false, 'other', Validation::COMPARE_SAME, $context));
     }
 
     /**