Refactor producing RendererInterface

This commit is contained in:
Master Yoda 2016-08-31 16:38:08 -07:00
parent 0d5cef9d36
commit 6e8b43a9f3
No known key found for this signature in database
GPG Key ID: CED549230775AD5B
13 changed files with 180 additions and 49 deletions

View File

@ -3,7 +3,7 @@
use CodeIgniter\Config\BaseConfig;
use CodeIgniter\Database\ConnectionInterface;
use CodeIgniter\Database\MigrationRunner;
use CodeIgniter\View\RenderableInterface;
use CodeIgniter\View\RendererInterface;
/**
* Services Configuration file.
@ -277,7 +277,7 @@ class Services
//--------------------------------------------------------------------
public static function pager($config = null, RenderableInterface $view = null, $getShared = true)
public static function pager($config = null, RendererInterface $view = null, $getShared = true)
{
if ($getShared)
{
@ -289,7 +289,7 @@ class Services
$config = new Pager();
}
if (! $view instanceof RenderableInterface)
if (! $view instanceof RendererInterface)
{
$view = self::renderer();
}

View File

@ -88,7 +88,7 @@ if (! function_exists('cache'))
if ( ! function_exists('view'))
{
/**
* Grabs the current RenderableInterface-compatible class
* Grabs the current RendererInterface-compatible class
* and tells it to render the specified view. Simply provides
* a convenience method that can be used in Controllers,
* libraries, and routed closures.

View File

@ -175,7 +175,7 @@ class AutoloadConfig
'CodeIgniter\Session\Handlers\FileHandler' => BASEPATH.'Session/Handlers/FileHandler.php',
'CodeIgniter\Session\Handlers\MemcachedHandler' => BASEPATH.'Session/Handlers/MemcachedHandler.php',
'CodeIgniter\Session\Handlers\RedisHandler' => BASEPATH.'Session/Handlers/RedisHandler.php',
'CodeIgniter\View\RenderableInterface' => BASEPATH.'View/RenderableInterface.php',
'CodeIgniter\View\RendererInterface' => BASEPATH.'View/RendererInterface.php',
'CodeIgniter\View\View' => BASEPATH.'View/View.php',
'Zend\Escaper\Escaper' => BASEPATH.'ThirdParty/ZendEscaper/Escaper.php',
'CodeIgniter\Log\TestLogger' => BASEPATH.'../tests/_support/Log/TestLogger.php',

View File

@ -37,7 +37,7 @@
*/
use CodeIgniter\Services;
use CodeIgniter\View\RenderableInterface;
use CodeIgniter\View\RendererInterface;
/**
* Views collector
@ -78,7 +78,7 @@ class Views extends BaseCollector
/**
* Instance of the Renderer service
* @var RenderableInterface
* @var RendererInterface
*/
protected $viewer;

View File

