Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

add data type guesser

add more data type guesses

use form events to create the default forms

revert routing naming changes
  • Loading branch information...
commit b22672cc4e25656cf7a6dc26a5e3a51078dd730d 1 parent 7545404
@docteurklein docteurklein authored
View
76 Form/DataTypeGuesser.php
@@ -0,0 +1,76 @@
+<?php
+
+namespace Knp\RadBundle\Form;
+
+use Symfony\Component\Form\FormTypeGuesserInterface;
+use Symfony\Component\Form\Guess\TypeGuess;
+use Symfony\Component\Form\Guess\Guess;
+
+class DataTypeGuesser implements FormTypeGuesserInterface
+{
+ private $data;
+
+ public function setData($data = null)
+ {
+ $this->data = $data;
+ }
+
+ public function guessType($class, $property)
+ {
+ if ($property === '_id') {
+ return new TypeGuess('hidden', array(), Guess::LOW_CONFIDENCE);
+ }
+
+ if (!isset($this->data->$property)) {
+ return;
+ }
+ $data = $this->data->$property;
+
+ $type = $this->getType($data);
+
+ return new TypeGuess($type, array(), Guess::LOW_CONFIDENCE);
+ }
+
+ public function guessRequired($class, $property)
+ {
+ }
+
+ public function guessPattern($class, $property)
+ {
+ }
+
+ public function guessMaxLength($class, $property)
+ {
+ }
+
+ public function guessMinLength($class, $property)
+ {
+ }
+
+ private function getType($value)
+ {
+ if (is_object($value)) {
+ switch (true) {
+ case $value instanceof \DateTime:
+ return 'date';
+ case $value instanceof \ArrayIterator:
+ return 'collection';
+ default:
+ return 'text';
+ }
+ }
+
+ $type = gettype($value);
+
+ switch ($type) {
+ case 'boolean':
+ return 'checkbox';
+ case 'array':
+ return 'collection';
+ case 'string':
+ default:
+ return 'text';
+ }
+ }
+}
+
View
38 Form/DefaultFormCreator.php
@@ -3,37 +3,63 @@
namespace Knp\RadBundle\Form;
use Symfony\Component\Form\FormFactoryInterface;
+use Symfony\Component\Form\Event\DataEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\Form\FormEvents;
+
use Knp\RadBundle\Reflection\ClassMetadataFetcher;
-class DefaultFormCreator implements FormCreatorInterface
+class DefaultFormCreator implements FormCreatorInterface, EventSubscriberInterface
{
private $fetcher;
private $factory;
+ private $dataTypeGuesser;
+
- public function __construct(ClassMetadataFetcher $fetcher = null, FormFactoryInterface $factory)
+ public function __construct(ClassMetadataFetcher $fetcher = null, FormFactoryInterface $factory, DataTypeGuesser $dataTypeGuesser)
{
$this->fetcher = $fetcher ?: new ClassMetadataFetcher;
$this->factory = $factory;
+ $this->dataTypeGuesser = $dataTypeGuesser;
+ }
+
+ public static function getSubscribedEvents()
+ {
+ return array(
+ FormEvents::PRE_SET_DATA => 'preSetData'
+ );
}
public function create($object, $purpose = null, array $options = array())
{
$builder = $this->factory->createBuilder('form', $object, $options);
+ return $builder->getForm();
+ }
+
+ public function preSetData(DataEvent $event)
+ {
+ $object = $event->getData();
+ $form = $event->getForm();
+
+ if (!is_object($object)) {
+ return;
+ }
+
+ $this->dataTypeGuesser->setData($object);
+
foreach ($this->fetcher->getMethods($object) as $method) {
if (0 === strpos($method, 'get') || 0 === strpos($method, 'is')) {
$propertyName = $this->extractPropertyName($method);
if ($this->hasRelatedSetter($object, $propertyName)) {
- $builder->add($propertyName);
+ $form->add($this->factory->createForProperty(get_class($object), $propertyName));
}
}
}
foreach ($this->fetcher->getProperties($object) as $property) {
- $builder->add($property);
+ $form->add($this->factory->createForProperty(get_class($object), $property));
}
-
- return $builder->getForm();
}
private function extractPropertyName($methodName)
View
29 Form/FormTypeExtension.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace Knp\RadBundle\Form;
+
+use Symfony\Component\Form\AbstractTypeExtension;
+use Symfony\Component\Form\FormBuilderInterface;
+
+use Knp\RadBundle\Form\DefaultFormCreator;
+
+class FormTypeExtension extends AbstractTypeExtension
+{
+ private $formCreator;
+
+ public function __construct(DefaultFormCreator $formCreator)
+ {
+ $this->formCreator = $formCreator;
+ }
+
+ public function getExtendedType()
+ {
+ return 'form';
+ }
+
+ public function buildForm(FormBuilderInterface $builder, array $options)
+ {
+ $builder->addEventSubscriber($this->formCreator);
+ }
+}
+
View
2  Reflection/ClassMetadataFetcher.php
@@ -26,7 +26,7 @@ public function newInstance($class)
public function reflect($classname)
{
- return new \ReflectionClass($classname);
+ return new \ReflectionObject($classname);
}
public function getParentClass($object)
View
12 Resources/config/form_manager.xml
@@ -8,6 +8,8 @@
<parameter key="knp_rad.form.manager.class">Knp\RadBundle\Form\FormManager</parameter>
<parameter key="knp_rad.form.type_creator.class">Knp\RadBundle\Form\FormTypeCreator</parameter>
<parameter key="knp_rad.form.default_creator.class">Knp\RadBundle\Form\DefaultFormCreator</parameter>
+ <parameter key="knp_rad.form.type_guesser.data.class">Knp\RadBundle\Form\DataTypeGuesser</parameter>
+ <parameter key="knp_rad.form.type_extension.data.class">Knp\RadBundle\Form\FormTypeExtension</parameter>
<parameter key="knp_rad.reflection.metadata_fetcher.class">Knp\RadBundle\Reflection\ClassMetadataFetcher</parameter>
</parameters>
@@ -27,9 +29,19 @@
<service id="knp_rad.form.default_creator" class="%knp_rad.form.default_creator.class%" public="false">
<argument type="service" id="knp_rad.reflection.metadata_fetcher" />
<argument type="service" id="form.factory"/>
+ <argument type="service" id="knp_rad.form.type_guesser.data"/>
<tag name="knp_rad.form.creator" priority="1"/>
</service>
<service id="knp_rad.reflection.metadata_fetcher" class="%knp_rad.reflection.metadata_fetcher.class%" public="false"></service>
+
+ <service id="knp_rad.form.type_guesser.data" class="%knp_rad.form.type_guesser.data.class%">
+ <tag name="form.type_guesser"/>
+ </service>
+
+ <service id="knp_rad.form.type_extension.data" class="%knp_rad.form.type_extension.data.class%">
+ <argument type="service" id="knp_rad.form.default_creator"/>
+ <tag name="form.type_extension" alias="form"/>
+ </service>
</services>
</container>
View
39 spec/Form/DataTypeGuesser.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace spec\Knp\RadBundle\Form;
+
+use PHPSpec2\ObjectBehavior;
+
+class DataTypeGuesser extends ObjectBehavior
+{
+ function it_should_be_initializable()
+ {
+ $this->shouldHaveType('Knp\RadBundle\Form\DataTypeGuesser');
+ }
+
+ function it_should_guess_form_type_given_internal_data_type()
+ {
+ $this->setData((object) array(
+ 'test' => true,
+ 'coll' => array(),
+ ));
+
+ $guess = $this->guessType('', 'test');
+ $guess->getType()->shouldBe('checkbox');
+
+ $guess = $this->guessType('', 'coll');
+ $guess->getType()->shouldBe('collection');
+
+ $guess = $this->guessType('', 'inexistant')->shouldReturn(null);
+ }
+
+ function it_should_guess_date_fields()
+ {
+ $this->setData((object) array(
+ 'date' => new \DateTime,
+ ));
+
+ $guess = $this->guessType('', 'date');
+ $guess->getType()->shouldBe('date');
+ }
+}
View
45 spec/Form/DefaultFormCreator.php
@@ -9,10 +9,11 @@ class DefaultFormCreator extends ObjectBehavior
/**
* @param Knp\RadBundle\Reflection\ClassMetadataFetcher $fetcher
* @param Symfony\Component\Form\FormFactoryInterface $factory
+ * @param Knp\RadBundle\Form\DataTypeGuesser $dataTypeGuesser
*/
- function let($fetcher, $factory)
+ function let($fetcher, $factory, $dataTypeGuesser)
{
- $this->beConstructedWith($fetcher, $factory);
+ $this->beConstructedWith($fetcher, $factory, $dataTypeGuesser);
}
/**
@@ -21,8 +22,11 @@ function let($fetcher, $factory)
* @param Knp\RadBundle\Form\ClassMetadataFetcher $fetcher
* @param Symfony\Component\Form\FormBuilder $builder
* @param Symfony\Component\Form\Form $form
+ * @param Symfony\Component\Form\Form $subForm1
+ * @param Symfony\Component\Form\Form $subForm2
+ * @param Symfony\Component\Form\Event\DataEvent $dataEvent
*/
- function it_should_create_form_based_on_object_mutators($object, $factory, $fetcher, $builder, $form)
+ function it_should_create_form_based_on_object_mutators($object, $factory, $fetcher, $builder, $form, $dataEvent, $subForm1, $subForm2)
{
$fetcher->getMethods($object)->willReturn(array(
'getName', 'setName',
@@ -33,9 +37,19 @@ function it_should_create_form_based_on_object_mutators($object, $factory, $fetc
$fetcher->hasMethod($object, 'setAdmin')->willReturn(true);
$fetcher->hasMethod($object, 'setId')->willReturn(false);
$factory->createBuilder('form', $object, array())->willReturn($builder)->shouldBeCalled();
- $builder->add('name')->shouldBeCalled();
- $builder->add('admin')->shouldBeCalled();
- $builder->add('id')->shouldNotBeCalled();
+
+ $dataEvent->getData()->willReturn($object);
+ $dataEvent->getForm()->willReturn($form);
+
+ $factory->createForProperty(ANY_ARGUMENT, 'name')->shouldBeCalled()->willReturn($subForm1);
+ $factory->createForProperty(ANY_ARGUMENT, 'admin')->shouldBeCalled()->willReturn($subForm2);
+ $factory->createForProperty(ANY_ARGUMENT, 'id')->shouldNotBeCalled();
+
+ $form->add($subForm1)->shouldBeCalled();
+ $form->add($subForm2)->shouldBeCalled();
+
+ $this->preSetData($dataEvent);
+
$builder->getForm()->willReturn($form);
$this->create($object)->shouldReturn($form);
@@ -47,15 +61,28 @@ function it_should_create_form_based_on_object_mutators($object, $factory, $fetc
* @param Knp\RadBundle\Form\ClassMetadataFetcher $fetcher
* @param Symfony\Component\Form\FormBuilder $builder
* @param Symfony\Component\Form\Form $form
+ * @param Symfony\Component\Form\Form $subForm1
+ * @param Symfony\Component\Form\Form $subForm2
+ * @param Symfony\Component\Form\Event\DataEvent $dataEvent
*/
- public function it_should_create_form_based_on_object_properties($object, $factory, $fetcher, $builder, $form)
+ public function it_should_create_form_based_on_object_properties($object, $factory, $fetcher, $builder, $form, $dataEvent, $subForm1, $subForm2)
{
$fetcher->getProperties($object)->willReturn(array(
'termOfService', 'locked',
));
$factory->createBuilder('form', $object, array())->willReturn($builder)->shouldBeCalled();
- $builder->add('termOfService')->shouldBeCalled();
- $builder->add('locked')->shouldBeCalled();
+
+ $dataEvent->getData()->willReturn($object);
+ $dataEvent->getForm()->willReturn($form->getWrappedSubject());
+
+ $factory->createForProperty(ANY_ARGUMENT, 'termOfService')->shouldBeCalled()->willReturn($subForm1);
+ $factory->createForProperty(ANY_ARGUMENT, 'locked')->shouldBeCalled()->willReturn($subForm2);
+
+ $form->add($subForm1)->shouldBeCalled();
+ $form->add($subForm2)->shouldBeCalled();
+
+ $this->preSetData($dataEvent);
+
$builder->getForm()->willReturn($form);
$this->create($object)->shouldReturn($form);
Please sign in to comment.
Something went wrong with that request. Please try again.