Allow Cells to be auto-located within */Cells directories (#6601)

* Allow Cells to be located in */Cell directories.

* Refactor to use factories.

* Apply suggestions from code review

Co-authored-by: kenjis <kenji.uui@gmail.com>

Co-authored-by: kenjis <kenji.uui@gmail.com>
This commit is contained in:
Lonnie Ezell 2022-09-30 08:09:17 -05:00 committed by GitHub
parent 00ff8f3ee3
commit adcfde7ca1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 63 additions and 12 deletions

View File

@ -640,6 +640,11 @@ parameters:
count: 2
path: system/View/Cell.php
-
message: "#^Call to an undefined static method CodeIgniter\\\\Config\\\\Factories\\:\\:cells\\(\\)\\.$#"
count: 1
path: system/View/Cell.php
-
message: "#^Property Config\\\\View\\:\\:\\$plugins \\(array\\) on left side of \\?\\? is not nullable\\.$#"
count: 1

View File

@ -12,6 +12,7 @@
namespace CodeIgniter\View;
use CodeIgniter\Cache\CacheInterface;
use CodeIgniter\Config\Factories;
use CodeIgniter\View\Exceptions\ViewException;
use Config\Services;
use ReflectionException;
@ -68,9 +69,13 @@ class Cell
*/
public function render(string $library, $params = null, int $ttl = 0, ?string $cacheName = null): string
{
[$class, $method] = $this->determineClass($library);
[$instance, $method] = $this->determineClass($library);
// Is it cached?
$class = is_object($instance)
? get_class($instance)
: null;
// Is the output cached?
$cacheName = ! empty($cacheName)
? $cacheName
: str_replace(['\\', '/'], '', $class) . $method . md5(serialize($params));
@ -79,9 +84,6 @@ class Cell
return $output;
}
// Not cached - so grab it...
$instance = new $class();
if (method_exists($instance, 'initController')) {
$instance->initController(Services::request(), Services::response(), Services::logger());
}
@ -197,7 +199,10 @@ class Cell
throw ViewException::forNoCellClass();
}
if (! class_exists($class, true)) {
// locate and return an instance of the cell
$class = Factories::cells($class);
if (! is_object($class)) {
throw ViewException::forInvalidCellClass($class);
}

View File

@ -0,0 +1,28 @@
<?php
/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <admin@codeigniter.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Tests\Support\Cells;
/**
* Class StarterCell
*
* This class is only used to provide a reference point
* during tests to make sure that things work as expected.
*/
class StarterCell
{
public function hello($params)
{
$name = $params['name'] ?? 'World';
return "Hello {$name}!";
}
}

View File

@ -251,4 +251,10 @@ final class CellTest extends CIUnitTestCase
{
$this->assertSame(Response::class, $this->cell->render('\Tests\Support\View\SampleClassWithInitController::index'));
}
public function testLocateCellSuccess()
{
$this->assertSame('Hello World!', $this->cell->render('StarterCell::hello'));
$this->assertSame('Hello CodeIgniter!', $this->cell->render('StarterCell::hello', ['name' => 'CodeIgniter']));
}
}

View File

@ -155,6 +155,7 @@ Others
- Added ``$routes->useSupportedLocalesOnly(true)`` so that the Router returns 404 Not Found if the locale in the URL is not supported in ``Config\App::$supportedLocales``. See :ref:`Localization <localization-in-routes>`
- Now you can specify Composer packages to auto-discover manually. See :ref:`Code Modules <modules-specify-composer-packages>`.
- Added new ``$routes->view()`` method to return a the view directly. See :ref:`View Routes <view-routes>`.
- View Cells are now first-class citizens and can located in the **app/Cells** directory. See :ref:`View Cells <view-cells-app-cells>`.
Changes
*******

View File

@ -2,16 +2,22 @@
View Cells
##########
View Cells allow you to insert HTML that is generated outside of your controller. It simply calls the specified
class and method, which must return a string of valid HTML. This method could be in any callable method, found in any class
that the autoloader can locate. The only restriction is that the class can not have any constructor parameters.
This is intended to be used within views, and is a great aid to modularizing your code.
View Cells allow you to insert HTML that is generated outside of your controller. It simply calls the specified class and method, which must return a string of valid HTML. This method could be in any callable method, found in any class that the autoloader can locate. The only restriction is that the class can not have any constructor parameters. This is intended to be used within views, and is a great aid to modularizing your code.
::
<?= view_cell('\App\Libraries\Blog::recentPosts') ?>
In this example, the class ``App\Libraries\Blog`` is loaded, and the method ``recentPosts()`` is run. The method
must return the generated HTML as a string. The method can be either a static method or not. Either way works.
In this example, the class ``App\Libraries\Blog`` is loaded, and the method ``recentPosts()`` is run. The method must return the generated HTML as a string. The method can be either a static method or not. Either way works.
.. _view-cells-app-cells:
app/Cells
---------
Since v4.3.0, if the Cell is a class, you can locate it in the **app/Cells** directory and it can be discovered automatically, allowing the use of just the class name and method::
<?= view_cell('Blog::recentPosts') ?>
This respects the :ref:`Factories preferApp option <factories-options>`, so if you have a class in both **app/Cells** and **MyNamespace/Cells**, the one in **app/Cells** will be used when ``preferApp`` is ``true``.
Cell Parameters
---------------