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: /**
28: * Renders the given cell.
29: *
30: * Example:
31: *
32: * ```
33: * // Taxonomy\View\Cell\TagCloudCell::smallList()
34: * $cell = $this->cell('Taxonomy.TagCloud::smallList', ['limit' => 10]);
35: *
36: * // App\View\Cell\TagCloudCell::smallList()
37: * $cell = $this->cell('TagCloud::smallList', ['limit' => 10]);
38: * ```
39: *
40: * The `display` action will be used by default when no action is provided:
41: *
42: * ```
43: * // Taxonomy\View\Cell\TagCloudCell::display()
44: * $cell = $this->cell('Taxonomy.TagCloud');
45: * ```
46: *
47: * Cells are not rendered until they are echoed.
48: *
49: * @param string $cell You must indicate cell name, and optionally a cell action. e.g.: `TagCloud::smallList`
50: * will invoke `View\Cell\TagCloudCell::smallList()`, `display` action will be invoked by default when none is provided.
51: * @param array $data Additional arguments for cell method. e.g.:
52: * `cell('TagCloud::smallList', ['a1' => 'v1', 'a2' => 'v2'])` maps to `View\Cell\TagCloud::smallList(v1, v2)`
53: * @param array $options Options for Cell's constructor
54: * @return \Cake\View\Cell The cell instance
55: * @throws \Cake\View\Exception\MissingCellException If Cell class was not found.
56: * @throws \BadMethodCallException If Cell class does not specified cell action.
57: */
58: protected function cell($cell, array $data = [], array $options = [])
59: {
60: $parts = explode('::', $cell);
61:
62: if (count($parts) === 2) {
63: list($pluginAndCell, $action) = [$parts[0], $parts[1]];
64: } else {
65: list($pluginAndCell, $action) = [$parts[0], 'display'];
66: }
67:
68: list($plugin) = pluginSplit($pluginAndCell);
69: $className = App::className($pluginAndCell, 'View/Cell', 'Cell');
70:
71: if (!$className) {
72: throw new MissingCellException(['className' => $pluginAndCell . 'Cell']);
73: }
74:
75: if (!empty($data)) {
76: $data = array_values($data);
77: }
78: $options = ['action' => $action, 'args' => $data] + $options;
79: $cell = $this->_createCell($className, $action, $plugin, $options);
80:
81: return $cell;
82: }
83:
84: /**
85: * Create and configure the cell instance.
86: *
87: * @param string $className The cell classname.
88: * @param string $action The action name.
89: * @param string $plugin The plugin name.
90: * @param array $options The constructor options for the cell.
91: * @return \Cake\View\Cell
92: */
93: protected function _createCell($className, $action, $plugin, $options)
94: {
95: /* @var \Cake\View\Cell $instance */
96: $instance = new $className($this->request, $this->response, $this->getEventManager(), $options);
97:
98: $builder = $instance->viewBuilder();
99: $builder->setTemplate(Inflector::underscore($action));
100:
101: if (!empty($plugin)) {
102: $builder->setPlugin($plugin);
103: }
104: if (!empty($this->helpers)) {
105: $builder->setHelpers($this->helpers);
106: }
107:
108: if ($this instanceof View) {
109: if (!empty($this->theme)) {
110: $builder->setTheme($this->theme);
111: }
112:
113: $class = get_class($this);
114: $builder->setClassName($class);
115: $instance->viewClass = $class;
116:
117: return $instance;
118: }
119:
120: if (method_exists($this, 'viewBuilder')) {
121: $builder->setTheme($this->viewBuilder()->getTheme());
122: }
123:
124: if (isset($this->viewClass)) {
125: $builder->setClassName($this->viewClass);
126: $instance->viewClass = $this->viewClass;
127: }
128:
129: return $instance;
130: }
131: }
132: