PageRenderTime 46ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/www/libs/nette-dev/Forms/Controls/FormControl.php

https://github.com/bazo/Mokuji
PHP | 630 lines | 245 code | 149 blank | 236 comment | 20 complexity | 0e32aa37ccd5a3c2acfd8822ce192f3e MD5 | raw file
Possible License(s): BSD-3-Clause, MIT
  1. <?php
  2. /**
  3. * Nette Framework
  4. *
  5. * @copyright Copyright (c) 2004, 2010 David Grudl
  6. * @license http://nettephp.com/license Nette license
  7. * @link http://nettephp.com
  8. * @category Nette
  9. * @package Nette\Forms
  10. */
  11. /**
  12. * Base class that implements the basic functionality common to form controls.
  13. *
  14. * @copyright Copyright (c) 2004, 2010 David Grudl
  15. * @package Nette\Forms
  16. *
  17. * @property-read Form $form
  18. * @property-read mixed $control
  19. * @property-read mixed $label
  20. * @property-read string $htmlName
  21. * @property string $htmlId
  22. * @property-read array $options
  23. * @property ITranslator $translator
  24. * @property mixed $value
  25. * @property-read Html $controlPrototype
  26. * @property-read Html $labelPrototype
  27. * @property-read Rules $rules
  28. * @property-read array $errors
  29. * @property bool $disabled
  30. * @property bool $rendered
  31. * @property bool $required
  32. */
  33. abstract class FormControl extends Component implements IFormControl
  34. {
  35. /** @var string */
  36. public static $idMask = 'frm%s-%s';
  37. /** @var string textual caption or label */
  38. public $caption;
  39. /** @var mixed unfiltered control value */
  40. protected $value;
  41. /** @var Html control element template */
  42. protected $control;
  43. /** @var Html label element template */
  44. protected $label;
  45. /** @var array */
  46. private $errors = array();
  47. /** @var bool */
  48. private $disabled = FALSE;
  49. /** @var string */
  50. private $htmlId;
  51. /** @var string */
  52. private $htmlName;
  53. /** @var Rules */
  54. private $rules;
  55. /** @var ITranslator */
  56. private $translator = TRUE; // means autodetect
  57. /** @var array user options */
  58. private $options = array();
  59. /**
  60. * @param string caption
  61. */
  62. public function __construct($caption = NULL)
  63. {
  64. $this->monitor('Nette\Forms\Form');
  65. parent::__construct();
  66. $this->control = Html::el('input');
  67. $this->label = Html::el('label');
  68. $this->caption = $caption;
  69. $this->rules = new Rules($this);
  70. }
  71. /**
  72. * This method will be called when the component becomes attached to Form.
  73. * @param IComponent
  74. * @return void
  75. */
  76. protected function attached($form)
  77. {
  78. if (!$this->disabled && $form instanceof Form && $form->isAnchored() && $form->isSubmitted()) {
  79. $this->htmlName = NULL;
  80. $this->loadHttpData();
  81. }
  82. }
  83. /**
  84. * Returns form.
  85. * @param bool throw exception if form doesn't exist?
  86. * @return Form
  87. */
  88. public function getForm($need = TRUE)
  89. {
  90. return $this->lookup('Nette\Forms\Form', $need);
  91. }
  92. /**
  93. * Returns name of control within a Form & INamingContainer scope.
  94. * @return string
  95. */
  96. public function getHtmlName()
  97. {
  98. if ($this->htmlName === NULL) {
  99. $s = '';
  100. $name = $this->getName();
  101. $obj = $this->lookup('Nette\Forms\INamingContainer', TRUE);
  102. while (!($obj instanceof Form)) {
  103. $s = "[$name]$s";
  104. $name = $obj->getName();
  105. $obj = $obj->lookup('Nette\Forms\INamingContainer', TRUE);
  106. }
  107. $name .= $s;
  108. if ($name === 'submit') {
  109. throw new InvalidArgumentException("Form control name 'submit' is not allowed due to JavaScript limitations.");
  110. }
  111. $this->htmlName = $name;
  112. }
  113. return $this->htmlName;
  114. }
  115. /**
  116. * Changes control's HTML id.
  117. * @param string new ID, or FALSE or NULL
  118. * @return FormControl provides a fluent interface
  119. */
  120. public function setHtmlId($id)
  121. {
  122. $this->htmlId = $id;
  123. return $this;
  124. }
  125. /**
  126. * Returns control's HTML id.
  127. * @return string
  128. */
  129. public function getHtmlId()
  130. {
  131. if ($this->htmlId === FALSE) {
  132. return NULL;
  133. } elseif ($this->htmlId === NULL) {
  134. $this->htmlId = sprintf(self::$idMask, $this->getForm()->getName(), $this->getHtmlName());
  135. $this->htmlId = str_replace(array('[]', '[', ']'), array('', '-', ''), $this->htmlId);
  136. }
  137. return $this->htmlId;
  138. }
  139. /**
  140. * Sets user-specific option.
  141. *
  142. * Common options:
  143. * - 'rendered' - indicate if method getControl() have been called
  144. * - 'required' - indicate if ':required' rule has been applied
  145. * - 'description' - textual or Html object description (recognized by ConventionalRenderer)
  146. *
  147. * @param string key
  148. * @param mixed value
  149. * @return FormControl provides a fluent interface
  150. */
  151. public function setOption($key, $value)
  152. {
  153. if ($value === NULL) {
  154. unset($this->options[$key]);
  155. } else {
  156. $this->options[$key] = $value;
  157. }
  158. return $this;
  159. }
  160. /**
  161. * Returns user-specific option.
  162. * @param string key
  163. * @param mixed default value
  164. * @return mixed
  165. */
  166. final public function getOption($key, $default = NULL)
  167. {
  168. return isset($this->options[$key]) ? $this->options[$key] : $default;
  169. }
  170. /**
  171. * Returns user-specific options.
  172. * @return array
  173. */
  174. final public function getOptions()
  175. {
  176. return $this->options;
  177. }
  178. /********************* translator ****************d*g**/
  179. /**
  180. * Sets translate adapter.
  181. * @param ITranslator
  182. * @return FormControl provides a fluent interface
  183. */
  184. public function setTranslator(ITranslator $translator = NULL)
  185. {
  186. $this->translator = $translator;
  187. return $this;
  188. }
  189. /**
  190. * Returns translate adapter.
  191. * @return ITranslator|NULL
  192. */
  193. final public function getTranslator()
  194. {
  195. if ($this->translator === TRUE) {
  196. return $this->getForm(FALSE) ? $this->getForm()->getTranslator() : NULL;
  197. }
  198. return $this->translator;
  199. }
  200. /**
  201. * Returns translated string.
  202. * @param string
  203. * @param int plural count
  204. * @return string
  205. */
  206. public function translate($s, $count = NULL)
  207. {
  208. $translator = $this->getTranslator();
  209. return $translator === NULL ? $s : $translator->translate($s, $count);
  210. }
  211. /********************* interface IFormControl ****************d*g**/
  212. /**
  213. * Sets control's value.
  214. * @param mixed
  215. * @return FormControl provides a fluent interface
  216. */
  217. public function setValue($value)
  218. {
  219. $this->value = $value;
  220. return $this;
  221. }
  222. /**
  223. * Returns control's value.
  224. * @return mixed
  225. */
  226. public function getValue()
  227. {
  228. return $this->value;
  229. }
  230. /**
  231. * Sets control's default value.
  232. * @param mixed
  233. * @return FormControl provides a fluent interface
  234. */
  235. public function setDefaultValue($value)
  236. {
  237. $form = $this->getForm(FALSE);
  238. if (!$form || !$form->isAnchored() || !$form->isSubmitted()) {
  239. $this->setValue($value);
  240. }
  241. return $this;
  242. }
  243. /**
  244. * Loads HTTP data.
  245. * @return void
  246. */
  247. public function loadHttpData()
  248. {
  249. $path = explode('[', strtr(str_replace(array('[]', ']'), '', $this->getHtmlName()), '.', '_'));
  250. $this->setValue(ArrayTools::get($this->getForm()->getHttpData(), $path));
  251. }
  252. /**
  253. * Disables or enables control.
  254. * @param bool
  255. * @return FormControl provides a fluent interface
  256. */
  257. public function setDisabled($value = TRUE)
  258. {
  259. $this->disabled = (bool) $value;
  260. return $this;
  261. }
  262. /**
  263. * Is control disabled?
  264. * @return bool
  265. */
  266. public function isDisabled()
  267. {
  268. return $this->disabled;
  269. }
  270. /********************* rendering ****************d*g**/
  271. /**
  272. * Generates control's HTML element.
  273. * @return Html
  274. */
  275. public function getControl()
  276. {
  277. $this->setOption('rendered', TRUE);
  278. $control = clone $this->control;
  279. $control->name = $this->getHtmlName();
  280. $control->disabled = $this->disabled;
  281. $control->id = $this->getHtmlId();
  282. return $control;
  283. }
  284. /**
  285. * Generates label's HTML element.
  286. * @param string
  287. * @return Html
  288. */
  289. public function getLabel($caption = NULL)
  290. {
  291. $label = clone $this->label;
  292. $label->for = $this->getHtmlId();
  293. if ($caption !== NULL) {
  294. $label->setText($this->translate($caption));
  295. } elseif ($this->caption instanceof Html) {
  296. $label->add($this->caption);
  297. } else {
  298. $label->setText($this->translate($this->caption));
  299. }
  300. return $label;
  301. }
  302. /**
  303. * Returns control's HTML element template.
  304. * @return Html
  305. */
  306. final public function getControlPrototype()
  307. {
  308. return $this->control;
  309. }
  310. /**
  311. * Returns label's HTML element template.
  312. * @return Html
  313. */
  314. final public function getLabelPrototype()
  315. {
  316. return $this->label;
  317. }
  318. /**
  319. * Sets 'rendered' indicator.
  320. * @param bool
  321. * @return FormControl provides a fluent interface
  322. * @deprecated
  323. */
  324. public function setRendered($value = TRUE)
  325. {
  326. $this->setOption('rendered', $value);
  327. return $this;
  328. }
  329. /**
  330. * Does method getControl() have been called?
  331. * @return bool
  332. * @deprecated
  333. */
  334. public function isRendered()
  335. {
  336. return !empty($this->options['rendered']);
  337. }
  338. /********************* rules ****************d*g**/
  339. /**
  340. * Adds a validation rule.
  341. * @param mixed rule type
  342. * @param string message to display for invalid data
  343. * @param mixed optional rule arguments
  344. * @return FormControl provides a fluent interface
  345. */
  346. public function addRule($operation, $message = NULL, $arg = NULL)
  347. {
  348. $this->rules->addRule($operation, $message, $arg);
  349. return $this;
  350. }
  351. /**
  352. * Adds a validation condition a returns new branch.
  353. * @param mixed condition type
  354. * @param mixed optional condition arguments
  355. * @return Rules new branch
  356. */
  357. public function addCondition($operation, $value = NULL)
  358. {
  359. return $this->rules->addCondition($operation, $value);
  360. }
  361. /**
  362. * Adds a validation condition based on another control a returns new branch.
  363. * @param IFormControl form control
  364. * @param mixed condition type
  365. * @param mixed optional condition arguments
  366. * @return Rules new branch
  367. */
  368. public function addConditionOn(IFormControl $control, $operation, $value = NULL)
  369. {
  370. return $this->rules->addConditionOn($control, $operation, $value);
  371. }
  372. /**
  373. * @return Rules
  374. */
  375. final public function getRules()
  376. {
  377. return $this->rules;
  378. }
  379. /**
  380. * Makes control mandatory.
  381. * @param string error message
  382. * @return FormControl provides a fluent interface
  383. * @deprecated
  384. */
  385. final public function setRequired($message = NULL)
  386. {
  387. $this->rules->addRule(':Filled', $message);
  388. return $this;
  389. }
  390. /**
  391. * Is control mandatory?
  392. * @return bool
  393. * @deprecated
  394. */
  395. final public function isRequired()
  396. {
  397. return !empty($this->options['required']);
  398. }
  399. /**
  400. * New rule or condition notification callback.
  401. * @param Rule
  402. * @return void
  403. */
  404. public function notifyRule(Rule $rule)
  405. {
  406. if (is_string($rule->operation) && strcasecmp($rule->operation, ':filled') === 0) {
  407. $this->setOption('required', TRUE);
  408. }
  409. }
  410. /********************* validation ****************d*g**/
  411. /**
  412. * Equal validator: are control's value and second parameter equal?
  413. * @param IFormControl
  414. * @param mixed
  415. * @return bool
  416. */
  417. public static function validateEqual(IFormControl $control, $arg)
  418. {
  419. $value = $control->getValue();
  420. foreach ((is_array($value) ? $value : array($value)) as $val) {
  421. foreach ((is_array($arg) ? $arg : array($arg)) as $item) {
  422. if ((string) $val === (string) ($item instanceof IFormControl ? $item->value : $item)) {
  423. return TRUE;
  424. }
  425. }
  426. }
  427. return FALSE;
  428. }
  429. /**
  430. * Filled validator: is control filled?
  431. * @param IFormControl
  432. * @return bool
  433. */
  434. public static function validateFilled(IFormControl $control)
  435. {
  436. return (string) $control->getValue() !== ''; // NULL, FALSE, '' ==> FALSE
  437. }
  438. /**
  439. * Valid validator: is control valid?
  440. * @param IFormControl
  441. * @return bool
  442. */
  443. public static function validateValid(IFormControl $control)
  444. {
  445. return $control->rules->validate(TRUE);
  446. }
  447. /**
  448. * Adds error message to the list.
  449. * @param string error message
  450. * @return void
  451. */
  452. public function addError($message)
  453. {
  454. if (!in_array($message, $this->errors, TRUE)) {
  455. $this->errors[] = $message;
  456. }
  457. $this->getForm()->addError($message);
  458. }
  459. /**
  460. * Returns errors corresponding to control.
  461. * @return array
  462. */
  463. public function getErrors()
  464. {
  465. return $this->errors;
  466. }
  467. /**
  468. * @return bool
  469. */
  470. public function hasErrors()
  471. {
  472. return (bool) $this->errors;
  473. }
  474. /**
  475. * @return void
  476. */
  477. public function cleanErrors()
  478. {
  479. $this->errors = array();
  480. }
  481. }