Browse Source

Merge branch 'master' into 3.next

Mark Story 8 years ago
parent
commit
d4eadb8a76

+ 6 - 2
src/Cache/Engine/RedisEngine.php

@@ -177,7 +177,9 @@ class RedisEngine extends CacheEngine
         $key = $this->_key($key);
 
         $value = (int)$this->_Redis->incrBy($key, $offset);
-        $this->_Redis->setTimeout($key, $duration);
+        if ($duration > 0) {
+            $this->_Redis->setTimeout($key, $duration);
+        }
 
         return $value;
     }
@@ -195,7 +197,9 @@ class RedisEngine extends CacheEngine
         $key = $this->_key($key);
 
         $value = (int)$this->_Redis->decrBy($key, $offset);
-        $this->_Redis->setTimeout($key, $duration);
+        if ($duration > 0) {
+            $this->_Redis->setTimeout($key, $duration);
+        }
 
         return $value;
     }

+ 2 - 2
src/Controller/Component/CookieComponent.php

@@ -316,8 +316,8 @@ class CookieComponent extends Component
             'expire' => $expires->format('U'),
             'path' => $config['path'],
             'domain' => $config['domain'],
-            'secure' => $config['secure'],
-            'httpOnly' => $config['httpOnly']
+            'secure' => (bool)$config['secure'],
+            'httpOnly' => (bool)$config['httpOnly']
         ]);
     }
 

+ 3 - 1
src/View/Helper.php

