MultiCheckbox.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (http://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. (http://cakefoundation.org)
  11. * @link http://cakephp.org CakePHP(tm) Project
  12. * @since 3.0.0
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\View\Widget;
  16. use Cake\View\Form\ContextInterface;
  17. use Cake\View\Helper\IdGeneratorTrait;
  18. use Cake\View\Widget\WidgetInterface;
  19. /**
  20. * Input widget class for generating multiple checkboxes.
  21. *
  22. */
  23. class MultiCheckbox implements WidgetInterface {
  24. use IdGeneratorTrait;
  25. /**
  26. * Template instance to use.
  27. *
  28. * @var \Cake\View\StringTemplate
  29. */
  30. protected $_templates;
  31. /**
  32. * Label widget instance.
  33. *
  34. * @var \Cake\View\Widget\Label
  35. */
  36. protected $_label;
  37. /**
  38. * Render multi-checkbox widget.
  39. *
  40. * This class uses the following templates:
  41. *
  42. * - `checkbox` Renders checkbox input controls. Accepts
  43. * the `name`, `value` and `attrs` variables.
  44. * - `checkboxWrapper` Renders the containing div/element for
  45. * a checkbox and its label. Accepts the `input`, and `label`
  46. * variables.
  47. *
  48. * @param \Cake\View\StringTemplate $templates
  49. * @param \Cake\View\Widget\Label $label
  50. */
  51. public function __construct($templates, $label) {
  52. $this->_templates = $templates;
  53. $this->_label = $label;
  54. }
  55. /**
  56. * Render multi-checkbox widget.
  57. *
  58. * Data supports the following options.
  59. *
  60. * - `name` The name attribute of the inputs to create.
  61. * `[]` will be appended to the name.
  62. * - `options` An array of options to create checkboxes out of.
  63. * - `val` Either a string/integer or array of values that should be
  64. * checked. Can also be a complex options set.
  65. * - `disabled` Either a boolean or an array of checkboxes to disable.
  66. * - `escape` Set to false to disable HTML escaping.
  67. * - `options` An associative array of value=>labels to generate options for.
  68. * - `idPrefix` Prefix for generated ID attributes.
  69. *
  70. * ### Options format
  71. *
  72. * The options option can take a variety of data format depending on
  73. * the complexity of HTML you want generated.
  74. *
  75. * You can generate simple options using a basic associative array:
  76. *
  77. * {{{
  78. * 'options' => ['elk' => 'Elk', 'beaver' => 'Beaver']
  79. * }}}
  80. *
  81. * If you need to define additional attributes on your option elements
  82. * you can use the complex form for options:
  83. *
  84. * {{{
  85. * 'options' => [
  86. * ['value' => 'elk', 'text' => 'Elk', 'data-foo' => 'bar'],
  87. * ]
  88. * }}}
  89. *
  90. * This form **requires** that both the `value` and `text` keys be defined.
  91. * If either is not set options will not be generated correctly.
  92. *
  93. * @param array $data The data to generate a checkbox set with.
  94. * @param \Cake\View\Form\ContextInterface The current form context.
  95. * @return string
  96. */
  97. public function render(array $data, ContextInterface $context) {
  98. $data += [
  99. 'name' => '',
  100. 'escape' => true,
  101. 'options' => [],
  102. 'disabled' => null,
  103. 'val' => null,
  104. 'idPrefix' => null
  105. ];
  106. $out = [];
  107. $this->_idPrefix = $data['idPrefix'];
  108. $this->_clearIds();
  109. foreach ($data['options'] as $key => $val) {
  110. $checkbox = [
  111. 'value' => $key,
  112. 'text' => $val,
  113. ];
  114. if (is_array($val) && isset($val['text'], $val['value'])) {
  115. $checkbox = $val;
  116. }
  117. $checkbox['name'] = $data['name'];
  118. $checkbox['escape'] = $data['escape'];
  119. if ($this->_isSelected($key, $data['val'])) {
  120. $checkbox['checked'] = true;
  121. }
  122. if ($this->_isDisabled($key, $data['disabled'])) {
  123. $checkbox['disabled'] = true;
  124. }
  125. if (empty($checkbox['id'])) {
  126. $checkbox['id'] = $this->_id($checkbox['name'], $checkbox['value']);
  127. }
  128. $out[] = $this->_renderInput($checkbox, $context);
  129. }
  130. return implode('', $out);
  131. }
  132. /**
  133. * Render a single checkbox & wrapper.
  134. *
  135. * @param array $checkbox An array containing checkbox key/value option pairs
  136. * @param \Cake\View\Form\ContextInterface Context object.
  137. * @return string
  138. */
  139. protected function _renderInput($checkbox, $context) {
  140. $input = $this->_templates->format('checkbox', [
  141. 'name' => $checkbox['name'] . '[]',
  142. 'value' => $checkbox['escape'] ? h($checkbox['value']) : $checkbox['value'],
  143. 'attrs' => $this->_templates->formatAttributes(
  144. $checkbox,
  145. ['name', 'value', 'text']
  146. )
  147. ]);
  148. $labelAttrs = [
  149. 'for' => $checkbox['id'],
  150. 'escape' => $checkbox['escape'],
  151. 'text' => $checkbox['text'],
  152. 'input' => $input,
  153. ];
  154. if (!empty($checkbox['checked']) && empty($labelAttrs['class'])) {
  155. $labelAttrs['class'] = 'selected';
  156. }
  157. $label = $this->_label->render($labelAttrs, $context);
  158. return $this->_templates->format('checkboxWrapper', [
  159. 'label' => $label,
  160. 'input' => $input
  161. ]);
  162. }
  163. /**
  164. * Helper method for deciding what options are selected.
  165. *
  166. * @param string $key The key to test.
  167. * @param array|string|null The selected values.
  168. * @return bool
  169. */
  170. protected function _isSelected($key, $selected) {
  171. if ($selected === null) {
  172. return false;
  173. }
  174. $isArray = is_array($selected);
  175. if (!$isArray) {
  176. return (string)$key === (string)$selected;
  177. }
  178. $strict = !is_numeric($key);
  179. return in_array((string)$key, $selected, $strict);
  180. }
  181. /**
  182. * Helper method for deciding what options are disabled.
  183. *
  184. * @param string $key The key to test.
  185. * @param array|null The disabled values.
  186. * @return bool
  187. */
  188. protected function _isDisabled($key, $disabled) {
  189. if ($disabled === null || $disabled === false) {
  190. return false;
  191. }
  192. if ($disabled === true || is_string($disabled)) {
  193. return true;
  194. }
  195. $strict = !is_numeric($key);
  196. return in_array((string)$key, $disabled, $strict);
  197. }
  198. /**
  199. * {@inheritDoc}
  200. */
  201. public function secureFields(array $data) {
  202. return [$data['name']];
  203. }
  204. }