Skip to content

Commit

Permalink
first commit :)
Browse files Browse the repository at this point in the history
  • Loading branch information
Cédric G committed Dec 2, 2011
0 parents commit 3a000d6
Show file tree
Hide file tree
Showing 20 changed files with 1,073 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
phpunit.xml
.directory
27 changes: 27 additions & 0 deletions DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Lexik\Bundle\FormFilterBundle\DependencyInjection;

use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;

/**
* This is the class that validates and merges configuration from your app/config files
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class}
*
* @author Cédric Girard <[email protected]>
*/
class Configuration implements ConfigurationInterface
{
/**
* {@inheritDoc}
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('lexik_form_filter');

return $treeBuilder;
}
}
30 changes: 30 additions & 0 deletions DependencyInjection/LexikFormFilterExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace Lexik\Bundle\FormFilterBundle\DependencyInjection;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;

/**
* This is the class that loads and manages your bundle configuration
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
*
* @author Cédric Girard <[email protected]>
*/
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');
}
}
25 changes: 25 additions & 0 deletions Filter/Extension/FilterExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Lexik\Bundle\FormFilterBundle\Filter\Extension;

use Symfony\Component\Form\AbstractExtension;

use Lexik\Bundle\FormFilterBundle\Filter\Extension\Type;

/**
* Load all filter types.
*
* @author Cédric Girard <[email protected]>
*/
class FilterExtension extends AbstractExtension
{
protected function loadTypes()
{
return array(
new Type\FilterFieldType(),
new Type\FilterType(),
new Type\FilterTextType(),
new Type\FilterNumberType(),
);
}
}
62 changes: 62 additions & 0 deletions Filter/Extension/Type/FilterFieldType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

namespace Lexik\Bundle\FormFilterBundle\Filter\Extension\Type;

use Symfony\Component\Form\Extension\Core\Type\FieldType as FormFieldType;
use Symfony\Component\Form\FormBuilder;

use Doctrine\ORM\QueryBuilder;

/**
* Base filter type.
*
* @author Cédric Girard <[email protected]>
*/
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);
}
}
}
111 changes: 111 additions & 0 deletions Filter/Extension/Type/FilterNumberType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<?php

namespace Lexik\Bundle\FormFilterBundle\Filter\Extension\Type;

use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\FormBuilder;

use Doctrine\ORM\QueryBuilder;

/**
* Filter type for numbers.
*
* @author Cédric Girard <[email protected]>
*/
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;
}
}
114 changes: 114 additions & 0 deletions Filter/Extension/Type/FilterTextType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?php

namespace Lexik\Bundle\FormFilterBundle\Filter\Extension\Type;

use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilder;

use Doctrine\ORM\QueryBuilder;

/**
* Filter type for strings.
*
* @author Cédric Girard <[email protected]>
*/
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;
}
}
Loading

0 comments on commit 3a000d6

Please sign in to comment.