@@ -197,7 +197,9 @@ class Helper implements EventListenerInterface
      */
     public function addClass(array $options = [], $class = null, $key = 'class')
     {
-        if (isset($options[$key]) && trim($options[$key])) {
+        if (isset($options[$key]) && is_array($options[$key])) {
+            $options[$key][] = $class;
+        } elseif (isset($options[$key]) && trim($options[$key])) {
             $options[$key] .= ' ' . $class;
         } else {
             $options[$key] = $class;

+ 31 - 0
src/View/Helper/FormHelper.php

@@ -101,36 +101,67 @@ class FormHelper extends Helper
             'binary' => 'file',
         ],
         'templates' => [
+            // Used for button elements in button().
             'button' => '<button{{attrs}}>{{text}}</button>',
+            // Used for checkboxes in checkbox() and multiCheckbox().
             'checkbox' => '<input type="checkbox" name="{{name}}" value="{{value}}"{{attrs}}>',
+            // Input group wrapper for checkboxes created via control().
             'checkboxFormGroup' => '{{label}}',
+            // Wrapper container for checkboxes.
             'checkboxWrapper' => '<div class="checkbox">{{label}}</div>',
+            // Widget ordering for date/time/datetime pickers.
             'dateWidget' => '{{year}}{{month}}{{day}}{{hour}}{{minute}}{{second}}{{meridian}}',
+            // Error message wrapper elements.
             'error' => '<div class="error-message">{{content}}</div>',
+            // Container for error items.
             'errorList' => '<ul>{{content}}</ul>',
+            // Error item wrapper.
             'errorItem' => '<li>{{text}}</li>',
+            // File input used by file().
             'file' => '<input type="file" name="{{name}}"{{attrs}}>',
+            // Fieldset element used by allControls().
             'fieldset' => '<fieldset{{attrs}}>{{content}}</fieldset>',
+            // Open tag used by create().
             'formStart' => '<form{{attrs}}>',
+            // Close tag used by end().
             'formEnd' => '</form>',
+            // General grouping container for control(). Defines input/label ordering.
             'formGroup' => '{{label}}{{input}}',
+            // Wrapper content used to hide other content.
             'hiddenBlock' => '<div style="display:none;">{{content}}</div>',
+            // Generic input element.
             'input' => '<input type="{{type}}" name="{{name}}"{{attrs}}/>',
+            // Submit input element.
             'inputSubmit' => '<input type="{{type}}"{{attrs}}/>',
+            // Container element used by control().
             'inputContainer' => '<div class="input {{type}}{{required}}">{{content}}</div>',
+            // Container element used by control() when a field has an error.
             'inputContainerError' => '<div class="input {{type}}{{required}} error">{{content}}{{error}}</div>',
+            // Label element when inputs are not nested inside the label.
             'label' => '<label{{attrs}}>{{text}}</label>',
+            // Label element used for radio and multi-checkbox inputs.
             'nestingLabel' => '{{hidden}}<label{{attrs}}>{{input}}{{text}}</label>',
+            // Legends created by allControls()
             'legend' => '<legend>{{text}}</legend>',
+            // Multi-Checkbox input set title element.
             'multicheckboxTitle' => '<legend>{{text}}</legend>',
+            // Multi-Checkbox wrapping container.
             'multicheckboxWrapper' => '<fieldset{{attrs}}>{{content}}</fieldset>',
+            // Option element used in select pickers.
             'option' => '<option value="{{value}}"{{attrs}}>{{text}}</option>',
+            // Option group element used in select pickers.
             'optgroup' => '<optgroup label="{{label}}"{{attrs}}>{{content}}</optgroup>',
+            // Select element,
             'select' => '<select name="{{name}}"{{attrs}}>{{content}}</select>',
+            // Multi-select element,
             'selectMultiple' => '<select name="{{name}}[]" multiple="multiple"{{attrs}}>{{content}}</select>',
+            // Radio input element,
             'radio' => '<input type="radio" name="{{name}}" value="{{value}}"{{attrs}}>',
+            // Wrapping container for radio input/label,
             'radioWrapper' => '{{label}}',
+            // Textarea input element,
             'textarea' => '<textarea name="{{name}}"{{attrs}}>{{value}}</textarea>',
+            // Container for submit buttons.
             'submitContainer' => '<div class="submit">{{content}}</div>',
         ]
     ];

+ 21 - 0
tests/TestCase/Cache/Engine/RedisEngineTest.php

@@ -340,6 +340,27 @@ class RedisEngineTest extends TestCase
     }
 
     /**
+     * Test that increment() and decrement() can live forever.
+     *
+     * @return void
+     */
+    public function testIncrementDecrementForvever()
+    {
+        $this->_configCache(['duration' => 0]);
+        Cache::delete('test_increment', 'redis');
+        Cache::delete('test_decrement', 'redis');
+
+        $result = Cache::increment('test_increment', 1, 'redis');
+        $this->assertEquals(1, $result);
+
+        $result = Cache::decrement('test_decrement', 1, 'redis');
+        $this->assertEquals(-1, $result);
+
+        $this->assertEquals(1, Cache::read('test_increment', 'redis'));
+        $this->assertEquals(-1, Cache::read('test_decrement', 'redis'));
+    }
+
+    /**
      * Test that increment and decrement set ttls.
      *
      * @return void

+ 19 - 0
tests/TestCase/Controller/Component/CookieComponentTest.php

@@ -106,6 +106,25 @@ class CookieComponentTest extends TestCase
     }
 
     /**
+     * Test backwards compatibility with settings that use type juggling.
+     *
+     * @return void
+     */
+    public function testSettingsCompatibility()
+    {
+        $this->Cookie->config([
+            'expires' => '+10 seconds',
+            'path' => '/',
+            'domain' => '',
+            'secure' => 0,
+            'key' => 'somerandomhaskeysomerandomhaskey',
+            'encryption' => 0,
+        ]);
+        $this->Cookie->write('key', 'value');
+        $this->assertSame('value', $this->Cookie->read('key'));
+    }
+
+    /**
      * sets up some default cookie data.
      *
      * @return void

+ 61 - 0
tests/TestCase/View/HelperTest.php

@@ -188,4 +188,65 @@ class HelperTest extends TestCase
         $result = $Helper->__debugInfo();
         $this->assertEquals($expected, $result);
     }
+
+    /**
+     * Test addClass() with 'class' => array
+     *
+     * @return void
+     */
+    public function testAddClassArray()
+    {
+        $helper = new TestHelper($this->View);
+        $input = ['class' => ['element1', 'element2']];
+        $expected = ['class' => [
+            'element1',
+            'element2',
+            'element3'
+        ]];
+
+        $this->assertEquals($expected, $helper->addClass($input, 'element3'));
+    }
+
+    /**
+     * Test addClass() with 'class' => string
+     *
+     * @return void
+     */
+    public function testAddClassString()
+    {
+        $helper = new TestHelper($this->View);
+
+        $input = ['class' => 'element1 element2'];
+        $expected = ['class' => 'element1 element2 element3'];
+
+        $this->assertEquals($expected, $helper->addClass($input, 'element3'));
+    }
+
+    /**
+     * Test addClass() with no class element
+     *
+     * @return void
+     */
+    public function testAddClassEmpty()
+    {
+        $helper = new TestHelper($this->View);
+
+        $input = [];
+        $expected = ['class' => 'element3'];
+
+        $this->assertEquals($expected, $helper->addClass($input, 'element3'));
+    }
+
+    /**
+     * Test addClass() with adding null class
+     */
+    public function testAddClassNull()
+    {
+        $helper = new TestHelper($this->View);
+
+        $input = [];
+        $expected = ['class' => ''];
+
+        $this->assertEquals($expected, $helper->addClass($input, null));
+    }
 }