mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-14 14:24:24 +00:00
Merge branch 'add_number_field' into 'master'
add a number field The field has three option : - lesser or equal than. If null, this option is ignored ; - greather or equal than. If null, this options is ignored ; - precision : the number of decimal after the number ; - text after the field : a text to show after the field. The field is rendered as an HTML integer input if precision = 0, or a symfony number field if precision > 0. ref chill-project/Chill-CustomFields#11 See merge request !6
This commit is contained in:
commit
af3bc324c2
181
CustomFields/CustomFieldNumber.php
Normal file
181
CustomFields/CustomFieldNumber.php
Normal file
@ -0,0 +1,181 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
|
||||
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Chill\CustomFieldsBundle\CustomFields;
|
||||
|
||||
use Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface;
|
||||
use Chill\CustomFieldsBundle\Entity\CustomField;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Validator\Constraints\GreaterThanOrEqual;
|
||||
use Symfony\Component\Validator\Constraints\LessThanOrEqual;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Bundle\TwigBundle\TwigEngine;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
|
||||
/**
|
||||
* Create a custom field number.
|
||||
*
|
||||
* This number may have a min and max value, and a precision.
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
* @author Marc Ducobu <marc@champs-libres.coop>
|
||||
*/
|
||||
class CustomFieldNumber implements CustomFieldInterface
|
||||
{
|
||||
/**
|
||||
* key for the minimal value of the field
|
||||
*/
|
||||
const MIN = 'min';
|
||||
const MAX = 'max';
|
||||
const SCALE = 'scale';
|
||||
const POST_TEXT = 'post_text';
|
||||
|
||||
/**
|
||||
*
|
||||
* @var TwigEngine
|
||||
*/
|
||||
private $templating = NULL;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var TranslatableStringHelper
|
||||
*/
|
||||
private $translatableStringHelper = NULL;
|
||||
|
||||
public function __construct(TwigEngine $templating, TranslatableStringHelper $translatableStringHelper)
|
||||
{
|
||||
$this->templating = $templating;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, CustomField $customField)
|
||||
{
|
||||
$options = $customField->getOptions();
|
||||
|
||||
//select the type depending to the SCALE
|
||||
$type = ($options[self::SCALE] === 0 or $options[self::SCALE] === NULL)?
|
||||
'integer' : 'number';
|
||||
|
||||
$fieldOptions = $this->prepareFieldOptions($customField, $type);
|
||||
|
||||
$builder->add($customField->getSlug(), $type, $fieldOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* prepare the options'form field
|
||||
*
|
||||
* @param CustomField $customField
|
||||
* @param string $type
|
||||
* @return mixed[]
|
||||
*/
|
||||
private function prepareFieldOptions(CustomField $customField, $type)
|
||||
{
|
||||
$options = $customField->getOptions();
|
||||
|
||||
/**
|
||||
* @var mixed[] the formField options
|
||||
*/
|
||||
$fieldOptions = array();
|
||||
|
||||
// add required
|
||||
$fieldOptions['required'] = False;
|
||||
|
||||
//add label
|
||||
$fieldOptions['label'] = $this->translatableStringHelper->localize($customField->getName());
|
||||
|
||||
// add constraints if required
|
||||
if ($options[self::MIN] !== NULL) {
|
||||
$fieldOptions['constraints'][] = new GreaterThanOrEqual(array('value' => $options[self::MIN]));
|
||||
}
|
||||
if ($options[self::MAX] !== NULL) {
|
||||
$fieldOptions['constraints'][] = new LessThanOrEqual(array('value' => $options[self::MAX]));
|
||||
}
|
||||
|
||||
// add precision to options if required
|
||||
if ($type === 'number') {
|
||||
$fieldOptions['scale'] = $options[self::SCALE];
|
||||
}
|
||||
|
||||
if (!empty($options[self::POST_TEXT])) {
|
||||
$fieldOptions['post_text'] = $options[self::POST_TEXT];
|
||||
}
|
||||
|
||||
return $fieldOptions;
|
||||
}
|
||||
|
||||
public function buildOptionsForm(FormBuilderInterface $builder)
|
||||
{
|
||||
return $builder
|
||||
->add(self::MIN, 'number', array(
|
||||
'scale' => 2,
|
||||
'label' => 'Greater or equal than',
|
||||
'required' => false
|
||||
))
|
||||
->add(self::MAX, 'number', array(
|
||||
'scale' => 2,
|
||||
'label' => 'Lesser or equal than',
|
||||
'required' => false
|
||||
))
|
||||
->add(self::SCALE, 'integer', array(
|
||||
'scale' => 0,
|
||||
'label' => 'Precision',
|
||||
'constraints' => array(
|
||||
new GreaterThanOrEqual(array('value' => 0))
|
||||
)
|
||||
))
|
||||
->add(self::POST_TEXT, 'text', array(
|
||||
'label' => 'Text after the field'
|
||||
))
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
public function deserialize($serialized, CustomField $customField)
|
||||
{
|
||||
return $serialized;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'Number';
|
||||
}
|
||||
|
||||
public function render($value, CustomField $customField, $documentType = 'html')
|
||||
{
|
||||
$template = 'ChillCustomFieldsBundle:CustomFieldsRendering:number.'
|
||||
.$documentType.'.twig';
|
||||
$options = $customField->getOptions();
|
||||
|
||||
return $this->templating
|
||||
->render($template, array(
|
||||
'number' => $value,
|
||||
'scale' => $options[self::SCALE],
|
||||
'post' => $options[self::POST_TEXT]
|
||||
));
|
||||
}
|
||||
|
||||
public function serialize($value, CustomField $customField)
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
@ -87,6 +87,7 @@ class CustomFieldType extends AbstractType
|
||||
->buildOptionsForm(
|
||||
$builder
|
||||
->create('options', null, array('compound' => true))
|
||||
->setRequired(false)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
53
Form/Extension/PostTextExtension.php
Normal file
53
Form/Extension/PostTextExtension.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Chill\CustomFieldsBundle\Form\Extension;
|
||||
|
||||
use Symfony\Component\Form\AbstractTypeExtension;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Form\FormView;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\PropertyAccess\PropertyAccess;
|
||||
|
||||
/**
|
||||
* This extension create the possibility to add some text
|
||||
* after the input.
|
||||
*
|
||||
* This can be used to print the units of the field, or some text.
|
||||
*
|
||||
* This class must be extended by Extension class specifics to each input.
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
abstract class PostTextExtension extends AbstractTypeExtension
|
||||
{
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefined(array('post_text'));
|
||||
}
|
||||
|
||||
public function buildView(FormView $view, FormInterface $form, array $options)
|
||||
{
|
||||
if (array_key_exists('post_text', $options)) {
|
||||
//set the post text variable to the view
|
||||
$view->vars['post_text'] = $options['post_text'];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
37
Form/Extension/PostTextIntegerExtension.php
Normal file
37
Form/Extension/PostTextIntegerExtension.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Chill\CustomFieldsBundle\Form\Extension;
|
||||
|
||||
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
|
||||
|
||||
/**
|
||||
* This class add the PostTextExtension to integer fields
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
class PostTextIntegerExtension extends PostTextExtension
|
||||
{
|
||||
public function getExtendedType()
|
||||
{
|
||||
// return IntegerType::class; !! only for symfony 2.8
|
||||
return 'integer';
|
||||
}
|
||||
|
||||
}
|
34
Form/Extension/PostTextNumberExtension.php
Normal file
34
Form/Extension/PostTextNumberExtension.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Chill\CustomFieldsBundle\Form\Extension;
|
||||
|
||||
/**
|
||||
* This class add the PostTextExtension to number fields
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
class PostTextNumberExtension extends PostTextExtension
|
||||
{
|
||||
public function getExtendedType()
|
||||
{
|
||||
return 'number';
|
||||
}
|
||||
|
||||
}
|
@ -39,6 +39,24 @@ services:
|
||||
- "@chill.main.helper.translatable_string"
|
||||
tags:
|
||||
- { name: 'chill.custom_field', type: 'text' }
|
||||
|
||||
chill.custom_field.number:
|
||||
class: Chill\CustomFieldsBundle\CustomFields\CustomFieldNumber
|
||||
arguments:
|
||||
- "@templating"
|
||||
- "@chill.main.helper.translatable_string"
|
||||
tags:
|
||||
- { name: 'chill.custom_field', type: 'number' }
|
||||
|
||||
chill.form_extension.post_text_integer:
|
||||
class: Chill\CustomFieldsBundle\Form\Extension\PostTextIntegerExtension
|
||||
tags:
|
||||
- { name: form.type_extension, alias: 'integer' }
|
||||
|
||||
chill.form_extension.post_text_number:
|
||||
class: Chill\CustomFieldsBundle\Form\Extension\PostTextNumberExtension
|
||||
tags:
|
||||
- { name: form.type_extension, alias: 'number' }
|
||||
|
||||
chill.custom_field.choice:
|
||||
class: Chill\CustomFieldsBundle\CustomFields\CustomFieldChoice
|
||||
|
@ -75,3 +75,9 @@ One box on the line: Un seul champ sur la ligne
|
||||
Title level: Niveau de titre
|
||||
Main title: Titre principal
|
||||
Subtitle: Sous-titre
|
||||
|
||||
#custom field number
|
||||
Greater or equal than: Plus grand ou égal à
|
||||
Lesser or equal than: Plus petit ou égal à
|
||||
Precision: Précision
|
||||
Text after the field: Texte après le champ
|
||||
|
1
Resources/views/CustomFieldsRendering/number.html.twig
Normal file
1
Resources/views/CustomFieldsRendering/number.html.twig
Normal file
@ -0,0 +1 @@
|
||||
{% if number is not empty %}{{ number|number_format(scale) }} {{ post|default('') }}{% endif %}
|
@ -94,4 +94,28 @@
|
||||
{% endfor -%}
|
||||
</div>
|
||||
|
||||
{% endblock choice_with_other_widget %}
|
||||
{% endblock choice_with_other_widget %}
|
||||
|
||||
{# extend the integer type to add post_text extension #}
|
||||
{% block integer_widget %}
|
||||
{%- if post_text is defined and post_text is not empty-%}
|
||||
<div class="input_with_post_text">
|
||||
{%- endif -%}
|
||||
{{ block('form_widget') }}
|
||||
{%- if post_text is defined and post_text is not empty-%}
|
||||
<span class="cf_post_text">{{ post_text }}</span>
|
||||
</div>
|
||||
{%- endif -%}
|
||||
{% endblock %}
|
||||
|
||||
{# extend the number type to add post_text extension #}
|
||||
{% block number_widget %}
|
||||
{%- if post_text is defined and post_text is not empty-%}
|
||||
<div class="input_with_post_text">
|
||||
{%- endif -%}
|
||||
{{ block('form_widget') }}
|
||||
{%- if post_text is defined and post_text is not empty-%}
|
||||
<span class="cf_post_text">{{ post_text }}</span>
|
||||
</div>
|
||||
{%- endif -%}
|
||||
{% endblock %}
|
||||
|
143
Tests/CustomFields/CustomFieldsNumberTest.php
Normal file
143
Tests/CustomFields/CustomFieldsNumberTest.php
Normal file
@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Chill\CustomFieldsBundle\Tests;
|
||||
|
||||
use Chill\CustomFieldsBundle\CustomFields\CustomFieldNumber;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Chill\CustomFieldsBundle\Entity\CustomField;
|
||||
|
||||
/**
|
||||
* Test CustomFieldsNumber
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
class CustomFieldsNumberTest extends \Symfony\Bundle\FrameworkBundle\Test\WebTestCase
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @var CustomFieldNumber
|
||||
*/
|
||||
private $customFieldNumber;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var FormBuilderInterface
|
||||
*/
|
||||
private $formBuilder;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$this->customFieldNumber = self::$kernel->getContainer()
|
||||
->get('chill.custom_field.number');
|
||||
|
||||
$this->formBuilder = self::$kernel->getContainer()
|
||||
->get('form.factory')
|
||||
->createBuilder('form', null, array(
|
||||
'csrf_protection' => false,
|
||||
'csrf_field_name' => '_token'
|
||||
));
|
||||
|
||||
$request = new \Symfony\Component\HttpFoundation\Request();
|
||||
$request->setLocale('fr');
|
||||
|
||||
self::$kernel->getContainer()
|
||||
->get('request_stack')
|
||||
->push($request);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param mixed[] $options
|
||||
* @return CustomField
|
||||
*/
|
||||
private function createCustomFieldNumber($options)
|
||||
{
|
||||
return (new CustomField())
|
||||
->setType('number')
|
||||
->setActive(true)
|
||||
->setOrdering(10)
|
||||
->setSlug('default')
|
||||
->setName(array('fr' => 'default'))
|
||||
->setOptions($options);
|
||||
}
|
||||
|
||||
public function testCreateValidForm()
|
||||
{
|
||||
$cf = $this->createCustomFieldNumber(array(
|
||||
'min' => null,
|
||||
'max' => null,
|
||||
'scale' => null,
|
||||
'post_text' => null
|
||||
));
|
||||
|
||||
$this->customFieldNumber->buildForm($this->formBuilder, $cf);
|
||||
|
||||
$form = $this->formBuilder->getForm();
|
||||
|
||||
$form->submit(array('default' => 10));
|
||||
|
||||
$this->assertTrue($form->isSynchronized());
|
||||
$this->assertEquals(10, $form['default']->getData());
|
||||
}
|
||||
|
||||
public function testCreateInvalidFormValueGreaterThanMaximum()
|
||||
{
|
||||
$cf = $this->createCustomFieldNumber(array(
|
||||
'min' => null,
|
||||
'max' => 10,
|
||||
'scale' => null,
|
||||
'post_text' => null
|
||||
));
|
||||
|
||||
$this->customFieldNumber->buildForm($this->formBuilder, $cf);
|
||||
|
||||
$form = $this->formBuilder->getForm();
|
||||
|
||||
$form->submit(array('default' => 100));
|
||||
|
||||
$this->assertTrue($form->isSynchronized());
|
||||
$this->assertFalse($form->isValid());
|
||||
$this->assertEquals(1, count($form['default']->getErrors()));
|
||||
}
|
||||
|
||||
public function testCreateInvalidFormValueLowerThanMinimum()
|
||||
{
|
||||
$cf = $this->createCustomFieldNumber(array(
|
||||
'min' => 1000,
|
||||
'max' => null,
|
||||
'scale' => null,
|
||||
'post_text' => null
|
||||
));
|
||||
|
||||
$this->customFieldNumber->buildForm($this->formBuilder, $cf);
|
||||
|
||||
$form = $this->formBuilder->getForm();
|
||||
|
||||
$form->submit(array('default' => 100));
|
||||
|
||||
$this->assertTrue($form->isSynchronized());
|
||||
$this->assertFalse($form->isValid());
|
||||
$this->assertEquals(1, count($form['default']->getErrors()));
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -66,7 +66,7 @@ security:
|
||||
anonymous: ~
|
||||
form_login:
|
||||
csrf_parameter: _csrf_token
|
||||
intention: authenticate
|
||||
csrf_token_id: authenticate
|
||||
csrf_provider: form.csrf_provider
|
||||
logout: ~
|
||||
access_control:
|
||||
|
@ -17,7 +17,7 @@
|
||||
],
|
||||
"require": {
|
||||
"php": "~5.5",
|
||||
"symfony/symfony": "2.7.*",
|
||||
"symfony/symfony": "~2.7",
|
||||
"doctrine/orm": "~2.4",
|
||||
"doctrine/dbal" : "~2.5",
|
||||
"doctrine/common": "~2.4",
|
||||
@ -57,4 +57,4 @@
|
||||
"symfony-app-dir": "Tests/Fixtures/App/app",
|
||||
"app-migrations-dir": "Tests/Fixtures/App/app/DoctrineMigrations"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user