1: <?php
2:
3: /**
4: * This file is part of the Nette Framework (http://nette.org)
5: *
6: * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
7: *
8: * For the full copyright and license information, please view
9: * the file license.txt that was distributed with this source code.
10: */
11:
12: namespace Nette\Application\UI;
13:
14: use Nette;
15:
16:
17: /**
18: * Control is renderable Presenter component.
19: *
20: * @author David Grudl
21: *
22: * @property-read Nette\Templating\ITemplate $template
23: * @property-read string $snippetId
24: */
25: abstract class Control extends PresenterComponent implements IRenderable
26: {
27: /** @var Nette\Templating\ITemplate */
28: private $template;
29:
30: /** @var array */
31: private $invalidSnippets = array();
32:
33: /** @var bool */
34: public $snippetMode;
35:
36:
37: /********************* template factory ****************d*g**/
38:
39:
40: /**
41: * @return Nette\Templating\ITemplate
42: */
43: final public function getTemplate()
44: {
45: if ($this->template === NULL) {
46: $value = $this->createTemplate();
47: if (!$value instanceof Nette\Templating\ITemplate && $value !== NULL) {
48: $class2 = get_class($value); $class = get_class($this);
49: throw new Nette\UnexpectedValueException("Object returned by $class::createTemplate() must be instance of Nette\\Templating\\ITemplate, '$class2' given.");
50: }
51: $this->template = $value;
52: }
53: return $this->template;
54: }
55:
56:
57: /**
58: * @param string|NULL
59: * @return Nette\Templating\ITemplate
60: */
61: protected function createTemplate($class = NULL)
62: {
63: $template = $class ? new $class : new Nette\Templating\FileTemplate;
64: $presenter = $this->getPresenter(FALSE);
65: $template->onPrepareFilters[] = $this->templatePrepareFilters;
66: $template->registerHelperLoader('Nette\Templating\Helpers::loader');
67:
68: // default parameters
69: $template->control = $template->_control = $this;
70: $template->presenter = $template->_presenter = $presenter;
71: if ($presenter instanceof Presenter) {
72: $template->setCacheStorage($presenter->getContext()->getService('nette.templateCacheStorage'));
73: $template->user = $presenter->getUser();
74: $template->netteHttpResponse = $presenter->getHttpResponse();
75: $template->netteCacheStorage = $presenter->getContext()->getByType('Nette\Caching\IStorage');
76: $template->baseUri = $template->baseUrl = rtrim($presenter->getHttpRequest()->getUrl()->getBaseUrl(), '/');
77: $template->basePath = preg_replace('#https?://[^/]+#A', '', $template->baseUrl);
78:
79: // flash message
80: if ($presenter->hasFlashSession()) {
81: $id = $this->getParameterId('flash');
82: $template->flashes = $presenter->getFlashSession()->$id;
83: }
84: }
85: if (!isset($template->flashes) || !is_array($template->flashes)) {
86: $template->flashes = array();
87: }
88:
89: return $template;
90: }
91:
92:
93: /**
94: * Descendant can override this method to customize template compile-time filters.
95: * @param Nette\Templating\Template
96: * @return void
97: */
98: public function templatePrepareFilters($template)
99: {
100: $template->registerFilter($this->getPresenter()->getContext()->nette->createLatte());
101: }
102:
103:
104: /**
105: * Returns widget component specified by name.
106: * @param string
107: * @return Nette\ComponentModel\IComponent
108: */
109: public function getWidget($name)
110: {
111: trigger_error(__METHOD__ . '() is deprecated, use getComponent() instead.', E_USER_WARNING);
112: return $this->getComponent($name);
113: }
114:
115:
116: /**
117: * Saves the message to template, that can be displayed after redirect.
118: * @param string
119: * @param string
120: * @return \stdClass
121: */
122: public function flashMessage($message, $type = 'info')
123: {
124: $id = $this->getParameterId('flash');
125: $messages = $this->getPresenter()->getFlashSession()->$id;
126: $messages[] = $flash = (object) array(
127: 'message' => $message,
128: 'type' => $type,
129: );
130: $this->getTemplate()->flashes = $messages;
131: $this->getPresenter()->getFlashSession()->$id = $messages;
132: return $flash;
133: }
134:
135:
136: /********************* rendering ****************d*g**/
137:
138:
139: /**
140: * Forces control or its snippet to repaint.
141: * @param string
142: * @return void
143: */
144: public function invalidateControl($snippet = NULL)
145: {
146: $this->invalidSnippets[$snippet] = TRUE;
147: }
148:
149:
150: /**
151: * Allows control or its snippet to not repaint.
152: * @param string
153: * @return void
154: */
155: public function validateControl($snippet = NULL)
156: {
157: if ($snippet === NULL) {
158: $this->invalidSnippets = array();
159:
160: } else {
161: unset($this->invalidSnippets[$snippet]);
162: }
163: }
164:
165:
166: /**
167: * Is required to repaint the control or its snippet?
168: * @param string snippet name
169: * @return bool
170: */
171: public function isControlInvalid($snippet = NULL)
172: {
173: if ($snippet === NULL) {
174: if (count($this->invalidSnippets) > 0) {
175: return TRUE;
176:
177: } else {
178: $queue = array($this);
179: do {
180: foreach (array_shift($queue)->getComponents() as $component) {
181: if ($component instanceof IRenderable) {
182: if ($component->isControlInvalid()) {
183: // $this->invalidSnippets['__child'] = TRUE; // as cache
184: return TRUE;
185: }
186:
187: } elseif ($component instanceof Nette\ComponentModel\IContainer) {
188: $queue[] = $component;
189: }
190: }
191: } while ($queue);
192:
193: return FALSE;
194: }
195:
196: } else {
197: return isset($this->invalidSnippets[NULL]) || isset($this->invalidSnippets[$snippet]);
198: }
199: }
200:
201:
202: /**
203: * Returns snippet HTML ID.
204: * @param string snippet name
205: * @return string
206: */
207: public function getSnippetId($name = NULL)
208: {
209: // HTML 4 ID & NAME: [A-Za-z][A-Za-z0-9:_.-]*
210: return 'snippet-' . $this->getUniqueId() . '-' . $name;
211: }
212:
213: }
214: