/core/Form/Form.class.php

https://github.com/bassta/onphp-framework · PHP · 498 lines · 313 code · 82 blank · 103 comment · 29 complexity · 7a78510560a8fc38f78ceb960f338102 MD5 · raw file

  1. <?php
  2. /****************************************************************************
  3. * Copyright (C) 2004-2009 by Konstantin V. Arkhipov, Anton E. Lebedevich *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU Lesser General Public License as *
  7. * published by the Free Software Foundation; either version 3 of the *
  8. * License, or (at your option) any later version. *
  9. * *
  10. ****************************************************************************/
  11. /**
  12. * Complete Form class.
  13. *
  14. * @ingroup Form
  15. * @ingroup Module
  16. *
  17. * @see http://onphp.org/examples.Form.en.html
  18. **/
  19. final class Form extends RegulatedForm
  20. {
  21. const WRONG = 0x0001;
  22. const MISSING = 0x0002;
  23. private $errors = array();
  24. private $labels = array();
  25. private $describedLabels = array();
  26. private $proto = null;
  27. private $importFiltering = true;
  28. /**
  29. * @return Form
  30. **/
  31. public static function create()
  32. {
  33. return new self;
  34. }
  35. public function getErrors()
  36. {
  37. return array_merge($this->errors, $this->violated);
  38. }
  39. public function hasError($name)
  40. {
  41. return array_key_exists($name, $this->errors)
  42. || array_key_exists($name, $this->violated);
  43. }
  44. public function getError($name)
  45. {
  46. if (array_key_exists($name, $this->errors)) {
  47. return $this->errors[$name];
  48. } elseif (array_key_exists($name, $this->violated)) {
  49. return $this->violated[$name];
  50. }
  51. return null;
  52. }
  53. public function getInnerErrors()
  54. {
  55. $result = $this->getErrors();
  56. foreach ($this->primitives as $name => $prm) {
  57. if (
  58. (
  59. ($prm instanceof PrimitiveFormsList)
  60. || ($prm instanceof PrimitiveForm)
  61. )
  62. && $prm->getValue()
  63. ) {
  64. if ($errors = $prm->getInnerErrors()) {
  65. $result[$name] = $errors;
  66. } else {
  67. unset($result[$name]);
  68. }
  69. }
  70. }
  71. return $result;
  72. }
  73. /**
  74. * @return Form
  75. **/
  76. public function dropAllErrors()
  77. {
  78. $this->errors = array();
  79. $this->violated = array();
  80. return $this;
  81. }
  82. /**
  83. * @return Form
  84. **/
  85. public function enableImportFiltering()
  86. {
  87. $this->importFiltering = true;
  88. return $this;
  89. }
  90. /**
  91. * @return Form
  92. **/
  93. public function disableImportFiltering()
  94. {
  95. $this->importFiltering = false;
  96. return $this;
  97. }
  98. /**
  99. * primitive marking
  100. **/
  101. //@{
  102. /**
  103. * @return Form
  104. **/
  105. public function markMissing($primitiveName, $label = null)
  106. {
  107. return $this->markCustom($primitiveName, Form::MISSING, $label);
  108. }
  109. /**
  110. * rule or primitive
  111. *
  112. * @return Form
  113. **/
  114. public function markWrong($name, $label = null)
  115. {
  116. if (isset($this->primitives[$name]))
  117. $this->errors[$name] = self::WRONG;
  118. elseif (isset($this->rules[$name]))
  119. $this->violated[$name] = self::WRONG;
  120. else
  121. throw new MissingElementException(
  122. $name.' does not match known primitives or rules'
  123. );
  124. if ($label !== null)
  125. $this->addWrongLabel($name, $label);
  126. return $this;
  127. }
  128. /**
  129. * @return Form
  130. **/
  131. public function markGood($primitiveName)
  132. {
  133. if (isset($this->primitives[$primitiveName]))
  134. unset($this->errors[$primitiveName]);
  135. elseif (isset($this->rules[$primitiveName]))
  136. unset($this->violated[$primitiveName]);
  137. else
  138. throw new MissingElementException(
  139. $primitiveName.' does not match known primitives or rules'
  140. );
  141. return $this;
  142. }
  143. /**
  144. * Set's custom error mark for primitive.
  145. *
  146. * @return Form
  147. **/
  148. public function markCustom($primitiveName, $customMark, $label = null)
  149. {
  150. Assert::isInteger($customMark);
  151. $this->errors[$this->get($primitiveName)->getName()] = $customMark;
  152. if ($label !== null)
  153. $this->addCustomLabel($primitiveName, $customMark, $label);
  154. return $this;
  155. }
  156. //@}
  157. /**
  158. * Returns plain list of error's labels
  159. **/
  160. public function getTextualErrors()
  161. {
  162. $list = array();
  163. foreach (array_keys($this->labels) as $name) {
  164. if ($label = $this->getTextualErrorFor($name))
  165. $list[] = $label;
  166. }
  167. return $list;
  168. }
  169. public function getTextualErrorFor($name)
  170. {
  171. if (
  172. isset(
  173. $this->violated[$name],
  174. $this->labels[$name][$this->violated[$name]]
  175. )
  176. )
  177. return $this->labels[$name][$this->violated[$name]];
  178. elseif (
  179. isset(
  180. $this->errors[$name],
  181. $this->labels[$name][$this->errors[$name]]
  182. )
  183. )
  184. return $this->labels[$name][$this->errors[$name]];
  185. else
  186. return null;
  187. }
  188. public function getErrorDescriptionFor($name)
  189. {
  190. if (
  191. isset(
  192. $this->violated[$name],
  193. $this->describedLabels[$name][$this->violated[$name]]
  194. )
  195. )
  196. return $this->describedLabels[$name][$this->violated[$name]];
  197. elseif (
  198. isset(
  199. $this->errors[$name],
  200. $this->describedLabels[$name][$this->errors[$name]]
  201. )
  202. )
  203. return $this->describedLabels[$name][$this->errors[$name]];
  204. else
  205. return null;
  206. }
  207. /**
  208. * @return Form
  209. **/
  210. public function addErrorDescription($name, $errorType, $description)
  211. {
  212. if (
  213. !isset($this->rules[$name])
  214. && !$this->get($name)->getName()
  215. )
  216. throw new MissingElementException(
  217. "knows nothing about '{$name}'"
  218. );
  219. $this->describedLabels[$name][$errorType] = $description;
  220. return $this;
  221. }
  222. /**
  223. * @return Form
  224. **/
  225. public function addWrongLabel($primitiveName, $label)
  226. {
  227. return $this->addErrorLabel($primitiveName, Form::WRONG, $label);
  228. }
  229. /**
  230. * @return Form
  231. **/
  232. public function addMissingLabel($primitiveName, $label)
  233. {
  234. return $this->addErrorLabel($primitiveName, Form::MISSING, $label);
  235. }
  236. /**
  237. * @return Form
  238. **/
  239. public function addCustomLabel($primitiveName, $customMark, $label)
  240. {
  241. return $this->addErrorLabel($primitiveName, $customMark, $label);
  242. }
  243. public function getWrongLabel($primitiveName)
  244. {
  245. return $this->getErrorLabel($primitiveName, Form::WRONG);
  246. }
  247. public function getMissingLabel($primitiveName)
  248. {
  249. return $this->getErrorLabel($primitiveName, Form::MISSING);
  250. }
  251. /**
  252. * @return Form
  253. **/
  254. public function import($scope)
  255. {
  256. foreach ($this->primitives as $prm)
  257. $this->importPrimitive($scope, $prm);
  258. return $this;
  259. }
  260. /**
  261. * @return Form
  262. **/
  263. public function importMore($scope)
  264. {
  265. foreach ($this->primitives as $prm) {
  266. if (!$prm->isImported())
  267. $this->importPrimitive($scope, $prm);
  268. }
  269. return $this;
  270. }
  271. /**
  272. * @return Form
  273. **/
  274. public function importOne($primitiveName, $scope)
  275. {
  276. return $this->importPrimitive($scope, $this->get($primitiveName));
  277. }
  278. /**
  279. * @return Form
  280. **/
  281. public function importValue($primitiveName, $value)
  282. {
  283. $prm = $this->get($primitiveName);
  284. return $this->checkImportResult($prm, $prm->importValue($value));
  285. }
  286. /**
  287. * @return Form
  288. **/
  289. public function importOneMore($primitiveName, $scope)
  290. {
  291. $prm = $this->get($primitiveName);
  292. if (!$prm->isImported())
  293. return $this->importPrimitive($scope, $prm);
  294. return $this;
  295. }
  296. public function exportValue($primitiveName)
  297. {
  298. return $this->get($primitiveName)->exportValue();
  299. }
  300. public function export()
  301. {
  302. $result = array();
  303. foreach ($this->primitives as $name => $prm) {
  304. if ($prm->isImported())
  305. $result[$name] = $prm->exportValue();
  306. }
  307. return $result;
  308. }
  309. public function toFormValue($value)
  310. {
  311. if ($value instanceof FormField)
  312. return $this->getValue($value->getName());
  313. elseif ($value instanceof LogicalObject)
  314. return $value->toBoolean($this);
  315. else
  316. return $value;
  317. }
  318. /**
  319. * @return Form
  320. **/
  321. public function setProto(EntityProto $proto)
  322. {
  323. $this->proto = $proto;
  324. return $this;
  325. }
  326. /**
  327. * @return EntityProto
  328. **/
  329. public function getProto()
  330. {
  331. return $this->proto;
  332. }
  333. public function __clone()
  334. {
  335. foreach ($this->primitives as $name => $primitive) {
  336. $this->primitives[$name] = clone $primitive;
  337. }
  338. }
  339. /**
  340. * @return Form
  341. **/
  342. private function importPrimitive($scope, BasePrimitive $prm)
  343. {
  344. if (!$this->importFiltering) {
  345. if ($prm instanceof FiltrablePrimitive) {
  346. $chain = $prm->getImportFilter();
  347. $prm->dropImportFilters();
  348. $result = $this->checkImportResult(
  349. $prm,
  350. $prm->import($scope)
  351. );
  352. $prm->setImportFilter($chain);
  353. return $result;
  354. } elseif ($prm instanceof PrimitiveForm) {
  355. return $this->checkImportResult(
  356. $prm,
  357. $prm->unfilteredImport($scope)
  358. );
  359. }
  360. }
  361. return $this->checkImportResult($prm, $prm->import($scope));
  362. }
  363. /**
  364. * @return Form
  365. **/
  366. private function checkImportResult(BasePrimitive $prm, $result)
  367. {
  368. if (
  369. $prm instanceof PrimitiveAlias
  370. && $result !== null
  371. )
  372. $this->markGood($prm->getInner()->getName());
  373. $name = $prm->getName();
  374. if (null === $result) {
  375. if ($prm->isRequired())
  376. $this->errors[$name] = self::MISSING;
  377. } elseif (true === $result) {
  378. unset($this->errors[$name]);
  379. } elseif ($error = $prm->getCustomError()) {
  380. $this->errors[$name] = $error;
  381. } else
  382. $this->errors[$name] = self::WRONG;
  383. return $this;
  384. }
  385. /**
  386. * Assigns specific label for given primitive and error type.
  387. * One more example of horrible documentation style.
  388. *
  389. * @param $name string primitive or rule name
  390. * @param $errorType enum Form::(WRONG|MISSING)
  391. * @param $label string YDFB WTF is this :-) (c) /.
  392. * @throws MissingElementException
  393. * @return Form
  394. **/
  395. private function addErrorLabel($name, $errorType, $label)
  396. {
  397. if (
  398. !isset($this->rules[$name])
  399. && !$this->get($name)->getName()
  400. )
  401. throw new MissingElementException(
  402. "knows nothing about '{$name}'"
  403. );
  404. $this->labels[$name][$errorType] = $label;
  405. return $this;
  406. }
  407. private function getErrorLabel($name, $errorType)
  408. {
  409. // checks for primitive's existence
  410. $this->get($name);
  411. if (isset($this->labels[$name][$errorType]))
  412. return $this->labels[$name][$errorType];
  413. return null;
  414. }
  415. }
  416. ?>