fix calendar css, take 2. (#213)
[openemr.git] / interface / modules / zend_modules / library / Zend / Form / Factory.php
blob56834f9dbaa50f94fb0e1bdbbac285690ba41c08
1 <?php
2 /**
3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
8 */
10 namespace Zend\Form;
12 use ArrayAccess;
13 use Traversable;
14 use Zend\InputFilter\Factory as InputFilterFactory;
15 use Zend\InputFilter\InputFilterInterface;
16 use Zend\Stdlib\ArrayUtils;
17 use Zend\Stdlib\Hydrator;
19 class Factory
21 /**
22 * @var InputFilterFactory
24 protected $inputFilterFactory;
26 /**
27 * @var FormElementManager
29 protected $formElementManager;
31 /**
32 * @param FormElementManager $formElementManager
34 public function __construct(FormElementManager $formElementManager = null)
36 if ($formElementManager) {
37 $this->setFormElementManager($formElementManager);
41 /**
42 * Set input filter factory to use when creating forms
44 * @param InputFilterFactory $inputFilterFactory
45 * @return Factory
47 public function setInputFilterFactory(InputFilterFactory $inputFilterFactory)
49 $this->inputFilterFactory = $inputFilterFactory;
50 return $this;
53 /**
54 * Get current input filter factory
56 * If none provided, uses an unconfigured instance.
58 * @return InputFilterFactory
60 public function getInputFilterFactory()
62 if (null === $this->inputFilterFactory) {
63 $this->setInputFilterFactory(new InputFilterFactory());
65 return $this->inputFilterFactory;
68 /**
69 * Set the form element manager
71 * @param FormElementManager $formElementManager
72 * @return Factory
74 public function setFormElementManager(FormElementManager $formElementManager)
76 $this->formElementManager = $formElementManager;
77 return $this;
80 /**
81 * Get form element manager
83 * @return FormElementManager
85 public function getFormElementManager()
87 if ($this->formElementManager === null) {
88 $this->setFormElementManager(new FormElementManager());
91 return $this->formElementManager;
94 /**
95 * Create an element, fieldset, or form
97 * Introspects the 'type' key of the provided $spec, and determines what
98 * type is being requested; if none is provided, assumes the spec
99 * represents simply an element.
101 * @param array|Traversable $spec
102 * @return ElementInterface
103 * @throws Exception\DomainException
105 public function create($spec)
107 $spec = $this->validateSpecification($spec, __METHOD__);
108 $type = isset($spec['type']) ? $spec['type'] : 'Zend\Form\Element';
110 $element = $this->getFormElementManager()->get($type);
112 if ($element instanceof FormInterface) {
113 return $this->configureForm($element, $spec);
116 if ($element instanceof FieldsetInterface) {
117 return $this->configureFieldset($element, $spec);
120 if ($element instanceof ElementInterface) {
121 return $this->configureElement($element, $spec);
124 throw new Exception\DomainException(sprintf(
125 '%s expects the $spec["type"] to implement one of %s, %s, or %s; received %s',
126 __METHOD__,
127 'Zend\Form\ElementInterface',
128 'Zend\Form\FieldsetInterface',
129 'Zend\Form\FormInterface',
130 $type
135 * Create an element
137 * @param array $spec
138 * @return ElementInterface
140 public function createElement($spec)
142 if (!isset($spec['type'])) {
143 $spec['type'] = 'Zend\Form\Element';
146 return $this->create($spec);
150 * Create a fieldset
152 * @param array $spec
153 * @return ElementInterface
155 public function createFieldset($spec)
157 if (!isset($spec['type'])) {
158 $spec['type'] = 'Zend\Form\Fieldset';
161 return $this->create($spec);
165 * Create a form
167 * @param array $spec
168 * @return ElementInterface
170 public function createForm($spec)
172 if (!isset($spec['type'])) {
173 $spec['type'] = 'Zend\Form\Form';
176 return $this->create($spec);
180 * Configure an element based on the provided specification
182 * Specification can contain any of the following:
183 * - type: the Element class to use; defaults to \Zend\Form\Element
184 * - name: what name to provide the element, if any
185 * - options: an array, Traversable, or ArrayAccess object of element options
186 * - attributes: an array, Traversable, or ArrayAccess object of element
187 * attributes to assign
189 * @param ElementInterface $element
190 * @param array|Traversable|ArrayAccess $spec
191 * @throws Exception\DomainException
192 * @return ElementInterface
194 public function configureElement(ElementInterface $element, $spec)
196 $spec = $this->validateSpecification($spec, __METHOD__);
198 $name = isset($spec['name']) ? $spec['name'] : null;
199 $options = isset($spec['options']) ? $spec['options'] : null;
200 $attributes = isset($spec['attributes']) ? $spec['attributes'] : null;
202 if ($name !== null && $name !== '') {
203 $element->setName($name);
206 if (is_array($options) || $options instanceof Traversable || $options instanceof ArrayAccess) {
207 $element->setOptions($options);
210 if (is_array($attributes) || $attributes instanceof Traversable || $attributes instanceof ArrayAccess) {
211 $element->setAttributes($attributes);
214 return $element;
218 * Configure a fieldset based on the provided specification
220 * Specification can contain any of the following:
221 * - type: the Fieldset class to use; defaults to \Zend\Form\Fieldset
222 * - name: what name to provide the fieldset, if any
223 * - options: an array, Traversable, or ArrayAccess object of element options
224 * - attributes: an array, Traversable, or ArrayAccess object of element
225 * attributes to assign
226 * - elements: an array or Traversable object where each entry is an array
227 * or ArrayAccess object containing the keys:
228 * - flags: (optional) array of flags to pass to FieldsetInterface::add()
229 * - spec: the actual element specification, per {@link configureElement()}
231 * @param FieldsetInterface $fieldset
232 * @param array|Traversable|ArrayAccess $spec
233 * @throws Exception\DomainException
234 * @return FieldsetInterface
236 public function configureFieldset(FieldsetInterface $fieldset, $spec)
238 $spec = $this->validateSpecification($spec, __METHOD__);
239 $fieldset = $this->configureElement($fieldset, $spec);
241 if (isset($spec['object'])) {
242 $this->prepareAndInjectObject($spec['object'], $fieldset, __METHOD__);
245 if (isset($spec['hydrator'])) {
246 $this->prepareAndInjectHydrator($spec['hydrator'], $fieldset, __METHOD__);
249 if (isset($spec['elements'])) {
250 $this->prepareAndInjectElements($spec['elements'], $fieldset, __METHOD__);
253 if (isset($spec['fieldsets'])) {
254 $this->prepareAndInjectFieldsets($spec['fieldsets'], $fieldset, __METHOD__);
257 $factory = (isset($spec['factory']) ? $spec['factory'] : $this);
258 $this->prepareAndInjectFactory($factory, $fieldset, __METHOD__);
260 return $fieldset;
264 * Configure a form based on the provided specification
266 * Specification follows that of {@link configureFieldset()}, and adds the
267 * following keys:
269 * - input_filter: input filter instance, named input filter class, or
270 * array specification for the input filter factory
271 * - hydrator: hydrator instance or named hydrator class
273 * @param FormInterface $form
274 * @param array|Traversable|ArrayAccess $spec
275 * @return FormInterface
277 public function configureForm(FormInterface $form, $spec)
279 $spec = $this->validateSpecification($spec, __METHOD__);
280 $form = $this->configureFieldset($form, $spec);
282 if (isset($spec['input_filter'])) {
283 $this->prepareAndInjectInputFilter($spec['input_filter'], $form, __METHOD__);
286 if (isset($spec['validation_group'])) {
287 $this->prepareAndInjectValidationGroup($spec['validation_group'], $form, __METHOD__);
290 return $form;
294 * Validate a provided specification
296 * Ensures we have an array, Traversable, or ArrayAccess object, and returns it.
298 * @param array|Traversable|ArrayAccess $spec
299 * @param string $method Method invoking the validator
300 * @return array|ArrayAccess
301 * @throws Exception\InvalidArgumentException for invalid $spec
303 protected function validateSpecification($spec, $method)
305 if (is_array($spec)) {
306 return $spec;
309 if ($spec instanceof Traversable) {
310 $spec = ArrayUtils::iteratorToArray($spec);
311 return $spec;
314 if (!$spec instanceof ArrayAccess) {
315 throw new Exception\InvalidArgumentException(sprintf(
316 '%s expects an array, or object implementing Traversable or ArrayAccess; received "%s"',
317 $method,
318 (is_object($spec) ? get_class($spec) : gettype($spec))
322 return $spec;
326 * Takes a list of element specifications, creates the elements, and injects them into the provided fieldset
328 * @param array|Traversable|ArrayAccess $elements
329 * @param FieldsetInterface $fieldset
330 * @param string $method Method invoking this one (for exception messages)
331 * @return void
333 protected function prepareAndInjectElements($elements, FieldsetInterface $fieldset, $method)
335 $elements = $this->validateSpecification($elements, $method);
337 foreach ($elements as $elementSpecification) {
338 if (null === $elementSpecification) {
339 continue;
342 $flags = isset($elementSpecification['flags']) ? $elementSpecification['flags'] : array();
343 $spec = isset($elementSpecification['spec']) ? $elementSpecification['spec'] : array();
345 if (!isset($spec['type'])) {
346 $spec['type'] = 'Zend\Form\Element';
349 $element = $this->create($spec);
350 $fieldset->add($element, $flags);
355 * Takes a list of fieldset specifications, creates the fieldsets, and injects them into the master fieldset
357 * @param array|Traversable|ArrayAccess $fieldsets
358 * @param FieldsetInterface $masterFieldset
359 * @param string $method Method invoking this one (for exception messages)
360 * @return void
362 public function prepareAndInjectFieldsets($fieldsets, FieldsetInterface $masterFieldset, $method)
364 $fieldsets = $this->validateSpecification($fieldsets, $method);
366 foreach ($fieldsets as $fieldsetSpecification) {
367 $flags = isset($fieldsetSpecification['flags']) ? $fieldsetSpecification['flags'] : array();
368 $spec = isset($fieldsetSpecification['spec']) ? $fieldsetSpecification['spec'] : array();
370 $fieldset = $this->createFieldset($spec);
371 $masterFieldset->add($fieldset, $flags);
376 * Prepare and inject an object
378 * Takes a string indicating a class name, instantiates the class
379 * by that name, and injects the class instance as the bound object.
381 * @param string $objectName
382 * @param FieldsetInterface $fieldset
383 * @param string $method
384 * @throws Exception\DomainException
385 * @return void
387 protected function prepareAndInjectObject($objectName, FieldsetInterface $fieldset, $method)
389 if (!is_string($objectName)) {
390 throw new Exception\DomainException(sprintf(
391 '%s expects string class name; received "%s"',
392 $method,
393 (is_object($objectName) ? get_class($objectName) : gettype($objectName))
397 if (!class_exists($objectName)) {
398 throw new Exception\DomainException(sprintf(
399 '%s expects string class name to be a valid class name; received "%s"',
400 $method,
401 $objectName
405 $fieldset->setObject(new $objectName);
409 * Prepare and inject a named hydrator
411 * Takes a string indicating a hydrator class name (or a concrete instance), try first to instantiates the class
412 * by pulling it from service manager, and injects the hydrator instance into the form.
414 * @param string|array|Hydrator\HydratorInterface $hydratorOrName
415 * @param FieldsetInterface $fieldset
416 * @param string $method
417 * @return void
418 * @throws Exception\DomainException If $hydratorOrName is not a string, does not resolve to a known class, or
419 * the class does not implement Hydrator\HydratorInterface
421 protected function prepareAndInjectHydrator($hydratorOrName, FieldsetInterface $fieldset, $method)
423 if ($hydratorOrName instanceof Hydrator\HydratorInterface) {
424 $fieldset->setHydrator($hydratorOrName);
425 return;
428 if (is_array($hydratorOrName)) {
429 if (!isset($hydratorOrName['type'])) {
430 throw new Exception\DomainException(sprintf(
431 '%s expects array specification to have a type value',
432 $method
435 $hydratorOptions = (isset($hydratorOrName['options'])) ? $hydratorOrName['options'] : array();
436 $hydratorOrName = $hydratorOrName['type'];
437 } else {
438 $hydratorOptions = array();
441 if (is_string($hydratorOrName)) {
442 $hydrator = $this->getHydratorFromName($hydratorOrName);
445 if (! isset($hydrator) || !$hydrator instanceof Hydrator\HydratorInterface) {
446 throw new Exception\DomainException(sprintf(
447 '%s expects a valid implementation of Zend\Stdlib\Hydrator\HydratorInterface; received "%s"',
448 $method,
449 $hydratorOrName
453 if (!empty($hydratorOptions) && $hydrator instanceof Hydrator\HydratorOptionsInterface) {
454 $hydrator->setOptions($hydratorOptions);
457 $fieldset->setHydrator($hydrator);
461 * Prepare and inject a named factory
463 * Takes a string indicating a factory class name (or a concrete instance), try first to instantiates the class
464 * by pulling it from service manager, and injects the factory instance into the fieldset.
466 * @param string|array|Factory $factoryOrName
467 * @param FieldsetInterface $fieldset
468 * @param string $method
469 * @return void
470 * @throws Exception\DomainException If $factoryOrName is not a string, does not resolve to a known class, or
471 * the class does not extend Form\Factory
473 protected function prepareAndInjectFactory($factoryOrName, FieldsetInterface $fieldset, $method)
475 if (is_array($factoryOrName)) {
476 if (!isset($factoryOrName['type'])) {
477 throw new Exception\DomainException(sprintf(
478 '%s expects array specification to have a type value',
479 $method
482 $factoryOrName = $factoryOrName['type'];
485 if (is_string($factoryOrName)) {
486 $factoryOrName = $this->getFactoryFromName($factoryOrName);
489 if (!$factoryOrName instanceof Factory) {
490 throw new Exception\DomainException(sprintf(
491 '%s expects a valid extention of Zend\Form\Factory; received "%s"',
492 $method,
493 $factoryOrName
497 $fieldset->setFormFactory($factoryOrName);
501 * Prepare an input filter instance and inject in the provided form
503 * If the input filter specified is a string, assumes it is a class name,
504 * and attempts to instantiate it. If the class does not exist, or does
505 * not extend InputFilterInterface, an exception is raised.
507 * Otherwise, $spec is passed on to the attached InputFilter Factory
508 * instance in order to create the input filter.
510 * @param string|array|Traversable $spec
511 * @param FormInterface $form
512 * @param string $method
513 * @return void
514 * @throws Exception\DomainException for unknown InputFilter class or invalid InputFilter instance
516 protected function prepareAndInjectInputFilter($spec, FormInterface $form, $method)
518 if ($spec instanceof InputFilterInterface) {
519 $form->setInputFilter($spec);
520 return;
523 if (is_string($spec)) {
524 if (!class_exists($spec)) {
525 throw new Exception\DomainException(sprintf(
526 '%s expects string input filter names to be valid class names; received "%s"',
527 $method,
528 $spec
531 $filter = new $spec;
532 if (!$filter instanceof InputFilterInterface) {
533 throw new Exception\DomainException(sprintf(
534 '%s expects a valid implementation of Zend\InputFilter\InputFilterInterface; received "%s"',
535 $method,
536 $spec
539 $form->setInputFilter($filter);
540 return;
543 $factory = $this->getInputFilterFactory();
544 $filter = $factory->createInputFilter($spec);
545 if (method_exists($filter, 'setFactory')) {
546 $filter->setFactory($factory);
548 $form->setInputFilter($filter);
552 * Prepare a validation group and inject in the provided form
554 * Takes an array of elements names
556 * @param string|array|Traversable $spec
557 * @param FormInterface $form
558 * @param string $method
559 * @return void
560 * @throws Exception\DomainException if validation group given is not an array
562 protected function prepareAndInjectValidationGroup($spec, FormInterface $form, $method)
564 if (!is_array($spec)) {
565 if (!class_exists($spec)) {
566 throw new Exception\DomainException(sprintf(
567 '%s expects an array for validation group; received "%s"',
568 $method,
569 $spec
574 $form->setValidationGroup($spec);
578 * Try to pull hydrator from service manager, or instantiates it from its name
580 * @param string $hydratorName
581 * @return mixed
582 * @throws Exception\DomainException
584 protected function getHydratorFromName($hydratorName)
586 $services = $this->getFormElementManager()->getServiceLocator();
588 if ($services && $services->has('HydratorManager')) {
589 $hydrators = $services->get('HydratorManager');
590 if ($hydrators->has($hydratorName)) {
591 return $hydrators->get($hydratorName);
595 if ($services && $services->has($hydratorName)) {
596 return $services->get($hydratorName);
599 if (!class_exists($hydratorName)) {
600 throw new Exception\DomainException(sprintf(
601 'Expects string hydrator name to be a valid class name; received "%s"',
602 $hydratorName
606 $hydrator = new $hydratorName;
607 return $hydrator;
611 * Try to pull factory from service manager, or instantiates it from its name
613 * @param string $factoryName
614 * @return mixed
615 * @throws Exception\DomainException
617 protected function getFactoryFromName($factoryName)
619 $services = $this->getFormElementManager()->getServiceLocator();
621 if ($services && $services->has($factoryName)) {
622 return $services->get($factoryName);
625 if (!class_exists($factoryName)) {
626 throw new Exception\DomainException(sprintf(
627 'Expects string factory name to be a valid class name; received "%s"',
628 $factoryName
632 $factory = new $factoryName;
633 return $factory;