Browse Source

Merge pull request #8182 from cakephp/issue-8163

Fix setting the template from the action of a Cell.
Mark Story 10 years ago
parent
commit
5adff0bc23

+ 12 - 12
src/View/Cell.php

@@ -176,6 +176,17 @@ abstract class Cell
         }
 
         $render = function () use ($template) {
+            try {
+                $reflect = new ReflectionMethod($this, $this->action);
+                $reflect->invokeArgs($this, $this->args);
+            } catch (ReflectionException $e) {
+                throw new BadMethodCallException(sprintf(
+                    'Class %s does not have a "%s" method.',
+                    get_class($this),
+                    $this->action
+                ));
+            }
+
             if ($template !== null &&
                 strpos($template, '/') === false &&
                 strpos($template, '.') === false
@@ -183,7 +194,7 @@ abstract class Cell
                 $template = Inflector::underscore($template);
             }
             if ($template === null) {
-                $template = $this->template;
+                $template = $this->viewBuilder()->template() ?: $this->template;
             }
 
             $builder = $this->viewBuilder();
@@ -194,17 +205,6 @@ abstract class Cell
             $name = substr($className, 0, -4);
             $builder->templatePath('Cell' . DS . $name);
 
-            try {
-                $reflect = new ReflectionMethod($this, $this->action);
-                $reflect->invokeArgs($this, $this->args);
-            } catch (ReflectionException $e) {
-                throw new BadMethodCallException(sprintf(
-                    'Class %s does not have a "%s" method.',
-                    get_class($this),
-                    $this->action
-                ));
-            }
-
             $this->View = $this->createView();
             try {
                 return $this->View->render($template);

+ 73 - 4
tests/TestCase/View/CellTest.php

@@ -15,13 +15,9 @@
 namespace Cake\Test\TestCase\View;
 
 use Cake\Cache\Cache;
-use Cake\Controller\Controller;
 use Cake\Core\Configure;
 use Cake\Core\Plugin;
-use Cake\Event\EventManager;
 use Cake\TestSuite\TestCase;
-use Cake\View\Cell;
-use Cake\View\CellTrait;
 use TestApp\View\CustomJsonView;
 
 /**
@@ -133,6 +129,33 @@ class CellTest extends TestCase
     }
 
     /**
+     * Tests that cell action setting the template using the property renders the correct template
+     *
+     * @return void
+     */
+    public function testSettingCellTemplateFromAction()
+    {
+        $appCell = $this->View->cell('Articles::customTemplate');
+
+        $this->assertContains('This is the alternate template', "{$appCell}");
+        $this->assertEquals('alternate_teaser_list', $appCell->template);
+        $this->assertEquals('alternate_teaser_list', $appCell->viewBuilder()->template());
+    }
+
+    /**
+     * Tests that cell action setting the template using the ViewBuilder renders the correct template
+     *
+     * @return void
+     */
+    public function testSettingCellTemplateFromActionViewBuilder()
+    {
+        $appCell = $this->View->cell('Articles::customTemplateViewBuilder');
+
+        $this->assertContains('This is the alternate template', "{$appCell}");
+        $this->assertEquals('alternate_teaser_list', $appCell->viewBuilder()->template());
+    }
+
+    /**
      * Tests manual render() invocation.
      *
      * @return void
@@ -361,4 +384,50 @@ class CellTest extends TestCase
         $this->assertEquals("dummy\n", $result);
         Cache::drop('cell');
     }
+
+    /**
+     * Test cached render when using an action changing the template used
+     *
+     * @return void
+     */
+    public function testCachedRenderSimpleCustomTemplate()
+    {
+        $mock = $this->getMock('Cake\Cache\CacheEngine');
+        $mock->method('init')
+            ->will($this->returnValue(true));
+        $mock->method('read')
+            ->will($this->returnValue(false));
+        $mock->expects($this->once())
+            ->method('write')
+            ->with('cell_test_app_view_cell_articles_cell_customTemplate', "<h1>This is the alternate template</h1>\n");
+        Cache::config('default', $mock);
+
+        $cell = $this->View->cell('Articles::customTemplate', [], ['cache' => true]);
+        $result = $cell->render();
+        $this->assertContains('This is the alternate template', $result);
+
+        Cache::drop('default');
+    }
+
+    /**
+     * Test that when the cell cache is enabled, the cell action is only invoke the first
+     * time the cell is rendered
+     *
+     * @return void
+     */
+    public function testCachedRenderSimpleCustomTemplateViewBuilder()
+    {
+        Cache::config('default', [
+            'className' => 'File',
+            'path' => CACHE,
+        ]);
+        $cell = $this->View->cell('Articles::customTemplateViewBuilder', [], ['cache' => ['key' => 'celltest']]);
+        $result = $cell->render();
+        $this->assertEquals(1, $cell->counter);
+        $cell->render();
+        $this->assertEquals(1, $cell->counter);
+        $this->assertContains('This is the alternate template', $result);
+        Cache::delete('celltest');
+        Cache::drop('default');
+    }
 }

+ 1 - 0
tests/test_app/TestApp/Template/Cell/Articles/alternate_teaser_list.ctp

@@ -0,0 +1 @@
+<h1>This is the alternate template</h1>

+ 31 - 0
tests/test_app/TestApp/View/Cell/ArticlesCell.php

@@ -28,6 +28,13 @@ class ArticlesCell extends \Cake\View\Cell
     protected $_validCellOptions = ['limit', 'page'];
 
     /**
+     * Counter used to test the cache cell feature
+     *
+     * @return void
+     */
+    public $counter = 0;
+
+    /**
      * Default cell action.
      *
      * @return void
@@ -52,6 +59,30 @@ class ArticlesCell extends \Cake\View\Cell
     }
 
     /**
+     * Renders a view using a different template than the action name
+     * The template is set using the ``Cell::$template`` property
+     *
+     * @return void
+     */
+    public function customTemplate()
+    {
+        $this->template = 'alternate_teaser_list';
+    }
+
+    /**
+     * Renders a view using a different template than the action name
+     * The template is set using the ViewBuilder bound to the Cell
+     *
+     * @return void
+     */
+    public function customTemplateViewBuilder()
+    {
+        $this->template = 'derp';
+        $this->counter++;
+        $this->viewBuilder()->template('alternate_teaser_list');
+    }
+
+    /**
      * Simple echo.
      *
      * @param string $msg1