Browse Source

Merge branch 'master' into 3.1

Mark Story 10 years ago
parent
commit
aa824c7f81

+ 2 - 2
src/Network/Http/Adapter/Stream.php

@@ -266,8 +266,8 @@ class Stream
             throw new Exception('Connection timed out ' . $url);
         }
         $headers = $meta['wrapper_data'];
-        if (isset($meta['wrapper_type']) && strtolower($meta['wrapper_type']) === 'curl') {
-            $headers = $meta['wrapper_data']['headers'];
+        if (isset($headers['headers']) && is_array($headers['headers'])) {
+            $headers = $headers['headers'];
         }
         return $this->createResponses($headers, $content);
     }

+ 5 - 2
src/Network/Http/FormData.php

@@ -83,11 +83,12 @@ class FormData implements Countable
      * If the $value is an array, multiple parts will be added.
      * Files will be read from their current position and saved in memory.
      *
-     * @param string $name The name of the part.
+     * @param string|\Cake\Network\Http\FormData $name The name of the part to add,
+     *   or the part data object.
      * @param mixed $value The value for the part.
      * @return $this
      */
-    public function add($name, $value)
+    public function add($name, $value = null)
     {
         if (is_array($value)) {
             $this->addRecursive($name, $value);
@@ -100,6 +101,8 @@ class FormData implements Countable
                 E_USER_DEPRECATED
             );
             $this->_parts[] = $this->addFile($name, $value);
+        } elseif ($name instanceof Part && $value === null) {
+            $this->_parts[] = $name;
         } else {
             $this->_parts[] = $this->newPart($name, $value);
         }

+ 1 - 1
src/Network/Http/FormData/Part.php

@@ -112,7 +112,7 @@ class Part
     public function contentId($id = null)
     {
         if ($id === null) {
-            return $this->_contentId = $id;
+            return $this->_contentId;
         }
         $this->_contentId = $id;
     }

+ 3 - 0
src/ORM/Behavior/TranslateBehavior.php

