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