PageRenderTime 29ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/Semdrops/SymfonySemdropsMobile/vendor/symfony/src/Symfony/Component/Form/FormFactory.php

https://github.com/castillojorge/SemdropsMobile
PHP | 401 lines | 196 code | 60 blank | 145 comment | 25 complexity | 32164545f2dc43ea16bd18e19b9d3915 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Form;
  11. use Symfony\Component\Form\Exception\FormException;
  12. use Symfony\Component\Form\Exception\UnexpectedTypeException;
  13. use Symfony\Component\Form\Exception\TypeDefinitionException;
  14. use Symfony\Component\Form\Exception\CreationException;
  15. class FormFactory implements FormFactoryInterface
  16. {
  17. private static $requiredOptions = array(
  18. 'data',
  19. 'required',
  20. 'max_length',
  21. );
  22. /**
  23. * Extensions
  24. * @var array An array of FormExtensionInterface
  25. */
  26. private $extensions = array();
  27. /**
  28. * All known types (cache)
  29. * @var array An array of FormTypeInterface
  30. */
  31. private $types = array();
  32. /**
  33. * The guesser chain
  34. * @var FormTypeGuesserChain
  35. */
  36. private $guesser;
  37. /**
  38. * Constructor.
  39. *
  40. * @param array $extensions An array of FormExtensionInterface
  41. *
  42. * @throws UnexpectedTypeException if any extension does not implement FormExtensionInterface
  43. */
  44. public function __construct(array $extensions)
  45. {
  46. foreach ($extensions as $extension) {
  47. if (!$extension instanceof FormExtensionInterface) {
  48. throw new UnexpectedTypeException($extension, 'Symfony\Component\Form\FormExtensionInterface');
  49. }
  50. }
  51. $this->extensions = $extensions;
  52. }
  53. /**
  54. * Returns whether the given type is supported.
  55. *
  56. * @param string $name The name of the type
  57. *
  58. * @return Boolean Whether the type is supported
  59. */
  60. public function hasType($name)
  61. {
  62. if (isset($this->types[$name])) {
  63. return true;
  64. }
  65. try {
  66. $this->loadType($name);
  67. } catch (FormException $e) {
  68. return false;
  69. }
  70. return true;
  71. }
  72. /**
  73. * Add a type.
  74. *
  75. * @param FormTypeInterface $type The type
  76. */
  77. public function addType(FormTypeInterface $type)
  78. {
  79. $this->loadTypeExtensions($type);
  80. $this->types[$type->getName()] = $type;
  81. }
  82. /**
  83. * Returns a type by name.
  84. *
  85. * This methods registers the type extensions from the form extensions.
  86. *
  87. * @param string|FormTypeInterface $name The name of the type or a type instance
  88. *
  89. * @return FormTypeInterface The type
  90. *
  91. * @throws FormException if the type can not be retrieved from any extension
  92. */
  93. public function getType($name)
  94. {
  95. if (!is_string($name)) {
  96. throw new UnexpectedTypeException($name, 'string');
  97. }
  98. if (!isset($this->types[$name])) {
  99. $this->loadType($name);
  100. }
  101. return $this->types[$name];
  102. }
  103. /**
  104. * Returns a form.
  105. *
  106. * @see createBuilder()
  107. *
  108. * @param string|FormTypeInterface $type The type of the form
  109. * @param mixed $data The initial data
  110. * @param array $options The options
  111. *
  112. * @return Form The form named after the type
  113. *
  114. * @throws FormException if any given option is not applicable to the given type
  115. */
  116. public function create($type, $data = null, array $options = array())
  117. {
  118. return $this->createBuilder($type, $data, $options)->getForm();
  119. }
  120. /**
  121. * Returns a form.
  122. *
  123. * @see createNamedBuilder()
  124. *
  125. * @param string|FormTypeInterface $type The type of the form
  126. * @param string $name The name of the form
  127. * @param mixed $data The initial data
  128. * @param array $options The options
  129. *
  130. * @return Form The form
  131. *
  132. * @throws FormException if any given option is not applicable to the given type
  133. */
  134. public function createNamed($type, $name, $data = null, array $options = array())
  135. {
  136. return $this->createNamedBuilder($type, $name, $data, $options)->getForm();
  137. }
  138. /**
  139. * Returns a form for a property of a class.
  140. *
  141. * @see createBuilderForProperty()
  142. *
  143. * @param string $class The fully qualified class name
  144. * @param string $property The name of the property to guess for
  145. * @param mixed $data The initial data
  146. * @param array $options The options for the builder
  147. *
  148. * @return Form The form named after the property
  149. *
  150. * @throws FormException if any given option is not applicable to the form type
  151. */
  152. public function createForProperty($class, $property, $data = null, array $options = array())
  153. {
  154. return $this->createBuilderForProperty($class, $property, $data, $options)->getForm();
  155. }
  156. /**
  157. * Returns a form builder
  158. *
  159. * @param string|FormTypeInterface $type The type of the form
  160. * @param mixed $data The initial data
  161. * @param array $options The options
  162. *
  163. * @return FormBuilder The form builder
  164. *
  165. * @throws FormException if any given option is not applicable to the given type
  166. */
  167. public function createBuilder($type, $data = null, array $options = array())
  168. {
  169. $name = is_object($type) ? $type->getName() : $type;
  170. return $this->createNamedBuilder($type, $name, $data, $options);
  171. }
  172. /**
  173. * Returns a form builder.
  174. *
  175. * @param string|FormTypeInterface $type The type of the form
  176. * @param string $name The name of the form
  177. * @param mixed $data The initial data
  178. * @param array $options The options
  179. *
  180. * @return FormBuilder The form builder
  181. *
  182. * @throws FormException if any given option is not applicable to the given type
  183. */
  184. public function createNamedBuilder($type, $name, $data = null, array $options = array())
  185. {
  186. $builder = null;
  187. $types = array();
  188. $knownOptions = array();
  189. $passedOptions = array_keys($options);
  190. $optionValues = array();
  191. if (!array_key_exists('data', $options)) {
  192. $options['data'] = $data;
  193. }
  194. while (null !== $type) {
  195. if ($type instanceof FormTypeInterface) {
  196. $this->addType($type);
  197. } else {
  198. $type = $this->getType($type);
  199. }
  200. $defaultOptions = $type->getDefaultOptions($options);
  201. $optionValues = array_merge_recursive($optionValues, $type->getAllowedOptionValues($options));
  202. foreach ($type->getExtensions() as $typeExtension) {
  203. $defaultOptions = array_replace($defaultOptions, $typeExtension->getDefaultOptions($options));
  204. $optionValues = array_merge_recursive($optionValues, $typeExtension->getAllowedOptionValues($options));
  205. }
  206. $options = array_replace($defaultOptions, $options);
  207. $knownOptions = array_merge($knownOptions, array_keys($defaultOptions));
  208. array_unshift($types, $type);
  209. $type = $type->getParent($options);
  210. }
  211. $type = end($types);
  212. $diff = array_diff(self::$requiredOptions, $knownOptions);
  213. if (count($diff) > 0) {
  214. throw new TypeDefinitionException(sprintf('Type "%s" should support the option(s) "%s"', $type->getName(), implode('", "', $diff)));
  215. }
  216. $diff = array_diff($passedOptions, $knownOptions);
  217. if (count($diff) > 1) {
  218. throw new CreationException(sprintf('The options "%s" do not exist', implode('", "', $diff)));
  219. }
  220. if (count($diff) > 0) {
  221. throw new CreationException(sprintf('The option "%s" does not exist', current($diff)));
  222. }
  223. foreach ($optionValues as $option => $allowedValues) {
  224. if (!in_array($options[$option], $allowedValues, true)) {
  225. throw new CreationException(sprintf('The option "%s" has the value "%s", but is expected to be one of "%s"', $option, $options[$option], implode('", "', $allowedValues)));
  226. }
  227. }
  228. for ($i = 0, $l = count($types); $i < $l && !$builder; ++$i) {
  229. $builder = $types[$i]->createBuilder($name, $this, $options);
  230. }
  231. if (!$builder) {
  232. throw new TypeDefinitionException(sprintf('Type "%s" or any of its parents should return a FormBuilder instance from createBuilder()', $type->getName()));
  233. }
  234. $builder->setTypes($types);
  235. $builder->setCurrentLoadingType($type->getName());
  236. foreach ($types as $type) {
  237. $type->buildForm($builder, $options);
  238. foreach ($type->getExtensions() as $typeExtension) {
  239. $typeExtension->buildForm($builder, $options);
  240. }
  241. }
  242. $builder->setCurrentLoadingType(null);
  243. return $builder;
  244. }
  245. /**
  246. * Returns a form builder for a property of a class.
  247. *
  248. * If any of the 'max_length', 'required' and type options can be guessed,
  249. * and are not provided in the options argument, the guessed value is used.
  250. *
  251. * @param string $class The fully qualified class name
  252. * @param string $property The name of the property to guess for
  253. * @param mixed $data The initial data
  254. * @param array $options The options for the builder
  255. *
  256. * @return FormBuilder The form builder named after the property
  257. *
  258. * @throws FormException if any given option is not applicable to the form type
  259. */
  260. public function createBuilderForProperty($class, $property, $data = null, array $options = array())
  261. {
  262. if (!$this->guesser) {
  263. $this->loadGuesser();
  264. }
  265. $typeGuess = $this->guesser->guessType($class, $property);
  266. $maxLengthGuess = $this->guesser->guessMaxLength($class, $property);
  267. $minLengthGuess = $this->guesser->guessMinLength($class, $property);
  268. $requiredGuess = $this->guesser->guessRequired($class, $property);
  269. $type = $typeGuess ? $typeGuess->getType() : 'text';
  270. if ($maxLengthGuess) {
  271. $options = array_merge(array('max_length' => $maxLengthGuess->getValue()), $options);
  272. }
  273. if ($minLengthGuess) {
  274. if ($maxLengthGuess) {
  275. $options = array_merge(array('pattern' => '.{'.$minLengthGuess->getValue().','.$maxLengthGuess->getValue().'}'), $options);
  276. } else {
  277. $options = array_merge(array('pattern' => '.{'.$minLengthGuess->getValue().',}'), $options);
  278. }
  279. }
  280. if ($requiredGuess) {
  281. $options = array_merge(array('required' => $requiredGuess->getValue()), $options);
  282. }
  283. // user options may override guessed options
  284. if ($typeGuess) {
  285. $options = array_merge($typeGuess->getOptions(), $options);
  286. }
  287. return $this->createNamedBuilder($type, $property, $data, $options);
  288. }
  289. /**
  290. * Initializes the guesser chain.
  291. */
  292. private function loadGuesser()
  293. {
  294. $guessers = array();
  295. foreach ($this->extensions as $extension) {
  296. $guesser = $extension->getTypeGuesser();
  297. if ($guesser) {
  298. $guessers[] = $guesser;
  299. }
  300. }
  301. $this->guesser = new FormTypeGuesserChain($guessers);
  302. }
  303. /**
  304. * Loads a type.
  305. *
  306. * @param string $name The type name
  307. *
  308. * @throws FormException if the type is not provided by any registered extension
  309. */
  310. private function loadType($name)
  311. {
  312. $type = null;
  313. foreach ($this->extensions as $extension) {
  314. if ($extension->hasType($name)) {
  315. $type = $extension->getType($name);
  316. break;
  317. }
  318. }
  319. if (!$type) {
  320. throw new FormException(sprintf('Could not load type "%s"', $name));
  321. }
  322. $this->loadTypeExtensions($type);
  323. $this->types[$name] = $type;
  324. }
  325. /**
  326. * Loads the extensions for a given type.
  327. *
  328. * @param FormTypeInterface $type The type
  329. */
  330. private function loadTypeExtensions(FormTypeInterface $type)
  331. {
  332. $typeExtensions = array();
  333. foreach ($this->extensions as $extension) {
  334. $typeExtensions = array_merge(
  335. $typeExtensions,
  336. $extension->getTypeExtensions($type->getName())
  337. );
  338. }
  339. $type->setExtensions($typeExtensions);
  340. }
  341. }