1: <?php
2: /**
3: * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
4: * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
5: *
6: * Licensed under The MIT License
7: * For full copyright and license information, please see the LICENSE.txt
8: * Redistributions of files must retain the above copyright notice.
9: *
10: * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
11: * @link https://cakephp.org CakePHP(tm) Project
12: * @since 3.0.0
13: * @license https://opensource.org/licenses/mit-license.php MIT License
14: */
15: namespace Cake\View;
16:
17: use Cake\Core\App;
18: use Cake\Utility\Inflector;
19: use Cake\View\Exception\MissingCellException;
20:
21: /**
22: * Provides cell() method for usage in Controller and View classes.
23: */
24: trait CellTrait
25: {
26: /**
27: * Renders the given cell.
28: *
29: * Example:
30: *
31: * ```
32: * // Taxonomy\View\Cell\TagCloudCell::smallList()
33: * $cell = $this->cell('Taxonomy.TagCloud::smallList', ['limit' => 10]);
34: *
35: * // App\View\Cell\TagCloudCell::smallList()
36: * $cell = $this->cell('TagCloud::smallList', ['limit' => 10]);
37: * ```
38: *
39: * The `display` action will be used by default when no action is provided:
40: *
41: * ```
42: * // Taxonomy\View\Cell\TagCloudCell::display()
43: * $cell = $this->cell('Taxonomy.TagCloud');
44: * ```
45: *
46: * Cells are not rendered until they are echoed.
47: *
48: * @param string $cell You must indicate cell name, and optionally a cell action. e.g.: `TagCloud::smallList`
49: * will invoke `View\Cell\TagCloudCell::smallList()`, `display` action will be invoked by default when none is provided.
50: * @param array $data Additional arguments for cell method. e.g.:
51: * `cell('TagCloud::smallList', ['a1' => 'v1', 'a2' => 'v2'])` maps to `View\Cell\TagCloud::smallList(v1, v2)`
52: * @param array $options Options for Cell's constructor
53: * @return \Cake\View\Cell The cell instance
54: * @throws \Cake\View\Exception\MissingCellException If Cell class was not found.
55: * @throws \BadMethodCallException If Cell class does not specified cell action.
56: */
57: protected function cell($cell, array $data = [], array $options = [])
58: {
59: $parts = explode('::', $cell);
60:
61: if (count($parts) === 2) {
62: list($pluginAndCell, $action) = [$parts[0], $parts[1]];
63: } else {
64: list($pluginAndCell, $action) = [$parts[0], 'display'];
65: }
66:
67: list($plugin) = pluginSplit($pluginAndCell);
68: $className = App::className($pluginAndCell, 'View/Cell', 'Cell');
69:
70: if (!$className) {
71: throw new MissingCellException(['className' => $pluginAndCell . 'Cell']);
72: }
73:
74: if (!empty($data)) {
75: $data = array_values($data);
76: }
77: $options = ['action' => $action, 'args' => $data] + $options;
78: $cell = $this->_createCell($className, $action, $plugin, $options);
79:
80: return $cell;
81: }
82:
83: /**
84: * Create and configure the cell instance.
85: *
86: * @param string $className The cell classname.
87: * @param string $action The action name.
88: * @param string $plugin The plugin name.
89: * @param array $options The constructor options for the cell.
90: * @return \Cake\View\Cell
91: */
92: protected function _createCell($className, $action, $plugin, $options)
93: {
94: /* @var \Cake\View\Cell $instance */
95: $instance = new $className($this->request, $this->response, $this->getEventManager(), $options);
96:
97: $builder = $instance->viewBuilder();
98: $builder->setTemplate(Inflector::underscore($action));
99:
100: if (!empty($plugin)) {
101: $builder->setPlugin($plugin);
102: }
103: if (!empty($this->helpers)) {
104: $builder->setHelpers($this->helpers);
105: }
106:
107: if ($this instanceof View) {
108: if (!empty($this->theme)) {
109: $builder->setTheme($this->theme);
110: }
111:
112: $class = get_class($this);
113: $builder->setClassName($class);
114: $instance->viewClass = $class;
115:
116: return $instance;
117: }
118:
119: if (method_exists($this, 'viewBuilder')) {
120: $builder->setTheme($this->viewBuilder()->getTheme());
121: }
122:
123: if (isset($this->viewClass)) {
124: $builder->setClassName($this->viewClass);
125: $instance->viewClass = $this->viewClass;
126: }
127:
128: return $instance;
129: }
130: }
131: