<?php
/**
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
* @link https://cakephp.org CakePHP(tm) Project
* @since 3.0.0
* @license https://opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\View;
use Cake\Core\App;
use Cake\Utility\Inflector;
use Cake\View\Exception\MissingCellException;
/**
* Provides cell() method for usage in Controller and View classes.
*/
trait CellTrait
{
/**
* Renders the given cell.
*
* Example:
*
* ```
* // Taxonomy\View\Cell\TagCloudCell::smallList()
* $cell = $this->cell('Taxonomy.TagCloud::smallList', ['limit' => 10]);
*
* // App\View\Cell\TagCloudCell::smallList()
* $cell = $this->cell('TagCloud::smallList', ['limit' => 10]);
* ```
*
* The `display` action will be used by default when no action is provided:
*
* ```
* // Taxonomy\View\Cell\TagCloudCell::display()
* $cell = $this->cell('Taxonomy.TagCloud');
* ```
*
* Cells are not rendered until they are echoed.
*
* @param string $cell You must indicate cell name, and optionally a cell action. e.g.: `TagCloud::smallList`
* will invoke `View\Cell\TagCloudCell::smallList()`, `display` action will be invoked by default when none is provided.
* @param array $data Additional arguments for cell method. e.g.:
* `cell('TagCloud::smallList', ['a1' => 'v1', 'a2' => 'v2'])` maps to `View\Cell\TagCloud::smallList(v1, v2)`
* @param array $options Options for Cell's constructor
* @return \Cake\View\Cell The cell instance
* @throws \Cake\View\Exception\MissingCellException If Cell class was not found.
* @throws \BadMethodCallException If Cell class does not specified cell action.
*/
protected function cell($cell, array $data = [], array $options = [])
{
$parts = explode('::', $cell);
if (count($parts) === 2) {
list($pluginAndCell, $action) = [$parts[0], $parts[1]];
} else {
list($pluginAndCell, $action) = [$parts[0], 'display'];
}
list($plugin) = pluginSplit($pluginAndCell);
$className = App::className($pluginAndCell, 'View/Cell', 'Cell');
if (!$className) {
throw new MissingCellException(['className' => $pluginAndCell . 'Cell']);
}
if (!empty($data)) {
$data = array_values($data);
}
$options = ['action' => $action, 'args' => $data] + $options;
$cell = $this->_createCell($className, $action, $plugin, $options);
return $cell;
}
/**
* Create and configure the cell instance.
*
* @param string $className The cell classname.
* @param string $action The action name.
* @param string $plugin The plugin name.
* @param array $options The constructor options for the cell.
* @return \Cake\View\Cell
*/
protected function _createCell($className, $action, $plugin, $options)
{
/** @var \Cake\View\Cell $instance */
$instance = new $className($this->request, $this->response, $this->getEventManager(), $options);
$builder = $instance->viewBuilder();
$builder->setTemplate(Inflector::underscore($action));
if (!empty($plugin)) {
$builder->setPlugin($plugin);
}
if (!empty($this->helpers)) {
$builder->setHelpers($this->helpers);
}
if ($this instanceof View) {
if (!empty($this->theme)) {
$builder->setTheme($this->theme);
}
$class = get_class($this);
$builder->setClassName($class);
$instance->viewClass = $class;
return $instance;
}
if (method_exists($this, 'viewBuilder')) {
$builder->setTheme($this->viewBuilder()->getTheme());
}
if (isset($this->viewClass)) {
$builder->setClassName($this->viewClass);
$instance->viewClass = $this->viewClass;
}
return $instance;
}
}