@ -37,7 +37,7 @@
*/
use Config\Services;
use CodeIgniter\View\RenderableInterface;
use CodeIgniter\View\RendererInterface;
/**
* Class Pager
@ -68,13 +68,13 @@ class Pager implements PagerInterface
/**
* The view engine to render the links with.
*
* @var RenderableInterface
* @var RendererInterface
*/
protected $view;
//--------------------------------------------------------------------
public function __construct($config, RenderableInterface $view)
public function __construct($config, RendererInterface $view)
{
$this->config = $config;
$this->view = $view;

View File

@ -37,13 +37,13 @@
*/
/**
* Interface RenderableInterface
* Interface RendererInterface
*
* The interface used for displaying Views and/or theme files.
*
* @package CodeIgniter\View
*/
interface RenderableInterface {
interface RendererInterface {
/**
* Builds the output based upon a file name and any
@ -62,6 +62,23 @@ interface RenderableInterface {
//--------------------------------------------------------------------
/**
* Builds the output based upon a string and any
* data that has already been set.
*
* @param string $view The view contents
* @param array $options Reserved for 3rd-party uses since
* it might be needed to pass additional info
* to other template engines.
* @param bool $saveData If true, will save data for use with any other calls,
* if false, will clean the data after displaying the view.
*
* @return string
*/
public function renderString(string $view, array $options=null, bool $saveData=false): string;
//--------------------------------------------------------------------
/**
* Sets several pieces of view data at once.
*
@ -69,7 +86,7 @@ interface RenderableInterface {
* @param string $context The context to escape it for: html, css, js, url
* If 'raw', no escaping will happen
*
* @return RenderableInterface
* @return RendererInterface
*/
public function setData(array $data=[], string $context=null);
@ -83,7 +100,7 @@ interface RenderableInterface {
* @param string $context The context to escape it for: html, css, js, url
* If 'raw' no escaping will happen
*
* @return RenderableInterface
* @return RendererInterface
*/
public function setVar(string $name, $value=null, string $context=null);
@ -92,7 +109,7 @@ interface RenderableInterface {
/**
* Removes all of the view data from the system.
*
* @return RenderableInterface
* @return RendererInterface
*/
public function resetData();

View File

@ -46,7 +46,7 @@ use CodeIgniter\Log\Logger;
*
* @package CodeIgniter\View
*/
class View implements RenderableInterface {
class View implements RendererInterface {
/**
* Data that is made available to the Views.
@ -184,6 +184,57 @@ class View implements RenderableInterface {
//--------------------------------------------------------------------
/**
* Builds the output based upon a string and any
* data that has already been set.
* Cache does not apply, because there is no "key".
*
* @param string $view The view contents
* @param array $options Reserved for 3rd-party uses since
* it might be needed to pass additional info
* to other template engines.
* @param bool $saveData If true, will save data for use with any other calls,
* if false, will clean the data after displaying the view.
*
* @return string
*/
public function renderString(string $view, array $options = null, bool $saveData = false): string
{
$start = microtime(true);
extract($this->data);
if ( ! $saveData)
{
$this->data = [];
}
ob_start();
$incoming = "?>".$view;
eval($incoming);
$output = ob_get_contents();
@ob_end_clean();
$this->logPerformance($start, microtime(true), $this->excerpt($view));
return $output;
}
//--------------------------------------------------------------------
/**
* Extract first bit of a long string and add ellipsis
*
* @param string $string
* @parm int $length
* @return string
*/
public function excerpt(string $string, int $length = 20): string
{
return (strlen($string) > $length) ? substr($string, 0, $length - 3).'...' : $string;
}
//--------------------------------------------------------------------
/**
* Sets several pieces of view data at once.
*
@ -191,9 +242,9 @@ class View implements RenderableInterface {
* @param string $context The context to escape it for: html, css, js, url
* If null, no escaping will happen
*
* @return RenderableInterface
* @return RendererInterface
*/
public function setData(array $data=[], string $context=null): RenderableInterface
public function setData(array $data=[], string $context=null): RendererInterface
{
if (! empty($context))
{
@ -215,9 +266,9 @@ class View implements RenderableInterface {
* @param string $context The context to escape it for: html, css, js, url
* If null, no escaping will happen
*
* @return RenderableInterface
* @return RendererInterface
*/
public function setVar(string $name, $value=null, string $context=null): RenderableInterface
public function setVar(string $name, $value=null, string $context=null): RendererInterface
{
if (! empty($context))
{
@ -234,7 +285,7 @@ class View implements RenderableInterface {
/**
* Removes all of the view data from the system.
*
* @return RenderableInterface
* @return RendererInterface
*/
public function resetData()
{

View File

@ -139,6 +139,18 @@ class ViewTest extends \CIUnitTestCase
//--------------------------------------------------------------------
public function testRenderString()
{
$view = new View($this->viewsDir, $this->loader);
$view->setVar('testString', 'Hello World');
$expected = '<h1>Hello World</h1>';
$this->assertEquals($expected, $view->renderString('<h1><?= $testString ?></h1>'));
}
//--------------------------------------------------------------------
public function testRendersThrowsExceptionIfFileNotFound()
{
$view = new View($this->viewsDir, $this->loader);

View File

@ -63,7 +63,7 @@ New packages:
- View
- Zend \\ Escaper, Exception \\ ... **third party**
- RenderableInterface, View
- RendererInterface, View
User Guide adapted or rewritten.

View File

@ -100,7 +100,7 @@ Service Accessors
:returns: The output from the view.
:rtype: string
Grabs the current RenderableInterface-compatible class
Grabs the current RendererInterface-compatible class
and tells it to render the specified view. Simply provides
a convenience method that can be used in Controllers,
libraries, and routed closures.

View File

@ -65,4 +65,3 @@ as the fourth parameter::
// Cache the view for 5 minutes
<?= view_cell('\App\Libraries\Blog::recentPosts', 'limit=5', 300, 'newcacheid') ?>

View File

@ -2,26 +2,52 @@
View Renderer
#############
The ``view()`` function is a convenience method that grabs an instance of the ``renderer`` service,
sets the data, and renders the view. While this is often exactly what you want, you may find times where you
want to work with it more directly. In that case you can access the View service directly::
The ``view()`` function is a convenience function that grabs an instance of the
``renderer`` service, sets the data, and renders the view. While this is often
exactly what you want, you may find times where you want to work with it more directly.
In that case you can access the View service directly::
$renderer = \Config\Services::renderer();
$view = \Config\Services::renderer();
.. important:: You should create services only within controllers. If you need access to the View class
from a library, you should set that as a dependency in the constructor.
Alternately, if you are not using the ``View`` class as your default renderer, you
can instantiate it directly::
$view = new \CodeIgniter\View\View();
.. important:: You should create services only within controllers. If you need
access to the View class from a library, you should set that as a dependency
in your library's constructor.
Then you can use any of the three standard methods that it provides:
**render(viewpath, options, save)**, **setVar(name, value, context)** and **setData(data, context)**.
What It Does
============
The ``View`` class processes conventional HTML/PHP scripts stored in the application's view path,
after extracting view parameters into PHP variables, accessible inside the scripts.
This means that your view parameter names need to be legal PHP variable names.
The View class uses an associative array internally, to accumulate view parameters
until you call its ``render()``. This means that your parameter (or variable) names
need to be unique, or a later variable setting will over-ride an earlier one.
This also impacts escaping parameter values for different contexts inside your
script. You will have to give each escaped value a unique parameter name.
No special meaning is attached to parameters whose value is an array. It is up
to you to process the array appropriately in your PHP code.
Method Chaining
===============
The `setVar()` and `setData()` methods are chainable, allowing you to combine a number of different calls together in a chain::
The `setVar()` and `setData()` methods are chainable, allowing you to combine a
number of different calls together in a chain::
service('renderer')->setVar('one', $one)
->setVar('two', $two)
->render('myView');
$view->setVar('one', $one)
->setVar('two', $two)
->render('myView');
Escaping Data
=============
@ -32,13 +58,13 @@ escape the data for. See below for context descriptions.
If you don't want the data to be escaped, you can pass `null` or `raw` as the final parameter to each function::
$renderer->setVar('one', $one, 'raw');
$view->setVar('one', $one, 'raw');
If you choose not to escape data, or you are passing in an object instance, you can manually escape the data within
the view with the ``esc()`` function. The first parameter is the string to escape. The second parameter is the
context to escape the data for (see below)::
<?= esc($object->getStat()) ?>
<?= \esc($object->getStat()) ?>
Escaping Contexts
-----------------
@ -60,11 +86,23 @@ context as the second parameter. Valid contexts are 'html', 'js', 'css', 'url',
}
</style>
View Renderer Options
=====================
Several options can be passed to the ``render()`` or ``renderString()`` methods:
- ``cache`` - the time in seconds, to save a view's results; ignored for renderString()
- ``cache_name`` - the ID used to save/retrieve a cached view result; defaults to the viewpath;
ignored for renderString()
- ``saveData`` - true if the view data parameters should be retained for subsequent calls
***************
Class Reference
***************
.. php:interface:: CodeIgniter\\View\\RendererableInterface
.. php:class:: CodeIgniter\\View\\View
.. php:method:: render($view[, $options[, $saveData=false]]])
@ -76,41 +114,56 @@ Class Reference
Builds the output based upon a file name and any data that has already been set::
echo $renderer->render('myview');
echo $view->render('myview');
Options supported:
.. php:method:: renderString($view[, $options[, $saveData=false]]])
- ``cache`` - the time in seconds, to save a view's results
- ``cache_name`` - the ID used to save/retrieve a cached view result; defaults to the viewpath
- ``saveData`` - true if the view data parameter should be retained for subsequent calls
:param string $view: Contents of the view to render, for instance content retrieved from a database
:param array $options: Array of options, as key/value pairs
:param boolean $saveData: If true, will save data for use with any other calls, if false, will clean the data after rendering the view.
:returns: The rendered text for the chosen view
:rtype: string
Builds the output based upon a view fragment and any data that has already been set::
echo $view->renderString('<div>My Sharona</div>');
This could be used for displaying content that might have been stored in a database,
but you need to be aware that this is a potential security vulnerability,
and that you **must** validate any such data, and probably escape it
appropriately!
.. php:method:: setData([$data[, $context=null]])
:param array $data: Array of view data strings, as key/value pairs
:param string $context: The context to use for data escaping.
:returns: The Renderer, for method chaining
:rtype: CodeIgniter\\View\\RenderableInterface.
:rtype: CodeIgniter\\View\\RendererInterface.
Sets several pieces of view data at once::
$renderer->setData(['name'=>'George', 'position'=>'Boss']);
$view->setData(['name'=>'George', 'position'=>'Boss']);
Supported escape contexts: html, css, js, url, or attr or raw.
If 'raw', no escaping will happen.
Each call adds to the array of data that the object is accumulating,
until the view is rendered.
.. php:method:: setVar($name[, $value=null[, $context=null]])
:param string $name: Name of the view data variable
:param mixed $value: The value of this view data
:param string $context: The context to use for data escaping.
:returns: The Renderer, for method chaining
:rtype: CodeIgniter\\View\\RenderableInterface.
:rtype: CodeIgniter\\View\\RendererInterface.
Sets a single piece of view data::
$renderer->setVar('name','Joe','html');
$view->setVar('name','Joe','html');
Supported escape contexts: html, css, js, url, attr or raw.
If 'raw', no escaping will happen.
If you use the a view data variable that you have previously used
for this object, the new value will replace the existing one.

View File

@ -31,9 +31,9 @@ Then save the file in your **application/Views** directory.
Displaying a View
=================
To load a particular view file you will use the following function::
To load and display a particular view file you will use the following function::
view('name');
echo view('name');
Where _name_ is the name of your view file.
@ -214,4 +214,3 @@ Now open your view file and create a loop::
</body>
</html>