Browse Source

Merge branch 'master' into 3.next

ADmad 8 years ago
parent
commit
4047bb17a6

+ 1 - 1
phpstan.neon

@@ -1,6 +1,6 @@
 parameters:
     autoload_files:
-        - %rootDir%/../../../tests/bootstrap.php
+        - tests/bootstrap.php
     ignoreErrors:
         - '#Function wincache_ucache_[a-zA-Z0-9_]+ not found#'
         - '#Function xcache_[a-zA-Z0-9_]+ not found#'

+ 1 - 1
src/Console/CommandScanner.php

@@ -21,7 +21,7 @@ use Cake\Filesystem\Folder;
 use Cake\Utility\Inflector;
 
 /**
- * Used by CommanCollection and CommandTask to scan the filesystem
+ * Used by CommandCollection and CommandTask to scan the filesystem
  * for command classes.
  *
  * @internal

+ 0 - 2
src/Controller/Component/AuthComponent.php

@@ -400,8 +400,6 @@ class AuthComponent extends Component
                 $this->_config['ajaxLogin'],
                 $this->RequestHandler->ajaxLayout
             );
-
-            return $response->withStatus(403);
         }
 
         return $response->withStatus(403);

+ 6 - 1
src/Datasource/EntityTrait.php

@@ -1383,7 +1383,12 @@ trait EntityTrait
      */
     public function __debugInfo()
     {
-        return $this->_properties + [
+        $properties = $this->_properties;
+        foreach ($this->_virtual as $field) {
+            $properties[$field] = $this->$field;
+        }
+
+        return $properties + [
             '[new]' => $this->isNew(),
             '[accessible]' => $this->_accessible,
             '[dirty]' => $this->_dirty,

+ 5 - 2
src/Datasource/Paginator.php

@@ -209,7 +209,7 @@ class Paginator implements PaginatorInterface
             'prevPage' => $page > 1,
             'nextPage' => $count > ($page * $limit),
             'pageCount' => $pageCount,
-            'sort' => key($order),
+            'sort' => $options['sort'],
             'direction' => current($order),
             'limit' => $defaults['limit'] != $limit ? $limit : null,
             'sortDefault' => $sortDefault,
@@ -354,8 +354,10 @@ class Paginator implements PaginatorInterface
             }
             $order = (isset($options['order']) && is_array($options['order'])) ? $options['order'] : [];
             $options['order'] = [$options['sort'] => $direction] + $order;
+        } else {
+            $options['sort'] = null;
         }
-        unset($options['sort'], $options['direction']);
+        unset($options['direction']);
 
         if (empty($options['order'])) {
             $options['order'] = [];
@@ -370,6 +372,7 @@ class Paginator implements PaginatorInterface
             $inWhitelist = in_array($field, $options['sortWhitelist'], true);
             if (!$inWhitelist) {
                 $options['order'] = [];
+                $options['sort'] = null;
 
                 return $options;
             }

+ 1 - 1
src/Event/EventDispatcherTrait.php

@@ -33,7 +33,7 @@ trait EventDispatcherTrait
      *
      * @var string
      */
-    protected $_eventClass = '\Cake\Event\Event';
+    protected $_eventClass = Event::class;
 
     /**
      * Returns the Cake\Event\EventManager manager instance for this object.

+ 8 - 1
src/Form/Form.php

@@ -19,6 +19,7 @@ use Cake\Event\EventDispatcherInterface;
 use Cake\Event\EventDispatcherTrait;
 use Cake\Event\EventListenerInterface;
 use Cake\Event\EventManager;
+use Cake\Form\Schema;
 use Cake\Validation\Validator;
 use Cake\Validation\ValidatorAwareInterface;
 use Cake\Validation\ValidatorAwareTrait;
@@ -42,6 +43,12 @@ use Cake\Validation\ValidatorAwareTrait;
  */
 class Form implements EventListenerInterface, EventDispatcherInterface, ValidatorAwareInterface
 {
+    /**
+     * Schema class.
+     *
+     * @var string
+     */
+    protected $_schemaClass = Schema::class;
 
     use EventDispatcherTrait;
     use ValidatorAwareTrait;
@@ -125,7 +132,7 @@ class Form implements EventListenerInterface, EventDispatcherInterface, Validato
     public function schema(Schema $schema = null)
     {
         if ($schema === null && empty($this->_schema)) {
-            $schema = $this->_buildSchema(new Schema());
+            $schema = $this->_buildSchema(new $this->_schemaClass);
         }
         if ($schema) {
             $this->_schema = $schema;

+ 7 - 0
src/ORM/Table.php

@@ -2139,6 +2139,13 @@ class Table implements RepositoryInterface, EventListenerInterface, EventDispatc
             return $entity;
         }
 
+        if (count($primaryColumns) === 0) {
+            $entityClass = get_class($entity);
+            $table = $this->getTable();
+            $message = "Cannot update `$entityClass`. The `$table` has no primary key.";
+            throw new InvalidArgumentException($message);
+        }
+
         if (!$entity->has($primaryColumns)) {
             $message = 'All primary key value(s) are needed for updating, ';
             $message .= get_class($entity) . ' is missing ' . implode(', ', $primaryColumns);

+ 1 - 0
src/Template/Error/missing_action.ctp

@@ -21,6 +21,7 @@ if (!empty($plugin)) {
     $namespace = str_replace('/', '\\', $plugin);
 }
 $prefixNs = '';
+$prefix = isset($prefix) ? $prefix : '';
 if (!empty($prefix)) {
     $prefix = array_map('Cake\Utility\Inflector::camelize', explode('/', $prefix));
     $prefixNs = '\\' . implode('\\', $prefix);

+ 2 - 2
src/TestSuite/Fixture/FixtureManager.php

@@ -290,7 +290,7 @@ class FixtureManager
                     $this->_insertionMap[$configName] = [];
                 }
 
-                foreach ($fixtures as $name => $fixture) {
+                foreach ($fixtures as $fixture) {
                     if (in_array($fixture->table, $tables)) {
                         try {
                             $fixture->dropConstraints($db);
@@ -314,7 +314,7 @@ class FixtureManager
                     }
                 }
 
-                foreach ($fixtures as $name => $fixture) {
+                foreach ($fixtures as $fixture) {
                     try {
                         $fixture->createConstraints($db);
                     } catch (PDOException $e) {

+ 8 - 1
src/View/View.php

@@ -279,6 +279,13 @@ class View implements EventDispatcherInterface
     protected $_stack = [];
 
     /**
+     * ViewBlock class.
+     *
+     * @var string
+     */
+    protected $_viewBlockClass = ViewBlock::class;
+
+    /**
      * Constant for view file type 'view'
      *
      * @var string
@@ -359,7 +366,7 @@ class View implements EventDispatcherInterface
                 'webroot' => '/'
             ]);
         }
-        $this->Blocks = new ViewBlock();
+        $this->Blocks = new $this->_viewBlockClass();
         $this->initialize();
         $this->loadHelpers();
     }

+ 8 - 1
tests/TestCase/Controller/Component/PaginatorComponentTest.php

@@ -189,6 +189,7 @@ class PaginatorComponentTest extends TestCase
                 'page' => 1,
                 'whitelist' => ['limit', 'sort', 'page', 'direction'],
                 'scope' => null,
+                'sort' => null,
             ]);
         $this->Paginator->paginate($table, $settings);
     }
@@ -324,6 +325,7 @@ class PaginatorComponentTest extends TestCase
                 'order' => ['PaginatorPosts.id' => 'DESC'],
                 'whitelist' => ['limit', 'sort', 'page', 'direction'],
                 'scope' => null,
+                'sort' => null,
             ]);
 
         $this->Paginator->paginate($table, $settings);
@@ -356,6 +358,7 @@ class PaginatorComponentTest extends TestCase
                 'order' => ['PaginatorPosts.id' => 'DESC'],
                 'whitelist' => ['limit', 'sort', 'page', 'direction'],
                 'scope' => null,
+                'sort' => null,
             ]);
 
         $this->Paginator->paginate($table, $settings);
@@ -665,6 +668,7 @@ class PaginatorComponentTest extends TestCase
                 'order' => ['PaginatorPosts.id' => 'asc'],
                 'whitelist' => ['limit', 'sort', 'page', 'direction'],
                 'scope' => null,
+                'sort' => 'id',
             ]);
 
         $this->controller->request = $this->controller->request->withQueryParams([
@@ -673,7 +677,7 @@ class PaginatorComponentTest extends TestCase
             'direction' => 'herp'
         ]);
         $this->Paginator->paginate($table);
-        $this->assertEquals('PaginatorPosts.id', $this->controller->request->getParam('paging.PaginatorPosts.sort'));
+        $this->assertEquals('id', $this->controller->request->getParam('paging.PaginatorPosts.sort'));
         $this->assertEquals('asc', $this->controller->request->getParam('paging.PaginatorPosts.direction'));
     }
 
@@ -1246,6 +1250,7 @@ class PaginatorComponentTest extends TestCase
                 'order' => [],
                 'whitelist' => ['limit', 'sort', 'page', 'direction'],
                 'scope' => null,
+                'sort' => null,
             ]);
         $this->Paginator->paginate($table, $settings);
     }
@@ -1280,6 +1285,7 @@ class PaginatorComponentTest extends TestCase
                 'page' => 1,
                 'whitelist' => ['limit', 'sort', 'page', 'direction'],
                 'scope' => null,
+                'sort' => null,
             ]);
         $this->Paginator->paginate($query, $settings);
     }
@@ -1340,6 +1346,7 @@ class PaginatorComponentTest extends TestCase
                 'page' => 1,
                 'whitelist' => ['limit', 'sort', 'page', 'direction'],
                 'scope' => null,
+                'sort' => null,
             ]);
         $this->Paginator->paginate($query, $settings);
     }

+ 47 - 1
tests/TestCase/Datasource/PaginatorTest.php

@@ -126,6 +126,7 @@ class PaginatorTest extends TestCase
                 'page' => 1,
                 'whitelist' => ['limit', 'sort', 'page', 'direction'],
                 'scope' => null,
+                'sort' => null,
             ]);
         $this->Paginator->paginate($table, $params, $settings);
     }
@@ -237,6 +238,7 @@ class PaginatorTest extends TestCase
                 'order' => ['PaginatorPosts.id' => 'DESC'],
                 'whitelist' => ['limit', 'sort', 'page', 'direction'],
                 'scope' => null,
+                'sort' => null,
             ]);
 
         $this->Paginator->paginate($table, [], $settings);
@@ -269,6 +271,7 @@ class PaginatorTest extends TestCase
                 'order' => ['PaginatorPosts.id' => 'DESC'],
                 'whitelist' => ['limit', 'sort', 'page', 'direction'],
                 'scope' => null,
+                'sort' => null,
             ]);
 
         $this->Paginator->paginate($table, [], $settings);
@@ -592,6 +595,7 @@ class PaginatorTest extends TestCase
                 'order' => ['PaginatorPosts.id' => 'asc'],
                 'whitelist' => ['limit', 'sort', 'page', 'direction'],
                 'scope' => null,
+                'sort' => 'id',
             ]);
 
         $params = [
@@ -601,7 +605,7 @@ class PaginatorTest extends TestCase
         ];
         $this->Paginator->paginate($table, $params);
         $pagingParams = $this->Paginator->getPagingParams();
-        $this->assertEquals('PaginatorPosts.id', $pagingParams['PaginatorPosts']['sort']);
+        $this->assertEquals('id', $pagingParams['PaginatorPosts']['sort']);
         $this->assertEquals('asc', $pagingParams['PaginatorPosts']['direction']);
     }
 
@@ -627,6 +631,45 @@ class PaginatorTest extends TestCase
     }
 
     /**
+     * testValidateSortRetainsOriginalSortValue
+     *
+     * @return void
+     * @see https://github.com/cakephp/cakephp/issues/11740
+     */
+    public function testValidateSortRetainsOriginalSortValue()
+    {
+        $table = $this->_getMockPosts(['query']);
+        $query = $this->_getMockFindQuery();
+
+        $table->expects($this->once())
+            ->method('query')
+            ->will($this->returnValue($query));
+
+        $query->expects($this->once())->method('applyOptions')
+            ->with([
+                'limit' => 20,
+                'page' => 1,
+                'order' => ['PaginatorPosts.id' => 'asc'],
+                'whitelist' => ['limit', 'sort', 'page', 'direction'],
+                'scope' => null,
+                'sortWhitelist' => ['id'],
+                'sort' => 'id',
+            ]);
+
+        $params = [
+            'page' => 1,
+            'sort' => 'id',
+            'direction' => 'herp'
+        ];
+        $options = [
+            'sortWhitelist' => ['id']
+        ];
+        $this->Paginator->paginate($table, $params, $options);
+        $pagingParams = $this->Paginator->getPagingParams();
+        $this->assertEquals('id', $pagingParams['PaginatorPosts']['sort']);
+    }
+
+    /**
      * Test that a really large page number gets clamped to the max page size.
      *
      * @return void
@@ -1145,6 +1188,7 @@ class PaginatorTest extends TestCase
                 'order' => [],
                 'whitelist' => ['limit', 'sort', 'page', 'direction'],
                 'scope' => null,
+                'sort' => null,
             ]);
         $this->Paginator->paginate($table, [], $settings);
     }
@@ -1179,6 +1223,7 @@ class PaginatorTest extends TestCase
                 'page' => 1,
                 'whitelist' => ['limit', 'sort', 'page', 'direction'],
                 'scope' => null,
+                'sort' => null,
             ]);
         $this->Paginator->paginate($query, $params, $settings);
     }
@@ -1239,6 +1284,7 @@ class PaginatorTest extends TestCase
                 'page' => 1,
                 'whitelist' => ['limit', 'sort', 'page', 'direction'],
                 'scope' => null,
+                'sort' => null,
             ]);
         $this->Paginator->paginate($query, $params, $settings);
     }

+ 2 - 1
tests/TestCase/Error/DebuggerTest.php

@@ -404,8 +404,9 @@ object(Cake\View\View) {
 	[protected] _current => null
 	[protected] _currentType => ''
 	[protected] _stack => []
+	[protected] _viewBlockClass => 'Cake\View\ViewBlock'
 	[protected] _eventManager => object(Cake\Event\EventManager) {}
-	[protected] _eventClass => '\Cake\Event\Event'
+	[protected] _eventClass => 'Cake\Event\Event'
 	[protected] _viewBuilder => null
 }
 TEXT;

+ 5 - 0
tests/TestCase/Form/FormTest.php

@@ -17,6 +17,8 @@ namespace Cake\Test\TestCase\Form;
 use Cake\Form\Form;
 use Cake\TestSuite\TestCase;
 use Cake\Validation\Validator;
+use TestApp\Form\AppForm;
+use TestApp\Form\FormSchema;
 
 /**
  * Form test case.
@@ -40,6 +42,9 @@ class FormTest extends TestCase
         $schema = $this->getMockBuilder('Cake\Form\Schema')->getMock();
         $this->assertSame($schema, $form->schema($schema));
         $this->assertSame($schema, $form->schema());
+
+        $form = new AppForm();
+        $this->assertInstanceOf(FormSchema::class, $form->schema());
     }
 
     /**

+ 1 - 0
tests/TestCase/ORM/EntityTest.php

@@ -1507,6 +1507,7 @@ class EntityTest extends TestCase
         $expected = [
             'foo' => 'bar',
             'somethingElse' => 'value',
+            'baz' => null,
             '[new]' => true,
             '[accessible]' => ['*' => true, 'id' => false, 'name' => true],
             '[dirty]' => ['somethingElse' => true, 'foo' => true],

+ 18 - 0
tests/TestCase/ORM/TableRegressionTest.php

@@ -15,6 +15,7 @@
 namespace Cake\Test\TestCase\ORM;
 
 use Cake\TestSuite\TestCase;
+use InvalidArgumentException;
 
 /**
  * Contains regression test for the Table class
@@ -63,4 +64,21 @@ class TableRegressionTest extends TestCase
         $entity = $table->newEntity(['name' => 'Jon']);
         $table->save($entity);
     }
+
+    /**
+     * Ensure that saving to a table with no primary key fails.
+     *
+     * @return void
+     */
+    public function testSaveNoPrimaryKeyException()
+    {
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('primary key');
+        $table = TableRegistry::get('Authors');
+        $table->getSchema()->dropConstraint('primary');
+
+        $entity = $table->find()->first();
+        $entity->name = 'new name';
+        $table->save($entity);
+    }
 }

+ 22 - 0
tests/test_app/TestApp/Form/AppForm.php

@@ -0,0 +1,22 @@
+<?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.5.13
+ * @license       https://opensource.org/licenses/mit-license.php MIT License
+ */
+namespace TestApp\Form;
+
+use Cake\Form\Form;
+
+class AppForm extends Form
+{
+    protected $_schemaClass = FormSchema::class;
+}

+ 24 - 0
tests/test_app/TestApp/Form/FormSchema.php

@@ -0,0 +1,24 @@
+<?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.5.13
+ * @license       https://opensource.org/licenses/mit-license.php MIT License
+ */
+namespace TestApp\Form;
+
+use Cake\Form\Schema;
+
+/**
+ * Contains the schema information for Form instances.
+ */
+class FormSchema extends Schema
+{
+}