PageRenderTime 44ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/helpers/FormHelper.php

https://github.com/wilkerlucio/fishy-framework
PHP | 495 lines | 354 code | 115 blank | 26 comment | 40 complexity | 4ccc409c9abfef757acb9fcb980392aa MD5 | raw file
  1. <?php
  2. /*
  3. * Copyright 2008 Wilker Lucio <wilkerlucio@gmail.com>
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /**
  18. * This class provides some functions to help form build
  19. *
  20. * @author Wilker Lucio
  21. */
  22. class Fishy_FormHelper
  23. {
  24. private static $form_stack = array();
  25. public static function form_for($object, $options = array(), $html_options = array())
  26. {
  27. global $CONTROLLER;
  28. $options = array_merge(array(
  29. 'multipart' => false,
  30. 'varname' => 'data'
  31. ), $options);
  32. $object->__form_var_name = $options['varname'];
  33. array_push(self::$form_stack, $object);
  34. $html_options = array_merge(array(
  35. 'accept-charset' => 'UTF-8',
  36. 'method' => 'post',
  37. 'action' => $object->exists() ? $CONTROLLER->url_to(array("action" => "update", "id" => $object->primary_key_value())) : $CONTROLLER->url_to("@create")
  38. ), $html_options);
  39. if ($options['multipart']) {
  40. $html_options['enctype'] = 'multipart/form-data';
  41. }
  42. return self::build_tag('form', $html_options, null, true);
  43. }
  44. public static function form_end()
  45. {
  46. array_pop(self::$form_stack);
  47. return '</form>';
  48. }
  49. public static function error_messages($options = array())
  50. {
  51. $options = array_merge(array(
  52. "id" => "errorExplanation"
  53. ), $options);
  54. $object = self::get_object();
  55. if (!is_a($object, 'ActiveRecord') || count($object->problems()) == 0) {
  56. return "";
  57. }
  58. $errors = '<div class="error-explanation" id="' . $options["id"] . '">';
  59. $errors .= '<ul>';
  60. foreach ($object->problems() as $problem) {
  61. $errors .= "<li>{$problem}</li>";
  62. }
  63. $errors .= '</ul>';
  64. $errors .= '</div>';
  65. return $errors;
  66. }
  67. public function label($field, $label, $html_options = array())
  68. {
  69. $object = self::get_object();
  70. $fieldname = self::get_field($field);
  71. $fieldid = self::get_field_id($field);
  72. $normal = self::get_normalized_field($field);
  73. $attributes = array_merge(array(
  74. 'for' => $fieldid,
  75. ), $html_options);
  76. return self::build_tag("label", $attributes, $label);
  77. }
  78. public static function text_field($field, $options = array(), $html_options = array())
  79. {
  80. $object = self::get_object();
  81. $fieldname = self::get_field($field);
  82. $fieldid = self::get_field_id($field);
  83. $normal = self::get_normalized_field($field);
  84. $attributes = array_merge(array(
  85. 'id' => $fieldid,
  86. 'name' => $fieldname,
  87. 'value' => $object->$normal,
  88. 'type' => 'text'
  89. ), $html_options);
  90. return self::tag_with_errors(self::build_tag('input', $attributes), $object, $normal);
  91. }
  92. public static function text_area($field, $options = array(), $html_options = array())
  93. {
  94. $object = self::get_object();
  95. $fieldname = self::get_field($field);
  96. $fieldid = self::get_field_id($field);
  97. $normal = self::get_normalized_field($field);
  98. $attributes = array_merge(array(
  99. 'id' => $fieldid,
  100. 'name' => $fieldname,
  101. 'class' => ''
  102. ), $html_options);
  103. if (!is_a($object, 'BlankObject') && $object->field_has_errors($normal)) {
  104. $attributes['class'] .= ' error';
  105. }
  106. return self::tag_with_errors(self::build_tag('textarea', $attributes, $object->$normal), $object, $normal);
  107. }
  108. public static function password_field($field, $options = array(), $html_options = array())
  109. {
  110. $html_options = array_merge(array('type' => 'password', 'value' => ''), $html_options);
  111. return self::text_field($field, $options, $html_options);
  112. }
  113. public static function hidden_field($field, $options = array(), $html_options = array())
  114. {
  115. $html_options = array_merge(array('type' => 'hidden'), $html_options);
  116. return self::text_field($field, $options, $html_options);
  117. }
  118. public static function file_field($field, $options = array(), $html_options = array())
  119. {
  120. $html_options = array_merge(array('type' => 'file', 'value' => ''), $html_options);
  121. return self::text_field($field, $options, $html_options);
  122. }
  123. public static function checkbox_field($field, $options = array(), $html_options = array())
  124. {
  125. $object = self::get_object();
  126. $fieldid = self::get_field_id($field);
  127. $normal = self::get_normalized_field($field);
  128. $attr = array('type' => 'checkbox', 'value' => 1);
  129. if ($object->$normal) {
  130. $attr['checked'] = 'checked';
  131. }
  132. $html_options = array_merge($attr, $html_options);
  133. return self::hidden_field($field, array(), array('value' => '0', 'id' => $fieldid . '_')) . self::text_field($field, $options, $html_options);
  134. }
  135. public static function radio_field($field, $value, $options = array(), $html_options = array())
  136. {
  137. $object = self::get_object();
  138. $fieldid = self::get_field_id($field);
  139. $normal = self::get_normalized_field($field);
  140. $attr = array('type' => 'radio', 'value' => $value, 'id' => "{$field}_{$value}_field");
  141. if ($object->$normal == $value) {
  142. $attr["checked"] = "checked";
  143. }
  144. $html_options = array_merge($attr, $html_options);
  145. return self::text_field($field, $options, $html_options);
  146. }
  147. public static function relational_field($field, $options = array(), $html_options = array())
  148. {
  149. $object = self::get_object();
  150. $normal = self::get_normalized_field($field);
  151. $options = array_merge(array(
  152. 'id_field' => 'id',
  153. 'value_field' => 'name'
  154. ), $options);
  155. if (!isset($options['query'])) $options['query'] = array('select' => "{$options['id_field']}, {$options['value_field']}", 'order' => $options['value_field']);
  156. $foreign = $object->describe_relation($field);
  157. $all = $foreign['model']->all($options['query']);
  158. $filter = ActiveRecord::model_diff($all, $object->$normal);
  159. $hidden_value = array();
  160. foreach ($object->$normal as $comes) {
  161. $hidden_value[] = $comes->primary_key_value();
  162. }
  163. $hidden_value = implode(',', $hidden_value);
  164. $common_html = array(
  165. 'multiple' => 'multiple',
  166. 'size' => '6'
  167. );
  168. $button_html = array(
  169. 'type' => 'button'
  170. );
  171. $hidden_id = self::get_field_id($field);
  172. $source_id = self::get_field_id($field . '_source');
  173. $destiny_id = self::get_field_id($field . '_destiny');
  174. $out = '';
  175. $out .= self::hidden_field($field, array(), array('value' => $hidden_value));
  176. $out .= self::select_for_model($field . '_source', $filter, $options['value_field'], $options['id_field'], array(), $common_html);
  177. $out .= "<br /><br />";
  178. $out .= self::build_tag('button', array_merge(array('onclick' => "Fishy.Util.move_options('#{$source_id}', '#{$destiny_id}')"), $button_html), 'Adicionar &darr;');
  179. $out .= self::build_tag('button', array_merge(array('onclick' => "Fishy.Util.move_options('#{$destiny_id}', '#{$source_id}')"), $button_html), 'Remover &uarr;');
  180. $out .= "<br /><br />";
  181. $out .= self::select_for_model($field . '_destiny', $object->$normal, $options['value_field'], $options['id_field'], array(), $common_html);
  182. $out .= "<script type=\"text/javascript\"> Fishy.Util.relational_map('#{$destiny_id}', '#{$hidden_id}') </script>";
  183. return $out;
  184. }
  185. public static function checkbox_group($field, $choices, $options = array(), $html_options = array())
  186. {
  187. $object = self::get_object();
  188. $fieldname = self::get_field($field);
  189. $fieldid = self::get_field_id($field);
  190. $normal = self::get_normalized_field($field);
  191. $options = array_merge(array(
  192. 'wrap_into' => '%s',
  193. 'checked' => null
  194. ), $options);
  195. if ($options['checked'] !== null && !is_array($options['checked'])) {
  196. $options['checked'] = array((string) $options['checked']);
  197. }
  198. $html_options = array_merge(array(
  199. 'name' => $fieldname . '[]',
  200. 'type' => 'checkbox'
  201. ), $html_options);
  202. $out = '';
  203. foreach ($choices as $value => $name) {
  204. $id = "{$fieldid}_{$value}";
  205. $attr = array_merge($html_options, array('value' => $value, 'id' => $id));
  206. if ($options['checked'] !== null && in_array($value, $options['checked'])) {
  207. $attr['checked'] = 'checked';
  208. }
  209. $out .= sprintf($options['wrap_into'], self::build_tag('input', $attr) . ' ' . self::build_tag('label', array('for' => $id), $name) . ' ');
  210. }
  211. return self::tag_with_errors($out, $object, $normal);
  212. }
  213. public static function select_num_range($start, $end)
  214. {
  215. $data = array();
  216. for ($i = $start; $i <= $end; $i++) {
  217. $data[$i] = $i;
  218. }
  219. return $data;
  220. }
  221. /**
  222. * Generates <select> tag
  223. *
  224. * @return void
  225. * @author wilker
  226. */
  227. public static function select($field, $choices, $options = array(), $html_options = array())
  228. {
  229. $object = self::get_object();
  230. $fieldname = self::get_field($field);
  231. $fieldid = self::get_field_id($field);
  232. $normal = self::get_normalized_field($field);
  233. $options = array_merge(array(
  234. 'include_blank' => null,
  235. 'selected' => $object->$normal
  236. ), $options);
  237. if ($options['selected'] !== null && !is_array($options['selected'])) {
  238. $options['selected'] = array((string) $options['selected']);
  239. }
  240. $html_options = array_merge(array(
  241. 'name' => $fieldname,
  242. 'id' => $fieldid
  243. ), $html_options);
  244. $out = '<select';
  245. $out .= self::build_html_attributes($html_options);
  246. $out .= ">";
  247. if ($options['include_blank'] !== null) {
  248. $out .= "<option value=\"\">{$options['include_blank']}</option>";
  249. }
  250. foreach ($choices as $value => $name) {
  251. $attr = array('value' => $value);
  252. if ($options['selected'] !== null && in_array($value, $options['selected'])) {
  253. $attr['selected'] = 'selected';
  254. }
  255. $out .= self::build_tag('option', $attr, $name);
  256. }
  257. $out .= "</select>";
  258. return self::tag_with_errors($out, $object, $normal);
  259. }
  260. public static function select_for_model($field, $collection, $name_field, $value_field = 'id', $options = array(), $html_options = array())
  261. {
  262. $object = self::get_object();
  263. $fieldname = self::get_field($field);
  264. $normal = self::get_normalized_field($field);
  265. $value = $object->$normal;
  266. if (!isset($options['selected'])) {
  267. if (is_array($value)) {
  268. $options['selected'] = array();
  269. $foreign = isset($options['foreign_value']) ? $options['foreign_value'] : 'id';
  270. foreach ($object->$normal as $row) {
  271. $options['selected'][] = $row->$foreign;
  272. }
  273. } else {
  274. $options['selected'] = $object->$normal;
  275. }
  276. }
  277. $choices = array();
  278. foreach ($collection as $item) {
  279. $choices[$item->$value_field] = $item->$name_field;
  280. }
  281. return self::select($field, $choices, $options, $html_options);
  282. }
  283. public static function checkbox_tree($field, $roots, $options = array(), $html_options = array())
  284. {
  285. if (count($roots) == 0) {
  286. return '';
  287. }
  288. $object = self::get_object();
  289. $fieldname = self::get_field($field);
  290. $normal = self::get_normalized_field($field);
  291. $options = array_merge(array(
  292. 'value_field' => 'id',
  293. 'label_field' => 'name',
  294. 'selected' => array()
  295. ), $options);
  296. $html_options = array_merge(array(
  297. 'type' => 'checkbox',
  298. 'name' => $fieldname
  299. ), $html_options);
  300. $content = '';
  301. foreach ($roots as $item) {
  302. $html_options['value'] = $item->$options['value_field'];
  303. if (in_array($item->$options['value_field'], $options['selected'])) {
  304. $html_options['checked'] = 'checked';
  305. } else {
  306. unset($html_options['checked']);
  307. }
  308. $tag = self::build_tag('input', $html_options);
  309. $tag .= $item->$options['label_field'];
  310. $tag .= self::checkbox_tree($field, $item->childs, $options, $html_options);
  311. $content .= self::build_tag('li', array(), $tag);
  312. }
  313. return self::build_tag('ul', array(), $content);
  314. }
  315. private static function get_object()
  316. {
  317. $stack_size = count(self::$form_stack);
  318. if ($stack_size > 0) {
  319. return self::$form_stack[$stack_size - 1];
  320. } else {
  321. return new BlankObject();
  322. }
  323. }
  324. private static function get_normalized_field($fieldname)
  325. {
  326. return preg_replace('/[^a-z0-9_-]/i', '', $fieldname);
  327. }
  328. private static function get_field($fieldname)
  329. {
  330. $object = self::get_object();
  331. if (is_a($object, 'BlankObject')) {
  332. return $fieldname;
  333. } else {
  334. $filtred_name = self::get_normalized_field($fieldname);
  335. $result = "{$object->__form_var_name}[$filtred_name]";
  336. if (Fishy_StringHelper::ends_with($fieldname, '[]')) {
  337. $result .= '[]';
  338. }
  339. return $result;
  340. }
  341. }
  342. private static function get_field_id($fieldname)
  343. {
  344. $object = self::get_object();
  345. $fieldname = self::get_normalized_field($fieldname);
  346. if (is_a($object, 'BlankObject')) {
  347. return $fieldname . '_field';
  348. } else {
  349. return $fieldname . '_field';
  350. }
  351. }
  352. private static function build_html_attributes($html_options)
  353. {
  354. $out = '';
  355. foreach ($html_options as $key => $value) {
  356. $out .= " $key=\"$value\"";
  357. }
  358. return $out;
  359. }
  360. private static function build_tag($tagname, $attributes = array(), $content = false, $force_open = false)
  361. {
  362. $attributes = self::build_html_attributes($attributes);
  363. if ($force_open) {
  364. return "<$tagname $attributes>";
  365. }
  366. if ($content !== false) {
  367. return "<$tagname $attributes>$content</$tagname>";
  368. } else {
  369. return "<$tagname $attributes />";
  370. }
  371. }
  372. private static function tag_with_errors($tag, $object, $normal)
  373. {
  374. if (!is_a($object, 'BlankObject') && $object->field_has_errors($normal)) {
  375. return self::build_tag("div", array("class" => "field-with-errors"), $tag);
  376. } else {
  377. return $tag;
  378. }
  379. }
  380. }