<?php
namespace Cake\View;
use BadMethodCallException;
use Cake\Cache\Cache;
use Cake\Datasource\ModelAwareTrait;
use Cake\Event\EventDispatcherTrait;
use Cake\Event\EventManager;
use Cake\Http\Response;
use Cake\Http\ServerRequest;
use Cake\ORM\Locator\LocatorAwareTrait;
use Cake\Utility\Inflector;
use Cake\View\Exception\MissingCellViewException;
use Cake\View\Exception\MissingTemplateException;
use Error;
use Exception;
use ReflectionException;
use ReflectionMethod;
abstract class Cell
{
use EventDispatcherTrait;
use LocatorAwareTrait;
use ModelAwareTrait;
use ViewVarsTrait;
protected $View;
protected $request;
protected $response;
protected $action;
protected $args = [];
protected $_validViewOptions = [
'viewPath'
];
protected $_validCellOptions = [];
protected $_cache = false;
public function __construct(
ServerRequest $request = null,
Response $response = null,
EventManager $eventManager = null,
array $cellOptions = []
) {
if ($eventManager !== null) {
$this->setEventManager($eventManager);
}
$this->request = $request;
$this->response = $response;
$this->modelFactory('Table', [$this->getTableLocator(), 'get']);
$this->_validCellOptions = array_merge(['action', 'args'], $this->_validCellOptions);
foreach ($this->_validCellOptions as $var) {
if (isset($cellOptions[$var])) {
$this->{$var} = $cellOptions[$var];
}
}
if (!empty($cellOptions['cache'])) {
$this->_cache = $cellOptions['cache'];
}
$this->initialize();
}
public function initialize()
{
}
public function render($template = null)
{
$cache = [];
if ($this->_cache) {
$cache = $this->_cacheConfig($this->action, $template);
}
$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
));
}
$builder = $this->viewBuilder()->setLayout(false);
if ($template !== null &&
strpos($template, '/') === false &&
strpos($template, '.') === false
) {
$template = Inflector::underscore($template);
}
if ($template !== null) {
$builder->setTemplate($template);
}
$className = get_class($this);
$namePrefix = '\View\Cell\\';
$name = substr($className, strpos($className, $namePrefix) + strlen($namePrefix));
$name = substr($name, 0, -4);
if (!$builder->getTemplatePath()) {
$builder->setTemplatePath('Cell' . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $name));
}
$template = $builder->getTemplate();
$this->View = $this->createView();
try {
return $this->View->render($template);
} catch (MissingTemplateException $e) {
throw new MissingCellViewException(['file' => $template, 'name' => $name], null, $e);
}
};
if ($cache) {
return Cache::remember($cache['key'], $render, $cache['config']);
}
return $render();
}
protected function _cacheConfig($action, $template = null)
{
if (empty($this->_cache)) {
return [];
}
$template = $template ?: 'default';
$key = 'cell_' . Inflector::underscore(get_class($this)) . '_' . $action . '_' . $template;
$key = str_replace('\\', '_', $key);
$default = [
'config' => 'default',
'key' => $key
];
if ($this->_cache === true) {
return $default;
}
return $this->_cache + $default;
}
public function __toString()
{
try {
return $this->render();
} catch (Exception $e) {
trigger_error(sprintf('Could not render cell - %s [%s, line %d]', $e->getMessage(), $e->getFile(), $e->getLine()), E_USER_WARNING);
return '';
} catch (Error $e) {
throw new Error(sprintf('Could not render cell - %s [%s, line %d]', $e->getMessage(), $e->getFile(), $e->getLine()));
}
}
public function __get($name)
{
$deprecated = [
'template' => 'getTemplate',
'plugin' => 'getPlugin',
'helpers' => 'getHelpers',
];
if (isset($deprecated[$name])) {
$method = $deprecated[$name];
deprecationWarning(sprintf(
'Cell::$%s is deprecated. Use $cell->viewBuilder()->%s() instead.',
$name,
$method
));
return $this->viewBuilder()->{$method}();
}
$protected = [
'action',
'args',
'request',
'response',
'View',
];
if (in_array($name, $protected, true)) {
deprecationWarning(sprintf(
'Cell::$%s is now protected and shouldn\'t be accessed from outside a child class.',
$name
));
}
return $this->{$name};
}
public function __set($name, $value)
{
$deprecated = [
'template' => 'setTemplate',
'plugin' => 'setPlugin',
'helpers' => 'setHelpers',
];
if (isset($deprecated[$name])) {
$method = $deprecated[$name];
deprecationWarning(sprintf(
'Cell::$%s is deprecated. Use $cell->viewBuilder()->%s() instead.',
$name,
$method
));
$this->viewBuilder()->{$method}($value);
return;
}
$protected = [
'action',
'args',
'request',
'response',
'View',
];
if (in_array($name, $protected, true)) {
deprecationWarning(sprintf(
'Cell::$%s is now protected and shouldn\'t be accessed from outside a child class.',
$name
));
}
$this->{$name} = $value;
}
public function __debugInfo()
{
return [
'action' => $this->action,
'args' => $this->args,
'request' => $this->request,
'response' => $this->response,
'viewBuilder' => $this->viewBuilder(),
];
}
}