PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/pkp/classes/form/Form.inc.php

https://github.com/lib-uoguelph-ca/ocs
PHP | 984 lines | 782 code | 51 blank | 151 comment | 36 complexity | a845706e0d337a2da6239b20af8fe8f1 MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. /**
  3. * @defgroup form
  4. */
  5. /**
  6. * @file classes/form/Form.inc.php
  7. *
  8. * Copyright (c) 2000-2012 John Willinsky
  9. * Distributed under the GNU GPL v2. For full terms see the file docs/COPYING.
  10. *
  11. * @class Form
  12. * @ingroup core
  13. *
  14. * @brief Class defining basic operations for handling HTML forms.
  15. */
  16. import('form.FormError');
  17. // Import all form validators for convenient use in sub-classes
  18. import('form.validation.FormValidatorAlphaNum');
  19. import('form.validation.FormValidatorArray');
  20. import('form.validation.FormValidatorArrayCustom');
  21. import('form.validation.FormValidatorControlledVocab');
  22. import('form.validation.FormValidatorCustom');
  23. import('form.validation.FormValidatorCaptcha');
  24. import('form.validation.FormValidatorEmail');
  25. import('form.validation.FormValidatorInSet');
  26. import('form.validation.FormValidatorLength');
  27. import('form.validation.FormValidatorLocale');
  28. import('form.validation.FormValidatorLocaleEmail');
  29. import('form.validation.FormValidatorPost');
  30. import('form.validation.FormValidatorRegExp');
  31. import('form.validation.FormValidatorUri');
  32. import('form.validation.FormValidatorUrl');
  33. class Form {
  34. /** The template file containing the HTML form */
  35. var $_template;
  36. /** Associative array containing form data */
  37. var $_data;
  38. /** Validation checks for this form */
  39. var $_checks;
  40. /** Errors occurring in form validation */
  41. var $_errors;
  42. /** Array of field names where an error occurred and the associated error message */
  43. var $errorsArray;
  44. /** Array of field names where an error occurred */
  45. var $errorFields;
  46. /** Array of errors for the form section currently being processed */
  47. var $formSectionErrors;
  48. /** Styles organized by parameter name */
  49. var $fbvStyles;
  50. /** Client-side validation rules **/
  51. var $cssValidation;
  52. /**
  53. * Constructor.
  54. * @param $template string the path to the form template file
  55. */
  56. function Form($template, $callHooks = true) {
  57. if ($callHooks === true && checkPhpVersion('4.3.0')) {
  58. $trace = debug_backtrace();
  59. // Call hooks based on the calling entity, assuming
  60. // this method is only called by a subclass. Results
  61. // in hook calls named e.g. "papergalleyform::Constructor"
  62. // Note that class names are always lower case.
  63. HookRegistry::call(strtolower($trace[1]['class']) . '::Constructor', array(&$this, &$template));
  64. }
  65. $this->_template = $template;
  66. $this->_data = array();
  67. $this->_checks = array();
  68. $this->_errors = array();
  69. $this->errorsArray = array();
  70. $this->errorFields = array();
  71. $this->formSectionErrors = array();
  72. $this->fbvStyles = array(
  73. 'size' => array('SMALL' => 'SMALL', 'MEDIUM' => 'MEDIUM', 'LARGE' => 'LARGE'),
  74. 'float' => array('RIGHT' => 'RIGHT', 'LEFT' => 'LEFT'),
  75. 'measure' => array('1OF2' => '1OF2', '3OF4' => '3OF4', '2OF3' => '2OF3'),
  76. 'layout' => array('THREE_COLUMNS' => 'THREE_COLUMNS', 'TWO_COLUMNS' => 'TWO_COLUMNS', 'ONE_COLUMN' => 'ONE_COLUMN')
  77. );
  78. }
  79. /**
  80. * Display the form.
  81. * @param $request PKPRequest
  82. * @param $fetch boolean if set to true will return the rendered
  83. * form rather than sending the response to the user
  84. * @return string the rendered form if fetch is true, otherwise null
  85. */
  86. function display($request = null, $fetch = false) {
  87. if (checkPhpVersion('4.3.0')) {
  88. $returner = null;
  89. $trace = debug_backtrace();
  90. // Call hooks based on the calling entity, assuming
  91. // this method is only called by a subclass. Results
  92. // in hook calls named e.g. "papergalleyform::display"
  93. // Note that class names are always lower case.
  94. if (HookRegistry::call(strtolower($trace[1]['class']) . '::' . $trace[0]['function'], array(&$this, &$returner))) {
  95. return $returner;
  96. }
  97. }
  98. $templateMgr =& TemplateManager::getManager($request);
  99. $templateMgr->setCacheability(CACHEABILITY_NO_STORE);
  100. $templateMgr->register_function('fieldLabel', array(&$this, 'smartyFieldLabel'));
  101. $templateMgr->register_function('form_language_chooser', array(&$this, 'smartyFormLanguageChooser'));
  102. $templateMgr->register_function('modal_language_chooser', array(&$this, 'smartyModalLanguageChooser'));
  103. $templateMgr->register_block('form_locale_iterator', array(&$this, 'formLocaleIterator'));
  104. // modifier vocabulary for creating forms
  105. $templateMgr->register_block('fbvFormSection', array(&$this, 'smartyFBVFormSection'));
  106. $templateMgr->register_block('fbvCustomElement', array(&$this, 'smartyFBVCustomElement'));
  107. $templateMgr->register_block('fbvFormArea', array(&$this, 'smartyFBVFormArea'));
  108. $templateMgr->register_function('fbvButton', array(&$this, 'smartyFBVButton'));
  109. $templateMgr->register_function('fbvTextInput', array(&$this, 'smartyFBVTextInput'));
  110. $templateMgr->register_function('fbvTextarea', array(&$this, 'smartyFBVTextArea'));
  111. $templateMgr->register_function('fbvSelect', array(&$this, 'smartyFBVSelect'));
  112. $templateMgr->register_function('fbvElement', array(&$this, 'smartyFBVElement'));
  113. $templateMgr->register_function('fbvElementMultilingual', array(&$this, 'smartyFBVElementMultilingual'));
  114. $templateMgr->register_function('fbvCheckbox', array(&$this, 'smartyFBVCheckbox'));
  115. $templateMgr->register_function('fbvRadioButton', array(&$this, 'smartyFBVRadioButton'));
  116. $templateMgr->register_function('fbvFileInput', array(&$this, 'smartyFBVFileInput'));
  117. $templateMgr->assign('fbvStyles', $this->fbvStyles);
  118. $templateMgr->assign($this->_data);
  119. $templateMgr->assign('isError', !$this->isValid());
  120. $templateMgr->assign('errors', $this->getErrorsArray());
  121. $templateMgr->assign('formLocales', AppLocale::getSupportedFormLocales());
  122. // Determine the current locale to display fields with
  123. $formLocale = Request::getUserVar('formLocale');
  124. if (empty($formLocale)) $formLocale = AppLocale::getLocale();
  125. if (!in_array($formLocale, array_keys(AppLocale::getSupportedFormLocales()))) {
  126. $formLocale = AppLocale::getPrimaryLocale();
  127. }
  128. $templateMgr->assign('formLocale', $formLocale);
  129. if ($fetch) {
  130. return $templateMgr->fetch($this->_template);
  131. } else {
  132. $templateMgr->display($this->_template);
  133. return null;
  134. }
  135. }
  136. /**
  137. * Get the value of a form field.
  138. * @param $key string
  139. * @return mixed
  140. */
  141. function getData($key) {
  142. return isset($this->_data[$key]) ? $this->_data[$key] : null;
  143. }
  144. /**
  145. * Set the value of a form field.
  146. * @param $key
  147. * @param $value
  148. */
  149. function setData($key, $value) {
  150. if (is_string($value)) $value = Core::cleanVar($value);
  151. $this->_data[$key] = $value;
  152. }
  153. /**
  154. * Initialize form data for a new form.
  155. */
  156. function initData() {
  157. if (checkPhpVersion('4.3.0')) {
  158. $trace = debug_backtrace();
  159. // Call hooks based on the calling entity, assuming
  160. // this method is only called by a subclass. Results
  161. // in hook calls named e.g. "papergalleyform::initData"
  162. // Note that class and function names are always lower
  163. // case.
  164. HookRegistry::call(strtolower($trace[1]['class'] . '::' . $trace[0]['function']), array(&$this));
  165. }
  166. }
  167. /**
  168. * Assign form data to user-submitted data.
  169. */
  170. function readInputData() {
  171. }
  172. /**
  173. * Validate form data.
  174. */
  175. function validate($callHooks = true) {
  176. if (!isset($this->errorsArray)) {
  177. $this->getErrorsArray();
  178. }
  179. foreach ($this->_checks as $check) {
  180. // WARNING: This line is for PHP4 compatibility when
  181. // instantiating forms without reference. Should not
  182. // be removed or otherwise used.
  183. // See http://pkp.sfu.ca/wiki/index.php/Information_for_Developers#Use_of_.24this_in_the_constructor
  184. // for an explanation why we have to replace the reference to $this here.
  185. $check->setForm($this);
  186. if (!isset($this->errorsArray[$check->getField()]) && !$check->isValid()) {
  187. if (method_exists($check, 'getErrorFields') && method_exists($check, 'isArray') && call_user_func(array(&$check, 'isArray'))) {
  188. $errorFields = call_user_func(array(&$check, 'getErrorFields'));
  189. for ($i=0, $count=count($errorFields); $i < $count; $i++) {
  190. $this->addError($errorFields[$i], $check->getMessage());
  191. $this->errorFields[$errorFields[$i]] = 1;
  192. }
  193. } else {
  194. $this->addError($check->getField(), $check->getMessage());
  195. $this->errorFields[$check->getField()] = 1;
  196. }
  197. }
  198. }
  199. if ($callHooks === true && checkPhpVersion('4.3.0')) {
  200. $trace = debug_backtrace();
  201. // Call hooks based on the calling entity, assuming
  202. // this method is only called by a subclass. Results
  203. // in hook calls named e.g. "papergalleyform::validate"
  204. // Note that class and function names are always lower
  205. // case.
  206. $value = null;
  207. if (HookRegistry::call(strtolower($trace[0]['class'] . '::' . $trace[0]['function']), array(&$this, &$value))) {
  208. return $value;
  209. }
  210. }
  211. return $this->isValid();
  212. }
  213. /**
  214. * Execute the form's action.
  215. * (Note that it is assumed that the form has already been validated.)
  216. */
  217. function execute() {
  218. if (checkPhpVersion('4.3.0')) {
  219. $trace = debug_backtrace();
  220. // Call hooks based on the calling entity, assuming
  221. // this method is only called by a subclass. Results
  222. // in hook calls named e.g. "papergalleyform::execute"
  223. // Note that class and function names are always lower
  224. // case.
  225. $value = null;
  226. HookRegistry::call(strtolower($trace[1]['class'] . '::' . $trace[0]['function']), array(&$this, &$vars));
  227. }
  228. }
  229. /**
  230. * Get the list of field names that need to support multiple locales
  231. * @return array
  232. */
  233. function getLocaleFieldNames() {
  234. $returner = array();
  235. if (checkPhpVersion('4.3.0')) {
  236. $trace = debug_backtrace();
  237. // Call hooks based on the calling entity, assuming
  238. // this method is only called by a subclass. Results
  239. // in hook calls named e.g. "papergalleyform::getLocaleFieldNames"
  240. // Note that class and function names are always lower
  241. // case.
  242. $value = null;
  243. HookRegistry::call(strtolower($trace[1]['class'] . '::' . $trace[0]['function']), array(&$this, &$returner));
  244. }
  245. return $returner;
  246. }
  247. /**
  248. * Determine whether or not the current request results from a resubmit
  249. * of locale data resulting from a form language change.
  250. * @return boolean
  251. */
  252. function isLocaleResubmit() {
  253. $formLocale = Request::getUserVar('formLocale');
  254. return (!empty($formLocale));
  255. }
  256. /**
  257. * Get the current form locale.
  258. * @return string
  259. */
  260. function getFormLocale() {
  261. $formLocale = Request::getUserVar('formLocale');
  262. if (empty($formLocale)) $formLocale = AppLocale::getLocale();
  263. return $formLocale;
  264. }
  265. /**
  266. * Adds specified user variables to input data.
  267. * @param $vars array the names of the variables to read
  268. */
  269. function readUserVars($vars) {
  270. if (checkPhpVersion('4.3.0')) {
  271. $trace = debug_backtrace();
  272. // Call hooks based on the calling entity, assuming
  273. // this method is only called by a subclass. Results
  274. // in hook calls named e.g. "papergalleyform::readUserVars"
  275. // Note that class and function names are always lower
  276. // case.
  277. $value = null;
  278. HookRegistry::call(strtolower($trace[1]['class'] . '::' . $trace[0]['function']), array(&$this, &$vars));
  279. }
  280. foreach ($vars as $k) {
  281. $this->setData($k, Request::getUserVar($k));
  282. }
  283. }
  284. /**
  285. * Adds specified user date variables to input data.
  286. * @param $vars array the names of the date variables to read
  287. */
  288. function readUserDateVars($vars) {
  289. if (checkPhpVersion('4.3.0')) {
  290. $trace = debug_backtrace();
  291. // Call hooks based on the calling entity, assuming
  292. // this method is only called by a subclass. Results
  293. // in hook calls named e.g. "papergalleyform::readUserDateVars"
  294. // Note that class and function names are always lower
  295. // case.
  296. $value = null;
  297. HookRegistry::call(strtolower($trace[1]['class'] . '::' . $trace[0]['function']), array(&$this, &$vars));
  298. }
  299. foreach ($vars as $k) {
  300. $this->setData($k, Request::getUserDateVar($k));
  301. }
  302. }
  303. /**
  304. * Add a validation check to the form.
  305. * @param $formValidator FormValidator
  306. */
  307. function addCheck($formValidator) {
  308. $this->_checks[] =& $formValidator;
  309. }
  310. /**
  311. * Add an error to the form.
  312. * Errors are typically assigned as the form is validated.
  313. * @param $field string the name of the field where the error occurred
  314. */
  315. function addError($field, $message) {
  316. $this->_errors[] = new FormError($field, $message);
  317. }
  318. /**
  319. * Add an error field for highlighting on form
  320. * @param $field string the name of the field where the error occurred
  321. */
  322. function addErrorField($field) {
  323. $this->errorFields[$field] = 1;
  324. }
  325. /**
  326. * Check if form passes all validation checks.
  327. * @return boolean
  328. */
  329. function isValid() {
  330. return empty($this->_errors);
  331. }
  332. /**
  333. * Return set of errors that occurred in form validation.
  334. * If multiple errors occurred processing a single field, only the first error is included.
  335. * @return array erroneous fields and associated error messages
  336. */
  337. function getErrorsArray() {
  338. $this->errorsArray = array();
  339. foreach ($this->_errors as $error) {
  340. if (!isset($this->errorsArray[$error->getField()])) {
  341. $this->errorsArray[$error->getField()] = $error->getMessage();
  342. }
  343. }
  344. return $this->errorsArray;
  345. }
  346. /**
  347. * Custom Smarty function for labelling/highlighting of form fields.
  348. * @param $params array can contain 'name' (field name/ID), 'required' (required field), 'key' (localization key), 'label' (non-localized label string), 'suppressId' (boolean)
  349. * @param $smarty Smarty
  350. */
  351. function smartyFieldLabel($params, &$smarty) {
  352. $returner = '';
  353. if (isset($params) && !empty($params)) {
  354. if (isset($params['key'])) {
  355. $params['label'] = __($params['key'], $params);
  356. }
  357. if (isset($this->errorFields[$params['name']])) {
  358. $class = ' class="error"';
  359. } else {
  360. $class = '';
  361. }
  362. $returner = '<label' . (isset($params['suppressId']) ? '' : ' for="' . $params['name'] . '"') . $class . '>' . $params['label'] . (isset($params['required']) && !empty($params['required']) ? '*' : '') . '</label>';
  363. }
  364. return $returner;
  365. }
  366. function _decomposeArray($name, $value, $stack) {
  367. $returner = '';
  368. if (is_array($value)) {
  369. foreach ($value as $key => $subValue) {
  370. $newStack = $stack;
  371. $newStack[] = $key;
  372. $returner .= $this->_decomposeArray($name, $subValue, $newStack);
  373. }
  374. } else {
  375. $name = htmlentities($name, ENT_COMPAT, LOCALE_ENCODING);
  376. $value = htmlentities($value, ENT_COMPAT, LOCALE_ENCODING);
  377. $returner .= '<input type="hidden" name="' . $name;
  378. while (($item = array_shift($stack)) !== null) {
  379. $item = htmlentities($item, ENT_COMPAT, LOCALE_ENCODING);
  380. $returner .= '[' . $item . ']';
  381. }
  382. $returner .= '" value="' . $value . "\" />\n";
  383. }
  384. return $returner;
  385. }
  386. /**
  387. * Add hidden form parameters for the localized fields for this form
  388. * and display the language chooser field
  389. * @param $params array
  390. * @param $smarty object
  391. */
  392. function smartyFormLanguageChooser($params, &$smarty) {
  393. $returner = '';
  394. // Print back all non-current language field values so that they
  395. // are not lost.
  396. $formLocale = $smarty->get_template_vars('formLocale');
  397. foreach ($this->getLocaleFieldNames() as $field) {
  398. $values = $this->getData($field);
  399. if (!is_array($values)) continue;
  400. foreach ($values as $locale => $value) {
  401. if ($locale != $formLocale) $returner .= $this->_decomposeArray($field, $value, array($locale));
  402. }
  403. }
  404. // Display the language selector widget.
  405. $formLocale = $smarty->get_template_vars('formLocale');
  406. $returner .= '<div id="languageSelector"><select size="1" name="formLocale" id="formLocale" onchange="changeFormAction(\'' . htmlentities($params['form'], ENT_COMPAT, LOCALE_ENCODING) . '\', \'' . htmlentities($params['url'], ENT_QUOTES, LOCALE_ENCODING) . '\')" class="selectMenu">';
  407. foreach (AppLocale::getSupportedLocales() as $locale => $name) {
  408. $returner .= '<option ' . ($locale == $formLocale?'selected="selected" ':'') . 'value="' . htmlentities($locale, ENT_COMPAT, LOCALE_ENCODING) . '">' . htmlentities($name, ENT_COMPAT, LOCALE_ENCODING) . '</option>';
  409. }
  410. $returner .= '</select></div>';
  411. return $returner;
  412. }
  413. /** form builder vocabulary - FBV */
  414. /**
  415. * Retrieve style info associated with style constants.
  416. * @param $category string
  417. * @param $value string
  418. */
  419. function getStyleInfoByIdentifier($category, $value) {
  420. $returner = null;
  421. switch ($category) {
  422. case 'size':
  423. switch($value) {
  424. case 'SMALL': $returner = 'small'; break;
  425. case 'MEDIUM': $returner = 'medium'; break;
  426. case 'LARGE': $returner = 'large'; break;
  427. }
  428. break;
  429. case 'float':
  430. switch($value) {
  431. case 'LEFT': $returner = 'full leftHalf'; break;
  432. case 'RIGHT': $returner = 'full rightHalf'; break;
  433. }
  434. break;
  435. case 'layout':
  436. switch($value) {
  437. case 'THREE_COLUMNS': $returner = 'full threeColumns'; break;
  438. case 'TWO_COLUMNS': $returner = 'full twoColumns'; break;
  439. case 'ONE_COLUMN': $returner = 'full'; break;
  440. }
  441. break;
  442. case 'measure':
  443. switch($value) {
  444. case '1OF2': $returner = 'size1of2'; break;
  445. case '2OF3': $returner = 'size2of3'; break;
  446. case '3OF4': $returner = 'size3of4'; break;
  447. }
  448. break;
  449. }
  450. if (!$returner) {
  451. $templateMgr =& TemplateManager::getManager();
  452. $templateMgr->trigger_error('FBV: invalid style value ['.$category.', '.$value.']');
  453. }
  454. return $returner;
  455. }
  456. /**
  457. * A form area that contains form sections.
  458. * parameters: id
  459. * @param $params array
  460. * @param $content string
  461. * @param $smarty object
  462. * @param $repeat
  463. */
  464. function smartyFBVFormArea($params, $content, &$smarty, &$repeat) {
  465. if (!isset($params['id'])) {
  466. $smarty->trigger_error('FBV: form area \'id\' not set.');
  467. }
  468. if (!$repeat) {
  469. $smarty->assign('FBV_id', $params['id']);
  470. $smarty->assign('FBV_content', $content);
  471. return $smarty->fetch('form/formArea.tpl');
  472. }
  473. return '';
  474. }
  475. /**
  476. * A form section that contains controls in a variety of layout possibilities.
  477. * parameters: title, float (optional), layout (optional), group (optional), required (optional), for (optinal)
  478. * @param $params array
  479. * @param $content string
  480. * @param $smarty object
  481. * @param $repeat
  482. */
  483. function smartyFBVFormSection($params, $content, &$smarty, &$repeat) {
  484. if (!$repeat) {
  485. $smarty->assign('FBV_group', isset($params['group']) ? $params['group'] : false);
  486. $smarty->assign('FBV_required', isset($params['required']) ? $params['required'] : false);
  487. $smarty->assign('FBV_labelFor', empty($params['for']) ? null : $params['for']);
  488. $smarty->assign('FBV_title', $params['title']);
  489. $smarty->assign('FBV_content', $content);
  490. $floatInfo = '';
  491. $float = isset($params['float']) ? $params['float'] : null;
  492. if ($float) {
  493. $floatInfo = $this->getStyleInfoByIdentifier('float', $float);
  494. }
  495. $layoutInfo = '';
  496. $layout = isset($params['layout']) ? $params['layout'] : null;
  497. if ($layout) {
  498. $layoutInfo = $this->getStyleInfoByIdentifier('layout', $layout);
  499. }
  500. $class = empty($layoutInfo) ? $floatInfo : $layoutInfo . ' ' . $floatInfo;
  501. if (!empty($this->formSectionErrors)) {
  502. $class = $class . (empty($class) ? '' : ' ') . 'error';
  503. }
  504. $smarty->assign('FBV_sectionErrors', $this->formSectionErrors);
  505. $smarty->assign('FBV_class', $class);
  506. $smarty->assign('FBV_layoutColumns', empty($layoutInfo) ? false : true);
  507. $this->formSectionErrors = array();
  508. return $smarty->fetch('form/formSection.tpl');
  509. } else {
  510. $this->formSectionErrors = array();
  511. }
  512. return '';
  513. }
  514. function smartyFBVElementMultilingual($params, &$smarty, $content = null) {
  515. if ( !isset($params['value']) || !is_array($params['value'])) {
  516. $smarty->trigger_error('FBV: value parameter must be an array for multilingual elements');
  517. }
  518. if ( !isset($params['name']) ) {
  519. $smarty->trigger_error('FBV: parameter must be set');
  520. }
  521. $required = isset($params['required'])?$params['required']:false;
  522. $returner = '';
  523. $values = $params['value'];
  524. $name = $params['name'];
  525. foreach (AppLocale::getSupportedLocales() as $locale => $localeName) {
  526. // if the field is required, only set the main locale as required and others optional
  527. if ( $locale == AppLocale::getPrimaryLocale() ) {
  528. $params['required'] = $required;
  529. } else {
  530. $params['required'] = false;
  531. }
  532. $params['name'] = $name . "[$locale]";
  533. $params['value'] = $values[$locale];
  534. $returner .= $localeName . ' ' . $this->smartyFBVElement($params, $smarty, $content) . '<br />';
  535. }
  536. return $returner;
  537. }
  538. /**
  539. * Form element.
  540. * parameters: type, id, label (optional), required (optional), measure, any other attributes specific to 'type'
  541. * @param $params array
  542. * @param $smarty object
  543. */
  544. function smartyFBVElement($params, &$smarty, $content = null) {
  545. if (isset($params['type'])) {
  546. switch (strtolower($params['type'])) {
  547. case 'text':
  548. $content = $this->smartyFBVTextInput($params, $smarty);
  549. break;
  550. case 'textarea':
  551. $content = $this->smartyFBVTextArea($params, $smarty);
  552. break;
  553. case 'checkbox':
  554. $content = $this->smartyFBVCheckbox($params, $smarty);
  555. unset($params['label']);
  556. break;
  557. case 'radio':
  558. $content = $this->smartyFBVRadioButton($params, $smarty);
  559. unset($params['label']);
  560. break;
  561. case 'select':
  562. $content = $this->smartyFBVSelect($params, $smarty);
  563. break;
  564. case 'custom':
  565. break;
  566. default: $content = null;
  567. }
  568. if (!$content) return '';
  569. unset($params['type']);
  570. $parent = $smarty->_tag_stack[count($smarty->_tag_stack)-1];
  571. $group = false;
  572. if ($parent) {
  573. if (isset($this->errorFields[$params['id']])) {
  574. array_push($this->formSectionErrors, $this->errorsArray[$params['id']]);
  575. }
  576. if (isset($parent[1]['group']) && $parent[1]['group']) {
  577. $group = true;
  578. }
  579. }
  580. $smarty->assign('FBV_content', $content);
  581. $smarty->assign('FBV_group', $group);
  582. $smarty->assign('FBV_id', isset($params['id']) ? $params['id'] : null);
  583. $smarty->assign('FBV_label', empty($params['label']) ? null : $params['label']);
  584. $smarty->assign('FBV_required', isset($params['required']) ? $params['required'] : false);
  585. $smarty->assign('FBV_measureInfo', empty($params['measure']) ? null : $this->getStyleInfoByIdentifier('measure', $params['measure']));
  586. return $smarty->fetch('form/element.tpl');
  587. }
  588. return '';
  589. }
  590. /**
  591. * Custom form element. User form code is placed between customElement tags.
  592. * parameters: id, label (optional), required (optional)
  593. * @param $params array
  594. * @param $content string
  595. * @param $smarty object
  596. * @param $repeat
  597. */
  598. function smartyFBVCustomElement($params, $content, &$smarty, &$repeat) {
  599. if (!$repeat) {
  600. $params['type'] = 'custom';
  601. return $this->smartyFBVElement($params, $smarty, $content);
  602. }
  603. return '';
  604. }
  605. /**
  606. * Form button.
  607. * parameters: label (or value), disabled (optional), type (optional), all other attributes associated with this control (except class)
  608. * @param $params array
  609. * @param $smarty object
  610. */
  611. function smartyFBVButton($params, &$smarty) {
  612. $buttonParams = '';
  613. // accept 'value' param, but the 'label' param is preferred
  614. if (isset($params['value'])) {
  615. $value = $params['value'];
  616. $params['label'] = isset($params['label']) ? $params['label'] : $value;
  617. unset($params['value']);
  618. }
  619. // the type of this button. the default value is 'button'
  620. $params['type'] = isset($params['type']) ? strtolower($params['type']) : 'button';
  621. $params['disabled'] = isset($params['disabled']) ? $params['disabled'] : false;
  622. foreach ($params as $key => $value) {
  623. switch ($key) {
  624. case 'label': $smarty->assign('FBV_label', $value); break;
  625. case 'type': $smarty->assign('FBV_type', $value); break;
  626. case 'class': break; //ignore class attributes
  627. case 'disabled': $smarty->assign('FBV_disabled', $params['disabled']); break;
  628. default: $buttonParams .= htmlspecialchars($key, ENT_QUOTES, LOCALE_ENCODING) . '="' . htmlspecialchars($value, ENT_QUOTES, LOCALE_ENCODING) . '" ';
  629. }
  630. }
  631. $smarty->assign('FBV_buttonParams', $buttonParams);
  632. return $smarty->fetch('form/button.tpl');
  633. }
  634. /**
  635. * Form text input.
  636. * parameters: size, disabled (optional), name (optional - assigned value of 'id' by default), all other attributes associated with this control (except class and type)
  637. * @param $params array
  638. * @param $smarty object
  639. */
  640. function smartyFBVTextInput($params, &$smarty) {
  641. if (!isset($params['id'])) {
  642. $smarty->trigger_error('FBV: text input form element \'id\' not set.');
  643. }
  644. $textInputParams = '';
  645. $params['name'] = isset($params['name']) ? $params['name'] : $params['id'];
  646. $params['disabled'] = isset($params['disabled']) ? $params['disabled'] : false;
  647. $params = $this->addClientSideValidation($params);
  648. $smarty->assign('FBV_validation', null); // Reset form validation fields in memory
  649. $smarty->assign('FBV_isPassword', isset($params['password']) ? true : false);
  650. // prepare the control's size info
  651. if (isset($params['size'])) {
  652. $sizeInfo = $this->getStyleInfoByIdentifier('size', $params['size']);
  653. $smarty->assign('FBV_sizeInfo', $sizeInfo);
  654. unset($params['size']);
  655. } else {
  656. $smarty->assign('FBV_sizeInfo', null);
  657. }
  658. foreach ($params as $key => $value) {
  659. switch ($key) {
  660. case 'class': break; //ignore class attributes
  661. case 'label': break;
  662. case 'type': break;
  663. case 'validation': $smarty->assign('FBV_validation', $params['validation']); break;
  664. case 'required': break; //ignore required field (define required fields in form class)
  665. case 'disabled': $smarty->assign('FBV_disabled', $params['disabled']); break;
  666. default: $textInputParams .= htmlspecialchars($key, ENT_QUOTES, LOCALE_ENCODING) . '="' . htmlspecialchars($value, ENT_QUOTES, LOCALE_ENCODING). '" ';
  667. }
  668. }
  669. $smarty->assign('FBV_textInputParams', $textInputParams);
  670. return $smarty->fetch('form/textInput.tpl');
  671. }
  672. /**
  673. * Form text area.
  674. * parameters: value, id, name (optional - assigned value of 'id' by default), disabled (optional), all other attributes associated with this control (except class)
  675. * @param $params array
  676. * @param $smarty object
  677. */
  678. function smartyFBVTextArea($params, &$smarty) {
  679. if (!isset($params['id'])) {
  680. $smarty->trigger_error('FBV: text area form element \'id\' not set.');
  681. }
  682. $params = $this->addClientSideValidation($params);
  683. $textAreaParams = '';
  684. $params['name'] = isset($params['name']) ? $params['name'] : $params['id'];
  685. $params['disabled'] = isset($params['disabled']) ? $params['disabled'] : false;
  686. $smarty->assign('FBV_validation', null); // Reset form validation fields in memory
  687. // prepare the control's size info
  688. if (isset($params['size'])) {
  689. $sizeInfo = $this->getStyleInfoByIdentifier('size', $params['size']);
  690. $smarty->assign('FBV_sizeInfo', $sizeInfo);
  691. unset($params['size']);
  692. } else {
  693. $smarty->assign('FBV_sizeInfo', null);
  694. }
  695. foreach ($params as $key => $value) {
  696. switch ($key) {
  697. case 'value': $smarty->assign('FBV_value', $value); break;
  698. case 'label': break;
  699. case 'type': break;
  700. case 'class': break; //ignore class attributes
  701. case 'required': break; //ignore required field (define required fields in form class)
  702. case 'disabled': $smarty->assign('FBV_disabled', $params['disabled']); break;
  703. default: $textAreaParams .= htmlspecialchars($key, ENT_QUOTES, LOCALE_ENCODING) . '="' . htmlspecialchars($value, ENT_QUOTES, LOCALE_ENCODING) . '" ';
  704. }
  705. }
  706. $smarty->assign('FBV_textAreaParams', $textAreaParams);
  707. return $smarty->fetch('form/textarea.tpl');
  708. }
  709. /**
  710. * Form select control.
  711. * parameters: from [array], selected [array index], defaultLabel (optional), defaultValue (optional), disabled (optional),
  712. * translate (optional), name (optional - value of 'id' by default), all other attributes associated with this control (except class)
  713. * @param $params array
  714. * @param $smarty object
  715. */
  716. function smartyFBVSelect($params, &$smarty) {
  717. if (!isset($params['id'])) {
  718. $smarty->trigger_error('FBV: select form element \'id\' not set.');
  719. }
  720. $selectParams = '';
  721. $params['name'] = isset($params['name']) ? $params['name'] : $params['id'];
  722. $params['translate'] = isset($params['translate']) ? $params['translate'] : true;
  723. $params['disabled'] = isset($params['disabled']) ? $params['disabled'] : false;
  724. if (!$params['defaultValue'] || !$params['defaultLabel']) {
  725. if (isset($params['defaultValue'])) unset($params['defaultValue']);
  726. if (isset($params['defaultLabel'])) unset($params['defaultLabel']);
  727. $smarty->assign('FBV_defaultValue', null);
  728. $smarty->assign('FBV_defaultLabel', null);
  729. }
  730. foreach ($params as $key => $value) {
  731. switch ($key) {
  732. case 'from': $smarty->assign('FBV_from', $value); break;
  733. case 'selected': $smarty->assign('FBV_selected', $value); break;
  734. case 'translate': $smarty->assign('FBV_translate', $value); break;
  735. case 'defaultValue': $smarty->assign('FBV_defaultValue', $value); break;
  736. case 'defaultLabel': $smarty->assign('FBV_defaultLabel', $value); break;
  737. case 'class': break; //ignore class attributes
  738. case 'disabled': $smarty->assign('FBV_disabled', $params['disabled']); break;
  739. default: $selectParams .= htmlspecialchars($key, ENT_QUOTES, LOCALE_ENCODING) . '="' . htmlspecialchars($value, ENT_QUOTES, LOCALE_ENCODING) . '" ';
  740. }
  741. }
  742. $smarty->assign('FBV_selectParams', $selectParams);
  743. return $smarty->fetch('form/select.tpl');
  744. }
  745. /**
  746. * Checkbox input control.
  747. * parameters: label, disabled (optional), translate (optional), name (optional - value of 'id' by default), all other attributes associated with this control (except class and type)
  748. * @param $params array
  749. * @param $smarty object
  750. */
  751. function smartyFBVCheckbox($params, &$smarty) {
  752. if (!isset($params['id'])) {
  753. $smarty->trigger_error('FBV: checkbox form element \'id\' not set.');
  754. }
  755. $params = $this->addClientSideValidation($params);
  756. $checkboxParams = '';
  757. $params['name'] = isset($params['name']) ? $params['name'] : $params['id'];
  758. $params['translate'] = isset($params['translate']) ? $params['translate'] : true;
  759. $params['checked'] = isset($params['checked']) ? $params['checked'] : false;
  760. $params['disabled'] = isset($params['disabled']) ? $params['disabled'] : false;
  761. $params['required'] = isset($params['required']) ? $params['required'] : false;
  762. $smarty->assign('FBV_validation', null); // Reset form validation fields in memory
  763. foreach ($params as $key => $value) {
  764. switch ($key) {
  765. case 'class': break; //ignore class attributes
  766. case 'type': break;
  767. case 'id': $smarty->assign('FBV_id', $params['id']); break;
  768. case 'label': $smarty->assign('FBV_label', $params['label']); break;
  769. case 'validation': $smarty->assign('FBV_validation', $params['validation']); break;
  770. case 'required': $smarty->assign('FBV_required', $params['required']); break;
  771. case 'translate': $smarty->assign('FBV_translate', $params['translate']); break;
  772. case 'checked': $smarty->assign('FBV_checked', $params['checked']); break;
  773. case 'disabled': $smarty->assign('FBV_disabled', $params['disabled']); break;
  774. default: $checkboxParams .= htmlspecialchars($key, ENT_QUOTES, LOCALE_ENCODING) . '="' . htmlspecialchars($value, ENT_QUOTES, LOCALE_ENCODING) . '" ';
  775. }
  776. }
  777. $smarty->assign('FBV_checkboxParams', $checkboxParams);
  778. return $smarty->fetch('form/checkbox.tpl');
  779. }
  780. /**
  781. * Radio input control.
  782. * parameters: label, disabled (optional), translate (optional), name (optional - value of 'id' by default), all other attributes associated with this control (except class and type)
  783. * @param $params array
  784. * @param $smarty object
  785. */
  786. function smartyFBVRadioButton($params, &$smarty) {
  787. if (!isset($params['id'])) {
  788. $smarty->trigger_error('FBV: radio input form element \'id\' not set.');
  789. }
  790. $radioParams = '';
  791. $params['name'] = isset($params['name']) ? $params['name'] : $params['id'];
  792. $params['translate'] = isset($params['translate']) ? $params['translate'] : true;
  793. $params['checked'] = isset($params['checked']) ? $params['checked'] : false;
  794. $params['disabled'] = isset($params['disabled']) ? $params['disabled'] : false;
  795. foreach ($params as $key => $value) {
  796. switch ($key) {
  797. case 'class': break; //ignore class attributes
  798. case 'type': break;
  799. case 'id': $smarty->assign('FBV_id', $params['id']); break;
  800. case 'label': $smarty->assign('FBV_label', $params['label']); break;
  801. case 'translate': $smarty->assign('FBV_translate', $params['translate']); break;
  802. case 'checked': $smarty->assign('FBV_checked', $params['checked']); break;
  803. case 'disabled': $smarty->assign('FBV_disabled', $params['disabled']); break;
  804. default: $radioParams .= htmlspecialchars($key, ENT_QUOTES, LOCALE_ENCODING) . '="' . htmlspecialchars($value, ENT_QUOTES, LOCALE_ENCODING) . '" ';
  805. }
  806. }
  807. $smarty->assign('FBV_radioParams', $radioParams);
  808. return $smarty->fetch('form/radioButton.tpl');
  809. }
  810. /**
  811. * File upload input.
  812. * parameters: submit (optional - name of submit button to include), disabled (optional), name (optional - value of 'id' by default), all other attributes associated with this control (except class and type)
  813. * @param $params array
  814. * @param $smarty object
  815. */
  816. function smartyFBVFileInput($params, &$smarty) {
  817. if (!isset($params['id'])) {
  818. $smarty->trigger_error('FBV: file input form element \'id\' not set.');
  819. }
  820. $radioParams = '';
  821. $params['name'] = isset($params['name']) ? $params['name'] : $params['id'];
  822. $params['translate'] = isset($params['translate']) ? $params['translate'] : true;
  823. $params['checked'] = isset($params['checked']) ? $params['checked'] : false;
  824. $params['disabled'] = isset($params['disabled']) ? $params['disabled'] : false;
  825. $params['submit'] = isset($params['submit']) ? $params['submit'] : false;
  826. foreach ($params as $key => $value) {
  827. switch ($key) {
  828. case 'class': break; //ignore class attributes
  829. case 'type': break;
  830. case 'id': $smarty->assign('FBV_id', $params['id']); break;
  831. case 'submit': $smarty->assign('FBV_submit', $params['submit']); break;
  832. case 'name': $smarty->assign('FBV_name', $params['name']); break;
  833. case 'label': $smarty->assign('FBV_label', $params['label']); break;
  834. case 'disabled': $smarty->assign('FBV_disabled', $params['disabled']); break;
  835. default: $radioParams .= htmlspecialchars($key, ENT_QUOTES, LOCALE_ENCODING) . '="' . htmlspecialchars($value, ENT_QUOTES, LOCALE_ENCODING) . '" ';
  836. }
  837. }
  838. $smarty->assign('FBV_radioParams', $radioParams);
  839. return $smarty->fetch('form/fileInput.tpl');
  840. }
  841. /**
  842. * Assign the appropriate class name to the element for client-side validation
  843. * @param $params array
  844. * return array
  845. */
  846. function addClientSideValidation($params) {
  847. // Assign the appropriate class name to the element for client-side validation
  848. $fieldId = $params['id'];
  849. if (isset($this->cssValidation[$fieldId])) {
  850. $params['validation'] = implode(' ', $this->cssValidation[$fieldId]);
  851. }
  852. return $params;
  853. }
  854. }
  855. ?>