Added the zend framework 2 library, the path is specified in line no.26 in zend_modul...
[openemr.git] / interface / modules / zend_modules / library / Zend / Form / Fieldset.php
blob4a6bf5b495c229859f1302e4cd3c5709524a07c4
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-2013 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 Traversable;
13 use Zend\Stdlib\Hydrator;
14 use Zend\Stdlib\Hydrator\HydratorAwareInterface;
15 use Zend\Stdlib\Hydrator\HydratorInterface;
16 use Zend\Stdlib\PriorityQueue;
18 class Fieldset extends Element implements FieldsetInterface
20 /**
21 * @var Factory
23 protected $factory;
25 /**
26 * @var ElementInterface[]
28 protected $byName = array();
30 /**
31 * @var array
33 protected $elements = array();
35 /**
36 * @var array
38 protected $fieldsets = array();
40 /**
41 * @var array
43 protected $messages = array();
45 /**
46 * @var PriorityQueue
48 protected $iterator;
50 /**
51 * Hydrator to use with bound object
53 * @var Hydrator\HydratorInterface
55 protected $hydrator;
57 /**
58 * The object bound to this fieldset, if any
60 * @var null|object
62 protected $object;
64 /**
65 * Should this fieldset be used as a base fieldset in the parent form ?
67 * @var bool
69 protected $useAsBaseFieldset = false;
71 /**
72 * @param null|int|string $name Optional name for the element
73 * @param array $options Optional options for the element
75 public function __construct($name = null, $options = array())
77 $this->iterator = new PriorityQueue();
78 parent::__construct($name, $options);
81 /**
82 * Set options for a fieldset. Accepted options are:
83 * - use_as_base_fieldset: is this fieldset use as the base fieldset?
85 * @param array|Traversable $options
86 * @return Element|ElementInterface
87 * @throws Exception\InvalidArgumentException
89 public function setOptions($options)
91 parent::setOptions($options);
93 if (isset($options['use_as_base_fieldset'])) {
94 $this->setUseAsBaseFieldset($options['use_as_base_fieldset']);
97 return $this;
101 * Compose a form factory to use when calling add() with a non-element/fieldset
103 * @param Factory $factory
104 * @return Form
106 public function setFormFactory(Factory $factory)
108 $this->factory = $factory;
109 return $this;
113 * Retrieve composed form factory
115 * Lazy-loads one if none present.
117 * @return Factory
119 public function getFormFactory()
121 if (null === $this->factory) {
122 $this->setFormFactory(new Factory());
125 return $this->factory;
129 * Add an element or fieldset
131 * $flags could contain metadata such as the alias under which to register
132 * the element or fieldset, order in which to prioritize it, etc.
134 * @todo Should we detect if the element/fieldset name conflicts?
135 * @param array|Traversable|ElementInterface $elementOrFieldset
136 * @param array $flags
137 * @return Fieldset|FieldsetInterface
138 * @throws Exception\InvalidArgumentException
140 public function add($elementOrFieldset, array $flags = array())
142 if (is_array($elementOrFieldset)
143 || ($elementOrFieldset instanceof Traversable && !$elementOrFieldset instanceof ElementInterface)
145 $factory = $this->getFormFactory();
146 $elementOrFieldset = $factory->create($elementOrFieldset);
149 if (!$elementOrFieldset instanceof ElementInterface) {
150 throw new Exception\InvalidArgumentException(sprintf(
151 '%s requires that $elementOrFieldset be an object implementing %s; received "%s"',
152 __METHOD__,
153 __NAMESPACE__ . '\ElementInterface',
154 (is_object($elementOrFieldset) ? get_class($elementOrFieldset) : gettype($elementOrFieldset))
158 $name = $elementOrFieldset->getName();
159 if ((null === $name || '' === $name)
160 && (!array_key_exists('name', $flags) || $flags['name'] === '')
162 throw new Exception\InvalidArgumentException(sprintf(
163 '%s: element or fieldset provided is not named, and no name provided in flags',
164 __METHOD__
168 if (array_key_exists('name', $flags) && $flags['name'] !== '') {
169 $name = $flags['name'];
171 // Rename the element or fieldset to the specified alias
172 $elementOrFieldset->setName($name);
174 $order = 0;
175 if (array_key_exists('priority', $flags)) {
176 $order = $flags['priority'];
179 $this->iterator->insert($elementOrFieldset, $order);
180 $this->byName[$name] = $elementOrFieldset;
182 if ($elementOrFieldset instanceof FieldsetInterface) {
183 if ($elementOrFieldset instanceof FieldsetPrepareAwareInterface) {
184 $elementOrFieldset->prepareFieldset();
187 $this->fieldsets[$name] = $elementOrFieldset;
188 return $this;
191 $this->elements[$name] = $elementOrFieldset;
192 return $this;
196 * Does the fieldset have an element/fieldset by the given name?
198 * @param string $elementOrFieldset
199 * @return bool
201 public function has($elementOrFieldset)
203 return array_key_exists($elementOrFieldset, $this->byName);
207 * Retrieve a named element or fieldset
209 * @param string $elementOrFieldset
210 * @return ElementInterface
212 public function get($elementOrFieldset)
214 if (!$this->has($elementOrFieldset)) {
215 throw new Exception\InvalidElementException(sprintf(
216 "No element by the name of [%s] found in form",
217 $elementOrFieldset
220 return $this->byName[$elementOrFieldset];
224 * Remove a named element or fieldset
226 * @param string $elementOrFieldset
227 * @return FieldsetInterface
229 public function remove($elementOrFieldset)
231 if (!$this->has($elementOrFieldset)) {
232 return $this;
235 $entry = $this->byName[$elementOrFieldset];
236 unset($this->byName[$elementOrFieldset]);
238 $this->iterator->remove($entry);
240 if ($entry instanceof FieldsetInterface) {
241 unset($this->fieldsets[$elementOrFieldset]);
242 return $this;
245 unset($this->elements[$elementOrFieldset]);
246 return $this;
250 * Set/change the priority of an element or fieldset
252 * @param string $elementOrFieldset
253 * @param int $priority
254 * @return FieldsetInterface
256 public function setPriority($elementOrFieldset, $priority)
258 $element = $this->get($elementOrFieldset);
259 $this->remove($elementOrFieldset);
260 $this->add($element, array('priority' => $priority));
261 return $this;
265 * Retrieve all attached elements
267 * Storage is an implementation detail of the concrete class.
269 * @return array|Traversable
271 public function getElements()
273 return $this->elements;
277 * Retrieve all attached fieldsets
279 * Storage is an implementation detail of the concrete class.
281 * @return array|Traversable
283 public function getFieldsets()
285 return $this->fieldsets;
289 * Set a hash of element names/messages to use when validation fails
291 * @param array|Traversable $messages
292 * @return Element|ElementInterface|FieldsetInterface
293 * @throws Exception\InvalidArgumentException
295 public function setMessages($messages)
297 if (!is_array($messages) && !$messages instanceof Traversable) {
298 throw new Exception\InvalidArgumentException(sprintf(
299 '%s expects an array or Traversable object of messages; received "%s"',
300 __METHOD__,
301 (is_object($messages) ? get_class($messages) : gettype($messages))
305 foreach ($messages as $key => $messageSet) {
306 if (!$this->has($key)) {
307 continue;
309 $element = $this->get($key);
310 $element->setMessages($messageSet);
313 return $this;
317 * Get validation error messages, if any
319 * Returns a hash of element names/messages for all elements failing
320 * validation, or, if $elementName is provided, messages for that element
321 * only.
323 * @param null|string $elementName
324 * @return array|Traversable
325 * @throws Exception\InvalidArgumentException
327 public function getMessages($elementName = null)
329 if (null === $elementName) {
330 $messages = array();
331 foreach ($this->byName as $name => $element) {
332 $messageSet = $element->getMessages();
333 if (!is_array($messageSet)
334 && !$messageSet instanceof Traversable
335 || empty($messageSet)) {
336 continue;
338 $messages[$name] = $messageSet;
340 return $messages;
343 if (!$this->has($elementName)) {
344 throw new Exception\InvalidArgumentException(sprintf(
345 'Invalid element name "%s" provided to %s',
346 $elementName,
347 __METHOD__
351 $element = $this->get($elementName);
352 return $element->getMessages();
356 * Ensures state is ready for use. Here, we append the name of the fieldsets to every elements in order to avoid
357 * name clashes if the same fieldset is used multiple times
359 * @param FormInterface $form
360 * @return mixed|void
362 public function prepareElement(FormInterface $form)
364 $name = $this->getName();
366 foreach ($this->byName as $elementOrFieldset) {
367 $elementOrFieldset->setName($name . '[' . $elementOrFieldset->getName() . ']');
369 // Recursively prepare elements
370 if ($elementOrFieldset instanceof ElementPrepareAwareInterface) {
371 $elementOrFieldset->prepareElement($form);
377 * Recursively populate values of attached elements and fieldsets
379 * @param array|Traversable $data
380 * @return void
381 * @throws Exception\InvalidArgumentException
383 public function populateValues($data)
385 if (!is_array($data) && !$data instanceof Traversable) {
386 throw new Exception\InvalidArgumentException(sprintf(
387 '%s expects an array or Traversable set of data; received "%s"',
388 __METHOD__,
389 (is_object($data) ? get_class($data) : gettype($data))
393 foreach ($data as $name => $value) {
394 if (!$this->has($name)) {
395 continue;
398 $element = $this->get($name);
400 if ($element instanceof FieldsetInterface && is_array($value)) {
401 $element->populateValues($value);
402 continue;
405 $element->setValue($value);
410 * Countable: return count of attached elements/fieldsets
412 * @return int
414 public function count()
416 return $this->iterator->count();
420 * IteratorAggregate: return internal iterator
422 * @return PriorityQueue
424 public function getIterator()
426 return $this->iterator;
430 * Set the object used by the hydrator
432 * @param object $object
433 * @return Fieldset|FieldsetInterface
434 * @throws Exception\InvalidArgumentException
436 public function setObject($object)
438 if (!is_object($object)) {
439 throw new Exception\InvalidArgumentException(sprintf(
440 '%s expects an object argument; received "%s"',
441 __METHOD__,
442 $object
446 $this->object = $object;
447 return $this;
451 * Get the object used by the hydrator
453 * @return mixed
455 public function getObject()
457 return $this->object;
461 * Checks if the object can be set in this fieldset
463 * @param object $object
464 * @return bool
466 public function allowObjectBinding($object)
468 return ($this->object && $object instanceof $this->object);
472 * Set the hydrator to use when binding an object to the element
474 * @param HydratorInterface $hydrator
475 * @return FieldsetInterface
477 public function setHydrator(HydratorInterface $hydrator)
479 $this->hydrator = $hydrator;
480 return $this;
484 * Get the hydrator used when binding an object to the fieldset
486 * If no hydrator is present and object implements HydratorAwareInterface,
487 * hydrator will be retrieved from the object.
489 * Will lazy-load Hydrator\ArraySerializable if none is present.
491 * @return HydratorInterface
493 public function getHydrator()
495 if (!$this->hydrator instanceof HydratorInterface) {
496 if ($this->object instanceof HydratorAwareInterface) {
497 $this->setHydrator($this->object->getHydrator());
498 } else {
499 $this->setHydrator(new Hydrator\ArraySerializable());
502 return $this->hydrator;
506 * Checks if this fieldset can bind data
508 * @return bool
510 public function allowValueBinding()
512 return is_object($this->object);
516 * Bind values to the bound object
518 * @param array $values
519 * @return mixed|void
521 public function bindValues(array $values = array())
523 $hydrator = $this->getHydrator();
524 $hydratableData = array();
526 foreach ($values as $name => $value) {
527 if (!$this->has($name)) {
528 continue;
531 $element = $this->byName[$name];
533 if ($element instanceof FieldsetInterface && $element->allowValueBinding()) {
534 $value = $element->bindValues($value);
537 $hydratableData[$name] = $value;
540 if (!empty($hydratableData)) {
541 $this->object = $hydrator->hydrate($hydratableData, $this->object);
544 return $this->object;
548 * Set if this fieldset is used as a base fieldset
550 * @param bool $useAsBaseFieldset
551 * @return Fieldset
553 public function setUseAsBaseFieldset($useAsBaseFieldset)
555 $this->useAsBaseFieldset = (bool) $useAsBaseFieldset;
556 return $this;
560 * Is this fieldset use as a base fieldset for a form ?
562 * @return bool
564 public function useAsBaseFieldset()
566 return $this->useAsBaseFieldset;
570 * Extract values from the bound object
572 * @return array
574 protected function extract()
576 if (!is_object($this->object)) {
577 return array();
580 $hydrator = $this->getHydrator();
581 if (!$hydrator instanceof Hydrator\HydratorInterface) {
582 return array();
585 $values = $hydrator->extract($this->object);
587 if (!is_array($values)) {
588 // Do nothing if the hydrator returned a non-array
589 return array();
592 // Recursively extract and populate values for nested fieldsets
593 foreach ($this->fieldsets as $fieldset) {
594 $name = $fieldset->getName();
596 if (isset($values[$name])) {
597 $object = $values[$name];
599 if ($fieldset->allowObjectBinding($object)) {
600 $fieldset->setObject($object);
601 $values[$name] = $fieldset->extract();
606 return $values;
610 * Make a deep clone of a fieldset
612 * @return void
614 public function __clone()
616 $items = $this->iterator->toArray(PriorityQueue::EXTR_BOTH);
618 $this->byName = array();
619 $this->elements = array();
620 $this->fieldsets = array();
621 $this->iterator = new PriorityQueue();
623 foreach ($items as $item) {
624 $elementOrFieldset = clone $item['data'];
625 $name = $elementOrFieldset->getName();
627 $this->iterator->insert($elementOrFieldset, $item['priority']);
628 $this->byName[$name] = $elementOrFieldset;
630 if ($elementOrFieldset instanceof FieldsetInterface) {
631 $this->fieldsets[$name] = $elementOrFieldset;
632 } elseif ($elementOrFieldset instanceof ElementInterface) {
633 $this->elements[$name] = $elementOrFieldset;
637 // Also make a deep copy of the object in case it's used within a collection
638 if (is_object($this->object)) {
639 $this->object = clone $this->object;