Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
86.96% |
20 / 23 |
CRAP | |
93.59% |
73 / 78 |
View | |
0.00% |
0 / 1 |
|
86.96% |
20 / 23 |
37.36 | |
93.59% |
73 / 78 |
__construct(Escaper $escaper = null, Request $request = null) | |
100.00% |
1 / 1 |
3 | |
100.00% |
4 / 4 |
|||
init() | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
assign($name, $value = null) | |
100.00% |
1 / 1 |
3 | |
100.00% |
7 / 7 |
|||
assignInstance($name, $instance) | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
registerHelper($name, $className) | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
__get($name) | |
100.00% |
1 / 1 |
2 | |
100.00% |
3 / 3 |
|||
__set($name, $value) | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
__isset($name) | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
__call($method, $args) | |
100.00% |
1 / 1 |
2 | |
100.00% |
4 / 4 |
|||
helper($name) | |
100.00% |
1 / 1 |
3 | |
100.00% |
6 / 6 |
|||
partial($template, array $data, $scriptPath = null) | |
0.00% |
0 / 1 |
5.20 | |
80.00% |
12 / 15 |
|||
getRequest() | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
getEscaper() | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
setScriptPath($path) | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
render($template) | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
escapeHtml($string) | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
escapeHtmlAttr($string) | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
escapeJs($string) | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
encodeJsonHtmlSafe($input) | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
escapeUrl($string) | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
escapeCss($string) | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
instantiateHelper($name) | |
100.00% |
1 / 1 |
1 | |
100.00% |
4 / 4 |
|||
castEscaperStringValue($input) | |
100.00% |
1 / 1 |
3 | |
100.00% |
4 / 4 |
<?php | |
/** | |
* Dewdrop | |
* | |
* @link https://github.com/DeltaSystems/dewdrop | |
* @copyright Delta Systems (http://deltasys.com) | |
* @license https://github.com/DeltaSystems/dewdrop/LICENSE | |
*/ | |
namespace Dewdrop\View; | |
use Dewdrop\Exception; | |
use Dewdrop\Pimple; | |
use Dewdrop\Request; | |
use Dewdrop\View\Helper\PageDelegateInterface; | |
use Zend\Escaper\Escaper; | |
// Solely for static analysis assistance | |
use Dewdrop\Fields\Helper\TableCell; | |
use Dewdrop\Fields\Listing\BulkActions; | |
use Dewdrop\View\Helper; | |
use Dewdrop\View\Helper\BulkActionCheckboxField; | |
/** | |
* A simple view implementation that allows for simple assignment of data, | |
* escaping for common contexts (e.g. HTML, HTML attribute, JS, etc.), | |
* and calling of helper objects for reusable view logic. | |
* | |
* Including method annotations here (http://www.phpdoc.org/docs/latest/references/phpdoc/tags/method.html) | |
* to assist static analysis in PHPStorm and Scrutinizer CI given the use | |
* of the __call() magic method in this class for view helpers. Won't cover | |
* us on custom helpers necessarily, but it will help catch most bugs/typos. | |
* | |
* @method string adminComponentNav() | |
* @method string adminNotice() | |
* @method string adminUrl() | |
* @method string bootstrapColumnsModal() | |
* @method string bootstrapDetailsView() | |
* @method mixed bootstrapFilterForm() | |
* @method mixed bootstrapForm() | |
* @method string bootstrapInputText() | |
* @method Helper\BootstrapRowActions bootstrapRowActions() | |
* @method string bootstrapSelect() | |
* @method mixed bootstrapTable() | |
* @method string bootstrapTextarea() | |
* @method string bowerUrl(string $url, string $wwwPath = null, string $docRoot = null) | |
* @method Helper\BulkActionForm bulkActionForm() | |
* @method BulkActionCheckboxField bulkActionCheckboxField(BulkActions $bulkActions, TableCell $tableCellRenderer) | |
* @method string checkboxList() | |
* @method \Dewdrop\Fields\Helper\CsvCell csvCellRenderer() | |
* @method string csvExport() | |
* @method Helper\DetectEditHelper detectEditHelper() | |
* @method Helper\EditForm editForm() | |
* @method \Dewdrop\Fields\Helper\EditControl editControlRenderer() | |
* @method \Zend\View\Helper\HeadLink headLink() | |
* @method \Zend\View\Helper\HeadMeta headMeta() | |
* @method \Zend\View\Helper\HeadScript headScript() | |
* @method \Zend\View\Helper\HeadStyle headStyle() | |
* @method void inlineScript() | |
* @method string inputCheckbox() | |
* @method string inputText() | |
* @method string inputTimestamp() | |
* @method string pagination() | |
* @method string select() | |
* @method string summernote() | |
* @method mixed table() | |
* @method \Dewdrop\Fields\Helper\TableCell tableCellRenderer() | |
* @method Helper\TableSortHandle tableSortHandle() | |
* @method string textarea() | |
* @method mixed urlCachePrefix() | |
* @method string wpAdminNotice() | |
* @method string wpCheckboxList() | |
* @method string wpColorPicker() | |
* @method Helper\WpEditForm wpEditForm() | |
* @method string wpEditor() | |
* @method Helper\WpEditRow wpEditRow() | |
* @method string wpImagePicker() | |
* @method string wpInputCheckbox() | |
* @method string wpInputText() | |
* @method string wpSelect() | |
* @method mixed wpTable() | |
* @method Helper\WpWrap wpWrap() | |
* @method Helper\Wrap wrap() | |
*/ | |
class View | |
{ | |
/** | |
* The data assigned to this view. Usually, a controller will be | |
* responsible for passing data to the view object using the assign() | |
* method. | |
* | |
* @var array | |
*/ | |
private $internalViewData = array(); | |
/** | |
* Helper instances created by calls to instantiateHelper(). | |
* | |
* @var array | |
*/ | |
private $helpers = array(); | |
/** | |
* The path in which to look for view scripts. | |
* | |
* @var string | |
*/ | |
private $scriptPath; | |
/** | |
* The current HTTP request. | |
* | |
* @var \Dewdrop\Request | |
*/ | |
private $request; | |
/** | |
* The available helper names and their associated classes. | |
* | |
* @var array | |
*/ | |
private $helperClasses = array( | |
'admincomponentnav' => '\Dewdrop\View\Helper\AdminComponentNav', | |
'adminnotice' => '\Dewdrop\View\Helper\AdminNotice', | |
'adminurl' => '\Dewdrop\View\Helper\AdminUrl', | |
'bootstraptable' => '\Dewdrop\View\Helper\BootstrapTable', | |
'bootstrapcolumnsmodal' => '\Dewdrop\View\Helper\BootstrapColumnsModal', | |
'bootstrapdetailsview' => '\Dewdrop\View\Helper\BootstrapDetailsView', | |
'bootstrapfilterform' => '\Dewdrop\View\Helper\BootstrapFilterForm', | |
'bootstrapform' => '\Dewdrop\View\Helper\BootstrapForm', | |
'bootstrapinputtext' => '\Dewdrop\View\Helper\BootstrapInputText', | |
'bootstraprowactions' => '\Dewdrop\View\Helper\BootstrapRowActions', | |
'bootstrapselect' => '\Dewdrop\View\Helper\BootstrapSelect', | |
'bootstraptextarea' => '\Dewdrop\View\Helper\BootstrapTextarea', | |
'bowerurl' => '\Dewdrop\View\Helper\BowerUrl', | |
'bulkactionform' => '\Dewdrop\View\Helper\BulkActionForm', | |
'bulkactioncheckboxfield' => '\Dewdrop\View\Helper\BulkActionCheckboxField', | |
'checkboxlist' => '\Dewdrop\View\Helper\CheckboxList', | |
'csvcellrenderer' => '\Dewdrop\View\Helper\CsvCellRenderer', | |
'csvexport' => '\Dewdrop\View\Helper\CsvExport', | |
'detectedithelper' => '\Dewdrop\View\Helper\DetectEditHelper', | |
'editform' => '\Dewdrop\View\Helper\EditForm', | |
'editcontrolrenderer' => '\Dewdrop\View\Helper\EditControlRenderer', | |
'headlink' => '\Zend\View\Helper\HeadLink', | |
'headmeta' => '\Zend\View\Helper\HeadMeta', | |
'headscript' => '\Zend\View\Helper\HeadScript', | |
'headstyle' => '\Zend\View\Helper\HeadStyle', | |
'inlinescript' => '\Dewdrop\View\Helper\InlineScript', | |
'inputcheckbox' => '\Dewdrop\View\Helper\InputCheckbox', | |
'inputtext' => '\Dewdrop\View\Helper\InputText', | |
'inputtimestamp' => '\Dewdrop\View\Helper\InputTimestamp', | |
'pagination' => '\Dewdrop\View\Helper\Pagination', | |
'select' => '\Dewdrop\View\Helper\Select', | |
'summernote' => '\Dewdrop\View\Helper\Summernote', | |
'table' => '\Dewdrop\View\Helper\Table', | |
'tablecellrenderer' => '\Dewdrop\View\Helper\TableCellRenderer', | |
'tablesorthandle' => '\Dewdrop\View\Helper\TableSortHandle', | |
'textarea' => '\Dewdrop\View\Helper\Textarea', | |
'urlcacheprefix' => '\Dewdrop\View\Helper\UrlCachePrefix', | |
'wpadminnotice' => '\Dewdrop\View\Helper\WpAdminNotice', | |
'wpcheckboxlist' => '\Dewdrop\View\Helper\WpCheckboxList', | |
'wpcolorpicker' => '\Dewdrop\View\Helper\WpColorPicker', | |
'wpeditform' => '\Dewdrop\View\Helper\WpEditForm', | |
'wpeditor' => '\Dewdrop\View\Helper\WpEditor', | |
'wpeditrow' => '\Dewdrop\View\Helper\WpEditRow', | |
'wpimagepicker' => '\Dewdrop\View\Helper\WpImagePicker', | |
'wpinputcheckbox' => '\Dewdrop\View\Helper\WpInputCheckbox', | |
'wpinputtext' => '\Dewdrop\View\Helper\WpInputText', | |
'wpselect' => '\Dewdrop\View\Helper\WpSelect', | |
'wptable' => '\Dewdrop\View\Helper\WpTable', | |
'wpwrap' => '\Dewdrop\View\Helper\WpWrap', | |
'wrap' => '\Dewdrop\View\Helper\Wrap', | |
); | |
/** | |
* Create a new view, optionally supplying an escaper object for use | |
* in sanitizing output in various contexts. | |
* | |
* @param Escaper $escaper | |
* @param Request $request | |
*/ | |
public function __construct(Escaper $escaper = null, Request $request = null) | |
{ | |
$this->escaper = ($escaper ?: new Escaper()); | |
$this->request = ($request ?: Pimple::getResource('dewdrop-request')); | |
$this->init(); | |
} | |
/** | |
* This method can be used by sub-classes to setup additional helpers, etc. | |
* | |
* @return void | |
*/ | |
public function init() | |
{ | |
} | |
/** | |
* Assign variables to this view's data. | |
* | |
* If the $name parameter is an array rather than a string, assign() will | |
* iterate over it, assigning variables for each key-value pair. For | |
* example, passing the following array would assign 3 different data | |
* variables: | |
* | |
* $this->assign( | |
* array( | |
* 'var1' => 1, | |
* 'var1' => 2, | |
* 'var1' => 3 | |
* ) | |
* ); | |
* | |
* @param string|array $name | |
* @param mixed $value | |
* @return \Dewdrop\View\View | |
*/ | |
public function assign($name, $value = null) | |
{ | |
if (!is_array($name)) { | |
$this->internalViewData[$name] = $value; | |
} else { | |
foreach ($name as $index => $value) { | |
$this->assign($index, $value); | |
} | |
} | |
return $this; | |
} | |
/** | |
* Assign a helper instance to the supplied name, rather than requiring | |
* that it be instantiated when the helper is accessed. Typically used | |
* to share helper instances with partials generated by a parent view, | |
* which reduces resource usage and allows things like CSS and JS added | |
* by partials to propagate intuitively. | |
* | |
* @param string $name | |
* @param object $instance | |
* @return $this | |
*/ | |
protected function assignInstance($name, $instance) | |
{ | |
$this->helpers[strtolower($name)] = $instance; | |
return $this; | |
} | |
/** | |
* Register a new helper name and class name. This can be used to replace | |
* a default helper implementation or to introduce a project-specific | |
* helper. | |
* | |
* @param string $name | |
* @param string $className The full class name/namespace. | |
* @return \Dewdrop\View\View | |
*/ | |
public function registerHelper($name, $className) | |
{ | |
$this->helperClasses[strtolower($name)] = $className; | |
return $this; | |
} | |
/** | |
* Retrieve the named index from the $data property or return null. This | |
* makes it easier to avoid undefined variable notices in your view scripts | |
* because you don't have to be quite so circumspect in ensuring variables | |
* are set before checking them. | |
* | |
* @param string $name | |
* @return mixed | |
*/ | |
public function __get($name) | |
{ | |
if (isset($this->internalViewData[$name])) { | |
return $this->internalViewData[$name]; | |
} else { | |
return null; | |
} | |
} | |
/** | |
* Delegate assignment to unknown class properties to the assign() method. | |
* | |
* @param string $name | |
* @param mixed $value | |
* @return \Dewdrop\View\View | |
*/ | |
public function __set($name, $value) | |
{ | |
$this->assign($name, $value); | |
return $this; | |
} | |
/** | |
* Check to see if the given item is present in the view's data array. | |
* | |
* @param string $name | |
* @return boolean | |
*/ | |
public function __isset($name) | |
{ | |
return array_key_exists($name, $this->internalViewData); | |
} | |
/** | |
* When calling an unknown method on this view, pass the method name to | |
* the helper() method and call the helper's direct() method. Using the | |
* __call() magic method in this way allows using helpers in this manner: | |
* | |
* $this->helperName('arg1', $arg2); | |
* | |
* Rather than having to call an additional method on the helper like this: | |
* | |
* $this->helper('helperName')->direct('arg1', $arg2); | |
* | |
* If the direct() method is unavailable, the helper instance is returned instead. | |
* | |
* @param string $method | |
* @param array $args | |
* @return \Dewdrop\View\Helper\AbstractHelper | |
*/ | |
public function __call($method, $args) | |
{ | |
$helper = $this->helper($method); | |
if (method_exists($helper, 'direct')) { | |
return call_user_func_array(array($helper, 'direct'), $args); | |
} else { | |
return $helper; | |
} | |
} | |
/** | |
* Get the helper matching the provided named. | |
* | |
* @param string $name | |
* @throws \Dewdrop\Exception | |
* @return \Dewdrop\View\Helper\AbstractHelper | |
*/ | |
public function helper($name) | |
{ | |
$name = strtolower($name); | |
if (isset($this->helpers[$name])) { | |
return $this->helpers[$name]; | |
} elseif (isset($this->helperClasses[$name])) { | |
return $this->instantiateHelper($name); | |
} else { | |
throw new Exception("No helper with name \"{$name}\" could be found."); | |
} | |
} | |
/** | |
* Render a partial view. By default, the same script path used by this | |
* view is passed along. This escaper from this view is also passed to | |
* the partial. | |
* | |
* @param string $template | |
* @param array $data | |
* @param string $scriptPath | |
* @return string | |
*/ | |
public function partial($template, array $data, $scriptPath = null) | |
{ | |
$partial = new View($this->escaper); | |
$partial->assignInstance('headscript', $this->headScript()); | |
$partial->assignInstance('headlink', $this->headLink()); | |
// Pass along any custom helper class assignments to the newly created partial | |
foreach ($this->helperClasses as $name => $className) { | |
$partial->registerHelper($name, $className); | |
} | |
foreach ($this->helpers as $name => $helper) { | |
if ($helper instanceof PageDelegateInterface) { | |
/* @var $partialHelper PageDelegateInterface */ | |
$partialHelper = $partial->helper($name); | |
$partialHelper->setPage($helper->getPage()); | |
} | |
} | |
$partial | |
->setScriptPath($scriptPath ?: $this->scriptPath) | |
->assign($data); | |
return $partial->render($template); | |
} | |
/** | |
* Get the current Request object for access to GET or POST data | |
* from helpers. | |
* | |
* @return \Dewdrop\Request | |
*/ | |
public function getRequest() | |
{ | |
return $this->request; | |
} | |
/** | |
* The escaper is made accessible so that partial/nested views can reuse | |
* the escaper object rather than having to make another. | |
* | |
* @return \Zend\Escaper\Escaper | |
*/ | |
public function getEscaper() | |
{ | |
return $this->escaper; | |
} | |
/** | |
* Set the path in which to look for view scripts. | |
* | |
* @param string $path | |
* @return \Dewdrop\View\View | |
*/ | |
public function setScriptPath($path) | |
{ | |
$this->scriptPath = realpath($path); | |
return $this; | |
} | |
/** | |
* Render the provided template file. | |
* | |
* The file's name should end in .phtml and be present in the assigned | |
* script path. This method returns the output as a string so that you | |
* have the opportunity to filter or otherwise handle it prior to actually | |
* adding it to the response. | |
* | |
* @param string $template | |
* @return string | |
*/ | |
public function render($template) | |
{ | |
ob_start(); | |
require $this->scriptPath . '/' . basename($template); | |
return ob_get_clean(); | |
} | |
/** | |
* Escape string included in normal HTML context (i.e. not in an attribute value). | |
* | |
* @see \Zend\Escaper\Escaper::escapeHtml | |
* @param string $string | |
* @return string | |
*/ | |
public function escapeHtml($string) | |
{ | |
return $this->escaper->escapeHtml( | |
$this->castEscaperStringValue($string) | |
); | |
} | |
/** | |
* Escape a string included in an HTML attribute value. | |
* | |
* @see \Zend\Escaper\Escaper::escapeHtmlAttr | |
* @param string $string | |
* @return string | |
*/ | |
public function escapeHtmlAttr($string) | |
{ | |
return $this->escaper->escapeHtmlAttr( | |
$this->castEscaperStringValue($string) | |
); | |
} | |
/** | |
* Escape a JavaScript string. | |
* | |
* @see \Zend\Escaper\Escaper::escapeJs | |
* @param string $string | |
* @return string | |
*/ | |
public function escapeJs($string) | |
{ | |
return $this->escaper->escapeJs( | |
$this->castEscaperStringValue($string) | |
); | |
} | |
/** | |
* This will encode the supplied input as JSON using flags that | |
* make it safe to embed that JSON in an HTML context like an | |
* inline script block. | |
* | |
* @param mixed $input | |
* @return string | |
*/ | |
public function encodeJsonHtmlSafe($input) | |
{ | |
return json_encode($input, JSON_HEX_QUOT|JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS); | |
} | |
/** | |
* Escape a URL. | |
* | |
* @see \Zend\Escaper\Escaper::escapeUrl | |
* @param string $string | |
* @return string | |
*/ | |
public function escapeUrl($string) | |
{ | |
return $this->escaper->escapeUrl( | |
$this->castEscaperStringValue($string) | |
); | |
} | |
/** | |
* Escape a CSS property value. | |
* | |
* @see \Zend\Escaper\Escaper::escapeCss | |
* @param string $string | |
* @return string | |
*/ | |
public function escapeCss($string) | |
{ | |
return $this->escaper->escapeCss( | |
$this->castEscaperStringValue($string) | |
); | |
} | |
/** | |
* Create an instance of helper associated with the provided name and | |
* store that instance in the $helpers property so that it can be retrieved | |
* on any subsequent calls. | |
* | |
* @param string $name | |
* @return \Dewdrop\View\Helper\AbstractHelper | |
*/ | |
private function instantiateHelper($name) | |
{ | |
$className = $this->helperClasses[$name]; | |
$helper = new $className($this); | |
$this->helpers[$name] = $helper; | |
return $helper; | |
} | |
/** | |
* \Zend\Escaper\Escaper does not play well with falsey non-string values | |
* like null or false. It throws exceptions claiming it cannot convert | |
* them to utf-8. This method will convert false and null to an empty | |
* string and then cast the return value to a string (which should catch | |
* ints and floats as well). | |
* | |
* @param mixed $input | |
* @return string | |
*/ | |
private function castEscaperStringValue($input) | |
{ | |
if (false === $input || null === $input) { | |
$input = ''; | |
} | |
return (string) $input; | |
} | |
} |