@@ -448,6 +448,9 @@ class TranslateBehavior extends Behavior
     public function groupTranslations($results)
     {
         return $results->map(function ($row) {
+            if (!$row instanceof EntityInterface) {
+                return $row;
+            }
             $translations = (array)$row->get('_i18n');
             $grouped = new Collection($translations);
 

+ 7 - 0
src/ORM/EagerLoader.php

@@ -391,6 +391,13 @@ class EagerLoader
                 sprintf('%s is not associated with %s', $parent->alias(), $alias)
             );
         }
+        if ($instance->alias() !== $alias) {
+            throw new InvalidArgumentException(sprintf(
+                "You have contained '%s' but that association was bound as '%s'.",
+                $alias,
+                $instance->alias()
+            ));
+        }
 
         $paths += ['aliasPath' => '', 'propertyPath' => '', 'root' => $alias];
         $paths['aliasPath'] .= '.' . $alias;

+ 3 - 2
src/ORM/Table.php

@@ -1159,9 +1159,10 @@ class Table implements RepositoryInterface, EventListenerInterface, EventDispatc
 
         $cacheConfig = isset($options['cache']) ? $options['cache'] : false;
         $cacheKey = isset($options['key']) ? $options['key'] : false;
-        unset($options['key'], $options['cache']);
+        $finder = isset($options['finder']) ? $options['finder'] : 'all';
+        unset($options['key'], $options['cache'], $options['finder']);
 
-        $query = $this->find('all', $options)->where($conditions);
+        $query = $this->find($finder, $options)->where($conditions);
 
         if ($cacheConfig) {
             if (!$cacheKey) {

+ 1 - 1
src/Routing/RouteBuilder.php

@@ -112,7 +112,7 @@ class RouteBuilder
      * @param array $params The scope's routing parameters.
      * @param array $options Options list.
      */
-    public function __construct($collection, $path, array $params = [], array $options = [])
+    public function __construct(RouteCollection $collection, $path, array $params = [], array $options = [])
     {
         $this->_collection = $collection;
         $this->_path = $path;

+ 1 - 6
src/View/View.php

@@ -685,12 +685,7 @@ class View implements EventDispatcherInterface
      */
     public function append($name, $value = null)
     {
-        if ($value !== null) {
-            $this->Blocks->concat($name, $value);
-            return;
-        }
-        $this->Blocks->start($name);
-        echo $this->Blocks->get($name);
+        $this->Blocks->concat($name, $value);
     }
 
     /**

+ 28 - 7
src/View/ViewBlock.php

@@ -27,6 +27,13 @@ class ViewBlock
 {
 
     /**
+     * Override content
+     *
+     * @var string
+     */
+    const OVERRIDE = 'override';
+
+    /**
      * Append content
      *
      * @var string
@@ -72,15 +79,18 @@ class ViewBlock
      * using View::get();
      *
      * @param string $name The name of the block to capture for.
+     * @param string $mode If ViewBlock::OVERRIDE existing content will be overridden by new content.
+     *   If ViewBlock::APPEND content will be appended to existing content.
+     *   If ViewBlock::PREPEND it will be prepended.
      * @throws \Cake\Core\Exception\Exception When starting a block twice
      * @return void
      */
-    public function start($name)
+    public function start($name, $mode = ViewBlock::OVERRIDE)
     {
-        if (in_array($name, $this->_active)) {
+        if (in_array($name, array_keys($this->_active))) {
             throw new Exception(sprintf("A view block with the name '%s' is already/still open.", $name));
         }
-        $this->_active[] = $name;
+        $this->_active[$name] = $mode;
         ob_start();
     }
 
@@ -98,9 +108,14 @@ class ViewBlock
             return;
         }
         if (!empty($this->_active)) {
-            $active = end($this->_active);
+            $mode = end($this->_active);
+            $active = key($this->_active);
             $content = ob_get_clean();
-            $this->_blocks[$active] = $content;
+            if ($mode === ViewBlock::OVERRIDE) {
+                $this->_blocks[$active] = $content;
+            } else {
+                $this->concat($active, $content, $mode);
+            }
             array_pop($this->_active);
         }
     }
@@ -119,8 +134,13 @@ class ViewBlock
      *   If ViewBlock::PREPEND it will be prepended.
      * @return void
      */
-    public function concat($name, $value, $mode = ViewBlock::APPEND)
+    public function concat($name, $value = null, $mode = ViewBlock::APPEND)
     {
+        if ($value === null) {
+            $this->start($name, $mode);
+            return;
+        }
+
         if (!isset($this->_blocks[$name])) {
             $this->_blocks[$name] = '';
         }
@@ -187,7 +207,8 @@ class ViewBlock
      */
     public function active()
     {
-        return end($this->_active);
+        end($this->_active);
+        return key($this->_active);
     }
 
     /**

+ 28 - 0
tests/TestCase/Network/Http/FormDataTest.php

@@ -71,6 +71,34 @@ class FormDataTest extends TestCase
     }
 
     /**
+     * Test adding a part object.
+     *
+     * @return void
+     */
+    public function testAddPartObject()
+    {
+        $data = new FormData();
+        $boundary = $data->boundary();
+
+        $part = $data->newPart('test', 'value');
+        $part->contentId('abc123');
+        $data->add($part);
+
+        $this->assertCount(1, $data, 'Should have 1 part');
+        $expected = [
+            '--' . $boundary,
+            'Content-Disposition: form-data; name="test"',
+            'Content-ID: <abc123>',
+            '',
+            'value',
+            '--' . $boundary . '--',
+            '',
+            '',
+        ];
+        $this->assertEquals(implode("\r\n", $expected), (string)$data);
+    }
+
+    /**
      * Test adding parts that are arrays.
      *
      * @return void

+ 17 - 2
tests/TestCase/ORM/EagerLoaderTest.php

@@ -376,6 +376,21 @@ class EagerLoaderTest extends TestCase
     }
 
     /**
+     * Check that normalizing contains checks alias names.
+     *
+     * @expectedException \InvalidArgumentException
+     * @expectedExceptionMessage You have contained 'Clients' but that association was bound as 'clients'
+     * @return void
+     */
+    public function testNormalizedChecksAliasNames()
+    {
+        $contains = ['Clients'];
+        $loader = new EagerLoader;
+        $loader->contain($contains);
+        $loader->normalized($this->table);
+    }
+
+    /**
      * Tests that the path for gettings to a deep assocition is materialized in an
      * array key
      *
@@ -385,11 +400,11 @@ class EagerLoaderTest extends TestCase
     {
         $contains = [
             'clients' => [
-            'orders' => [
+                'orders' => [
                     'orderTypes',
                     'stuff' => ['stuffTypes']
                 ],
-            'companies' => [
+                'companies' => [
                     'categories'
                 ]
             ]

+ 59 - 7
tests/TestCase/ORM/TableTest.php

@@ -3277,7 +3277,7 @@ class TableTest extends TestCase
     public function testSaveBelongsToManyJoinData()
     {
         $articles = TableRegistry::get('Articles');
-        $article = $articles->get(1, ['contain' => ['Tags']]);
+        $article = $articles->get(1, ['contain' => ['tags']]);
         $data = [
             'tags' => [
                 ['id' => 1, '_joinData' => ['highlighted' => 1]],
@@ -3376,7 +3376,7 @@ class TableTest extends TestCase
             'saveStrategy' => 'replace',
         ]);
 
-        $entity = $table->get(1, ['contain' => 'Tags']);
+        $entity = $table->get(1, ['contain' => 'tags']);
         $this->assertCount(2, $entity->tags, 'Fixture data did not change.');
 
         $entity->tags = [];
@@ -3384,7 +3384,7 @@ class TableTest extends TestCase
         $this->assertSame($result, $entity);
         $this->assertSame([], $entity->tags, 'No tags on the entity.');
 
-        $entity = $table->get(1, ['contain' => 'Tags']);
+        $entity = $table->get(1, ['contain' => 'tags']);
         $this->assertSame([], $entity->tags, 'No tags in the db either.');
     }
 
@@ -3401,7 +3401,7 @@ class TableTest extends TestCase
             'saveStrategy' => 'replace',
         ]);
 
-        $entity = $table->get(1, ['contain' => 'Tags']);
+        $entity = $table->get(1, ['contain' => 'tags']);
         $this->assertCount(2, $entity->tags, 'Fixture data did not change.');
 
         $tag = new \Cake\ORM\Entity([
@@ -3413,7 +3413,7 @@ class TableTest extends TestCase
         $this->assertCount(1, $entity->tags, 'Only one tag left.');
         $this->assertEquals($tag, $entity->tags[0]);
 
-        $entity = $table->get(1, ['contain' => 'Tags']);
+        $entity = $table->get(1, ['contain' => 'tags']);
         $this->assertCount(1, $entity->tags, 'Only one tag in the db.');
         $this->assertEquals($tag->id, $entity->tags[0]->id);
     }
@@ -3425,8 +3425,8 @@ class TableTest extends TestCase
      */
     public function testSaveBelongsToManyIgnoreNonEntityData()
     {
-        $articles = TableRegistry::get('Articles');
-        $article = $articles->get(1, ['contain' => ['Tags']]);
+        $articles = TableRegistry::get('articles');
+        $article = $articles->get(1, ['contain' => ['tags']]);
         $article->tags = [
             '_ids' => [2, 1]
         ];
@@ -3822,6 +3822,58 @@ class TableTest extends TestCase
         $this->assertSame($entity, $result);
     }
 
+    public function providerForTestGetWithCustomFinder()
+    {
+        return [
+            [ ['fields' => ['id'], 'finder' => 'custom'] ]
+        ];
+    }
+
+    /**
+     * Test that get() will call a custom finder.
+     *
+     * @dataProvider providerForTestGetWithCustomFinder
+     * @param array $options
+     * @return void
+     */
+    public function testGetWithCustomFinder($options)
+    {
+        $table = $this->getMock(
+            '\Cake\ORM\Table',
+            ['callFinder', 'query'],
+            [[
+                'connection' => $this->connection,
+                'schema' => [
+                    'id' => ['type' => 'integer'],
+                    'bar' => ['type' => 'integer'],
+                    '_constraints' => ['primary' => ['type' => 'primary', 'columns' => ['bar']]]
+                ]
+            ]]
+        );
+
+        $query = $this->getMock(
+            '\Cake\ORM\Query',
+            ['addDefaultTypes', 'firstOrFail', 'where', 'cache'],
+            [$this->connection, $table]
+        );
+
+        $entity = new \Cake\ORM\Entity;
+        $table->expects($this->once())->method('query')
+            ->will($this->returnValue($query));
+        $table->expects($this->once())->method('callFinder')
+            ->with('custom', $query, ['fields' => ['id']])
+            ->will($this->returnValue($query));
+
+        $query->expects($this->once())->method('where')
+            ->with([$table->alias() . '.bar' => 10])
+            ->will($this->returnSelf());
+        $query->expects($this->never())->method('cache');
+        $query->expects($this->once())->method('firstOrFail')
+            ->will($this->returnValue($entity));
+        $result = $table->get(10, $options);
+        $this->assertSame($entity, $result);
+    }
+
     public function providerForTestGetWithCache()
     {
         return [