Browse Source

Merge branch 'master' into 3.next

Mark Story 8 years ago
parent
commit
7061a90c76

+ 2 - 2
.travis.yml

@@ -4,7 +4,7 @@ php:
   - 7.0
   - 5.6
   - 7.1
-  - nightly
+  - 7.2
 
 dist: trusty
 
@@ -34,7 +34,7 @@ matrix:
   fast_finish: true
 
   allow_failures:
-    - php: nightly
+    - php: 7.2
 
   include:
     - php: 7.0

+ 7 - 2
src/Database/QueryCompiler.php

@@ -235,8 +235,13 @@ class QueryCompiler
             }
 
             $joins .= sprintf(' %s JOIN %s %s', $join['type'], $join['table'], $join['alias']);
-            if (isset($join['conditions']) && count($join['conditions'])) {
-                $joins .= sprintf(' ON %s', $join['conditions']->sql($generator));
+
+            $condition = '';
+            if (isset($join['conditions']) && $join['conditions'] instanceof ExpressionInterface) {
+                $condition = $join['conditions']->sql($generator);
+            }
+            if (strlen($condition)) {
+                $joins .= " ON {$condition}";
             } else {
                 $joins .= ' ON 1 = 1';
             }

+ 2 - 2
src/Datasource/EntityTrait.php

@@ -752,7 +752,7 @@ trait EntityTrait
         if ($isDirty === false) {
             unset($this->_dirty[$property]);
 
-            return false;
+            return $this;
         }
 
         $this->_dirty[$property] = true;
@@ -1182,7 +1182,7 @@ trait EntityTrait
      * Stores whether or not a property value can be changed or set in this entity.
      * The special property `*` can also be marked as accessible or protected, meaning
      * that any other property specified before will take its value. For example
-     * `$entity->accessible('*', true)` means that any property not specified already
+     * `$entity->setAccess('*', true)` means that any property not specified already
      * will be accessible by default.
      *
      * You can also call this method with an array of properties, in which case they

+ 2 - 2
src/ORM/Association.php

@@ -419,10 +419,10 @@ abstract class Association
 
                     throw new RuntimeException(sprintf(
                         $errorMessage,
-                        get_class($this->_sourceTable),
+                        $this->_sourceTable ? get_class($this->_sourceTable) : 'null',
                         $this->getName(),
                         $this->type(),
-                        get_class($this->_targetTable),
+                        $this->_targetTable ? get_class($this->_targetTable) : 'null',
                         $className
                     ));
                 }

+ 2 - 1
src/ORM/Marshaller.php

