sfWidget.class.php 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. <?php
  2. /*
  3. * This file is part of the symfony package.
  4. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  5. *
  6. * For the full copyright and license information, please view the LICENSE
  7. * file that was distributed with this source code.
  8. */
  9. /**
  10. * sfWidget is the base class for all widgets.
  11. *
  12. * @package symfony
  13. * @subpackage widget
  14. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  15. * @version SVN: $Id: sfWidget.class.php 17473 2009-04-21 07:59:34Z fabien $
  16. */
  17. abstract class sfWidget
  18. {
  19. protected
  20. $requiredOptions = array(),
  21. $attributes = array(),
  22. $options = array();
  23. protected static
  24. $xhtml = true,
  25. $charset = 'UTF-8';
  26. /**
  27. * Constructor.
  28. *
  29. * @param array $options An array of options
  30. * @param array $attributes An array of default HTML attributes
  31. */
  32. public function __construct($options = array(), $attributes = array())
  33. {
  34. $this->configure($options, $attributes);
  35. $currentOptionKeys = array_keys($this->options);
  36. $optionKeys = array_keys($options);
  37. // check option names
  38. if ($diff = array_diff($optionKeys, array_merge($currentOptionKeys, $this->requiredOptions)))
  39. {
  40. throw new InvalidArgumentException(sprintf('%s does not support the following options: \'%s\'.', get_class($this), implode('\', \'', $diff)));
  41. }
  42. // check required options
  43. if ($diff = array_diff($this->requiredOptions, array_merge($currentOptionKeys, $optionKeys)))
  44. {
  45. throw new RuntimeException(sprintf('%s requires the following options: \'%s\'.', get_class($this), implode('\', \'', $diff)));
  46. }
  47. $this->options = array_merge($this->options, $options);
  48. $this->attributes = array_merge($this->attributes, $attributes);
  49. }
  50. /**
  51. * Configures the current widget.
  52. *
  53. * This method allows each widget to add options or HTML attributes
  54. * during widget creation.
  55. *
  56. * If some options and HTML attributes are given in the sfWidget constructor
  57. * they will take precedence over the options and HTML attributes you configure
  58. * in this method.
  59. *
  60. * @param array $options An array of options
  61. * @param array $attributes An array of HTML attributes
  62. *
  63. * @see __construct()
  64. */
  65. protected function configure($options = array(), $attributes = array())
  66. {
  67. }
  68. /**
  69. * Renders the widget as HTML.
  70. *
  71. * All subclasses must implement this method.
  72. *
  73. * @param string $name The name of the HTML widget
  74. * @param mixed $value The value of the widget
  75. * @param array $attributes An array of HTML attributes
  76. * @param array $errors An array of errors
  77. *
  78. * @return string A HTML representation of the widget
  79. */
  80. abstract public function render($name, $value = null, $attributes = array(), $errors = array());
  81. /**
  82. * Adds a required option.
  83. *
  84. * @param string $name The option name
  85. */
  86. public function addRequiredOption($name)
  87. {
  88. $this->requiredOptions[] = $name;
  89. }
  90. /**
  91. * Returns all required option names.
  92. *
  93. * @param array An array of required option names
  94. */
  95. public function getRequiredOptions()
  96. {
  97. return $this->requiredOptions;
  98. }
  99. /**
  100. * Adds a new option value with a default value.
  101. *
  102. * @param string $name The option name
  103. * @param mixed $value The default value
  104. */
  105. public function addOption($name, $value = null)
  106. {
  107. $this->options[$name] = $value;
  108. }
  109. /**
  110. * Changes an option value.
  111. *
  112. * @param string $name The option name
  113. * @param mixed $value The value
  114. */
  115. public function setOption($name, $value)
  116. {
  117. if (!in_array($name, array_merge(array_keys($this->options), $this->requiredOptions)))
  118. {
  119. throw new InvalidArgumentException(sprintf('%s does not support the following option: \'%s\'.', get_class($this), $name));
  120. }
  121. $this->options[$name] = $value;
  122. }
  123. /**
  124. * Gets an option value.
  125. *
  126. * @param string The option name
  127. *
  128. * @return mixed The option value
  129. */
  130. public function getOption($name)
  131. {
  132. return isset($this->options[$name]) ? $this->options[$name] : null;
  133. }
  134. /**
  135. * Returns true if the option exists.
  136. *
  137. * @param string $name The option name
  138. *
  139. * @return bool true if the option exists, false otherwise
  140. */
  141. public function hasOption($name)
  142. {
  143. return array_key_exists($name, $this->options);
  144. }
  145. /**
  146. * Gets all options.
  147. *
  148. * @return array An array of named options
  149. */
  150. public function getOptions()
  151. {
  152. return $this->options;
  153. }
  154. /**
  155. * Sets the options.
  156. *
  157. * @param array $options An array of options
  158. */
  159. public function setOptions($options)
  160. {
  161. $this->options = $options;
  162. }
  163. /**
  164. * Returns the default HTML attributes.
  165. *
  166. * @param array An array of HTML attributes
  167. */
  168. public function getAttributes()
  169. {
  170. return $this->attributes;
  171. }
  172. /**
  173. * Sets a default HTML attribute.
  174. *
  175. * @param string $name The attribute name
  176. * @param string $value The attribute value
  177. */
  178. public function setAttribute($name, $value)
  179. {
  180. $this->attributes[$name] = $value;
  181. }
  182. /**
  183. * Returns the HTML attribute value for a given attribute name.
  184. *
  185. * @param string $name The attribute name.
  186. *
  187. * @return string The attribute value, or null if the attribute does not exist
  188. */
  189. public function getAttribute($name)
  190. {
  191. return isset($this->attributes[$name]) ? $this->attributes[$name] : null;
  192. }
  193. /**
  194. * Sets the HTML attributes.
  195. *
  196. * @param array $attributes An array of HTML attributes
  197. */
  198. public function setAttributes($attributes)
  199. {
  200. $this->attributes = $attributes;
  201. }
  202. /**
  203. * Sets the charset to use when rendering widgets.
  204. *
  205. * @param string $charset The charset
  206. */
  207. static public function setCharset($charset)
  208. {
  209. self::$charset = $charset;
  210. }
  211. /**
  212. * Returns the charset to use when rendering widgets.
  213. *
  214. * @return string The charset (defaults to UTF-8)
  215. */
  216. static public function getCharset()
  217. {
  218. return self::$charset;
  219. }
  220. /**
  221. * Sets the XHTML generation flag.
  222. *
  223. * @param bool $boolean true if widgets must be generated as XHTML, false otherwise
  224. */
  225. static public function setXhtml($boolean)
  226. {
  227. self::$xhtml = (boolean) $boolean;
  228. }
  229. /**
  230. * Returns whether to generate XHTML tags or not.
  231. *
  232. * @return bool true if widgets must be generated as XHTML, false otherwise
  233. */
  234. static public function isXhtml()
  235. {
  236. return self::$xhtml;
  237. }
  238. /**
  239. * Renders a HTML tag.
  240. *
  241. * @param string $tag The tag name
  242. * @param array $attributes An array of HTML attributes to be merged with the default HTML attributes
  243. *
  244. * @param string An HTML tag string
  245. */
  246. public function renderTag($tag, $attributes = array())
  247. {
  248. if (empty($tag))
  249. {
  250. return '';
  251. }
  252. return sprintf('<%s%s%s', $tag, $this->attributesToHtml($attributes), self::$xhtml ? ' />' : ('input' != $tag ? sprintf('></%s>', $tag) : '>'));
  253. }
  254. /**
  255. * Renders a HTML content tag.
  256. *
  257. * @param string $tag The tag name
  258. * @param string $content The content of the tag
  259. * @param array $attributes An array of HTML attributes to be merged with the default HTML attributes
  260. *
  261. * @param string An HTML tag string
  262. */
  263. public function renderContentTag($tag, $content = null, $attributes = array())
  264. {
  265. if (empty($tag))
  266. {
  267. return '';
  268. }
  269. return sprintf('<%s%s>%s</%s>', $tag, $this->attributesToHtml($attributes), $content, $tag);
  270. }
  271. /**
  272. * Escapes a string.
  273. *
  274. * @param string $value string to escape
  275. * @return string escaped string
  276. */
  277. static public function escapeOnce($value)
  278. {
  279. $value = is_object($value) ? $value->__toString() : (string) $value;
  280. return self::fixDoubleEscape(htmlspecialchars($value, ENT_QUOTES, self::getCharset()));
  281. }
  282. /**
  283. * Fixes double escaped strings.
  284. *
  285. * @param string $escaped string to fix
  286. * @return string single escaped string
  287. */
  288. static public function fixDoubleEscape($escaped)
  289. {
  290. return preg_replace('/&amp;([a-z]+|(#\d+)|(#x[\da-f]+));/i', '&$1;', $escaped);
  291. }
  292. /**
  293. * Converts an array of attributes to its HTML representation.
  294. *
  295. * @param array $attributes An array of attributes
  296. *
  297. * @return string The HTML representation of the HTML attribute array.
  298. */
  299. public function attributesToHtml($attributes)
  300. {
  301. $attributes = array_merge($this->attributes, $attributes);
  302. return implode('', array_map(array($this, 'attributesToHtmlCallback'), array_keys($attributes), array_values($attributes)));
  303. }
  304. /**
  305. * Prepares an attribute key and value for HTML representation.
  306. *
  307. * @param string $k The attribute key
  308. * @param string $v The attribute value
  309. *
  310. * @return string The HTML representation of the HTML key attribute pair.
  311. */
  312. protected function attributesToHtmlCallback($k, $v)
  313. {
  314. return is_null($v) || '' === $v ? '' : sprintf(' %s="%s"', $k, $this->escapeOnce($v));
  315. }
  316. }