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 / Annotation / AnnotationBuilder.php
blobb674ca2163113cd6abc4bbd6c0a325dec68da6ad
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\Annotation;
12 use ArrayObject;
13 use ReflectionClass;
14 use Zend\Code\Annotation\AnnotationCollection;
15 use Zend\Code\Annotation\AnnotationManager;
16 use Zend\Code\Annotation\Parser;
17 use Zend\Code\Reflection\ClassReflection;
18 use Zend\EventManager\Event;
19 use Zend\EventManager\EventManager;
20 use Zend\EventManager\EventManagerAwareInterface;
21 use Zend\EventManager\EventManagerInterface;
22 use Zend\Form\Exception;
23 use Zend\Form\Factory;
24 use Zend\Form\FormFactoryAwareInterface;
25 use Zend\Stdlib\ArrayUtils;
27 /**
28 * Parses a class' properties for annotations in order to create a form and
29 * input filter definition.
31 class AnnotationBuilder implements EventManagerAwareInterface, FormFactoryAwareInterface
33 /**
34 * @var AnnotationManager
36 protected $annotationManager;
38 /**
39 * @var EventManagerInterface
41 protected $events;
43 /**
44 * @var Factory
46 protected $formFactory;
48 /**
49 * @var object
51 protected $entity;
53 /**
54 * @var array Default annotations to register
56 protected $defaultAnnotations = array(
57 'AllowEmpty',
58 'Attributes',
59 'ComposedObject',
60 'ErrorMessage',
61 'Exclude',
62 'Filter',
63 'Flags',
64 'Hydrator',
65 'Input',
66 'InputFilter',
67 'Name',
68 'Object',
69 'Options',
70 'Required',
71 'Type',
72 'ValidationGroup',
73 'Validator'
76 /**
77 * Set form factory to use when building form from annotations
79 * @param Factory $formFactory
80 * @return AnnotationBuilder
82 public function setFormFactory(Factory $formFactory)
84 $this->formFactory = $formFactory;
85 return $this;
88 /**
89 * Set annotation manager to use when building form from annotations
91 * @param AnnotationManager $annotationManager
92 * @return AnnotationBuilder
94 public function setAnnotationManager(AnnotationManager $annotationManager)
96 $parser = new Parser\DoctrineAnnotationParser();
97 foreach ($this->defaultAnnotations as $annotationName) {
98 $class = __NAMESPACE__ . '\\' . $annotationName;
99 $parser->registerAnnotation($class);
101 $annotationManager->attach($parser);
102 $this->annotationManager = $annotationManager;
103 return $this;
107 * Set event manager instance
109 * @param EventManagerInterface $events
110 * @return AnnotationBuilder
112 public function setEventManager(EventManagerInterface $events)
114 $events->setIdentifiers(array(
115 __CLASS__,
116 get_class($this),
118 $events->attach(new ElementAnnotationsListener());
119 $events->attach(new FormAnnotationsListener());
120 $this->events = $events;
121 return $this;
125 * Retrieve form factory
127 * Lazy-loads the default form factory if none is currently set.
129 * @return Factory
131 public function getFormFactory()
133 if ($this->formFactory) {
134 return $this->formFactory;
137 $this->formFactory = new Factory();
138 return $this->formFactory;
142 * Retrieve annotation manager
144 * If none is currently set, creates one with default annotations.
146 * @return AnnotationManager
148 public function getAnnotationManager()
150 if ($this->annotationManager) {
151 return $this->annotationManager;
154 $this->setAnnotationManager(new AnnotationManager());
155 return $this->annotationManager;
159 * Get event manager
161 * @return EventManagerInterface
163 public function getEventManager()
165 if (null === $this->events) {
166 $this->setEventManager(new EventManager());
168 return $this->events;
172 * Creates and returns a form specification for use with a factory
174 * Parses the object provided, and processes annotations for the class and
175 * all properties. Information from annotations is then used to create
176 * specifications for a form, its elements, and its input filter.
178 * @param string|object $entity Either an instance or a valid class name for an entity
179 * @throws Exception\InvalidArgumentException if $entity is not an object or class name
180 * @return ArrayObject
182 public function getFormSpecification($entity)
184 if (!is_object($entity)) {
185 if ((is_string($entity) && (!class_exists($entity))) // non-existent class
186 || (!is_string($entity)) // not an object or string
188 throw new Exception\InvalidArgumentException(sprintf(
189 '%s expects an object or valid class name; received "%s"',
190 __METHOD__,
191 var_export($entity, 1)
196 $this->entity = $entity;
197 $annotationManager = $this->getAnnotationManager();
198 $formSpec = new ArrayObject();
199 $filterSpec = new ArrayObject();
201 $reflection = new ClassReflection($entity);
202 $annotations = $reflection->getAnnotations($annotationManager);
204 if ($annotations instanceof AnnotationCollection) {
205 $this->configureForm($annotations, $reflection, $formSpec, $filterSpec);
208 foreach ($reflection->getProperties() as $property) {
209 $annotations = $property->getAnnotations($annotationManager);
211 if ($annotations instanceof AnnotationCollection) {
212 $this->configureElement($annotations, $property, $formSpec, $filterSpec);
216 if (!isset($formSpec['input_filter'])) {
217 $formSpec['input_filter'] = $filterSpec;
220 return $formSpec;
224 * Create a form from an object.
226 * @param string|object $entity
227 * @return \Zend\Form\Form
229 public function createForm($entity)
231 $formSpec = ArrayUtils::iteratorToArray($this->getFormSpecification($entity));
232 $formFactory = $this->getFormFactory();
233 return $formFactory->createForm($formSpec);
237 * Get the entity used to construct the form.
239 * @return object
241 public function getEntity()
243 return $this->entity;
247 * Configure the form specification from annotations
249 * @param AnnotationCollection $annotations
250 * @param ClassReflection $reflection
251 * @param ArrayObject $formSpec
252 * @param ArrayObject $filterSpec
253 * @return void
254 * @triggers discoverName
255 * @triggers configureForm
257 protected function configureForm($annotations, $reflection, $formSpec, $filterSpec)
259 $name = $this->discoverName($annotations, $reflection);
260 $formSpec['name'] = $name;
261 $formSpec['attributes'] = array();
262 $formSpec['elements'] = array();
263 $formSpec['fieldsets'] = array();
265 $events = $this->getEventManager();
266 foreach ($annotations as $annotation) {
267 $events->trigger(__FUNCTION__, $this, array(
268 'annotation' => $annotation,
269 'name' => $name,
270 'formSpec' => $formSpec,
271 'filterSpec' => $filterSpec,
277 * Configure an element from annotations
279 * @param AnnotationCollection $annotations
280 * @param \Zend\Code\Reflection\PropertyReflection $reflection
281 * @param ArrayObject $formSpec
282 * @param ArrayObject $filterSpec
283 * @return void
284 * @triggers checkForExclude
285 * @triggers discoverName
286 * @triggers configureElement
288 protected function configureElement($annotations, $reflection, $formSpec, $filterSpec)
290 // If the element is marked as exclude, return early
291 if ($this->checkForExclude($annotations)) {
292 return;
295 $events = $this->getEventManager();
296 $name = $this->discoverName($annotations, $reflection);
298 $elementSpec = new ArrayObject(array(
299 'flags' => array(),
300 'spec' => array(
301 'name' => $name
304 $inputSpec = new ArrayObject(array(
305 'name' => $name,
308 $event = new Event();
309 $event->setParams(array(
310 'name' => $name,
311 'elementSpec' => $elementSpec,
312 'inputSpec' => $inputSpec,
313 'formSpec' => $formSpec,
314 'filterSpec' => $filterSpec,
316 foreach ($annotations as $annotation) {
317 $event->setParam('annotation', $annotation);
318 $events->trigger(__FUNCTION__, $this, $event);
321 // Since "type" is a reserved name in the filter specification,
322 // we need to add the specification without the name as the key.
323 // In all other cases, though, the name is fine.
324 if ($event->getParam('inputSpec')->count() > 1) {
325 if ($name === 'type') {
326 $filterSpec[] = $event->getParam('inputSpec');
327 } else {
328 $filterSpec[$name] = $event->getParam('inputSpec');
332 $elementSpec = $event->getParam('elementSpec');
333 $type = (isset($elementSpec['spec']['type']))
334 ? $elementSpec['spec']['type']
335 : 'Zend\Form\Element';
337 // Compose as a fieldset or an element, based on specification type
338 if (static::isSubclassOf($type, 'Zend\Form\FieldsetInterface')) {
339 if (!isset($formSpec['fieldsets'])) {
340 $formSpec['fieldsets'] = array();
342 $formSpec['fieldsets'][] = $elementSpec;
343 } else {
344 if (!isset($formSpec['elements'])) {
345 $formSpec['elements'] = array();
347 $formSpec['elements'][] = $elementSpec;
352 * Discover the name of the given form or element
354 * @param AnnotationCollection $annotations
355 * @param \Reflector $reflection
356 * @return string
358 protected function discoverName($annotations, $reflection)
360 $results = $this->getEventManager()->trigger('discoverName', $this, array(
361 'annotations' => $annotations,
362 'reflection' => $reflection,
363 ), function ($r) {
364 return (is_string($r) && !empty($r));
366 return $results->last();
370 * Determine if an element is marked to exclude from the definitions
372 * @param AnnotationCollection $annotations
373 * @return true|false
375 protected function checkForExclude($annotations)
377 $results = $this->getEventManager()->trigger('checkForExclude', $this, array(
378 'annotations' => $annotations,
379 ), function ($r) {
380 return (true === $r);
382 return (bool) $results->last();
386 * Checks if the object has this class as one of its parents
388 * @see https://bugs.php.net/bug.php?id=53727
389 * @see https://github.com/zendframework/zf2/pull/1807
391 * @param string $className
392 * @param string $type
393 * @return bool
395 protected static function isSubclassOf($className, $type)
397 if (is_subclass_of($className, $type)) {
398 return true;
400 if (version_compare(PHP_VERSION, '5.3.7', '>=')) {
401 return false;
403 if (!interface_exists($type)) {
404 return false;
406 $r = new ReflectionClass($className);
407 return $r->implementsInterface($type);