@@ -472,7 +472,8 @@ class Marshaller
         $primaryKey = array_map([$target, 'aliasField'], $primaryKey);
 
         if ($multi) {
-            if (count(current($ids)) !== count($primaryKey)) {
+            $first = current($ids);
+            if (!is_array($first) || count($first) !== count($primaryKey)) {
                 return [];
             }
             $filter = new TupleComparison($primaryKey, $ids, [], 'IN');

+ 2 - 0
src/ORM/Rule/ExistsIn.php

@@ -56,6 +56,8 @@ class ExistsIn
      * @param object|string $repository The repository where the field will be looked for,
      * or the association name for the repository.
      * @param array $options The options that modify the rules behavior.
+     *     Options 'allowNullableNulls' will make the rule pass if given foreign keys are set to `null`.
+     *     Notice: allowNullableNulls cannot pass by database columns set to `NOT NULL`.
      */
     public function __construct($fields, $repository, array $options = [])
     {

+ 1 - 1
src/View/Helper/FormHelper.php

@@ -1575,7 +1575,7 @@ class FormHelper extends Helper
         $hidden = '';
         if ($hiddenField) {
             $hidden = $this->hidden($fieldName, [
-                'value' => '',
+                'value' => $hiddenField === true ? '' : $hiddenField,
                 'form' => isset($attributes['form']) ? $attributes['form'] : null,
                 'name' => $attributes['name'],
             ]);

+ 42 - 16
tests/TestCase/ORM/EntityTest.php

@@ -769,11 +769,11 @@ class EntityTest extends TestCase
     }
 
     /**
-     * Tests dirty() method on a newly created object
+     * Tests isDirty() method on a newly created object
      *
      * @return void
      */
-    public function testDirty()
+    public function testIsDirty()
     {
         $entity = new Entity([
             'id' => 1,
@@ -781,19 +781,45 @@ class EntityTest extends TestCase
             'author_id' => 3
         ]);
         $this->assertTrue($entity->dirty('id'));
-        $this->assertTrue($entity->dirty('title'));
-        $this->assertTrue($entity->dirty('author_id'));
+        $this->assertTrue($entity->isDirty('id'));
+        $this->assertTrue($entity->isDirty('title'));
+        $this->assertTrue($entity->isDirty('author_id'));
 
         $this->assertTrue($entity->dirty());
+        $this->assertTrue($entity->isDirty());
 
         $entity->dirty('id', false);
         $this->assertFalse($entity->dirty('id'));
         $this->assertTrue($entity->dirty('title'));
-        $entity->dirty('title', false);
-        $this->assertFalse($entity->dirty('title'));
-        $this->assertTrue($entity->dirty());
-        $entity->dirty('author_id', false);
-        $this->assertFalse($entity->dirty());
+
+        $entity->setDirty('title', false);
+        $this->assertFalse($entity->isDirty('title'));
+        $this->assertTrue($entity->isDirty(), 'should be dirty, one field left');
+
+        $entity->setDirty('author_id', false);
+        $this->assertFalse($entity->isDirty(), 'all fields are clean.');
+    }
+
+    /**
+     * Test setDirty().
+     *
+     * @return void
+     */
+    public function testSetDirty()
+    {
+        $entity = new Entity([
+            'id' => 1,
+            'title' => 'Foo',
+            'author_id' => 3
+        ], ['markClean' => true]);
+
+        $this->assertFalse($entity->isDirty());
+        $this->assertSame($entity, $entity->setDirty('title', true));
+        $this->assertSame($entity, $entity->setDirty('id', false));
+
+        $entity->setErrors(['title' => ['badness']]);
+        $entity->setDirty('title', true);
+        $this->assertEmpty($entity->getErrors('title'), 'Making a field dirty clears errors.');
     }
 
     /**
@@ -807,17 +833,17 @@ class EntityTest extends TestCase
             'title' => 'Foo',
         ]);
 
-        $entity->dirty('title', false);
-        $this->assertFalse($entity->dirty('title'));
+        $entity->setDirty('title', false);
+        $this->assertFalse($entity->isDirty('title'));
 
         $entity->set('title', 'Foo');
-        $this->assertTrue($entity->dirty('title'));
+        $this->assertTrue($entity->isDirty('title'));
 
         $entity->set('title', 'Foo');
-        $this->assertTrue($entity->dirty('title'));
+        $this->assertTrue($entity->isDirty('title'));
 
         $entity->set('something', 'else');
-        $this->assertTrue($entity->dirty('something'));
+        $this->assertTrue($entity->isDirty('something'));
     }
 
     /**
@@ -832,8 +858,8 @@ class EntityTest extends TestCase
             'title' => 'Foo',
             'author_id' => 3
         ]);
-        $entity->dirty('id', false);
-        $entity->dirty('title', false);
+        $entity->setDirty('id', false);
+        $entity->setDirty('title', false);
         $expected = ['author_id' => 3];
         $result = $entity->extract(['id', 'title', 'author_id'], true);
         $this->assertEquals($expected, $result);

+ 1 - 0
tests/TestCase/Routing/RouterTest.php

@@ -3017,6 +3017,7 @@ class RouterTest extends TestCase
     {
         $route1 = $this->getMockBuilder('Cake\Routing\Route\RedirectRoute')
             ->setConstructorArgs(['/mobile\''])
+            ->setMethods(['parse'])
             ->getMock();
         $class = '\\' . get_class($route1);
 

+ 18 - 0
tests/TestCase/View/Helper/FormHelperTest.php

@@ -4738,6 +4738,24 @@ class FormHelperTest extends TestCase
     }
 
     /**
+     * Test setting a hiddenField value on radio buttons.
+     *
+     * @return void
+     */
+    public function testRadioHiddenFieldValue()
+    {
+        $result = $this->Form->radio('title', ['option A'], ['hiddenField' => 'N']);
+        $expected = [
+            ['input' => ['type' => 'hidden', 'name' => 'title', 'value' => 'N']],
+            'label' => ['for' => 'title-0'],
+            ['input' => ['type' => 'radio', 'name' => 'title', 'value' => '0', 'id' => 'title-0']],
+            'option A',
+            '/label',
+        ];
+        $this->assertHtml($expected, $result);
+    }
+
+    /**
      * testControlRadio method
      *
      * Test that input works with radio types.

+ 5 - 1
tests/TestCase/View/Helper/RssHelperTest.php

@@ -260,7 +260,11 @@ class RssHelperTest extends TestCase
             ['title' => 'title3', 'guid' => 'http://www.example.com/guid3', 'link' => 'http://www.example.com/link3', 'description' => 'description3']
         ];
 
-        $result = $this->Rss->items($items, create_function('$v', '$v[\'title\'] = $v[\'title\'] . \'-transformed\'; return $v;'));
+        $result = $this->Rss->items($items, function ($v) {
+            $v['title'] = $v['title'] . '-transformed';
+
+            return $v;
+        });
         $expected = [
             '<item',
                 '<title', 'title1-transformed', '/title',