Commit d419be2a authored by Julien Fastré's avatar Julien Fastré

set some fields visibility as configurable

Some fields can now be hidden through configuration
parent d70be5ea
Pipeline #506 failed with stage
......@@ -75,7 +75,7 @@ class PersonController extends Controller
$this->denyAccessUnlessGranted('CHILL_PERSON_UPDATE', $person,
'You are not allowed to edit this person');
$form = $this->createForm(new PersonType(), $person,
$form = $this->createForm(PersonType::class, $person,
array(
"action" => $this->generateUrl('chill_person_general_update',
array("person_id" => $person_id)),
......@@ -98,7 +98,7 @@ class PersonController extends Controller
$this->denyAccessUnlessGranted('CHILL_PERSON_UPDATE', $person,
'You are not allowed to edit this person');
$form = $this->createForm(new PersonType(), $person,
$form = $this->createForm(PersonType::class, $person,
array("cFGroup" => $this->getCFGroup()));
if ($request->getMethod() === 'POST') {
......
......@@ -31,10 +31,25 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
// set configuration for validation
$container->setParameter('chill_person.validation.birtdate_not_before',
$config['validation']['birthdate_not_after']);
$this->handlePersonFieldsParameters($container, $config['person_fields']);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
}
private function handlePersonFieldsParameters(ContainerBuilder $container, $config)
{
if (array_key_exists('enabled', $config)) {
unset($config['enabled']);
}
$container->setParameter('chill_person.person_fields', $config);
foreach ($config as $key => $value) {
$container->setParameter('chill_person.person_fields.'.$key, $value);
}
}
private function declarePersonAsCustomizable (ContainerBuilder $container)
{
......@@ -66,6 +81,18 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
$asseticConfig['bundles'][] = 'ChillPersonBundle';
$container->prependExtensionConfig('assetic',
array('bundles' => array('ChillPersonBundle')));
//add person_fields parameter as global
$chillPersonConfig = $container->getExtensionConfig($this->getAlias());
$config = $this->processConfiguration(new Configuration(), $chillPersonConfig);
$twigConfig = array(
'globals' => array(
'chill_person' => array(
'fields' => $config['person_fields']
)
)
);
$container->prependExtensionConfig('twig', $twigConfig);
$this-> declarePersonAsCustomizable($container);
......
......@@ -27,40 +27,70 @@ class Configuration implements ConfigurationInterface
$rootNode
->canBeDisabled()
->children()
->arrayNode('search')
->canBeDisabled()
->arrayNode('search')
->canBeDisabled()
->children()
->booleanNode('use_double_metaphone')
->defaultFalse()
->end()
->booleanNode('use_trigrams')
->defaultFalse()
->end()
->end()
->end()
->arrayNode('validation')
->canBeDisabled()
->children()
->scalarNode('birthdate_not_after')
->info($this->validationBirthdateNotAfterInfos)
->defaultValue('P1D')
->validate()
->ifTrue(function($period) {
try {
$interval = new \DateInterval($period);
} catch (\Exception $ex) {
return true;
}
return false;
})
->thenInvalid('Invalid period for birthdate validation : "%s" '
. 'The parameter should match duration as defined by ISO8601 : '
. 'https://en.wikipedia.org/wiki/ISO_8601#Durations')
->end()
->end()
->end();
->booleanNode('use_double_metaphone')
->defaultFalse()
->end() // use_double_metaphone, parent = children for 'search'
->booleanNode('use_trigrams')
->defaultFalse()
->end() // use_trigrams, parent = children of 'search'
->end() //children for 'search', parent = array node 'search'
->end() // array 'search', parent = children of root
->arrayNode('validation')
->canBeDisabled()
->children()
->scalarNode('birthdate_not_after')
->info($this->validationBirthdateNotAfterInfos)
->defaultValue('P1D')
->validate()
->ifTrue(function($period) {
try {
$interval = new \DateInterval($period);
} catch (\Exception $ex) {
return true;
}
return false;
})
->thenInvalid('Invalid period for birthdate validation : "%s" '
. 'The parameter should match duration as defined by ISO8601 : '
. 'https://en.wikipedia.org/wiki/ISO_8601#Durations')
->end() // birthdate_not_after, parent = children of validation
->end() // children for 'validation', parent = validation
->end() //validation, parent = children of root
->end() // children of root, parent = root
->arrayNode('person_fields')
->canBeDisabled()
->children()
->append($this->addFieldNode('place_of_birth'))
->append($this->addFieldNode('email'))
->append($this->addFieldNode('phonenumber'))
->append($this->addFieldNode('nationality'))
->append($this->addFieldNode('country_of_birth'))
->append($this->addFieldNode('marital_status'))
->append($this->addFieldNode('spoken_languages'))
->end() //children for 'person_fields', parent = array 'person_fields'
->end() // person_fields, parent = children of root
->end() // children of 'root', parent = root
;
return $treeBuilder;
}
private function addFieldNode($key)
{
$tree = new TreeBuilder();
$node = $tree->root($key, 'enum');
$node
->values(array('hidden', 'visible'))
->defaultValue('visible')
->info("If the field $key must be shown")
->end();
//var_dump($node);
return $node;
}
}
......@@ -28,6 +28,25 @@ use Chill\PersonBundle\Form\Type\GenderType;
class PersonType extends AbstractType
{
/**
* array of configuration for person_fields.
*
* Contains whether we should add fields some optional fields (optional per
* instance)
*
* @var string[]
*/
protected $config = array();
/**
*
* @param string[] $personFieldsConfiguration configuration of visibility of some fields
*/
public function __construct(array $personFieldsConfiguration)
{
$this->config = $personFieldsConfiguration;
}
/**
* @param FormBuilderInterface $builder
* @param array $options
......@@ -38,27 +57,48 @@ class PersonType extends AbstractType
->add('firstName')
->add('lastName')
->add('birthdate', 'date', array('required' => false, 'widget' => 'single_text', 'format' => 'dd-MM-yyyy'))
->add('placeOfBirth', 'text', array('required' => false))
->add('gender', new GenderType(), array(
'required' => true
))
->add('memo', 'textarea', array('required' => false))
->add('phonenumber', 'textarea', array('required' => false))
->add('email', 'textarea', array('required' => false))
->add('countryOfBirth', 'select2_chill_country', array(
;
if ($this->config['place_of_birth'] === 'visible') {
$builder->add('placeOfBirth', 'text', array('required' => false));
}
if ($this->config['phonenumber'] === 'visible') {
$builder->add('phonenumber', 'textarea', array('required' => false));
}
if ($this->config['email'] === 'visible') {
$builder->add('email', 'textarea', array('required' => false));
}
if ($this->config['country_of_birth'] === 'visible') {
$builder->add('countryOfBirth', 'select2_chill_country', array(
'required' => false
))
->add('nationality', 'select2_chill_country', array(
));
}
if ($this->config['nationality'] === 'visible') {
$builder->add('nationality', 'select2_chill_country', array(
'required' => false
))
->add('spokenLanguages', 'select2_chill_language', array(
));
}
if ($this->config['spoken_languages'] === 'visible') {
$builder->add('spokenLanguages', 'select2_chill_language', array(
'required' => false,
'multiple' => true
))
->add('maritalStatus', 'select2_chill_marital_status', array(
));
}
if ($this->config['marital_status'] === 'visible'){
$builder->add('maritalStatus', 'select2_chill_marital_status', array(
'required' => false
))
;
));
}
if($options['cFGroup']) {
$builder
......
parameters:
# cl_chill_person.example.class: Chill\PersonBundle\Example
services:
services:
chill.person.form.person_creation:
class: Chill\PersonBundle\Form\PersonType
arguments:
- %chill_person.person_fields%
tags:
- { name: form.type }
chill.person.accompanying_period_closing_motive:
class: Chill\PersonBundle\Form\Type\ClosingMotiveType
scope: request
......
......@@ -43,23 +43,40 @@
<fieldset>
<legend><h2>{{ 'Birth information'|trans }}</h2></legend>
{{ form_row(form.birthdate, {'label': 'Date of birth'} ) }}
{%- if form.placeOfBirth is defined -%}
{{ form_row(form.placeOfBirth, { 'label' : 'Place of birth'} ) }}
{%- endif -%}
{%- if form.countryOfBirht is defined -%}
{{ form_row(form.countryOfBirth, { 'label' : 'Country of birth' } ) }}
{%- endif -%}
</fieldset>
{%- if form.nationality is defined or form.spokenLanguages is defined or form.maritalStatus is defined -%}
<fieldset>
<legend><h2>{{ 'Administrative information'|trans }}</h2></legend>
{%- if form.nationality is defined -%}
{{ form_row(form.nationality, { 'label' : 'Nationality'|trans} ) }}
{%- endif -%}
{%- if form.spokenLanguages is defined -%}
{{ form_row(form.spokenLanguages, {'label' : 'Spoken languages'}) }}
{%- endif -%}
{%- if form.maritalStatus is defined -%}
{{ form_row(form.maritalStatus, { 'label' : 'Marital status'} ) }}
{%- endif -%}
</fieldset>
{%- endif -%}
{%- if form.email is defined or form.phonenumber is defined -%}
<fieldset>
<legend><h2>{{ 'Contact information'|trans }}</h2></legend>
{%- if form.email is defined -%}
{{ form_row(form.email, {'label': 'Email'}) }}
{%- endif -%}
{%- if form.phonenumber is defined -%}
{{ form_row(form.phonenumber, {'label': 'Phonenumber'}) }}
{%- endif -%}
</fieldset>
{%- endif -%}
{{ form_rest(form) }}
......
......@@ -86,8 +86,11 @@ This view should receive those arguments:
{%- endif -%}
</dd>
{%- if chill_person.fields.place_of_birth == 'visible' -%}
<dt>{{ 'Place of birth'|trans }}&nbsp;:</dt>
<dd>{{ person.placeOfBirth }}</dd>
{%- endif -%}
{%- if chill_person.fields.country_of_birth == 'visible' -%}
<dt>{{ 'Country of birth'|trans }}&nbsp;:</dt>
<dd>{% spaceless %}
{% if person.countryOfBirth is not null %}
......@@ -96,6 +99,7 @@ This view should receive those arguments:
{{ 'Unknown country of birth'|trans }}
{% endif %}
{% endspaceless %}</dd>
{%- endif -%}
</dl>
{% if is_granted('CHILL_PERSON_UPDATE', person) %}
......@@ -106,10 +110,12 @@ This view should receive those arguments:
</div>
<div class="grid-10 push-1 grid-mobile-12 grid-tablet-12 push-mobile-0 push-tablet-0 parent">
{%- if chill_person.fields.nationality == 'visible' or chill_person.fields.spoken_languages == 'visible'-%}
<div class="grid-6">
<figure class="person-details">
<h2 class="chill-orange">{{ 'Administrative information'|trans|upper }}</h2>
{%- if chill_person.fields.nationality == 'visible' -%}
<dl>
<dt>{{ 'Nationality'|trans }}&nbsp;:</dt>
<dd>
......@@ -120,6 +126,8 @@ This view should receive those arguments:
{% endif %}
</dd>
</dl>
{%- endif -%}
{%- if chill_person.fields.spoken_languages == 'visible' -%}
<dl>
<dt>{{'Spoken languages'|trans}}&nbsp;:</dt>
<dd>
......@@ -132,6 +140,8 @@ This view should receive those arguments:
{% endif %}
</dd>
</dl>
{%- endif -%}
{%- if chill_person.fields.marital_status == 'visible' -%}
<dl>
<dt>{{'Marital status'|trans}}&nbsp;:</dt>
<dd>
......@@ -142,24 +152,31 @@ This view should receive those arguments:
{% endif %}
</dd>
</dl>
{%- endif -%}
{% if is_granted('CHILL_PERSON_UPDATE', person) %}
{{ include(edit_tmp_name, edit_tmp_args) }}
{% endif %}
</figure>
</div>
{%- endif -%}
{%- if chill_person.fields.email == 'visible' or chill_person.fields.phonenumber == 'visible' -%}
<div class="grid-6">
<figure class="person-details">
<h2 class="chill-blue"><i class="fa fa-envelope-o"></i>&nbsp;{{ 'Contact information'|trans|upper }}</h2>
{%- if chill_person.fields.email == 'visible' -%}
<dl>
<dt>{{ 'Email'|trans }}&nbsp;:</dt>
<dd><pre>{{ person.email}}&nbsp;</pre></dd>
</dl>
{%- endif -%}
{%- if chill_person.fields.phonenumber == 'visible' -%}
<dl>
<dt>{{ 'Phonenumber'|trans }}&nbsp;:</dt>
<dd><pre>{{ person.phonenumber}}&nbsp;</pre></dd>
</dl>
{% endif %}
{% if is_granted('CHILL_PERSON_UPDATE', person) %}
......@@ -167,6 +184,7 @@ This view should receive those arguments:
{% endif %}
</figure>
</div>
{%- endif -%}
</div>
{% if cFGroup and (cFGroup.getActiveCustomFields|length > 0) %}
......
......@@ -70,6 +70,7 @@
{{ person.birthdate|localizeddate('long', 'none') }}
{% endif %}
</div>
{%- if chill_person.fields.nationality == 'visible' -%}
<div class="grid-3">
<span class="open_sansbold">{{ 'Nationality'|trans|upper}}&nbsp;:</span>
{% if person.nationality is not null %}
......@@ -78,6 +79,8 @@
{% trans %}Without nationality{% endtrans %}
{% endif %}
</div>
{%- endif -%}
{%- if chill_person.fields.spoken_languages == 'visible' -%}
<div class="grid-3">
<span class="open_sansbold">{{ 'Spoken languages'|trans|upper}}&nbsp;:</span>
{% if person.spokenLanguages|length == 0 %}
......@@ -87,7 +90,8 @@
{{ lang.name|localize_translatable_string }}{% if not loop.last %},{% endif %}
{% endfor %}
{% endif %}
</div>
</div>
{%- endif -%}
</div>
</div>
{% endblock %}
......
......@@ -96,6 +96,24 @@ class PersonControllerUpdateTest extends WebTestCase
"The person edit form is accessible");
}
/**
* Test the configurable fields are present
*
* @group configurable_fields
*/
public function testHiddenFielsArePresent()
{
$crawler = $this->client->request('GET', $this->editUrl);
$configurables = array('placeOfBirth', 'phonenumber', 'email',
'countryOfBirth', 'nationality', 'spokenLanguages', 'maritalStatus');
$form = $crawler->selectButton('Submit')->form(); //;
foreach($configurables as $key) {
$this->assertTrue($form->has('chill_personbundle_person['.$key.']'));
}
}
/**
* Test if the edit page of a given person is not accessible for a user
* of another center of the person
......
<?php
/*
* Chill is a suite of a modules, Chill is a software for social workers
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.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\PersonBundle\Tests\Controller;
//ini_set('memory_limit', '-1');
use Chill\PersonBundle\Entity\Person;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
/**
* Test the edition of persons
*
* As I am logged in as "center a_social"
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class PersonControllerUpdateWithHiddenFieldsTest extends WebTestCase
{
/** @var \Doctrine\ORM\EntityManagerInterface The entity manager */
private $em;
/** @var Person The person on which the test is executed */
private $person;
/** @var string The url using for editing the person's information */
private $editUrl;
/** @var string The url using for seeing the person's information */
private $viewUrl;
/**
* Prepare client and create a random person
*/
public function setUp()
{
static::bootKernel(array('environment' => 'test_with_hidden_fields'));
$this->em = static::$kernel->getContainer()
->get('doctrine.orm.entity_manager');
$center = $this->em->getRepository('ChillMainBundle:Center')
->findOneBy(array('name' => 'Center A'));
$this->person = (new Person())
->setLastName("My Beloved")
->setFirstName("Jesus")
->setCenter($center)
->setGender(Person::MALE_GENDER);
$this->em->persist($this->person);
$this->em->flush();
$this->editUrl = '/en/person/'.$this->person->getId().'/general/edit';
$this->viewUrl = '/en/person/'.$this->person->getId().'/general';
$this->client = static::createClient(
array(
'environment' => 'test_with_hidden_fields'
),
array(
'PHP_AUTH_USER' => 'center a_social',
'PHP_AUTH_PW' => 'password',
)
);
}
/**
* Reload the person from the db
*/
protected function refreshPerson()
{
$this->person = $this->em->getRepository('ChillPersonBundle:Person')
->find($this->person->getId());
}
/**
* Test the edit page are accessible
*/
public function testEditPageIsSuccessful()
{
$this->client->request('GET', $this->editUrl);
$this->assertTrue($this->client->getResponse()->isSuccessful(),
"The person edit form is accessible");
}
/**
* Test the configurable fields are absent
*
* @group configurable_fields
*/
public function testHiddenFielsAreAbsent()
{
$crawler = $this->client->request('GET', $this->editUrl);
$configurables = array('placeOfBirth', 'phonenumber', 'email',
'countryOfBirth', 'nationality', 'spokenLanguages', 'maritalStatus');
$form = $crawler->selectButton('Submit')->form(); //;
foreach($configurables as $key) {
$this->assertFalse($form->has('chill_personbundle_person['.$key.']'));
}
}
/**
* Test the edition of a field
*
* Given I fill the field with $value
* And I submit the form
* Then I am redirected to the 'general' page
* And the person is updated in the db
*
* @dataProvider validTextFieldsProvider
* @param string $field
* @param string $value
* @param \Closure $callback
*/
public function testEditTextField($field, $value, \Closure $callback)
{
$crawler = $this->client->request('GET', $this->editUrl);
$form = $crawler->selectButton('Submit')
->form();
//transform countries into value if needed
switch ($field) {
case 'nationality':
case 'countryOfBirth':
if ($value !== NULL) {
$country = $this->em->getRepository('ChillMainBundle:Country')
->findOneByCountryCode($value);
$transformedValue = $country->getId();
} else {
$transformedValue = NULL;
}
break;
default:
$transformedValue = $value;
}
$form->get('chill_personbundle_person['.$field. ']')
->setValue($transformedValue);
$this->client->submit($form);
$this->refreshPerson();
$this->assertTrue($this->client->getResponse()->isRedirect($this->viewUrl),
'the page is redirected to general view');
$this->assertEquals($value, $callback($this->person),
'the value '.$field.' is updated in db');
$crawler = $this->client->followRedirect();
$this->assertGreaterThan(0, $crawler->filter('.success')->count(),
'a element .success is shown');
if($field == 'birthdate' or $field == 'memo' or $field == 'countryOfBirth' or $field == 'nationality'
or $field == 'gender') {
// we do not perform test on the web page contents.
} else {
$this->assertGreaterThan(0, $crawler->filter('html:contains("'.$value.'")')->count());
}
}
/**
* provide valid values to test, with field name and
* a function to find the value back from person entity
*
* @return mixed[]
*/
public function validTextFieldsProvider()
{
return array(
['firstName', 'random Value', function(Person $person) { return $person->getFirstName(); } ],
['lastName' , 'random Value', function(Person $person) { return $person->getLastName(); } ],
['birthdate', '15-12-1980', function(Person $person) { return $person->getBirthdate()->format('d-m-Y'); }],
['memo', 'jfkdlmq jkfldmsq jkmfdsq', function(Person $person) { return $person->getMemo(); }],
['birthdate', '', function(Person $person) { return $person->getBirthdate(); }],
['gender', Person::FEMALE_GENDER, function(Person $person) { return $person->getGender(); }],
);
}
public function tearDown()
{
$this->refreshPerson();
$this->em->remove($this->person);
$this->em->flush();
}
private function getVeryLongText()
{
return <<<EOT
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse molestie at enim id auctor. Vivamus malesuada elit ipsum, ac mollis ex facilisis sit amet. Phasellus accumsan, quam ut aliquet accumsan, augue ligula consequat erat, condimentum iaculis orci magna egestas eros. In vel blandit sapien. Duis ut dui vitae tortor iaculis malesuada vitae vitae lorem. Morbi efficitur dolor orci, a rhoncus urna blandit quis. Aenean at placerat dui, ut tincidunt nulla. In ultricies tempus ligula ac rutrum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce urna nibh, placerat vel auctor sed, maximus quis magna. Vivamus quam ante, consectetur vel feugiat quis, aliquet id ante. Integer gravida erat dignissim ante commodo mollis. Donec imperdiet mauris elit, nec blandit dolor feugiat ut. Proin iaculis enim ut tortor pretium commodo. Etiam aliquet hendrerit dolor sed fringilla. Vestibulum facilisis nibh tincidunt dui egestas, vitae congue mi imperdiet. Duis vulputate ultricies lectus id cursus. Fusce bibendum sem dignissim, bibendum purus quis, mollis ex. Cras ac est justo. Duis congue mattis ipsum, vitae sagittis justo dictum sit amet. Duis aliquam pharetra sem, non laoreet ante laoreet ac. Mauris ornare mi tempus rutrum consequat.
EOT;
}
}
......@@ -61,6 +61,8 @@ class PersonControllerViewTest extends WebTestCase
/**
* Test if the view page is accessible
*
* @group configurable_fields
*/
public function testViewPerson()
{
......@@ -76,6 +78,10 @@ class PersonControllerViewTest extends WebTestCase
$this->assertGreaterThan(0, $crawler->filter('html:contains("Tested Person")')->count());
$this->assertGreaterThan(0, $crawler->filter('html:contains("Réginald")')->count());
$this->assertContains('Email addresses', $crawler->text());
$this->assertContains('Phonenumber', $crawler->text());
$this->assertContains('Langues parlées', $crawler->text());
$this->assertContains(/* Etat */ 'civil', $crawler->text());
}
/**
......
<?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\PersonBundle\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Chill\PersonBundle\Entity\Person;
/**
* @author Julien Fastré <julien.fastre@champs-libres.coop>