From 3a000d6a1198c5fb74c0d485dfdaed3dbffea6a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20G?= Date: Fri, 2 Dec 2011 15:40:43 +0100 Subject: [PATCH] first commit :) --- .gitignore | 2 + DependencyInjection/Configuration.php | 27 ++++ .../LexikFormFilterExtension.php | 30 ++++ Filter/Extension/FilterExtension.php | 25 +++ Filter/Extension/Type/FilterFieldType.php | 62 ++++++++ Filter/Extension/Type/FilterNumberType.php | 111 +++++++++++++ Filter/Extension/Type/FilterTextType.php | 114 ++++++++++++++ Filter/Extension/Type/FilterType.php | 29 ++++ Filter/Extension/Type/FilterTypeInterface.php | 22 +++ Filter/QueryBuilder.php | 90 +++++++++++ LexikFormFilterBundle.php | 9 ++ README.md | 147 ++++++++++++++++++ Resources/config/services.xml | 20 +++ .../views/Form/form_div_layout.html.twig | 45 ++++++ Tests/Filter/QueryBuilderTest.php | 82 ++++++++++ Tests/Fixtures/Entity/Item.php | 80 ++++++++++ Tests/Fixtures/Filter/ItemFilterType.php | 44 ++++++ Tests/TestCase.php | 97 ++++++++++++ Tests/bootstrap.php | 4 + phpunit.xml.dist | 33 ++++ 20 files changed, 1073 insertions(+) create mode 100644 .gitignore create mode 100644 DependencyInjection/Configuration.php create mode 100644 DependencyInjection/LexikFormFilterExtension.php create mode 100644 Filter/Extension/FilterExtension.php create mode 100644 Filter/Extension/Type/FilterFieldType.php create mode 100644 Filter/Extension/Type/FilterNumberType.php create mode 100644 Filter/Extension/Type/FilterTextType.php create mode 100644 Filter/Extension/Type/FilterType.php create mode 100644 Filter/Extension/Type/FilterTypeInterface.php create mode 100644 Filter/QueryBuilder.php create mode 100644 LexikFormFilterBundle.php create mode 100644 README.md create mode 100644 Resources/config/services.xml create mode 100644 Resources/views/Form/form_div_layout.html.twig create mode 100644 Tests/Filter/QueryBuilderTest.php create mode 100644 Tests/Fixtures/Entity/Item.php create mode 100644 Tests/Fixtures/Filter/ItemFilterType.php create mode 100644 Tests/TestCase.php create mode 100644 Tests/bootstrap.php create mode 100644 phpunit.xml.dist diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a5581fe --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +phpunit.xml +.directory diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php new file mode 100644 index 0000000..d483512 --- /dev/null +++ b/DependencyInjection/Configuration.php @@ -0,0 +1,27 @@ + + */ +class Configuration implements ConfigurationInterface +{ + /** + * {@inheritDoc} + */ + public function getConfigTreeBuilder() + { + $treeBuilder = new TreeBuilder(); + $rootNode = $treeBuilder->root('lexik_form_filter'); + + return $treeBuilder; + } +} diff --git a/DependencyInjection/LexikFormFilterExtension.php b/DependencyInjection/LexikFormFilterExtension.php new file mode 100644 index 0000000..027c019 --- /dev/null +++ b/DependencyInjection/LexikFormFilterExtension.php @@ -0,0 +1,30 @@ + + */ +class LexikFormFilterExtension extends Extension +{ + /** + * {@inheritDoc} + */ + public function load(array $configs, ContainerBuilder $container) + { + $configuration = new Configuration(); + $config = $this->processConfiguration($configuration, $configs); + + $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader->load('services.xml'); + } +} diff --git a/Filter/Extension/FilterExtension.php b/Filter/Extension/FilterExtension.php new file mode 100644 index 0000000..c500872 --- /dev/null +++ b/Filter/Extension/FilterExtension.php @@ -0,0 +1,25 @@ + + */ +class FilterExtension extends AbstractExtension +{ + protected function loadTypes() + { + return array( + new Type\FilterFieldType(), + new Type\FilterType(), + new Type\FilterTextType(), + new Type\FilterNumberType(), + ); + } +} \ No newline at end of file diff --git a/Filter/Extension/Type/FilterFieldType.php b/Filter/Extension/Type/FilterFieldType.php new file mode 100644 index 0000000..ffd7b06 --- /dev/null +++ b/Filter/Extension/Type/FilterFieldType.php @@ -0,0 +1,62 @@ + + */ +class FilterFieldType extends FormFieldType implements FilterTypeInterface +{ + /** + * {@inheritdoc} + */ + public function buildForm(FormBuilder $builder, array $options) + { + parent::buildForm($builder, $options); + + if ($options['apply_filter'] instanceof \Closure) { + $builder->setAttribute('apply_filter', $options['apply_filter']); + } + } + + /** + * {@inheritdoc} + */ + public function getDefaultOptions(array $options) + { + $options = parent::getDefaultOptions($options); + $options['required'] = false; + $options['apply_filter'] = null; + + return $options; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'filter_field'; + } + + /** + * Default implementation of the applyFieldFilter() method. + * We just add a 'and where' clause. + */ + public function applyFilter(QueryBuilder $queryBuilder, $field, $values) + { + if (!empty($values['value'])) { + $paramName = sprintf(':%s_param', $field); + + $queryBuilder->andWhere(sprintf('%s.%s = %s', $queryBuilder->getRootAlias(), $field, $paramName)) + ->setParameter($paramName, $values['value'], \PDO::PARAM_STR); + } + } +} diff --git a/Filter/Extension/Type/FilterNumberType.php b/Filter/Extension/Type/FilterNumberType.php new file mode 100644 index 0000000..48f311f --- /dev/null +++ b/Filter/Extension/Type/FilterNumberType.php @@ -0,0 +1,111 @@ + + */ +class FilterNumberType extends NumberType implements FilterTypeInterface +{ + const OPERATOR_EQUAL = '='; + const OPERATOR_GREATER_THAN = '>'; + const OPERATOR_GREATER_THAN_EQUAL = '>='; + const OPERATOR_LOWER_THAN_ = '<'; + const OPERATOR_LOWER_THAN_EQUAL = '<='; + + const SELECT_OPERATOR = 'select_operator'; + + /** + * {@inheritdoc} + */ + public function buildForm(FormBuilder $builder, array $options) + { + $attributes = array(); + + if ($options['condition_operator'] == self::SELECT_OPERATOR) { + $numberOptions = array_intersect_key($options, parent::getDefaultOptions(array())); + $numberOptions['required'] = isset($options['required']) ? $options['required'] : false; + $numberOptions['trim'] = isset($options['trim']) ? $options['trim'] : true; + + $builder->add('condition_operator', 'choice', array( + 'choices' => self::getOperatorChoices(), + )); + $builder->add('text', 'number', $numberOptions); + } else { + parent::buildForm($builder, $options); + + $attributes['condition_operator'] = $options['condition_operator']; + } + + $builder->setAttribute('filter_options', $attributes); + } + + /** + * {@inheritdoc} + */ + public function getDefaultOptions(array $options) + { + $options = parent::getDefaultOptions($options); + $options['condition_operator'] = self::OPERATOR_EQUAL; + + return $options; + } + + /** + * {@inheritdoc} + */ + public function getParent(array $options) + { + return ($options['condition_operator'] == self::SELECT_OPERATOR) ? 'filter' : 'filter_field'; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'filter_number'; + } + + public function applyFilter(QueryBuilder $queryBuilder, $field, $values) + { + if (!empty($values['value'])) { + $paramName = sprintf(':%s_param', $field); + $condition = sprintf('%s.%s %s %s', + $queryBuilder->getRootAlias(), + $field, + $values['condition_operator'], + $paramName + ); + + $queryBuilder->andWhere($condition) + ->setParameter($paramName, $values['value']); + } + } + + /** + * Retruns an array of available conditions operator. + * + * @return array + */ + static public function getOperatorChoices() + { + $choices = array(); + + $reflection = new \ReflectionClass(__CLASS__); + foreach ($reflection->getConstants() as $name => $value) { + if ('OPERATOR_' === substr($name, 0, 9)) { + $choices[$value] = strtolower(str_replace(array('OPERATOR_', '_'), array('', ' '), $name)); + } + } + + return $choices; + } +} \ No newline at end of file diff --git a/Filter/Extension/Type/FilterTextType.php b/Filter/Extension/Type/FilterTextType.php new file mode 100644 index 0000000..b1cbdb8 --- /dev/null +++ b/Filter/Extension/Type/FilterTextType.php @@ -0,0 +1,114 @@ + + */ +class FilterTextType extends TextType implements FilterTypeInterface +{ + const PATTERN_EQUALS = '%s'; + const PATTERN_START_WITH = '%%%s'; + const PATTERN_END_WITH = '%s%%'; + const PATTERN_CONTAINS = '%%%s%%'; + + const SELECT_PATTERN = 'select_pattern'; + + /** + * {@inheritdoc} + */ + public function buildForm(FormBuilder $builder, array $options) + { + parent::buildForm($builder, $options); + + $attributes = array(); + + if ($options['condition_pattern'] == self::SELECT_PATTERN) { + $textOptions = array_intersect_key($options, parent::getDefaultOptions(array())); + $textOptions['required'] = isset($options['required']) ? $options['required'] : false; + $textOptions['trim'] = isset($options['trim']) ? $options['trim'] : true; + + $builder->add('condition_pattern', 'choice', array( + 'choices' => self::getConditionChoices(), + )); + $builder->add('text', 'text', $textOptions); + } else { + $attributes['condition_pattern'] = $options['condition_pattern']; + } + + $builder->setAttribute('filter_options', $attributes); + } + + /** + * {@inheritdoc} + */ + public function getDefaultOptions(array $options) + { + $options = parent::getDefaultOptions($options); + $options['condition_pattern'] = self::PATTERN_EQUALS; + + return $options; + } + + /** + * {@inheritdoc} + */ + public function getParent(array $options) + { + return ($options['condition_pattern'] == self::SELECT_PATTERN) ? 'filter' : 'filter_field'; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'filter_text'; + } + + /** + * {@inheritdoc} + */ + public function applyFilter(QueryBuilder $queryBuilder, $field, $values) + { + if (!empty($values['value'])) { + $paramName = sprintf(':%s_param', $field); + $value = sprintf($values['condition_pattern'], $values['value']); + $condition = sprintf('%s.%s %s %s', + $queryBuilder->getRootAlias(), + $field, + ($values['condition_pattern'] == self::PATTERN_EQUALS) ? '=' : 'LIKE', + $paramName + ); + + $queryBuilder->andWhere($condition) + ->setParameter($paramName, $value, \PDO::PARAM_STR); + } + } + + /** + * Retruns an array of available conditions patterns. + * + * @return array + */ + static public function getConditionChoices() + { + $choices = array(); + + $reflection = new \ReflectionClass(__CLASS__); + foreach ($reflection->getConstants() as $name => $value) { + if ('PATTERN_' === substr($name, 0, 8)) { + $choices[$value] = strtolower(str_replace(array('PATTERN_', '_'), array('', ' '), $name)); + } + } + + return $choices; + } +} \ No newline at end of file diff --git a/Filter/Extension/Type/FilterType.php b/Filter/Extension/Type/FilterType.php new file mode 100644 index 0000000..7ef8fb3 --- /dev/null +++ b/Filter/Extension/Type/FilterType.php @@ -0,0 +1,29 @@ + + */ +class FilterType extends FormType +{ + /** + * {@inheritdoc} + */ + public function getParent(array $options) + { + return 'filter_field'; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'filter'; + } +} diff --git a/Filter/Extension/Type/FilterTypeInterface.php b/Filter/Extension/Type/FilterTypeInterface.php new file mode 100644 index 0000000..5ec129d --- /dev/null +++ b/Filter/Extension/Type/FilterTypeInterface.php @@ -0,0 +1,22 @@ + + */ +interface FilterTypeInterface +{ + /** + * Add condition(s) to the query builder for the current type. + * + * @param Doctrine\ORM\QueryBuilder $queryBuilder + * @param string $field + * @param array $values + */ + public function applyFilter(QueryBuilder $queryBuilder, $field, $values); +} \ No newline at end of file diff --git a/Filter/QueryBuilder.php b/Filter/QueryBuilder.php new file mode 100644 index 0000000..edd3d48 --- /dev/null +++ b/Filter/QueryBuilder.php @@ -0,0 +1,90 @@ + + */ +class QueryBuilder +{ + /** + * Build a filter query. + * + * @param \Symfony\Component\Form\Form $form + * @param \Doctrine\ORM\QueryBuilder $queryBuilder + * @return \Doctrine\ORM\QueryBuilder + */ + public function buildQuery(Form $form, \Doctrine\ORM\QueryBuilder $queryBuilder) + { + foreach ($form->getChildren() as $child) { + $this->addFilerCondition($queryBuilder, $child); + } + + return $queryBuilder; + } + + /** + * Add a condition to the builder for the given form. + * + * @param \Doctrine\ORM\QueryBuilder $queryBuilder + * @param Form $form + */ + protected function addFilerCondition(\Doctrine\ORM\QueryBuilder $queryBuilder, Form $form) + { + $values = $this->prepareFilterValues($form); + + // apply the filter by using the closure set with the 'apply_filter' option + if ($form->hasAttribute('apply_filter')) { + $closure = $form->getAttribute('apply_filter'); + $closure($queryBuilder, $form->getName(), $values); + } else { + // if no closure we use the applyFilter() method from an FilterTypeInterface + $types = array_reverse($form->getTypes()); + $filterApplied = false; + $i = 0; + + while ($iapplyFilter($queryBuilder, $form->getName(), $values); + $filterApplied = true; + } + + $i++; + } + } + } + + /** + * Prepare all values needed to apply the filer. + * + * @param Form $form + * @return array + */ + protected function prepareFilterValues(Form $form) + { + $values = array(); + $data = $form->getData(); + + if (is_array($data)) { + $values = array('value' => $data['text']); + unset($data['text']); + $values += $data; + } else { + $values = array('value' => $data); + } + + if ($form->hasAttribute('filter_options')) { + $values = array_merge($values, $form->getAttribute('filter_options')); + } + + return $values; + } +} \ No newline at end of file diff --git a/LexikFormFilterBundle.php b/LexikFormFilterBundle.php new file mode 100644 index 0000000..49fdcf7 --- /dev/null +++ b/LexikFormFilterBundle.php @@ -0,0 +1,9 @@ + + +Register the namespaces with the autoloader: + + // app/autoload.php + $loader->registerNamespaces(array( + // ... + 'Lexik' => __DIR__.'/../vendor/bundles', + // ... + )); + +Register the bundle with your kernel: + + // in AppKernel::registerBundles() + $bundles = array( + // ... + new Lexik\Bundle\FormFilterBundle\LexikFormFilterBundle(), + // ... + ); + + +Usage +===== + +Here an example of how to use the bundle. +Once the bundle is loaded in your app, add this in your `app/config.yml` + + twig: + form: + resources: + - LexikFormFilterBundle:Form:form_div_layout.html.twig + + +Let's use the following entity: + + // MyEntity.php + namespace Project\Bundle\SuperBundle\Entity; + + use Doctrine\ORM\Mapping as ORM; + + /** + * @ORM\Entity + */ + class MyEntity + { + /** + * @ORM\Id + * @ORM\Column(type="integer") + * @ORM\GeneratedValue(strategy="AUTO") + */ + protected $id; + + /** + * @ORM\Column(type="string") + */ + protected $name; + + /** + * @ORM\Column(type="integer") + */ + protected $rank; + } + +Create a type extended from AbstractType, add `name` and `rank` and use the filter_xxxx types. + + // MySuperFilterType.php + namespace Project\Bundle\SuperBundle\Filter; + + use Symfony\Component\Form\AbstractType; + use Symfony\Component\Form\FormBuilder; + + class MySuperFilterType extends AbstractType + { + public function buildForm(FormBuilder $builder, array $options) + { + $builder->add('name', 'filter_text'); + $builder->add('rank', 'filter_number'); + } + + public function getName() + { + return 'my_super_filter'; + } + } + +Then in an action, create a form object from the MySuperFilterType. Let's say we filter when the form is submitted with a post method. + + // DefaultController.php + namespace Project\Bundle\SuperBundle\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\Controller; + use Project\Bundle\SuperBundle\Filter\MySuperFilterType; + + class DefaultController extends Controller + { + public function testFilterAction() + { + $form = $this->get('form.factory')->create(new MySuperFilterType()); + + if ($this->get('request')->getMethod() == 'POST') { + // bind values from the request + $form->bindRequest($this->get('request')); + + // initliaze a query builder + $queryBuilder = $this->get('doctrine.orm.entity_manager') + ->getRepository('ProjectSuperBundle:MyEntity') + ->createQueryBuilder('e'); + + // build the query from the given form object + $this->get('lexik_form_filter.query_builder')->buildQuery($form, $queryBuilder); + + var_dump($queryBuilder->getDql()); + } + + return $this->render('ProjectSuperBundle:Default:testFilter.html.twig', array( + 'form' => $form->createView(), + )); + } + } + +Display the form + + // testFilter.html.twig +
+ {{ form_rest(form) }} + +
diff --git a/Resources/config/services.xml b/Resources/config/services.xml new file mode 100644 index 0000000..80ab3d2 --- /dev/null +++ b/Resources/config/services.xml @@ -0,0 +1,20 @@ + + + + + + Lexik\Bundle\FormFilterBundle\Filter\QueryBuilder + + + + + + + + + + + + diff --git a/Resources/views/Form/form_div_layout.html.twig b/Resources/views/Form/form_div_layout.html.twig new file mode 100644 index 0000000..0c1a0bc --- /dev/null +++ b/Resources/views/Form/form_div_layout.html.twig @@ -0,0 +1,45 @@ +{% extends "form_div_layout.html.twig" %} + +{# Rows #} +{% block filter_field_row %} + {{ block('field_row') }} +{% endblock filter_field_row %} + +{% block filter_text_row %} + {% if form.offsetExists('condition_pattern') %} +
+ {{ form_label(form) }} + {{ form_widget(form.condition_pattern) }} + {{ form_widget(form.text) }} +
+ {% else %} + {{ block('filter_field_row') }} + {% endif %} +{% endblock filter_text_row %} + +{% block filter_number_row %} + {% if form.offsetExists('condition_operator') %} +
+ {{ form_label(form) }} + {{ form_widget(form.condition_operator) }} + {{ form_widget(form.text) }} +
+ {% else %} + {{ block('filter_field_row') }} + {% endif %} +{% endblock filter_number_row %} + +{# Widgets #} +{% block filter_field_widget %} + {{ block('field_widget') }} +{% endblock filter_field_widget %} + +{# Labels #} +{% block filter_field_label %} + {{ block('field_label') }} +{% endblock filter_field_label %} + +{# Errors #} +{% block filter_field_errors %} + {{ block('field_errors') }} +{% endblock filter_field_errors %} diff --git a/Tests/Filter/QueryBuilderTest.php b/Tests/Filter/QueryBuilderTest.php new file mode 100644 index 0000000..fb0eb38 --- /dev/null +++ b/Tests/Filter/QueryBuilderTest.php @@ -0,0 +1,82 @@ + + */ +class QueryBuilderTest extends TestCase +{ + public function testBuildQuery() + { + $form = $this->formFactory->create(new ItemFilterType()); + $filterQueryBuilder = new QueryBuilder(); + + // without binding the form + $doctrineQueryBuilder = $this->createDoctrineQueryBuilder(); + + $expectedDql = 'SELECT i FROM Lexik\Bundle\FormFilterBundle\Tests\Fixtures\Entity i'; + $filterQueryBuilder->buildQuery($form, $doctrineQueryBuilder); + $this->assertEquals($expectedDql, $doctrineQueryBuilder->getDql()); + $this->assertEquals(array(), $doctrineQueryBuilder->getParameters()); + + // bind a request to the form - 1 params + $doctrineQueryBuilder = $this->createDoctrineQueryBuilder(); + $request = $this->craeteRequest(array('name' => 'blabla', 'position' => '')); + $form->bindRequest($request); + + $expectedDql = 'SELECT i FROM Lexik\Bundle\FormFilterBundle\Tests\Fixtures\Entity i WHERE i.name = :name_param'; + $filterQueryBuilder->buildQuery($form, $doctrineQueryBuilder); + $this->assertEquals($expectedDql, $doctrineQueryBuilder->getDql()); + $this->assertEquals(array(':name_param' => 'blabla'), $doctrineQueryBuilder->getParameters()); + + // bind a request to the form - 2 params + $doctrineQueryBuilder = $this->createDoctrineQueryBuilder(); + $request = $this->craeteRequest(array('name' => 'blabla', 'position' => 2)); + $form->bindRequest($request); + + $expectedDql = 'SELECT i FROM Lexik\Bundle\FormFilterBundle\Tests\Fixtures\Entity i WHERE i.name = :name_param AND i.position = :position_param'; + $filterQueryBuilder->buildQuery($form, $doctrineQueryBuilder); + $this->assertEquals($expectedDql, $doctrineQueryBuilder->getDql()); + $this->assertEquals(array(':name_param' => 'blabla', ':position_param' => 2), $doctrineQueryBuilder->getParameters()); + + // use filter type options + $form = $this->formFactory->create(new ItemFilterType(true)); + + $doctrineQueryBuilder = $this->createDoctrineQueryBuilder(); + $request = $this->craeteRequest(array('name' => array('text' => 'blabla', 'condition_pattern' => '%s%%'), 'position' => 2)); + $form->bindRequest($request); + + $expectedDql = 'SELECT i FROM Lexik\Bundle\FormFilterBundle\Tests\Fixtures\Entity i WHERE i.name LIKE :name_param AND i.position > :position_param'; + $filterQueryBuilder->buildQuery($form, $doctrineQueryBuilder); + $this->assertEquals($expectedDql, $doctrineQueryBuilder->getDql()); + $this->assertEquals(array(':name_param' => 'blabla%', ':position_param' => 2), $doctrineQueryBuilder->getParameters()); + } + + protected function createDoctrineQueryBuilder() + { + return $this->em->createQueryBuilder() + ->select('i') + ->from('Lexik\Bundle\FormFilterBundle\Tests\Fixtures\Entity', 'i'); + } + + protected function craeteRequest($values) + { + return new Request( + array(), + array('item_filter' => $values), + array(), + array(), + array(), + array('REQUEST_METHOD' => 'POST') + ); + } +} \ No newline at end of file diff --git a/Tests/Fixtures/Entity/Item.php b/Tests/Fixtures/Entity/Item.php new file mode 100644 index 0000000..c3532ed --- /dev/null +++ b/Tests/Fixtures/Entity/Item.php @@ -0,0 +1,80 @@ + + */ +class Item +{ + /** + * @ORM\Id + * @ORM\Column(type="integer") + * @ORM\GeneratedValue(strategy="AUTO") + */ + protected $id; + + /** + * @ORM\Column(type="string") + */ + protected $name; + + /** + * @ORM\Column(type="integer") + */ + protected $position; + + /** + * Get id + * + * @return integer + */ + public function getId() + { + return $this->id; + } + + /** + * Set name + * + * @param string $name + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * Get name + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Get position + * + * @return int + */ + public function getPosition() + { + return $this->position; + } + + /** + * Set position + * + * @param int $position + */ + public function setPosition($position) + { + $this->position = $position; + } +} \ No newline at end of file diff --git a/Tests/Fixtures/Filter/ItemFilterType.php b/Tests/Fixtures/Filter/ItemFilterType.php new file mode 100644 index 0000000..6828246 --- /dev/null +++ b/Tests/Fixtures/Filter/ItemFilterType.php @@ -0,0 +1,44 @@ + + */ +class ItemFilterType extends AbstractType +{ + protected $addTypeOptions; + + public function __construct($addTypeOptions = false) + { + $this->addTypeOptions = $addTypeOptions; + } + + public function buildForm(FormBuilder $builder, array $options) + { + if (!$this->addTypeOptions) { + $builder->add('name', 'filter_text'); + $builder->add('position', 'filter_number'); + } else { + $builder->add('name', 'filter_text', array( + 'condition_pattern' => FilterTextType::SELECT_PATTERN, + )); + $builder->add('position', 'filter_number', array( + 'condition_operator' => FilterNumberType::OPERATOR_GREATER_THAN, + )); + } + } + + public function getName() + { + return 'item_filter'; + } +} \ No newline at end of file diff --git a/Tests/TestCase.php b/Tests/TestCase.php new file mode 100644 index 0000000..55fae0e --- /dev/null +++ b/Tests/TestCase.php @@ -0,0 +1,97 @@ +em = $this->getMockSqliteEntityManager(); + $this->formFactory = $this->getFormFactory(); + } + + /** + * Create a form factory instance. + * + * @return Symfony\Component\Form\FormFactory + */ + public function getFormFactory() + { + $formFactory = new FormFactory(array( + new CoreExtension(), + new FilterExtension(), + )); + + return $formFactory; + } + + /** + * EntityManager mock object together with annotation mapping driver and + * pdo_sqlite database in memory + * + * @return EntityManager + */ + public function getMockSqliteEntityManager() + { + $conn = array( + 'driver' => 'pdo_sqlite', + 'memory' => true, + ); + + $cache = new \Doctrine\Common\Cache\ArrayCache(); + + $reader = new AnnotationReader($cache); + $reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\'); + $mappingDriver = new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader, array( + __DIR__.'/../../../../../../vendor/doctrine/lib', + __DIR__.'/Fixtures/Entity', + )); + + $config = $this->getMock('Doctrine\\ORM\\Configuration'); + $config->expects($this->any()) + ->method('getMetadataCacheImpl') + ->will($this->returnValue($cache)); + $config->expects($this->any()) + ->method('getQueryCacheImpl') + ->will($this->returnValue($cache)); + $config->expects($this->once()) + ->method('getProxyDir') + ->will($this->returnValue(sys_get_temp_dir())); + $config->expects($this->once()) + ->method('getProxyNamespace') + ->will($this->returnValue('Proxy')); + $config->expects($this->once()) + ->method('getAutoGenerateProxyClasses') + ->will($this->returnValue(true)); + $config->expects($this->any()) + ->method('getMetadataDriverImpl') + ->will($this->returnValue($mappingDriver)); + $config->expects($this->any()) + ->method('getClassMetadataFactoryName') + ->will($this->returnValue('Doctrine\\ORM\Mapping\\ClassMetadataFactory')); + + $em = EntityManager::create($conn, $config); + + return $em; + } +} diff --git a/Tests/bootstrap.php b/Tests/bootstrap.php new file mode 100644 index 0000000..2b17030 --- /dev/null +++ b/Tests/bootstrap.php @@ -0,0 +1,4 @@ + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + + + + + + + +