1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
15: namespace Cake\View;
16:
17: use BadMethodCallException;
18: use Cake\Cache\Cache;
19: use Cake\Datasource\ModelAwareTrait;
20: use Cake\Event\EventDispatcherTrait;
21: use Cake\Event\EventManager;
22: use Cake\Http\Response;
23: use Cake\Http\ServerRequest;
24: use Cake\ORM\Locator\LocatorAwareTrait;
25: use Cake\Utility\Inflector;
26: use Cake\View\Exception\MissingCellViewException;
27: use Cake\View\Exception\MissingTemplateException;
28: use Error;
29: use Exception;
30: use ReflectionException;
31: use ReflectionMethod;
32:
33: 34: 35:
36: abstract class Cell
37: {
38: use EventDispatcherTrait;
39: use LocatorAwareTrait;
40: use ModelAwareTrait;
41: use ViewVarsTrait;
42:
43: 44: 45: 46: 47: 48:
49: protected $View;
50:
51: 52: 53: 54: 55: 56: 57:
58: protected $request;
59:
60: 61: 62: 63: 64:
65: protected $response;
66:
67: 68: 69: 70: 71:
72: protected $action;
73:
74: 75: 76: 77: 78:
79: protected $args = [];
80:
81: 82: 83: 84: 85: 86: 87:
88: protected $_validViewOptions = [
89: 'viewPath'
90: ];
91:
92: 93: 94: 95: 96: 97: 98:
99: protected $_validCellOptions = [];
100:
101: 102: 103: 104: 105:
106: protected $_cache = false;
107:
108: 109: 110: 111: 112: 113: 114: 115:
116: public function __construct(
117: ServerRequest $request = null,
118: Response $response = null,
119: EventManager $eventManager = null,
120: array $cellOptions = []
121: ) {
122: if ($eventManager !== null) {
123: $this->setEventManager($eventManager);
124: }
125: $this->request = $request;
126: $this->response = $response;
127: $this->modelFactory('Table', [$this->getTableLocator(), 'get']);
128:
129: $this->_validCellOptions = array_merge(['action', 'args'], $this->_validCellOptions);
130: foreach ($this->_validCellOptions as $var) {
131: if (isset($cellOptions[$var])) {
132: $this->{$var} = $cellOptions[$var];
133: }
134: }
135: if (!empty($cellOptions['cache'])) {
136: $this->_cache = $cellOptions['cache'];
137: }
138:
139: $this->initialize();
140: }
141:
142: 143: 144: 145: 146: 147: 148: 149:
150: public function initialize()
151: {
152: }
153:
154: 155: 156: 157: 158: 159: 160: 161:
162: public function render($template = null)
163: {
164: $cache = [];
165: if ($this->_cache) {
166: $cache = $this->_cacheConfig($this->action, $template);
167: }
168:
169: $render = function () use ($template) {
170: try {
171: $reflect = new ReflectionMethod($this, $this->action);
172: $reflect->invokeArgs($this, $this->args);
173: } catch (ReflectionException $e) {
174: throw new BadMethodCallException(sprintf(
175: 'Class %s does not have a "%s" method.',
176: get_class($this),
177: $this->action
178: ));
179: }
180:
181: $builder = $this->viewBuilder()->setLayout(false);
182:
183: if ($template !== null) {
184: $builder->setTemplate($template);
185: }
186:
187: $className = get_class($this);
188: $namePrefix = '\View\Cell\\';
189: $name = substr($className, strpos($className, $namePrefix) + strlen($namePrefix));
190: $name = substr($name, 0, -4);
191: if (!$builder->getTemplatePath()) {
192: $builder->setTemplatePath('Cell' . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $name));
193: }
194: $template = $builder->getTemplate();
195:
196: $this->View = $this->createView();
197: try {
198: return $this->View->render($template);
199: } catch (MissingTemplateException $e) {
200: $attributes = $e->getAttributes();
201: $attributes = ['file' => basename($attributes['file']), 'name' => $name];
202:
203: throw new MissingCellViewException($attributes, null, $e);
204: }
205: };
206:
207: if ($cache) {
208: return Cache::remember($cache['key'], $render, $cache['config']);
209: }
210:
211: return $render();
212: }
213:
214: 215: 216: 217: 218: 219: 220: 221: 222:
223: protected function _cacheConfig($action, $template = null)
224: {
225: if (empty($this->_cache)) {
226: return [];
227: }
228: $template = $template ?: 'default';
229: $key = 'cell_' . Inflector::underscore(get_class($this)) . '_' . $action . '_' . $template;
230: $key = str_replace('\\', '_', $key);
231: $default = [
232: 'config' => 'default',
233: 'key' => $key
234: ];
235: if ($this->_cache === true) {
236: return $default;
237: }
238:
239: return $this->_cache + $default;
240: }
241:
242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252:
253: public function __toString()
254: {
255: try {
256: return $this->render();
257: } catch (Exception $e) {
258: trigger_error(sprintf('Could not render cell - %s [%s, line %d]', $e->getMessage(), $e->getFile(), $e->getLine()), E_USER_WARNING);
259:
260: return '';
261: } catch (Error $e) {
262: throw new Error(sprintf('Could not render cell - %s [%s, line %d]', $e->getMessage(), $e->getFile(), $e->getLine()));
263: }
264: }
265:
266: 267: 268: 269: 270: 271:
272: public function __get($name)
273: {
274: $deprecated = [
275: 'template' => 'getTemplate',
276: 'plugin' => 'getPlugin',
277: 'helpers' => 'getHelpers',
278: ];
279: if (isset($deprecated[$name])) {
280: $method = $deprecated[$name];
281: deprecationWarning(sprintf(
282: 'Cell::$%s is deprecated. Use $cell->viewBuilder()->%s() instead.',
283: $name,
284: $method
285: ));
286:
287: return $this->viewBuilder()->{$method}();
288: }
289:
290: $protected = [
291: 'action',
292: 'args',
293: 'request',
294: 'response',
295: 'View',
296: ];
297: if (in_array($name, $protected, true)) {
298: deprecationWarning(sprintf(
299: 'Cell::$%s is now protected and shouldn\'t be accessed from outside a child class.',
300: $name
301: ));
302: }
303:
304: return $this->{$name};
305: }
306:
307: 308: 309: 310: 311: 312: 313:
314: public function __set($name, $value)
315: {
316: $deprecated = [
317: 'template' => 'setTemplate',
318: 'plugin' => 'setPlugin',
319: 'helpers' => 'setHelpers',
320: ];
321: if (isset($deprecated[$name])) {
322: $method = $deprecated[$name];
323: deprecationWarning(sprintf(
324: 'Cell::$%s is deprecated. Use $cell->viewBuilder()->%s() instead.',
325: $name,
326: $method
327: ));
328: $this->viewBuilder()->{$method}($value);
329:
330: return;
331: }
332:
333: $protected = [
334: 'action',
335: 'args',
336: 'request',
337: 'response',
338: 'View',
339: ];
340: if (in_array($name, $protected, true)) {
341: deprecationWarning(sprintf(
342: 'Cell::$%s is now protected and shouldn\'t be accessed from outside a child class.',
343: $name
344: ));
345: }
346:
347: $this->{$name} = $value;
348: }
349:
350: 351: 352: 353: 354:
355: public function __debugInfo()
356: {
357: return [
358: 'action' => $this->action,
359: 'args' => $this->args,
360: 'request' => $this->request,
361: 'response' => $this->response,
362: 'viewBuilder' => $this->viewBuilder(),
363: ];
364: }
365: }
366: