From 23438926b117aacfe857a92b49ac5af3a57bc246 Mon Sep 17 00:00:00 2001 From: Marc Ducobu Date: Thu, 22 Oct 2015 15:02:49 +0200 Subject: [PATCH 01/54] Refactoring CustomFields/CustomFieldChoice.php : indentation --- CustomFields/CustomFieldChoice.php | 93 ++++++++++++++---------------- 1 file changed, 44 insertions(+), 49 deletions(-) diff --git a/CustomFields/CustomFieldChoice.php b/CustomFields/CustomFieldChoice.php index 76e9b2355..a20eb4814 100644 --- a/CustomFields/CustomFieldChoice.php +++ b/CustomFields/CustomFieldChoice.php @@ -40,43 +40,42 @@ use Symfony\Component\Translation\Translator; */ class CustomFieldChoice implements CustomFieldInterface { - const ALLOW_OTHER = 'other'; + const ALLOW_OTHER = 'other'; const OTHER_VALUE_LABEL = 'otherValueLabel'; - const MULTIPLE = 'multiple'; - const EXPANDED = 'expanded'; - const CHOICES = 'choices'; + const MULTIPLE = 'multiple'; + const EXPANDED = 'expanded'; + const CHOICES = 'choices'; - /** - * - * @var RequestStack - */ - private $requestStack; - - private $defaultLocales; - - /** - * - * @var TwigEngine - */ - private $templating; + /** + * + * @var RequestStack + */ + private $requestStack; + + private $defaultLocales; + + /** + * + * @var TwigEngine + */ + private $templating; /** * @var TranslatableStringHelper Helper that find the string in current locale from an array of translation */ private $translatableStringHelper; - public function __construct( - RequestStack $requestStack, - Translator $translator, - TwigEngine $templating, - TranslatableStringHelper $translatableStringHelper - ) - { - $this->requestStack = $requestStack; - $this->defaultLocales = $translator->getFallbackLocales(); - $this->templating = $templating; + public function __construct( + RequestStack $requestStack, + Translator $translator, + TwigEngine $templating, + TranslatableStringHelper $translatableStringHelper) + { + $this->requestStack = $requestStack; + $this->defaultLocales = $translator->getFallbackLocales(); + $this->templating = $templating; $this->translatableStringHelper = $translatableStringHelper; - } + } public function buildForm(FormBuilderInterface $builder, CustomField $customField) { @@ -93,11 +92,10 @@ class CustomFieldChoice implements CustomFieldInterface //prepare $options $options = array( - 'multiple' => $customFieldOptions[self::MULTIPLE], - 'choices' => $choices, - 'required' => false, - 'label' => $this->translatableStringHelper->localize($customField->getName()) - ); + 'multiple' => $customFieldOptions[self::MULTIPLE], + 'choices' => $choices, + 'required' => false, + 'label' => $this->translatableStringHelper->localize($customField->getName())); //if allow_other = true if ($customFieldOptions[self::ALLOW_OTHER] == true) { @@ -131,30 +129,28 @@ class CustomFieldChoice implements CustomFieldInterface public function buildOptionsForm(FormBuilderInterface $builder) { - $builder->add(self::MULTIPLE, 'choice', array( - 'expanded' => true, - 'multiple' => false, - 'choices' => array( - 1 => 'Multiple', - 0 => 'Unique' - ), - 'empty_data' => 0 - )) + $builder + ->add(self::MULTIPLE, 'choice', array( + 'expanded' => true, + 'multiple' => false, + 'choices' => array( + 1 => 'Multiple', + 0 => 'Unique'), + 'empty_data' => 0 + )) ->add(self::EXPANDED, 'choice', array( 'expanded' => true, 'multiple' => false, 'choices' => array( 1 => 'Expanded', - 0 => 'Non expanded' - ), + 0 => 'Non expanded'), 'empty_data' => 0 - )) + )) ->add(self::ALLOW_OTHER, 'choice', array( 'label' => 'Allow other', 'choices' => array( 0 => 'No', - 1 => 'Yes' - ), + 1 => 'Yes'), 'empty_data' => 0, 'expanded' => true, 'multiple' => false @@ -164,8 +160,7 @@ class CustomFieldChoice implements CustomFieldInterface ->add(self::CHOICES, new ChoicesType(), array( 'type' => new ChoicesListType($this->defaultLocales), 'allow_add' => true - )) - ; + )); return $builder; } From 98088e5f7af8dca94566f03164ef2fcc07af9215 Mon Sep 17 00:00:00 2001 From: Marc Ducobu Date: Thu, 22 Oct 2015 15:05:02 +0200 Subject: [PATCH 02/54] Refactoring Form/CustomFieldType.php : indentation --- Form/CustomFieldType.php | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Form/CustomFieldType.php b/Form/CustomFieldType.php index 459397e2d..77d8366c1 100644 --- a/Form/CustomFieldType.php +++ b/Form/CustomFieldType.php @@ -62,14 +62,13 @@ class CustomFieldType extends AbstractType $builder->add( - $this->customFieldProvider - ->getCustomFieldByType($options['type']) - ->buildOptionsForm( - $builder - ->create('options', null, array('compound' => true)) + $this->customFieldProvider + ->getCustomFieldByType($options['type']) + ->buildOptionsForm( + $builder + ->create('options', null, array('compound' => true)) ) - ); - + ); } /** From 46bba567767a45d3f76071136383a1c3e19e6a8f Mon Sep 17 00:00:00 2001 From: Marc Ducobu Date: Thu, 22 Oct 2015 15:06:14 +0200 Subject: [PATCH 03/54] Refacotring Form/Type/ChoicesListType.php : indenation --- Form/Type/ChoicesListType.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Form/Type/ChoicesListType.php b/Form/Type/ChoicesListType.php index 26ad33bf5..7cd3c4c3d 100644 --- a/Form/Type/ChoicesListType.php +++ b/Form/Type/ChoicesListType.php @@ -39,9 +39,9 @@ class ChoicesListType extends AbstractType if (NULL === $formData['slug']) { $slug = $form['name'][$locales[0]]->getData(); - $slug= strtolower($slug); - $slug= preg_replace('/[^a-zA-Z0-9 -]/','', $slug); // only take alphanumerical characters, but keep the spaces and dashes too... - $slug= str_replace(' ','-', $slug); // replace spaces by dashes + $slug = strtolower($slug); + $slug = preg_replace('/[^a-zA-Z0-9 -]/','', $slug); // only take alphanumerical characters, but keep the spaces and dashes too... + $slug = str_replace(' ','-', $slug); // replace spaces by dashes $data['slug'] = $slug; $event->setData($data); From bfca9baaeba0efaeb76386c5bc62d39fb85a0f36 Mon Sep 17 00:00:00 2001 From: Marc Ducobu Date: Thu, 22 Oct 2015 15:06:57 +0200 Subject: [PATCH 04/54] Refactoring Form/Type/ChoicesType.php : removing useless spaces --- Form/Type/ChoicesType.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/Form/Type/ChoicesType.php b/Form/Type/ChoicesType.php index 75d409bfc..581b2620b 100644 --- a/Form/Type/ChoicesType.php +++ b/Form/Type/ChoicesType.php @@ -21,6 +21,4 @@ class ChoicesType extends AbstractType { return 'collection'; } - - } \ No newline at end of file From 6af61f71dc63f421ebb51aaaf721bb7e60ab0f59 Mon Sep 17 00:00:00 2001 From: Marc Ducobu Date: Thu, 22 Oct 2015 15:07:38 +0200 Subject: [PATCH 05/54] Refactoring Resources/views/CustomFieldsRendering/choice.html.twig : indentation --- .../CustomFieldsRendering/choice.html.twig | 44 +++++++++++-------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/Resources/views/CustomFieldsRendering/choice.html.twig b/Resources/views/CustomFieldsRendering/choice.html.twig index c4dc4328f..02f6ab13b 100644 --- a/Resources/views/CustomFieldsRendering/choice.html.twig +++ b/Resources/views/CustomFieldsRendering/choice.html.twig @@ -1,23 +1,29 @@ {% if selected|length > 0 %} -
    -{%- for choice in choices -%} - {% if choice['slug'] in selected %}{%- set is_selected = true -%}{%- else -%}{%- set is_selected = false -%}{%- endif -%} - {%- if is_selected -%} -
  • - {%- if is_selected -%} -   - {%- else -%} -   - {%- endif -%} - {%- if choice['slug'] is not same as('_other') -%} - {{ choice['name']|localize_translatable_string }} - {%- else -%} - {{ choice['name'] }} - {%- endif -%} -
  • - {%- endif -%} -{%- endfor -%} -
+
    + {%- for choice in choices -%} + {% if choice['slug'] in selected %} + {%- set is_selected = true -%} + {%- else -%} + {%- set is_selected = false -%} + {%- endif -%} + + {%- if is_selected -%} +
  • + {%- if is_selected -%} +   + {%- else -%} +   + {%- endif -%} + + {%- if choice['slug'] is not same as('_other') -%} + {{ choice['name']|localize_translatable_string }} + {%- else -%} + {{ choice['name'] }} + {%- endif -%} +
  • + {%- endif -%} + {%- endfor -%} +
{% else %}
{{ 'None'|trans }}
{% endif %} \ No newline at end of file From f068ac288fe2307b004060637f3a0d231dab334f Mon Sep 17 00:00:00 2001 From: Marc Ducobu Date: Thu, 22 Oct 2015 15:09:43 +0200 Subject: [PATCH 06/54] Debug JS - close refs #626 --- Resources/views/Form/fields.html.twig | 78 ++++++++++----------------- 1 file changed, 27 insertions(+), 51 deletions(-) diff --git a/Resources/views/Form/fields.html.twig b/Resources/views/Form/fields.html.twig index a097bc78f..76ec0cb5c 100644 --- a/Resources/views/Form/fields.html.twig +++ b/Resources/views/Form/fields.html.twig @@ -35,61 +35,37 @@ {# render the possibility to add different elements in a choice list #} {% block cf_choices_widget %} -{{ form(form) }} + {{ form(form) }} + + {# we use javascrit to add an additional element. All functions are personnalized with the id ( = form.vars.id) #} + + jQuery(document).ready(initializeCFChoiceOptionsChoices('{{ form.vars.id }}')); + {% endblock cf_choices_widget %} From d21595d306901a7f1f06f4206816c8bb9455615b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 26 Oct 2015 22:01:23 +0100 Subject: [PATCH 07/54] add gitlab-ci to project MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Squashed commit of the following: commit 7baa7bddc3a1613816c691e454841baa885a5095 Author: Julien Fastré Date: Mon Oct 26 21:13:47 2015 +0100 fix auth and database url commit c47ad68586749e19fce125da9820d0fd0b2bf575 Author: Julien Fastré Date: Mon Oct 26 20:59:33 2015 +0100 add gitlab-ci --- .gitignore | 2 ++ .gitlab-ci.yml | 17 +++++++++++++++++ .../App/app/config/parameters.gitlab-ci.yml | 7 +++++++ 3 files changed, 26 insertions(+) create mode 100644 .gitlab-ci.yml create mode 100644 Tests/Fixtures/App/app/config/parameters.gitlab-ci.yml diff --git a/.gitignore b/.gitignore index 90d5ec78f..08abe3eac 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,5 @@ bin/* /tmp/* src/Chill/CustomFieldsBundle/vendor/* bootstrap.php.cache +#the file created by composer to store creds +auth.json diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 000000000..9f2233cb5 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,17 @@ +services: + - chill/database:latest + +before_script: + - composer config github-oauth.github.com $GITHUB_TOKEN + - composer install --no-interaction + - cp Tests/Fixtures/App/app/config/parameters.gitlab-ci.yml Tests/Fixtures/App/app/config/parameters.yml + - ./console.sh --env=test cache:warmup + - ./console.sh doctrine:migrations:migrate --env=test --no-interaction + - ./console.sh doctrine:fixtures:load --env=test --no-interaction + +test:php-5.6: + stage: test + script: phpunit --testdox +test:php-7: + stage: test + script: phpunit --testdox diff --git a/Tests/Fixtures/App/app/config/parameters.gitlab-ci.yml b/Tests/Fixtures/App/app/config/parameters.gitlab-ci.yml new file mode 100644 index 000000000..9e3b75daf --- /dev/null +++ b/Tests/Fixtures/App/app/config/parameters.gitlab-ci.yml @@ -0,0 +1,7 @@ +parameters: + database_host: chill__database + database_port: 5432 + database_name: postgres + database_user: postgres + database_password: postgres + locale: fr From e2c1a9bb9f51a39ad037819b2f4c88e54780a1ab Mon Sep 17 00:00:00 2001 From: Marc Ducobu Date: Fri, 30 Oct 2015 10:36:27 +0100 Subject: [PATCH 08/54] Adding customfileds config in the Admin section menu --- Controller/AdminController.php | 37 +++++++++++++++++++ Resources/config/routing/customfield.yml | 16 ++++++-- .../routing/customfieldsdefaultgroup.yml | 2 +- .../config/routing/customfieldsgroup.yml | 2 +- Resources/views/Admin/layout.html.twig | 31 ++++++++++++++++ Resources/views/Admin/menu.html.twig | 20 ++++++++++ Resources/views/CustomField/edit.html.twig | 2 +- Resources/views/CustomField/index.html.twig | 2 +- Resources/views/CustomField/new.html.twig | 2 +- Resources/views/CustomField/show.html.twig | 2 +- .../CustomFieldsDefaultGroup/list.html.twig | 2 +- .../views/CustomFieldsGroup/edit.html.twig | 2 +- .../views/CustomFieldsGroup/index.html.twig | 2 +- .../views/CustomFieldsGroup/new.html.twig | 2 +- .../views/CustomFieldsGroup/show.html.twig | 2 +- 15 files changed, 112 insertions(+), 14 deletions(-) create mode 100644 Controller/AdminController.php create mode 100644 Resources/views/Admin/layout.html.twig create mode 100644 Resources/views/Admin/menu.html.twig diff --git a/Controller/AdminController.php b/Controller/AdminController.php new file mode 100644 index 000000000..b538d9092 --- /dev/null +++ b/Controller/AdminController.php @@ -0,0 +1,37 @@ + + * + * 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 . + */ + +namespace Chill\CustomFieldsBundle\Controller; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Bundle\FrameworkBundle\Controller\Controller; + +/** + * Controller for the custom fields configuration section (in + * the admin) + * + */ +class AdminController extends Controller +{ + public function indexAction() + { + return $this->render('ChillCustomFieldsBundle:Admin:layout.html.twig'); + } +} \ No newline at end of file diff --git a/Resources/config/routing/customfield.yml b/Resources/config/routing/customfield.yml index eb92fdc96..0f8e7b8d3 100644 --- a/Resources/config/routing/customfield.yml +++ b/Resources/config/routing/customfield.yml @@ -1,11 +1,21 @@ -customfield: +customfield_section: path: /{_locale}/admin/customfield/ + defaults: { _controller: "ChillCustomFieldsBundle:Admin:index" } + options: + menus: + admin_section: + order: 1000 + label: "Custom fields configuration" + icons: ['asterisk'] + +customfield: + path: /{_locale}/admin/customfield/list defaults: { _controller: "ChillCustomFieldsBundle:CustomField:index" } options: menus: - admin: + admin_custom_fields: order: 1000 - label: "CustomFields" + label: "CustomFields List" customfield_show: path: /{_locale}/admin/customfield/{id}/show diff --git a/Resources/config/routing/customfieldsdefaultgroup.yml b/Resources/config/routing/customfieldsdefaultgroup.yml index d16434e8d..9919337af 100644 --- a/Resources/config/routing/customfieldsdefaultgroup.yml +++ b/Resources/config/routing/customfieldsdefaultgroup.yml @@ -3,7 +3,7 @@ customfieldsdefaultgroup: defaults: { _controller: "ChillCustomFieldsBundle:CustomFieldsDefaultGroup:list" } options: menus: - admin: + admin_custom_fields: order: 1000 label: "CustomFields Default Groups : List" diff --git a/Resources/config/routing/customfieldsgroup.yml b/Resources/config/routing/customfieldsgroup.yml index c8a992856..f34e0169b 100644 --- a/Resources/config/routing/customfieldsgroup.yml +++ b/Resources/config/routing/customfieldsgroup.yml @@ -3,7 +3,7 @@ customfieldsgroup: defaults: { _controller: "ChillCustomFieldsBundle:CustomFieldsGroup:index" } options: menus: - admin: + admin_custom_fields: order: 1010 label: "CustomFields Groups" diff --git a/Resources/views/Admin/layout.html.twig b/Resources/views/Admin/layout.html.twig new file mode 100644 index 000000000..27c0c61ac --- /dev/null +++ b/Resources/views/Admin/layout.html.twig @@ -0,0 +1,31 @@ +{# + * Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, + / + * + * 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 . +#} + +{% extends "ChillMainBundle::Admin/layoutWithVerticalMenu.html.twig" %} + +{% block vertical_menu_content %} + {{ chill_menu('admin_custom_fields', { + 'layout': 'ChillCustomFieldsBundle::Admin/menu.html.twig', + }) }} +{% endblock %} + +{% block layout_wvm_content %} + {% block admin_content %} +

{{ 'CustomFields configuration' |trans }}

+ {% endblock %} +{% endblock %} \ No newline at end of file diff --git a/Resources/views/Admin/menu.html.twig b/Resources/views/Admin/menu.html.twig new file mode 100644 index 000000000..aeefd1013 --- /dev/null +++ b/Resources/views/Admin/menu.html.twig @@ -0,0 +1,20 @@ +{# + * Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, + / + * + * 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 . +#} + +{% extends "ChillMainBundle::Menu/verticalMenu.html.twig" %} +{% block v_menu_title %}{{ 'Custom fields configuration menu'|trans }}{% endblock %} \ No newline at end of file diff --git a/Resources/views/CustomField/edit.html.twig b/Resources/views/CustomField/edit.html.twig index 47f98ee92..bcc2e5d88 100644 --- a/Resources/views/CustomField/edit.html.twig +++ b/Resources/views/CustomField/edit.html.twig @@ -14,7 +14,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} -{% extends "ChillMainBundle::Admin/layout.html.twig" %} +{% extends "ChillCustomFieldsBundle::Admin/layout.html.twig" %} {% block admin_content %}

CustomField edit

diff --git a/Resources/views/CustomField/index.html.twig b/Resources/views/CustomField/index.html.twig index 1802c3a9c..36c5f1243 100644 --- a/Resources/views/CustomField/index.html.twig +++ b/Resources/views/CustomField/index.html.twig @@ -14,7 +14,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} -{% extends "ChillMainBundle::Admin/layout.html.twig" %} +{% extends "ChillCustomFieldsBundle::Admin/layout.html.twig" %} {% block admin_content %}

CustomField list

diff --git a/Resources/views/CustomField/new.html.twig b/Resources/views/CustomField/new.html.twig index 771abbd10..a94f16b3b 100644 --- a/Resources/views/CustomField/new.html.twig +++ b/Resources/views/CustomField/new.html.twig @@ -14,7 +14,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} -{% extends "ChillMainBundle::Admin/layout.html.twig" %} +{% extends "ChillCustomFieldsBundle::Admin/layout.html.twig" %} {% block admin_content %}

CustomField creation

diff --git a/Resources/views/CustomField/show.html.twig b/Resources/views/CustomField/show.html.twig index 451a544db..69a4d9e25 100644 --- a/Resources/views/CustomField/show.html.twig +++ b/Resources/views/CustomField/show.html.twig @@ -14,7 +14,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} -{% extends "ChillMainBundle::Admin/layout.html.twig" %} +{% extends "ChillCustomFieldsBundle::Admin/layout.html.twig" %} {% block admin_content %}

CustomField

diff --git a/Resources/views/CustomFieldsDefaultGroup/list.html.twig b/Resources/views/CustomFieldsDefaultGroup/list.html.twig index 560aedc8d..036bc04d5 100644 --- a/Resources/views/CustomFieldsDefaultGroup/list.html.twig +++ b/Resources/views/CustomFieldsDefaultGroup/list.html.twig @@ -14,7 +14,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} -{% extends "ChillMainBundle::Admin/layout.html.twig" %} +{% extends "ChillCustomFieldsBundle::Admin/layout.html.twig" %} {% block admin_content %}

CustomFieldsDefaultGroup list

diff --git a/Resources/views/CustomFieldsGroup/edit.html.twig b/Resources/views/CustomFieldsGroup/edit.html.twig index 57f86745e..3197f9d90 100644 --- a/Resources/views/CustomFieldsGroup/edit.html.twig +++ b/Resources/views/CustomFieldsGroup/edit.html.twig @@ -14,7 +14,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} -{% extends "ChillMainBundle::Admin/layout.html.twig" %} +{% extends "ChillCustomFieldsBundle::Admin/layout.html.twig" %} {% block admin_content %}

CustomFieldsGroup edit

diff --git a/Resources/views/CustomFieldsGroup/index.html.twig b/Resources/views/CustomFieldsGroup/index.html.twig index bea9b6409..4f751490d 100644 --- a/Resources/views/CustomFieldsGroup/index.html.twig +++ b/Resources/views/CustomFieldsGroup/index.html.twig @@ -14,7 +14,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} -{% extends "ChillMainBundle::Admin/layout.html.twig" %} +{% extends "ChillCustomFieldsBundle::Admin/layout.html.twig" %} {% block admin_content %}

CustomFieldsGroup list

diff --git a/Resources/views/CustomFieldsGroup/new.html.twig b/Resources/views/CustomFieldsGroup/new.html.twig index b83aec347..19ab309f6 100644 --- a/Resources/views/CustomFieldsGroup/new.html.twig +++ b/Resources/views/CustomFieldsGroup/new.html.twig @@ -14,7 +14,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} -{% extends "ChillMainBundle::Admin/layout.html.twig" %} +{% extends "ChillCustomFieldsBundle::Admin/layout.html.twig" %} {% block admin_content %}

CustomFieldsGroup creation

diff --git a/Resources/views/CustomFieldsGroup/show.html.twig b/Resources/views/CustomFieldsGroup/show.html.twig index 5fd8681bb..84a0141d2 100644 --- a/Resources/views/CustomFieldsGroup/show.html.twig +++ b/Resources/views/CustomFieldsGroup/show.html.twig @@ -14,7 +14,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} -{% extends "ChillMainBundle::Admin/layout.html.twig" %} +{% extends "ChillCustomFieldsBundle::Admin/layout.html.twig" %} {% block admin_content %}

CustomFieldsGroup

From 6ad8d412440dc2d31ad23b2813e3f3a384a2a994 Mon Sep 17 00:00:00 2001 From: Marc Ducobu Date: Fri, 30 Oct 2015 10:40:26 +0100 Subject: [PATCH 09/54] Adding composer.lock in gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 08abe3eac..52d2b6ff7 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ .gitignore~ *~ composer.phar +composer.lock /nbproject/private/ parameters.yml app/config/parameters.yml From 1ebfe7749b86e2f600366484d94d23709bb3d0df Mon Sep 17 00:00:00 2001 From: Marc Ducobu Date: Fri, 30 Oct 2015 10:41:32 +0100 Subject: [PATCH 10/54] Removing .travis.yml file --- .travis.yml | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 104cafa19..000000000 --- a/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: php -php: -- 5.5 -- 5.6 -- hhvm-nightly -matrix: - allow_failures: - - php: hhvm-nightly -addons: - postgresql: '9.3' -sudo: false -install: - - composer config -g github-oauth.github.com $GITHUB_COMPOSER_AUTH - - composer install --dev - - cp Tests/Fixtures/App/app/config/parameters.travis.yml Tests/Fixtures/App/app/config/parameters.yml -before_script: - - psql -c 'create database test0;' -U postgres - - "./console.sh --env=test cache:warmup" - - "./console.sh doctrine:migrations:migrate --no-interaction" - - "./console.sh doctrine:fixtures:load --no-interaction --env=test" -script: phpunit --coverage-text -notifications: - email: - - info@champs-libres.coop -env: - global: - secure: MoVsISTKaeamuFNoylDv/nM6NBXBtCoH5tuGwX3RHpRK/zRXh421RgO8z/GTHxGt63r04EfYrsCXXng8fN4ZVA2Bjb9chGAozYZJOSwZ9Vmfjycu3k0v/+hikAj33DT+CEdVk4fggEZh5dcVbaJDRgaUZkwMLUtyCqeiv+J5X68= From e4aadc891cc53ee9312f3be3ff75cf055fb283d2 Mon Sep 17 00:00:00 2001 From: Marc Ducobu Date: Fri, 30 Oct 2015 10:42:45 +0100 Subject: [PATCH 11/54] Removing travis build image --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index fa6aeb184..cde8c8590 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ CustomFields ============ -[![Build Status](https://travis-ci.org/Chill-project/CustomFields.png)](http://travis-ci.org/#!/Chill-project/CustomFields) - Add custom fields to entities This bundle is part of the Chill project. From 5e211b3f0688debf203efb2a8e136c7432904af7 Mon Sep 17 00:00:00 2001 From: Marc Ducobu Date: Fri, 30 Oct 2015 15:56:43 +0100 Subject: [PATCH 12/54] Adding ref to the dov --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cde8c8590..08a2f468c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ CustomFields ============ -Add custom fields to entities +The bundle for adding custom fields to Chill. This bundle is part of the Chill project. -This bundle is part of the Chill project. +Documentation & installation +============================ + +Read documentation here : http://chill.readthedocs.org From 7cf270cee425392b7e2f9188825ef68fa2b29ca8 Mon Sep 17 00:00:00 2001 From: Marc Ducobu Date: Fri, 30 Oct 2015 15:57:27 +0100 Subject: [PATCH 13/54] Removing travis config file --- Tests/Fixtures/App/app/config/parameters.travis.yml | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 Tests/Fixtures/App/app/config/parameters.travis.yml diff --git a/Tests/Fixtures/App/app/config/parameters.travis.yml b/Tests/Fixtures/App/app/config/parameters.travis.yml deleted file mode 100644 index 28d5cd26c..000000000 --- a/Tests/Fixtures/App/app/config/parameters.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -parameters: - database_host: 127.0.0.1 - database_port: 5432 - database_name: test0 - database_user: postgres - database_password: postgres - locale: fr \ No newline at end of file From 9d65ca5088404c6cab9f78303e2466cd9b62d33b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Sat, 31 Oct 2015 17:55:10 +0100 Subject: [PATCH 14/54] layout of index page for customfieldsgroup - add a "default" column (according to chill-project/custom-fields#3 ) - translation --- Controller/CustomFieldsGroupController.php | 58 ++++++++++++++++++- .../config/routing/customfieldsgroup.yml | 4 ++ Resources/translations/messages.fr.yml | 11 ++++ .../views/CustomFieldsGroup/index.html.twig | 30 ++++++---- 4 files changed, 89 insertions(+), 14 deletions(-) diff --git a/Controller/CustomFieldsGroupController.php b/Controller/CustomFieldsGroupController.php index 9897da5f4..0be440be4 100644 --- a/Controller/CustomFieldsGroupController.php +++ b/Controller/CustomFieldsGroupController.php @@ -4,7 +4,7 @@ namespace Chill\CustomFieldsBundle\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Bundle\FrameworkBundle\Controller\Controller; - +use Doctrine\ORM\Query; use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; /** @@ -22,12 +22,64 @@ class CustomFieldsGroupController extends Controller { $em = $this->getDoctrine()->getManager(); - $entities = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup')->findAll(); + $cfGroups = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup')->findAll(); + $defaultGroups = $this->getDefaultGroupsId(); + + $makeDefaultFormViews = array(); + foreach ($cfGroups as $group) { + if (!in_array($group->getId(), $defaultGroups)){ + $makeDefaultFormViews[$group->getId()] = $this->createMakeDefaultForm($group)->createView(); + } + } return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:index.html.twig', array( - 'entities' => $entities, + 'entities' => $cfGroups, + 'default_groups' => $defaultGroups, + 'make_default_forms' => $makeDefaultFormViews )); } + + /** + * Get an array of CustomFieldsGroupId which are marked as default + * for their entity + * + * @return int[] + */ + private function getDefaultGroupsId() + { + $em = $this->getDoctrine()->getManager(); + + $customFieldsGroupIds = $em->createQuery('SELECT g.id FROM ' + . 'ChillCustomFieldsBundle:CustomFieldsDefaultGroup d ' + . 'JOIN d.customFieldsGroup g') + ->getResult(Query::HYDRATE_SCALAR); + + $result = array(); + foreach ($customFieldsGroupIds as $row) { + $result[] = $row['id']; + } + + return $result; + } + + /** + * create a form to make the group default + * + * @param CustomFieldsGroup $group + * @return \Symfony\Component\Form\Form + */ + private function createMakeDefaultForm(CustomFieldsGroup $group) + { + return $this->createFormBuilder($group, array( + 'method' => 'POST', + 'action' => $this->generateUrl('customfieldsgroup_makedefault') + )) + ->add('id', 'hidden') + ->add('submit', 'submit', array('label' => 'Make default')) + ->getForm(); + } + + /** * Creates a new CustomFieldsGroup entity. * diff --git a/Resources/config/routing/customfieldsgroup.yml b/Resources/config/routing/customfieldsgroup.yml index f34e0169b..446a15aa3 100644 --- a/Resources/config/routing/customfieldsgroup.yml +++ b/Resources/config/routing/customfieldsgroup.yml @@ -10,6 +10,10 @@ customfieldsgroup: customfieldsgroup_show: path: /{_locale}/admin/customfieldsgroup/{id}/show defaults: { _controller: "ChillCustomFieldsBundle:CustomFieldsGroup:show" } + +customfieldsgroup_makedefault: + path: /{_locale}/admin/customfieldsgroup/make_default + defaults: { _controller: "ChillCustomFieldsBundle:CustomFieldsGroup:makeDefault" } customfieldsgroup_new: path: /{_locale}/admin/customfieldsgroup/new diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index 78b57984c..ad8407fbc 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -1,3 +1,14 @@ 'Not available in your language': 'Traduction pas disponible dans votre langue' 'Other value': 'Autre valeur' 'None': 'Pas spécifié' + +Custom fields configuration: Configuration des champs personnalisés +CustomFieldsGroup list: Groupes de champs personnalisés +Entity: Entité +"Is default ?": "Par défaut ?" +"Some module select default groups for some usage. Example: the default person group is shown under person page.": "Certains modules sélectionnent en priorité les formulaires par défaut. Exemple: le formulaire par défaut pour une personne est affiché sur la page principale pour la personne" +Make default: Assigner comme formulaire par défaut +Create a new group: Créer un nouveau groupe + +CustomFields List: Liste des champs personnalisés +CustomFields Groups: Groupe de champs personnalisés diff --git a/Resources/views/CustomFieldsGroup/index.html.twig b/Resources/views/CustomFieldsGroup/index.html.twig index 4f751490d..787c65436 100644 --- a/Resources/views/CustomFieldsGroup/index.html.twig +++ b/Resources/views/CustomFieldsGroup/index.html.twig @@ -17,30 +17,38 @@ {% extends "ChillCustomFieldsBundle::Admin/layout.html.twig" %} {% block admin_content %} -

CustomFieldsGroup list

+

{{ 'CustomFieldsGroup list'|trans }}

- - - - + + + + {% for entity in entities %} - - - + + + @@ -52,7 +60,7 @@ From bb1e690bec518816d35cac9af79e2ca0f285cd56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 5 Nov 2015 22:41:54 +0100 Subject: [PATCH 15/54] fix "create" page with translation and layout --- Resources/translations/messages.fr.yml | 1 + .../views/CustomFieldsGroup/index.html.twig | 12 +++++------- .../views/CustomFieldsGroup/new.html.twig | 19 ++++++++++--------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index ad8407fbc..2a7873d98 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -4,6 +4,7 @@ Custom fields configuration: Configuration des champs personnalisés CustomFieldsGroup list: Groupes de champs personnalisés +CustomFieldsGroup creation: Nouveau groupe de champs personnalisés Entity: Entité "Is default ?": "Par défaut ?" "Some module select default groups for some usage. Example: the default person group is shown under person page.": "Certains modules sélectionnent en priorité les formulaires par défaut. Exemple: le formulaire par défaut pour une personne est affiché sur la page principale pour la personne" diff --git a/Resources/views/CustomFieldsGroup/index.html.twig b/Resources/views/CustomFieldsGroup/index.html.twig index 787c65436..697f9e874 100644 --- a/Resources/views/CustomFieldsGroup/index.html.twig +++ b/Resources/views/CustomFieldsGroup/index.html.twig @@ -57,11 +57,9 @@
IdNameEntityActions{{ 'Name'|trans }}{{ 'Entity'|trans }}{{ 'Is default ?'|trans }} {{ 'Actions'|trans }}
{{ entity.id }}{{ entity.name['fr'] }}{{ entity.entity }}{{ entity.name|localize_translatable_string }}{{ entity.entity|trans }} + {%- if entity.id in default_groups -%} + + {%- else -%} + {{ form_start(make_default_forms[entity.id]) }} + {{ form_widget(make_default_forms[entity.id].submit, { 'attr' : { 'class' : 'sc-button bt-action' } } ) }} + {{ form_end(make_default_forms[entity.id]) }} + {%- endif -%} +
- +

+ + {{ 'Create a new group'|trans }} + +

{% endblock %} diff --git a/Resources/views/CustomFieldsGroup/new.html.twig b/Resources/views/CustomFieldsGroup/new.html.twig index 19ab309f6..3c0692773 100644 --- a/Resources/views/CustomFieldsGroup/new.html.twig +++ b/Resources/views/CustomFieldsGroup/new.html.twig @@ -17,15 +17,16 @@ {% extends "ChillCustomFieldsBundle::Admin/layout.html.twig" %} {% block admin_content %} -

CustomFieldsGroup creation

+

{{ 'CustomFieldsGroup creation'|trans }}

- {{ form(form) }} - - +

+ {{ form_end(form) }} {% endblock %} From 043f5a1eafeba8c7144230eb46a8a4310628dd7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 5 Nov 2015 23:49:22 +0100 Subject: [PATCH 16/54] fix show page --- Controller/CustomFieldsGroupController.php | 28 +++++- Resources/translations/messages.fr.yml | 13 ++- .../views/CustomFieldsGroup/show.html.twig | 92 ++++++++++++++----- 3 files changed, 107 insertions(+), 26 deletions(-) diff --git a/Controller/CustomFieldsGroupController.php b/Controller/CustomFieldsGroupController.php index 0be440be4..a5c67e95f 100644 --- a/Controller/CustomFieldsGroupController.php +++ b/Controller/CustomFieldsGroupController.php @@ -6,6 +6,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Doctrine\ORM\Query; use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; +use Chill\CustomFieldsBundle\Entity\CustomField; /** * CustomFieldsGroup controller. @@ -152,11 +153,9 @@ class CustomFieldsGroupController extends Controller throw $this->createNotFoundException('Unable to find CustomFieldsGroup entity.'); } - $deleteForm = $this->createDeleteForm($id); - return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:show.html.twig', array( 'entity' => $entity, - 'delete_form' => $deleteForm->createView(), + 'create_field_form' => $this->createCreateFieldForm($entity)->createView() )); } @@ -201,6 +200,29 @@ class CustomFieldsGroupController extends Controller return $form; } + + private function createCreateFieldForm(CustomFieldsGroup $customFieldsGroup) + { + + $fieldChoices = array(); + foreach ($this->get('chill.custom_field.provider')->getAllFields() + as $key => $customType) { + $fieldChoices[$key] = $customType->getName(); + } + + return $this->createFormBuilder(new CustomField(), array( + 'method' => 'GET', + 'action' => $this->generateUrl('customfield_new', + array('cfGroup' => $customFieldsGroup->getId())), + 'csrf_protection' => false + )) + ->add('type', 'choice', array( + 'choices' => $fieldChoices + )) + ->add('submit', 'submit') + ->getForm(); + } + /** * Edits an existing CustomFieldsGroup entity. * diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index 2a7873d98..463bc0dd3 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -2,7 +2,7 @@ 'Other value': 'Autre valeur' 'None': 'Pas spécifié' -Custom fields configuration: Configuration des champs personnalisés + CustomFieldsGroup list: Groupes de champs personnalisés CustomFieldsGroup creation: Nouveau groupe de champs personnalisés Entity: Entité @@ -10,6 +10,17 @@ Entity: Entité "Some module select default groups for some usage. Example: the default person group is shown under person page.": "Certains modules sélectionnent en priorité les formulaires par défaut. Exemple: le formulaire par défaut pour une personne est affiché sur la page principale pour la personne" Make default: Assigner comme formulaire par défaut Create a new group: Créer un nouveau groupe +CustomFieldsGroup details: Détail du groupe de champs personnalisés +Fields associated with this group: Champs associés à ce groupe +Any field is currently associated with this group: Aucun champ n'est associé à ce groupe actuellement +Create a new field: Créer un champ personnalisé +Add a new field: Ajouter un champ personnalisé +ordering: ordre +label_field: label du champ +active: actif + +#menu entries +Custom fields configuration: Champs personnalisés CustomFields List: Liste des champs personnalisés CustomFields Groups: Groupe de champs personnalisés diff --git a/Resources/views/CustomFieldsGroup/show.html.twig b/Resources/views/CustomFieldsGroup/show.html.twig index 84a0141d2..bdbe2bad5 100644 --- a/Resources/views/CustomFieldsGroup/show.html.twig +++ b/Resources/views/CustomFieldsGroup/show.html.twig @@ -16,37 +16,85 @@ #} {% extends "ChillCustomFieldsBundle::Admin/layout.html.twig" %} +{% block title%}{{ 'CustomFieldsGroup details'|trans }}{% endblock %} + {% block admin_content %} -

CustomFieldsGroup

+

{{ 'CustomFieldsGroup details'|trans }}

- - + + - - - - - - + +
Id{{ entity.id }}{{ 'Name'|trans }}{{ entity.getName|localize_translatable_string }}
Name{{ entity.getName(app.request.locale) }}
Entity{{ entity.entity }}{{ 'Entity'|trans }}{{ entity.entity|trans }}
- + + +

{{ 'Fields associated with this group'|trans }}

+ + {%- if entity.customFields|length > 0 -%} + + + + + + + + + + + + {%- for field in entity.customFields -%} + + + + + + + + {%- endfor -%} + +
{{ 'ordering'|trans|capitalize }}{{ 'label_field'|trans|capitalize }}{{ 'type'|trans|capitalize }}{{ 'active'|trans|capitalize }} 
{{ field.ordering }}{{ field.name|localize_translatable_string }}{{ field.type|trans }} + {%- if field.active -%} + + {%- else -%} + + {%- endif -%} + + {{ 'edit'|trans|capitalize }} +
+ {{ form_start(create_field_form) }} +
+ {{ form_widget(create_field_form.type) }} +
+ {{ form_widget(create_field_form.submit, { 'attr': { 'class': 'sc-button bt-create' }, 'label': 'Add a new field' } ) }} + {{ form_end(create_field_form) }} + {%- else -%} +

+ {{ 'Any field is currently associated with this group'|trans }} +

+ {{ form_start(create_field_form) }} +
+ {{ form_widget(create_field_form.type) }} +
+ {{ form_widget(create_field_form.submit, { 'attr': { 'class': 'sc-button bt-create' }, 'label': 'Create a new field' } ) }} + {{ form_end(create_field_form) }} + {%- endif -%} {% endblock %} From 59ce45713128f7e1c40da760242db159d44295cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Sat, 7 Nov 2015 08:59:57 +0100 Subject: [PATCH 17/54] add a title --- Resources/views/CustomFieldsGroup/index.html.twig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Resources/views/CustomFieldsGroup/index.html.twig b/Resources/views/CustomFieldsGroup/index.html.twig index 697f9e874..3b8eefe81 100644 --- a/Resources/views/CustomFieldsGroup/index.html.twig +++ b/Resources/views/CustomFieldsGroup/index.html.twig @@ -16,6 +16,8 @@ #} {% extends "ChillCustomFieldsBundle::Admin/layout.html.twig" %} +{% block title %}{{ 'CustomFieldsGroup list'|trans }}{% endblock %} + {% block admin_content %}

{{ 'CustomFieldsGroup list'|trans }}

From e1435d0883df8446902c40cae7b7f300bf94ccda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Sat, 7 Nov 2015 09:38:12 +0100 Subject: [PATCH 18/54] fix form to jump to create a custom field --- Controller/CustomFieldsGroupController.php | 19 ++++++++++++++----- .../CustomFieldsGroupToIdTransformer.php | 16 ++++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/Controller/CustomFieldsGroupController.php b/Controller/CustomFieldsGroupController.php index a5c67e95f..9e0794d73 100644 --- a/Controller/CustomFieldsGroupController.php +++ b/Controller/CustomFieldsGroupController.php @@ -7,6 +7,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Doctrine\ORM\Query; use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; use Chill\CustomFieldsBundle\Entity\CustomField; +use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldsGroupToIdTransformer; /** * CustomFieldsGroup controller. @@ -210,17 +211,25 @@ class CustomFieldsGroupController extends Controller $fieldChoices[$key] = $customType->getName(); } - return $this->createFormBuilder(new CustomField(), array( + $customfield = (new CustomField()) + ->setCustomFieldsGroup($customFieldsGroup); + + $builder = $this->get('form.factory') + ->createNamedBuilder(null, 'form', $customfield, array( 'method' => 'GET', - 'action' => $this->generateUrl('customfield_new', - array('cfGroup' => $customFieldsGroup->getId())), + 'action' => $this->generateUrl('customfield_new'), 'csrf_protection' => false )) ->add('type', 'choice', array( 'choices' => $fieldChoices )) - ->add('submit', 'submit') - ->getForm(); + ->add('customFieldsGroup', 'hidden') + ->add('submit', 'submit'); + $builder->get('customFieldsGroup') + ->addViewTransformer(new CustomFieldsGroupToIdTransformer( + $this->getDoctrine()->getManager())); + + return $builder->getForm(); } /** diff --git a/Form/DataTransformer/CustomFieldsGroupToIdTransformer.php b/Form/DataTransformer/CustomFieldsGroupToIdTransformer.php index 662ef42f1..f2dac9b0c 100644 --- a/Form/DataTransformer/CustomFieldsGroupToIdTransformer.php +++ b/Form/DataTransformer/CustomFieldsGroupToIdTransformer.php @@ -33,6 +33,14 @@ class CustomFieldsGroupToIdTransformer implements DataTransformerInterface if (null === $customFieldsGroup) { return ""; } + + if (!$customFieldsGroup instanceof CustomFieldsGroup) { + throw new TransformationFailedException(sprintf('Transformation failed: ' + . 'the expected type of the transforme function is an ' + . 'object of type Chill\CustomFieldsBundle\Entity\CustomFieldsGroup, ' + . '%s given (value : %s)', gettype($customFieldsGroup), + $customFieldsGroup)); + } return $customFieldsGroup->getId(); } @@ -49,6 +57,14 @@ class CustomFieldsGroupToIdTransformer implements DataTransformerInterface if (!$id) { return null; } + + if ($id instanceof CustomFieldsGroup) { + throw new TransformationFailedException(sprintf( + 'The transformation failed: the expected argument on ' + . 'reverseTransform is an object of type int,' + . 'Chill\CustomFieldsBundle\Entity\CustomFieldsGroup, ' + . 'given', gettype($id))); + } $customFieldsGroup = $this->om ->getRepository('ChillCustomFieldsBundle:customFieldsGroup')->find($id) From 45d34dc312d7b3af57c49c229e9553268f82bffd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Sat, 7 Nov 2015 09:51:36 +0100 Subject: [PATCH 19/54] fix customfieldsgroup edit view --- Resources/translations/messages.fr.yml | 1 + .../views/CustomFieldsGroup/edit.html.twig | 25 ++++++++++++++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index 463bc0dd3..4968ebb67 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -18,6 +18,7 @@ Add a new field: Ajouter un champ personnalisé ordering: ordre label_field: label du champ active: actif +CustomFieldsGroup edit: Edition d'un groupe de champs personnalisé #menu entries diff --git a/Resources/views/CustomFieldsGroup/edit.html.twig b/Resources/views/CustomFieldsGroup/edit.html.twig index 3197f9d90..823f492c2 100644 --- a/Resources/views/CustomFieldsGroup/edit.html.twig +++ b/Resources/views/CustomFieldsGroup/edit.html.twig @@ -16,17 +16,30 @@ #} {% extends "ChillCustomFieldsBundle::Admin/layout.html.twig" %} -{% block admin_content %} -

CustomFieldsGroup edit

+{% block title %}{{ 'CustomFieldsGroup edit'|trans }}{% endblock %} - {{ form(edit_form) }} +{% block admin_content %} +

{{ 'CustomFieldsGroup edit'|trans }}

+ + {{ form_start(edit_form) }} + {{ form_row(edit_form.name) }} + {{ form_row(edit_form.entity) }} + {% if edit_form.options is defined %} + {{ form_row(edit_form.options) }} + {% endif %} + {{ form_row(edit_form.submit, { 'attr': { 'class': 'sc-button bt-edit' } } ) }} + {{ form_end(edit_form) }} {% endblock %} From 41c47df0c363daad2a4562894fe869ac01b848ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Sat, 7 Nov 2015 09:56:28 +0100 Subject: [PATCH 20/54] remove delete action and form --- Controller/CustomFieldsGroupController.php | 47 +--------------------- 1 file changed, 2 insertions(+), 45 deletions(-) diff --git a/Controller/CustomFieldsGroupController.php b/Controller/CustomFieldsGroupController.php index 9e0794d73..211d7494a 100644 --- a/Controller/CustomFieldsGroupController.php +++ b/Controller/CustomFieldsGroupController.php @@ -175,12 +175,10 @@ class CustomFieldsGroupController extends Controller } $editForm = $this->createEditForm($entity); - $deleteForm = $this->createDeleteForm($id); return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:edit.html.twig', array( 'entity' => $entity, 'edit_form' => $editForm->createView(), - 'delete_form' => $deleteForm->createView(), )); } @@ -246,7 +244,6 @@ class CustomFieldsGroupController extends Controller throw $this->createNotFoundException('Unable to find CustomFieldsGroup entity.'); } - $deleteForm = $this->createDeleteForm($id); $editForm = $this->createEditForm($entity); $editForm->handleRequest($request); @@ -259,49 +256,9 @@ class CustomFieldsGroupController extends Controller return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:edit.html.twig', array( 'entity' => $entity, 'edit_form' => $editForm->createView(), - 'delete_form' => $deleteForm->createView(), )); } - /** - * Deletes a CustomFieldsGroup entity. - * - */ - public function deleteAction(Request $request, $id) - { - $form = $this->createDeleteForm($id); - $form->handleRequest($request); - - if ($form->isValid()) { - $em = $this->getDoctrine()->getManager(); - $entity = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup')->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find CustomFieldsGroup entity.'); - } - - $em->remove($entity); - $em->flush(); - } - - return $this->redirect($this->generateUrl('customfieldsgroup')); - } - - /** - * Creates a form to delete a CustomFieldsGroup entity by id. - * - * @param mixed $id The entity id - * - * @return \Symfony\Component\Form\Form The form - */ - private function createDeleteForm($id) - { - return $this->createFormBuilder() - ->setAction($this->generateUrl('customfieldsgroup_delete', array('id' => $id))) - ->setMethod('DELETE') - ->add('submit', 'submit', array('label' => 'Delete')) - ->getForm() - ; - } + /** * This function render the customFieldsGroup as a form. @@ -341,7 +298,7 @@ class CustomFieldsGroupController extends Controller } var_dump($form->getData()); - var_dump(json_encode($form->getData())); + var_dump(json_enccode($form->getData())); } From 0dcf2c33f07d921bddda318720008b068fefcbe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Sun, 8 Nov 2015 17:59:43 +0100 Subject: [PATCH 21/54] create custom fields default group from new layout --- .../CustomFieldsDefaultGroupController.php | 33 ------------- Controller/CustomFieldsGroupController.php | 48 ++++++++++++++++++- Resources/translations/messages.fr.yml | 2 +- 3 files changed, 47 insertions(+), 36 deletions(-) diff --git a/Controller/CustomFieldsDefaultGroupController.php b/Controller/CustomFieldsDefaultGroupController.php index 860d3c554..b7ce2dad1 100644 --- a/Controller/CustomFieldsDefaultGroupController.php +++ b/Controller/CustomFieldsDefaultGroupController.php @@ -41,37 +41,4 @@ class CustomFieldsDefaultGroupController extends Controller 'form' => $form->createView() )); } - - /** - * Set the CustomField Group with id $cFGroupId as default - */ - public function setAGroupAsDefaultAction(Request $request) - { - $cFGroupId = $request->query->get('cFGroup'); - - $em = $this->getDoctrine()->getManager(); - - $cFGroup = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup')->findOneById($cFGroupId); - - if(!$cFGroup) { - throw new Exception("No CF GROUP with ID".$cFGroupId, 1); - } - - $cFDefaultGroup = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsDefaultGroup') - ->findOneByEntity($cFGroup->getEntity()); - - if($cFDefaultGroup) { - $em->remove($cFDefaultGroup); - $em->flush(); - } - - $newCFDefaultGroup = new CustomFieldsDefaultGroup(); - $newCFDefaultGroup->setCustomFieldsGroup($cFGroup); - $newCFDefaultGroup->setEntity($cFGroup->getEntity()); - - $em->persist($newCFDefaultGroup); - $em->flush(); - - return $this->redirect($this->generateUrl('customfieldsdefaultgroup')); - } } \ No newline at end of file diff --git a/Controller/CustomFieldsGroupController.php b/Controller/CustomFieldsGroupController.php index 211d7494a..3c7e0f3ef 100644 --- a/Controller/CustomFieldsGroupController.php +++ b/Controller/CustomFieldsGroupController.php @@ -8,6 +8,7 @@ use Doctrine\ORM\Query; use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; use Chill\CustomFieldsBundle\Entity\CustomField; use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldsGroupToIdTransformer; +use Chill\CustomFieldsBundle\Entity\CustomFieldsDefaultGroup; /** * CustomFieldsGroup controller. @@ -70,7 +71,7 @@ class CustomFieldsGroupController extends Controller * @param CustomFieldsGroup $group * @return \Symfony\Component\Form\Form */ - private function createMakeDefaultForm(CustomFieldsGroup $group) + private function createMakeDefaultForm(CustomFieldsGroup $group = null) { return $this->createFormBuilder($group, array( 'method' => 'POST', @@ -256,9 +257,52 @@ class CustomFieldsGroupController extends Controller return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:edit.html.twig', array( 'entity' => $entity, 'edit_form' => $editForm->createView(), - )); + + )); } + /** + * Set the CustomField Group with id $cFGroupId as default + */ + public function makeDefaultAction(Request $request) + { + + $form = $this->createMakeDefaultForm(null); + $form->handleRequest($request); + + $cFGroupId = $form->get('id')->getData(); + + $em = $this->getDoctrine()->getManager(); + + $cFGroup = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup')->findOneById($cFGroupId); + + if(!$cFGroup) { + throw $this + ->createNotFoundException("customFieldsGroup not found with " + . "id $cFGroupId"); + } + + $cFDefaultGroup = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsDefaultGroup') + ->findOneByEntity($cFGroup->getEntity()); + + if($cFDefaultGroup) { + $em->remove($cFDefaultGroup); + $em->flush(); /*this is necessary, if not doctrine + * will not remove old entity before adding a new one, + * and this leads to violation constraint of unique entity + * in postgresql + */ + } + + $newCFDefaultGroup = new CustomFieldsDefaultGroup(); + $newCFDefaultGroup->setCustomFieldsGroup($cFGroup); + $newCFDefaultGroup->setEntity($cFGroup->getEntity()); + + $em->persist($newCFDefaultGroup); + $em->flush(); + + return $this->redirect($this->generateUrl('customfieldsgroup')); + } /** * This function render the customFieldsGroup as a form. diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index 4968ebb67..2eb85c380 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -8,7 +8,7 @@ CustomFieldsGroup creation: Nouveau groupe de champs personnalisés Entity: Entité "Is default ?": "Par défaut ?" "Some module select default groups for some usage. Example: the default person group is shown under person page.": "Certains modules sélectionnent en priorité les formulaires par défaut. Exemple: le formulaire par défaut pour une personne est affiché sur la page principale pour la personne" -Make default: Assigner comme formulaire par défaut +Make default: Rendre groupe par défaut Create a new group: Créer un nouveau groupe CustomFieldsGroup details: Détail du groupe de champs personnalisés Fields associated with this group: Champs associés à ce groupe From 3e23c1f1562e6f65eb691d540d65478676b6d540 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Sun, 8 Nov 2015 18:47:16 +0100 Subject: [PATCH 22/54] show options in show view --- Controller/CustomFieldsGroupController.php | 26 ++++++++++++++++++- Resources/translations/messages.fr.yml | 1 + .../views/CustomFieldsGroup/show.html.twig | 18 ++++++++++++- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/Controller/CustomFieldsGroupController.php b/Controller/CustomFieldsGroupController.php index 3c7e0f3ef..f31edd4df 100644 --- a/Controller/CustomFieldsGroupController.php +++ b/Controller/CustomFieldsGroupController.php @@ -154,12 +154,36 @@ class CustomFieldsGroupController extends Controller if (!$entity) { throw $this->createNotFoundException('Unable to find CustomFieldsGroup entity.'); } + + $options = $this->getOptionsAvailable($entity->getEntity()); return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:show.html.twig', array( 'entity' => $entity, - 'create_field_form' => $this->createCreateFieldForm($entity)->createView() + 'create_field_form' => $this->createCreateFieldForm($entity)->createView(), + 'options' => $options )); } + + /** + * Return an array of available key option for custom fields group + * on the given entity + * + * @param string $entity the entity to filter + */ + private function getOptionsAvailable($entity) + { + $options = $this->getParameter('chill_custom_fields.' + . 'customizables_entities'); + + foreach($options as $key => $definition) { + if ($definition['class'] == $entity) { + foreach ($definition['options'] as $key => $value) { + yield $key; + } + } + } + // [$entity->getEntity()]; + } /** * Displays a form to edit an existing CustomFieldsGroup entity. diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index 2eb85c380..ab8cd4877 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -18,6 +18,7 @@ Add a new field: Ajouter un champ personnalisé ordering: ordre label_field: label du champ active: actif +No value defined for this option: Pas de valeur pour cette option CustomFieldsGroup edit: Edition d'un groupe de champs personnalisé diff --git a/Resources/views/CustomFieldsGroup/show.html.twig b/Resources/views/CustomFieldsGroup/show.html.twig index bdbe2bad5..d2f9d4e33 100644 --- a/Resources/views/CustomFieldsGroup/show.html.twig +++ b/Resources/views/CustomFieldsGroup/show.html.twig @@ -16,7 +16,7 @@ #} {% extends "ChillCustomFieldsBundle::Admin/layout.html.twig" %} -{% block title%}{{ 'CustomFieldsGroup details'|trans }}{% endblock %} +{% block title %}{{ 'CustomFieldsGroup details'|trans }}{% endblock %} {% block admin_content %}

{{ 'CustomFieldsGroup details'|trans }}

@@ -31,6 +31,22 @@ {{ 'Entity'|trans }} {{ entity.entity|trans }} + {%- for key in options -%} + + {{ key ~ '_label'|trans }} + + {%- if entity.options[key] is not defined -%} + {{ 'No value defined for this option'|trans }} + {%- elseif entity.options[key] is iterable -%} + {{ entity.options[key]|join(', ') }} + {% else %} + {{ entity.options[key] }} + {%- endif -%} + + + {%- else -%} + + {%- endfor -%} From 421f54e194406fa43a937d1a804eb2ba843637de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Sun, 8 Nov 2015 18:52:05 +0100 Subject: [PATCH 23/54] remove code for custom fields default group CRUD The CRUD of default groups is handled now by the custom fields index page. The CRUD is not necessary. --- .../CustomFieldsDefaultGroupController.php | 44 ------------------ Resources/config/routing.yml | 4 -- .../routing/customfieldsdefaultgroup.yml | 12 ----- .../CustomFieldsDefaultGroup/list.html.twig | 46 ------------------- 4 files changed, 106 deletions(-) delete mode 100644 Controller/CustomFieldsDefaultGroupController.php delete mode 100644 Resources/config/routing/customfieldsdefaultgroup.yml delete mode 100644 Resources/views/CustomFieldsDefaultGroup/list.html.twig diff --git a/Controller/CustomFieldsDefaultGroupController.php b/Controller/CustomFieldsDefaultGroupController.php deleted file mode 100644 index b7ce2dad1..000000000 --- a/Controller/CustomFieldsDefaultGroupController.php +++ /dev/null @@ -1,44 +0,0 @@ -getDoctrine()->getManager(); - - $defaultGroups = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsDefaultGroup')->findAll(); - - $form = $this->get('form.factory') - ->createNamedBuilder(null, 'form', null, array( - 'method' => 'GET', - 'action' => $this->generateUrl('customfieldsdefaultgroup_set'), - 'csrf_protection' => false - )) - ->add('cFGroup', 'entity', array( - 'class' => 'ChillCustomFieldsBundle:CustomFieldsGroup', - 'property' => 'name[fr]' - )) - ->getForm(); - - return $this->render('ChillCustomFieldsBundle:CustomFieldsDefaultGroup:list.html.twig', array( - 'defaultGroups' => $defaultGroups, - 'form' => $form->createView() - )); - } -} \ No newline at end of file diff --git a/Resources/config/routing.yml b/Resources/config/routing.yml index 42718a48c..a6b554e69 100644 --- a/Resources/config/routing.yml +++ b/Resources/config/routing.yml @@ -5,7 +5,3 @@ chill_customfields_customfieldsgroup: chill_customfields_customfield: resource: "@ChillCustomFieldsBundle/Resources/config/routing/customfield.yml" prefix: / - -chill_customfields_customfieldsdefaultgroup: - resource: "@ChillCustomFieldsBundle/Resources/config/routing/customfieldsdefaultgroup.yml" - prefix: / \ No newline at end of file diff --git a/Resources/config/routing/customfieldsdefaultgroup.yml b/Resources/config/routing/customfieldsdefaultgroup.yml deleted file mode 100644 index 9919337af..000000000 --- a/Resources/config/routing/customfieldsdefaultgroup.yml +++ /dev/null @@ -1,12 +0,0 @@ -customfieldsdefaultgroup: - path: /{_locale}/admin/customfieldsdefaultgroup/ - defaults: { _controller: "ChillCustomFieldsBundle:CustomFieldsDefaultGroup:list" } - options: - menus: - admin_custom_fields: - order: 1000 - label: "CustomFields Default Groups : List" - -customfieldsdefaultgroup_set: - path: /{_locale}/admin/customfieldsdefaultgroup/set/group/as/default/ - defaults: { _controller: "ChillCustomFieldsBundle:CustomFieldsDefaultGroup:setAGroupAsDefault" } \ No newline at end of file diff --git a/Resources/views/CustomFieldsDefaultGroup/list.html.twig b/Resources/views/CustomFieldsDefaultGroup/list.html.twig deleted file mode 100644 index 036bc04d5..000000000 --- a/Resources/views/CustomFieldsDefaultGroup/list.html.twig +++ /dev/null @@ -1,46 +0,0 @@ -{# - * Copyright (C) 2014, Champs Libres Cooperative SCRLFS, - * - * 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 . -#} -{% extends "ChillCustomFieldsBundle::Admin/layout.html.twig" %} - -{% block admin_content %} -

CustomFieldsDefaultGroup list

- - - - - - - - - - {% for defaultGroup in defaultGroups %} - - - - - {% endfor %} - -
EntityCustomFieldGroup
{{ defaultGroup.entity }}{{ defaultGroup.customFieldsGroup.name['fr'] }}
- - {{ form_start(form) }} - {{ form_row(form.cFGroup) }} - - - {{ form_end(form) }} -{% endblock %} From cbcc722c0d9a9c5e66cf088728de511d908b048d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Sun, 8 Nov 2015 21:18:03 +0100 Subject: [PATCH 24/54] remove the field "customFieldsGroup" on custom field creation The customFieldsGroup field is hidden when creating a new customFields. The customFieldsGroup is retrieved from the url (`customFieldsGroup` value in the URL). This should ease the task for administrator and be consistent with the UI which group customFields into customFieldsGroup. --- Controller/CustomFieldController.php | 19 ++++++++++--- Form/CustomFieldType.php | 40 +++++++++++++++++++++------- Resources/config/services.yml | 1 + 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/Controller/CustomFieldController.php b/Controller/CustomFieldController.php index f9958d70d..df23c6e40 100644 --- a/Controller/CustomFieldController.php +++ b/Controller/CustomFieldController.php @@ -4,7 +4,7 @@ namespace Chill\CustomFieldsBundle\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Bundle\FrameworkBundle\Controller\Controller; - +use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldsGroupToIdTransformer; use Chill\CustomFieldsBundle\Entity\CustomField; /** @@ -85,9 +85,10 @@ class CustomFieldController extends Controller 'action' => $this->generateUrl('customfield_create', array('type' => $type)), 'method' => 'POST', - 'type' => $type + 'type' => $type, + 'group_widget' => ($entity->getCustomFieldsGroup()) ? 'hidden' :'entity' )); - + $form->add('submit', 'submit', array('label' => 'Create')); return $form; @@ -100,6 +101,18 @@ class CustomFieldController extends Controller public function newAction(Request $request) { $entity = new CustomField(); + + //add the custom field group if defined in URL + $cfGroupId = $request->query->get('customFieldsGroup', null); + $cfGroup = $this->getDoctrine()->getManager() + ->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup') + ->find($cfGroupId); + if (!$cfGroup) { + throw $this->createNotFoundException('CustomFieldsGroup with id ' + . $cfGroupId.' is not found !'); + } + $entity->setCustomFieldsGroup($cfGroup); + $form = $this->createCreateForm($entity, $request->query->get('type')); return $this->render('ChillCustomFieldsBundle:CustomField:new.html.twig', array( diff --git a/Form/CustomFieldType.php b/Form/CustomFieldType.php index 77d8366c1..7130b8e60 100644 --- a/Form/CustomFieldType.php +++ b/Form/CustomFieldType.php @@ -6,9 +6,11 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Chill\CustomFieldsBundle\Service\CustomFieldProvider; -use Chill\CustomFieldsBundle\Entity\CustomField; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; +use Doctrine\Common\Persistence\ObjectManager; +use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldsGroupToIdTransformer; + class CustomFieldType extends AbstractType { @@ -20,10 +22,17 @@ class CustomFieldType extends AbstractType private $culture = 'fr'; + /** + * @var ObjectManager + */ + private $om; - public function __construct(CustomFieldProvider $compiler) + + public function __construct(CustomFieldProvider $compiler, + ObjectManager $om) { $this->customFieldProvider = $compiler; + $this->om = $om; } /** * @param FormBuilderInterface $builder @@ -40,11 +49,22 @@ class CustomFieldType extends AbstractType $builder ->add('name', 'translatable_string') - ->add('active', 'checkbox', array('required' => false)) - ->add('customFieldsGroup', 'entity', array( + ->add('active', 'checkbox', array('required' => false)); + + if ($options['group_widget'] === 'entity') { + $builder->add('customFieldsGroup', 'entity', array( 'class' => 'ChillCustomFieldsBundle:CustomFieldsGroup', 'property' => 'name['.$this->culture.']' - )) + )); + } elseif ($options['group_widget'] === 'hidden') { + $builder->add('customFieldsGroup', 'hidden'); + $builder->get('customFieldsGroup') + ->addViewTransformer(new CustomFieldsGroupToIdTransformer($this->om)); + } else { + throw new \LogicException('The value of group_widget is not handled'); + } + + $builder ->add('ordering', 'number') ->add('type', 'hidden', array('data' => $options['type'])) ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) @@ -80,10 +100,12 @@ class CustomFieldType extends AbstractType 'data_class' => 'Chill\CustomFieldsBundle\Entity\CustomField' )); - $resolver->setRequired(array('type')) - ->addAllowedValues(array('type' => - array_keys($this->customFieldProvider->getAllFields()) - )); + $resolver->setRequired(array('type', 'group_widget')) + ->addAllowedValues(array( + 'type' => array_keys($this->customFieldProvider->getAllFields()), + 'group_widget' => array('hidden', 'entity') + )) + ->setDefault('group_widget', 'entity'); } /** diff --git a/Resources/config/services.yml b/Resources/config/services.yml index af7b05b91..1f073c09b 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -11,6 +11,7 @@ services: class: Chill\CustomFieldsBundle\Form\CustomFieldType arguments: - "@chill.custom_field.provider" + - "@doctrine.orm.entity_manager" tags: - { name: 'form.type', alias: 'custom_field_choice' } From b96076022f64107be331ef4bd1414b993251d31b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 25 Nov 2015 08:45:17 +0100 Subject: [PATCH 25/54] [wip] layout of custom field edition [ci skip] --- Controller/CustomFieldController.php | 2 +- CustomFields/CustomFieldChoice.php | 6 +++-- Resources/translations/messages.fr.yml | 23 +++++++++++++++++- Resources/views/CustomField/edit.html.twig | 28 +++++++++++++++++----- Resources/views/Form/fields.html.twig | 17 +++++++++---- 5 files changed, 62 insertions(+), 14 deletions(-) diff --git a/Controller/CustomFieldController.php b/Controller/CustomFieldController.php index df23c6e40..98b8b1c96 100644 --- a/Controller/CustomFieldController.php +++ b/Controller/CustomFieldController.php @@ -159,7 +159,7 @@ class CustomFieldController extends Controller $editForm = $this->createEditForm($entity, $entity->getType()); $deleteForm = $this->createDeleteForm($id); - + return $this->render('ChillCustomFieldsBundle:CustomField:edit.html.twig', array( 'entity' => $entity, 'edit_form' => $editForm->createView(), diff --git a/CustomFields/CustomFieldChoice.php b/CustomFields/CustomFieldChoice.php index a20eb4814..304b33ef3 100644 --- a/CustomFields/CustomFieldChoice.php +++ b/CustomFields/CustomFieldChoice.php @@ -136,7 +136,8 @@ class CustomFieldChoice implements CustomFieldInterface 'choices' => array( 1 => 'Multiple', 0 => 'Unique'), - 'empty_data' => 0 + 'empty_data' => 0, + 'label' => 'Multiplicity' )) ->add(self::EXPANDED, 'choice', array( 'expanded' => true, @@ -144,7 +145,8 @@ class CustomFieldChoice implements CustomFieldInterface 'choices' => array( 1 => 'Expanded', 0 => 'Non expanded'), - 'empty_data' => 0 + 'empty_data' => 0, + 'label' => 'Choice display' )) ->add(self::ALLOW_OTHER, 'choice', array( 'label' => 'Allow other', diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index ab8cd4877..d9cf635fd 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -2,7 +2,7 @@ 'Other value': 'Autre valeur' 'None': 'Pas spécifié' - +#customfieldsgroup administration CustomFieldsGroup list: Groupes de champs personnalisés CustomFieldsGroup creation: Nouveau groupe de champs personnalisés Entity: Entité @@ -26,3 +26,24 @@ CustomFieldsGroup edit: Edition d'un groupe de champs personnalisé Custom fields configuration: Champs personnalisés CustomFields List: Liste des champs personnalisés CustomFields Groups: Groupe de champs personnalisés + +#customfield administration +CustomField edit: Modification d'un champ personnalisé +General informations: Informations générales +Options: Options +Custom fields group: Groupe de champ personnalisé +Ordering: Ordre d'apparition +Back to the group: Retour au groupe de champs personnalisé + +#custom field choice +Multiplicity: Multiplicité +Multiple: Multiple +Unique: Un seul choix possible +Choice display: Affichage des choix +Expanded: Choix étendus (boutons radio) +Non expanded: Choix rassemblés +Allow other: Autoriser une autre valeur +No: Non +Yes: Oui +Other value label (empty if use by default): Label du champ "autre valeur" +Choices: Choix diff --git a/Resources/views/CustomField/edit.html.twig b/Resources/views/CustomField/edit.html.twig index bcc2e5d88..9b32ab809 100644 --- a/Resources/views/CustomField/edit.html.twig +++ b/Resources/views/CustomField/edit.html.twig @@ -16,17 +16,33 @@ #} {% extends "ChillCustomFieldsBundle::Admin/layout.html.twig" %} -{% block admin_content %} -

CustomField edit

+{% block title %}{{ 'CustomField edit'|trans }}{% endblock title %} - {{ form(edit_form) }} +{% block admin_content %} +

{{ 'CustomField edit'|trans }}

+ +

{{ 'General informations'|trans }}

+ {{ form_start(edit_form) }} + {{ form_row(edit_form.name) }} + {{ form_row(edit_form.active) }} + {% if edit_form.customFieldsGroup is defined %} + {{ form_row(edit_form.customFieldsGroup) }} + {% endif %} + {{ form_row(edit_form.ordering) }} + {% if edit_form.options is not empty %} +

{{ 'Options'|trans }}

+ {% for option in edit_form.options %} + {{ form_row(option) }} + {% endfor %} + {% endif %} + {{ form_row(edit_form.submit, {'attr': { 'class': 'sc-button btn-update' } } ) }} + {{ form_end(edit_form) }} {% endblock %} diff --git a/Resources/views/Form/fields.html.twig b/Resources/views/Form/fields.html.twig index 76ec0cb5c..3a23a5adf 100644 --- a/Resources/views/Form/fields.html.twig +++ b/Resources/views/Form/fields.html.twig @@ -32,10 +32,19 @@ {% endblock cf_choices_list_widget %} -{# render the possibility to add different elements in a choice list #} -{% block cf_choices_widget %} +{# CFChoice : render the different elements in a choice list #} +{% block cf_choices_row %} +

{{ 'Choices'|trans }}

- {{ form(form) }} + + {% for choice in form %} + + {% endfor %} +
+ {{ form_row(choice.name) }} +
+ + {# we use javascrit to add an additional element. All functions are personnalized with the id ( = form.vars.id) #} -{% endblock cf_choices_widget %} +{% endblock cf_choices_row %} {% block choice_with_other_widget %}
From f24a088a0d26f2b1d9f94e659e6e397cd2abe230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 25 Nov 2015 21:26:30 +0100 Subject: [PATCH 26/54] [wip] re-introduce 'add element' functionality --- Resources/views/Form/fields.html.twig | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Resources/views/Form/fields.html.twig b/Resources/views/Form/fields.html.twig index 3a23a5adf..8f611e6de 100644 --- a/Resources/views/Form/fields.html.twig +++ b/Resources/views/Form/fields.html.twig @@ -35,15 +35,20 @@ {# CFChoice : render the different elements in a choice list #} {% block cf_choices_row %}

{{ 'Choices'|trans }}

- + {{ dump(form.vars.prototype.children) }} +
{% for choice in form %} {% endfor %}
{{ form_row(choice.name) }} + {{ form_row(choice.active) }} + {{ form_row(choice.slug) }}
- +
{# we use javascrit to add an additional element. All functions are personnalized with the id ( = form.vars.id) #} From bf99b68a2a1ffdde68faac63ba80208d25009fd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 27 Nov 2015 13:37:07 +0100 Subject: [PATCH 27/54] Improve rendering of options and fields --- CustomFields/CustomFieldText.php | 8 +++++- CustomFields/CustomFieldTitle.php | 11 +++++--- Resources/translations/messages.fr.yml | 21 +++++++++++++++ Resources/views/CustomField/edit.html.twig | 2 +- Resources/views/CustomField/new.html.twig | 31 +++++++++++++++++----- Resources/views/Form/fields.html.twig | 8 +++--- 6 files changed, 65 insertions(+), 16 deletions(-) diff --git a/CustomFields/CustomFieldText.php b/CustomFields/CustomFieldText.php index 08e4ab58f..a11705707 100644 --- a/CustomFields/CustomFieldText.php +++ b/CustomFields/CustomFieldText.php @@ -122,7 +122,13 @@ class CustomFieldText implements CustomFieldInterface return $builder ->add(self::MAX_LENGTH, 'integer', array('empty_data' => 256)) ->add(self::MULTIPLE_CF_INLINE, 'choice', array( - 'choices' => array('1' => 'True', '0' => 'False'))) + 'choices' => array( + '1' => 'Multiple boxes on the line', + '0' => 'One box on the line' + ), + 'label' => 'Box appearance', + 'expanded' => True + )) ; } } diff --git a/CustomFields/CustomFieldTitle.php b/CustomFields/CustomFieldTitle.php index 78b6f08d6..6c15543eb 100644 --- a/CustomFields/CustomFieldTitle.php +++ b/CustomFields/CustomFieldTitle.php @@ -96,10 +96,13 @@ class CustomFieldTitle implements CustomFieldInterface public function buildOptionsForm(FormBuilderInterface $builder) { return $builder->add(self::TYPE, 'choice', - array('choices' => array( - self::TYPE_TITLE => self::TYPE_TITLE, - self::TYPE_SUBTITLE => self::TYPE_SUBTITLE - )) + array( + 'choices' => array( + self::TYPE_TITLE => 'Main title', + self::TYPE_SUBTITLE => 'Subtitle' + ), + 'label' => 'Title level' + ) ); } } diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index d9cf635fd..469f4f2a9 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -20,6 +20,7 @@ label_field: label du champ active: actif No value defined for this option: Pas de valeur pour cette option CustomFieldsGroup edit: Edition d'un groupe de champs personnalisé +type: type #menu entries @@ -29,11 +30,19 @@ CustomFields Groups: Groupe de champs personnalisés #customfield administration CustomField edit: Modification d'un champ personnalisé +CustomField creation: Nouveau champ personnalisé General informations: Informations générales Options: Options Custom fields group: Groupe de champ personnalisé Ordering: Ordre d'apparition Back to the group: Retour au groupe de champs personnalisé +Slug: Identifiant textuel + +#custom field name +choice: choix +title: titre +text: texte +text field: champ texte #custom field choice Multiplicity: Multiplicité @@ -47,3 +56,15 @@ No: Non Yes: Oui Other value label (empty if use by default): Label du champ "autre valeur" Choices: Choix +Add an element: Ajouter un élément + +#custom field text +Max length: Longueur maximum +Box appearance: Apparence du champ +Multiple boxes on the line: Plusieurs champs sur la ligne +One box on the line: Un seul champ sur la ligne + +#custom field title +Title level: Niveau de titre +Main title: Titre principal +Subtitle: Sous-titre diff --git a/Resources/views/CustomField/edit.html.twig b/Resources/views/CustomField/edit.html.twig index 9b32ab809..08fbed2ce 100644 --- a/Resources/views/CustomField/edit.html.twig +++ b/Resources/views/CustomField/edit.html.twig @@ -40,7 +40,7 @@
  • - + {{ 'Back to the group'|trans }}
  • diff --git a/Resources/views/CustomField/new.html.twig b/Resources/views/CustomField/new.html.twig index a94f16b3b..556c464ec 100644 --- a/Resources/views/CustomField/new.html.twig +++ b/Resources/views/CustomField/new.html.twig @@ -16,14 +16,33 @@ #} {% extends "ChillCustomFieldsBundle::Admin/layout.html.twig" %} -{% block admin_content %} -

    CustomField creation

    +{% block title %}{{ 'CustomField creation'|trans }}{% endblock title %} - {{ form(form) }} -
      +{% block admin_content %} +

      {{ 'CustomField creation'|trans }}

      + +

      {{ 'General informations'|trans }}

      + {{ form_start(form) }} + {{ form_row(form.name) }} + {{ form_row(form.active) }} + {{ form_row(form.slug) }} + {% if form.customFieldsGroup is defined %} + {{ form_row(form.customFieldsGroup) }} + {% endif %} + {{ form_row(form.ordering) }} + {% if form.options is not empty %} +

      {{ 'Options'|trans }}

      + {% for option in form.options %} + {{ form_row(option) }} + {% endfor %} + {% endif %} + {{ form_row(form.submit, {'attr': { 'class': 'sc-button btn-create' } } ) }} + {{ form_end(form) }} + + diff --git a/Resources/views/Form/fields.html.twig b/Resources/views/Form/fields.html.twig index 8f611e6de..04febae3c 100644 --- a/Resources/views/Form/fields.html.twig +++ b/Resources/views/Form/fields.html.twig @@ -35,17 +35,17 @@ {# CFChoice : render the different elements in a choice list #} {% block cf_choices_row %}

      {{ 'Choices'|trans }}

      - {{ dump(form.vars.prototype.children) }} +
      + ~ form_row(form.vars.prototype.children.slug) -}}"> {% for choice in form %} + {% endfor %}
      {{ form_row(choice.name) }} {{ form_row(choice.active) }} {{ form_row(choice.slug) }} -
      @@ -67,7 +67,7 @@ } function initializeCFChoiceOptionsChoices(div_id) { - var add_element_link = $('Add an element'); + var add_element_link = $('{{ 'Add an element'|trans }}'); var div = $('#' + div_id); div.append(add_element_link); div.data('index', div.find(':input').length / 5); From fa3245b99bdf5e554d13374177734dc1b68de1e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 27 Nov 2015 13:42:06 +0100 Subject: [PATCH 28/54] add a btn on edit link --- Resources/views/CustomFieldsGroup/index.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/views/CustomFieldsGroup/index.html.twig b/Resources/views/CustomFieldsGroup/index.html.twig index 3b8eefe81..9a722b180 100644 --- a/Resources/views/CustomFieldsGroup/index.html.twig +++ b/Resources/views/CustomFieldsGroup/index.html.twig @@ -50,7 +50,7 @@ {{ 'show'|trans }}
    • - {{ 'edit'|trans }} + {{ 'edit'|trans }}
    From cbf9cee65c392cf9d84584b176a2e623011c2930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 27 Nov 2015 13:51:36 +0100 Subject: [PATCH 29/54] clean code of usnused methods --- Controller/CustomFieldController.php | 90 +-------------------- Resources/config/routing/customfield.yml | 18 ----- Resources/views/CustomField/index.html.twig | 66 --------------- 3 files changed, 4 insertions(+), 170 deletions(-) delete mode 100644 Resources/views/CustomField/index.html.twig diff --git a/Controller/CustomFieldController.php b/Controller/CustomFieldController.php index 98b8b1c96..204652612 100644 --- a/Controller/CustomFieldController.php +++ b/Controller/CustomFieldController.php @@ -4,7 +4,6 @@ namespace Chill\CustomFieldsBundle\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Bundle\FrameworkBundle\Controller\Controller; -use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldsGroupToIdTransformer; use Chill\CustomFieldsBundle\Entity\CustomField; /** @@ -14,40 +13,6 @@ use Chill\CustomFieldsBundle\Entity\CustomField; class CustomFieldController extends Controller { - /** - * Lists all CustomField entities. - * - */ - public function indexAction() - { - $em = $this->getDoctrine()->getManager(); - - $entities = $em->getRepository('ChillCustomFieldsBundle:CustomField')->findAll(); - - //prepare form for new custom type - $fieldChoices = array(); - foreach ($this->get('chill.custom_field.provider')->getAllFields() - as $key => $customType) { - $fieldChoices[$key] = $customType->getName(); - } - $form = $this->get('form.factory') - ->createNamedBuilder(null, 'form', null, array( - 'method' => 'GET', - 'action' => $this->generateUrl('customfield_new'), - 'csrf_protection' => false - )) - ->add('type', 'choice', array( - 'choices' => $fieldChoices - )) - ->getForm(); - - return $this->render('ChillCustomFieldsBundle:CustomField:index.html.twig', array( - 'entities' => $entities, - 'form' => $form->createView() - )); - } - - /** * Creates a new CustomField entity. * @@ -124,6 +89,7 @@ class CustomFieldController extends Controller /** * Finds and displays a CustomField entity. * + * @deprecated is not used since there is no link to show action */ public function showAction($id) { @@ -135,12 +101,8 @@ class CustomFieldController extends Controller throw $this->createNotFoundException('Unable to find CustomField entity.'); } - $deleteForm = $this->createDeleteForm($id); - return $this->render('ChillCustomFieldsBundle:CustomField:show.html.twig', array( - 'entity' => $entity, - 'delete_form' => $deleteForm->createView(), - )); + 'entity' => $entity, )); } /** @@ -158,12 +120,10 @@ class CustomFieldController extends Controller } $editForm = $this->createEditForm($entity, $entity->getType()); - $deleteForm = $this->createDeleteForm($id); return $this->render('ChillCustomFieldsBundle:CustomField:edit.html.twig', array( 'entity' => $entity, 'edit_form' => $editForm->createView(), - 'delete_form' => $deleteForm->createView(), )); } @@ -179,7 +139,8 @@ class CustomFieldController extends Controller $form = $this->createForm('custom_field_choice', $entity, array( 'action' => $this->generateUrl('customfield_update', array('id' => $entity->getId())), 'method' => 'PUT', - 'type' => $type + 'type' => $type, + 'group_widget' => 'hidden' )); $form->add('submit', 'submit', array('label' => 'Update')); @@ -200,7 +161,6 @@ class CustomFieldController extends Controller throw $this->createNotFoundException('Unable to find CustomField entity.'); } - $deleteForm = $this->createDeleteForm($id); $editForm = $this->createEditForm($entity, $entity->getType()); $editForm->handleRequest($request); @@ -213,48 +173,6 @@ class CustomFieldController extends Controller return $this->render('ChillCustomFieldsBundle:CustomField:edit.html.twig', array( 'entity' => $entity, 'edit_form' => $editForm->createView(), - 'delete_form' => $deleteForm->createView(), )); } - /** - * Deletes a CustomField entity. - * - */ - public function deleteAction(Request $request, $id) - { - $form = $this->createDeleteForm($id); - $form->handleRequest($request); - - if ($form->isValid()) { - $em = $this->getDoctrine()->getManager(); - $entity = $em->getRepository('ChillCustomFieldsBundle:CustomField')->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find CustomField entity.'); - } - - $em->remove($entity); - $em->flush(); - } - - return $this->redirect($this->generateUrl('customfield')); - } - - /** - * Creates a form to delete a CustomField entity by id. - * - * @param mixed $id The entity id - * - * @return \Symfony\Component\Form\Form The form - */ - private function createDeleteForm($id) - { - return $this->createFormBuilder() - ->setAction($this->generateUrl('customfield_delete', array('id' => $id))) - ->setMethod('DELETE') - ->add('submit', 'submit', array('label' => 'Delete')) - ->getForm() - ; - } - } diff --git a/Resources/config/routing/customfield.yml b/Resources/config/routing/customfield.yml index 0f8e7b8d3..eabef0fad 100644 --- a/Resources/config/routing/customfield.yml +++ b/Resources/config/routing/customfield.yml @@ -8,19 +8,6 @@ customfield_section: label: "Custom fields configuration" icons: ['asterisk'] -customfield: - path: /{_locale}/admin/customfield/list - defaults: { _controller: "ChillCustomFieldsBundle:CustomField:index" } - options: - menus: - admin_custom_fields: - order: 1000 - label: "CustomFields List" - -customfield_show: - path: /{_locale}/admin/customfield/{id}/show - defaults: { _controller: "ChillCustomFieldsBundle:CustomField:show" } - customfield_new: path: /{_locale}/admin/customfield/new defaults: { _controller: "ChillCustomFieldsBundle:CustomField:new" } @@ -38,8 +25,3 @@ customfield_update: path: /{_locale}/admin/customfield/{id}/update defaults: { _controller: "ChillCustomFieldsBundle:CustomField:update" } requirements: { _method: post|put } - -customfield_delete: - path: /{_locale}/admin/customfield/{id}/delete - defaults: { _controller: "ChillCustomFieldsBundle:CustomField:delete" } - requirements: { _method: post|delete } diff --git a/Resources/views/CustomField/index.html.twig b/Resources/views/CustomField/index.html.twig deleted file mode 100644 index 36c5f1243..000000000 --- a/Resources/views/CustomField/index.html.twig +++ /dev/null @@ -1,66 +0,0 @@ -{# - * Copyright (C) 2014, Champs Libres Cooperative SCRLFS, - * - * 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 . -#} -{% extends "ChillCustomFieldsBundle::Admin/layout.html.twig" %} - -{% block admin_content %} -

    CustomField list

    - - - - - - - - - - - - - {% for entity in entities %} - - - - - - - - {% endfor %} - -
    IdLabelTypeActiveActions
    {{ entity.id }}{{ entity.name(app.request.locale) }}{{ entity.type }}{{ entity.active }} - -
    - -
      -
    • - {{ form_start(form) }} - - {{ form_row(form) }} - - - {{ form_end(form) }} -
    • -
    - {% endblock %} From 46173231d2d9c66ebad345e039984739d6dbac74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 27 Nov 2015 14:18:19 +0100 Subject: [PATCH 30/54] adding flash messages for customfield --- Controller/CustomFieldController.php | 17 +++++++++++++++-- Resources/translations/messages.fr.yml | 3 +++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Controller/CustomFieldController.php b/Controller/CustomFieldController.php index 204652612..8342ea765 100644 --- a/Controller/CustomFieldController.php +++ b/Controller/CustomFieldController.php @@ -27,9 +27,16 @@ class CustomFieldController extends Controller $em = $this->getDoctrine()->getManager(); $em->persist($entity); $em->flush(); + + $this->addFlash('success', $this->get('translator') + ->trans('The custom field has been created')); - return $this->redirect($this->generateUrl('customfield_show', array('id' => $entity->getId()))); - } + return $this->redirect($this->generateUrl('customfieldsgroup_show', + array('id' => $entity->getCustomFieldsGroup()->getId()))); + } + + $this->addFlash('error', $this->get('translator') + ->trans("The custom field form contains errors")); return $this->render('ChillCustomFieldsBundle:CustomField:new.html.twig', array( 'entity' => $entity, @@ -166,9 +173,15 @@ class CustomFieldController extends Controller if ($editForm->isValid()) { $em->flush(); + + $this->addFlash('success', $this->get('translator') + ->trans("The custom field has been updated")); return $this->redirect($this->generateUrl('customfield_edit', array('id' => $id))); } + + $this->addFlash('error', $this->get('translator') + ->trans("The custom field form contains errors")); return $this->render('ChillCustomFieldsBundle:CustomField:edit.html.twig', array( 'entity' => $entity, diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index 469f4f2a9..38e037506 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -37,6 +37,9 @@ Custom fields group: Groupe de champ personnalisé Ordering: Ordre d'apparition Back to the group: Retour au groupe de champs personnalisé Slug: Identifiant textuel +The custom field has been created: Le champ personnalisé est créé +The custom field form contains errors: Le formulaire contient des erreurs +The custom field has been updated: Le champ personnalisé a été mis à jour #custom field name choice: choix From 2401270754746b631a370c1a2a523e433e25b5d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 27 Nov 2015 14:26:46 +0100 Subject: [PATCH 31/54] add flash message for custom fields group --- Controller/CustomFieldsGroupController.php | 15 +++++++++++++++ Resources/translations/messages.fr.yml | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/Controller/CustomFieldsGroupController.php b/Controller/CustomFieldsGroupController.php index f31edd4df..46b95fd5a 100644 --- a/Controller/CustomFieldsGroupController.php +++ b/Controller/CustomFieldsGroupController.php @@ -97,9 +97,15 @@ class CustomFieldsGroupController extends Controller $em = $this->getDoctrine()->getManager(); $em->persist($entity); $em->flush(); + + $this->addFlash('success', $this->get('translator') + ->trans("The custom fields group has been created")); return $this->redirect($this->generateUrl('customfieldsgroup_show', array('id' => $entity->getId()))); } + + $this->addFlash('error', $this->get('translator') + ->trans("The custom fields group form contains errors")); return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:new.html.twig', array( 'entity' => $entity, @@ -274,9 +280,15 @@ class CustomFieldsGroupController extends Controller if ($editForm->isValid()) { $em->flush(); + + $this->addFlash('success', $this->get('translator') + ->trans("The custom fields group has been updated")); return $this->redirect($this->generateUrl('customfieldsgroup_edit', array('id' => $id))); } + + $this->addFlash('error', $this->get('translator') + ->trans("The custom fields group form contains errors")); return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:edit.html.twig', array( 'entity' => $entity, @@ -324,6 +336,9 @@ class CustomFieldsGroupController extends Controller $em->persist($newCFDefaultGroup); $em->flush(); + + $this->addFlash('success', $this->get('translator') + ->trans("The default custom fields group has been changed")); return $this->redirect($this->generateUrl('customfieldsgroup')); } diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index 38e037506..77c13fd1c 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -21,6 +21,10 @@ active: actif No value defined for this option: Pas de valeur pour cette option CustomFieldsGroup edit: Edition d'un groupe de champs personnalisé type: type +The custom fields group has been created: Le groupe de champs personnalisés a été créé +The custom fields group has been updated: Le groupe de champs personnalisés a été mis à jour +The custom fields group form contains errors: Le formulaire contient des erreurs +The default custom fields group has been changed: Le groupe par défaut a été changé #menu entries From c9ca7c1e1bcab73787229c05eb8beb8400340de9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 30 Nov 2015 21:31:58 +0100 Subject: [PATCH 32/54] fix creation of custom field without cfgroup id --- .gitignore | 2 ++ Controller/CustomFieldController.php | 17 ++++++++++------- Resources/views/CustomField/new.html.twig | 6 ++++++ Tests/CustomFields/CustomFieldsTextTest.php | 1 + 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 52d2b6ff7..b11589291 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,5 @@ src/Chill/CustomFieldsBundle/vendor/* bootstrap.php.cache #the file created by composer to store creds auth.json +Tests/Fixtures/App/app/config/parameters.yml + diff --git a/Controller/CustomFieldController.php b/Controller/CustomFieldController.php index 8342ea765..46b013f82 100644 --- a/Controller/CustomFieldController.php +++ b/Controller/CustomFieldController.php @@ -76,14 +76,17 @@ class CustomFieldController extends Controller //add the custom field group if defined in URL $cfGroupId = $request->query->get('customFieldsGroup', null); - $cfGroup = $this->getDoctrine()->getManager() - ->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup') - ->find($cfGroupId); - if (!$cfGroup) { - throw $this->createNotFoundException('CustomFieldsGroup with id ' - . $cfGroupId.' is not found !'); + + if ($cfGroupId !== null) { + $cfGroup = $this->getDoctrine()->getManager() + ->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup') + ->find($cfGroupId); + if (!$cfGroup) { + throw $this->createNotFoundException('CustomFieldsGroup with id ' + . $cfGroupId.' is not found !'); + } + $entity->setCustomFieldsGroup($cfGroup); } - $entity->setCustomFieldsGroup($cfGroup); $form = $this->createCreateForm($entity, $request->query->get('type')); diff --git a/Resources/views/CustomField/new.html.twig b/Resources/views/CustomField/new.html.twig index 556c464ec..783cbb1d6 100644 --- a/Resources/views/CustomField/new.html.twig +++ b/Resources/views/CustomField/new.html.twig @@ -41,9 +41,15 @@ {% endblock %} diff --git a/Tests/CustomFields/CustomFieldsTextTest.php b/Tests/CustomFields/CustomFieldsTextTest.php index 205dc7dfe..00130df80 100644 --- a/Tests/CustomFields/CustomFieldsTextTest.php +++ b/Tests/CustomFields/CustomFieldsTextTest.php @@ -100,4 +100,5 @@ class CustomFieldsTextTest extends WebTestCase $form = $crawler->selectButton('custom_field_choice_submit')->form(); $this->assertTrue($form->has('custom_field_choice[options][maxLength]')); } + } From 9b5544beaf0cfeef90710855875d548dba836227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 30 Nov 2015 22:10:04 +0100 Subject: [PATCH 33/54] create test for custom fields group complete scenario a deps is added on the bundle "person" in order to make test working. --- .../CustomFieldsGroupControllerTest.php | 67 +++++++++++++++++++ .../CustomFieldsGroupControllerTest_TODO.php | 55 --------------- Tests/Fixtures/App/app/AppKernel.php | 3 +- composer.json | 10 ++- 4 files changed, 76 insertions(+), 59 deletions(-) create mode 100644 Tests/Controller/CustomFieldsGroupControllerTest.php delete mode 100644 Tests/Controller/CustomFieldsGroupControllerTest_TODO.php diff --git a/Tests/Controller/CustomFieldsGroupControllerTest.php b/Tests/Controller/CustomFieldsGroupControllerTest.php new file mode 100644 index 000000000..920e02986 --- /dev/null +++ b/Tests/Controller/CustomFieldsGroupControllerTest.php @@ -0,0 +1,67 @@ + 'test_customizable_entities_test_not_empty_config')); + // Create a new client to browse the application + $client = static::createClient(array(), array( + 'PHP_AUTH_USER' => 'admin', + 'PHP_AUTH_PW' => 'olala', + )); + + //create the entity + $this->createCustomFieldsGroup($client); + + // Edit the entity + $this->editCustomFieldsGroup($client); + } + + private function createCustomFieldsGroup(Client &$client) + { + // Create a new entry in the database + $crawler = $client->request('GET', '/fr/admin/customfieldsgroup/'); + $this->assertEquals(200, $client->getResponse()->getStatusCode(), + "Unexpected HTTP status code for GET /customfieldsgroup/"); + + $crawler = $client->click($crawler->selectLink('Créer un nouveau groupe')->link()); + + // Fill in the form and submit it + $form = $crawler->selectButton('Créer')->form(array( + 'custom_fields_group[name][fr]' => 'Test', + 'custom_fields_group[entity]' => 'Chill\PersonBundle\Entity\Person' + )); + + $crawler = $client->submit($form); + + $crawler = $client->followRedirect(); + + // Check data in the show view + $this->assertGreaterThan(0, $crawler->filter('td:contains("Test")')->count(), + 'Missing element td:contains("Test")'); + } + + private function editCustomFieldsGroup(Client $client) + { + $crawler = $client->request('GET', '/fr/admin/customfieldsgroup/'); + $crawler = $client->click($crawler->selectLink('modifier')->link()); + fwrite(STDOUT, $crawler->text()); + $form = $crawler->selectButton('Update')->form(array( + 'custom_fields_group[name][fr]' => 'Foo', + )); + + $client->submit($form); + $crawler = $client->followRedirect(); + + // Check the element contains an attribute with value equals "Foo" + $this->assertGreaterThan(0, $crawler->filter('[value="Foo"]')->count(), + 'Missing element [value="Foo"]'); + } +} diff --git a/Tests/Controller/CustomFieldsGroupControllerTest_TODO.php b/Tests/Controller/CustomFieldsGroupControllerTest_TODO.php deleted file mode 100644 index afa7bad25..000000000 --- a/Tests/Controller/CustomFieldsGroupControllerTest_TODO.php +++ /dev/null @@ -1,55 +0,0 @@ -request('GET', '/customfieldsgroup/'); - $this->assertEquals(200, $client->getResponse()->getStatusCode(), "Unexpected HTTP status code for GET /customfieldsgroup/"); - $crawler = $client->click($crawler->selectLink('Create a new entry')->link()); - - // Fill in the form and submit it - $form = $crawler->selectButton('Create')->form(array( - 'cl_customfieldsbundle_customfieldsgroup[field_name]' => 'Test', - // ... other fields to fill - )); - - $client->submit($form); - $crawler = $client->followRedirect(); - - // Check data in the show view - $this->assertGreaterThan(0, $crawler->filter('td:contains("Test")')->count(), 'Missing element td:contains("Test")'); - - // Edit the entity - $crawler = $client->click($crawler->selectLink('Edit')->link()); - - $form = $crawler->selectButton('Update')->form(array( - 'cl_customfieldsbundle_customfieldsgroup[field_name]' => 'Foo', - // ... other fields to fill - )); - - $client->submit($form); - $crawler = $client->followRedirect(); - - // Check the element contains an attribute with value equals "Foo" - $this->assertGreaterThan(0, $crawler->filter('[value="Foo"]')->count(), 'Missing element [value="Foo"]'); - - // Delete the entity - $client->submit($crawler->selectButton('Delete')->form()); - $crawler = $client->followRedirect(); - - // Check the entity has been delete on the list - $this->assertNotRegExp('/Foo/', $client->getResponse()->getContent()); - } - - */ -} diff --git a/Tests/Fixtures/App/app/AppKernel.php b/Tests/Fixtures/App/app/AppKernel.php index 59ec46bfa..d2e57ab94 100644 --- a/Tests/Fixtures/App/app/AppKernel.php +++ b/Tests/Fixtures/App/app/AppKernel.php @@ -17,7 +17,8 @@ class AppKernel extends Kernel new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(), new \Chill\MainBundle\ChillMainBundle, new \Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle(), - new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle() + new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(), + new Chill\PersonBundle\ChillPersonBundle(), #add here all the required bundle (some bundle are not required) ); } diff --git a/composer.json b/composer.json index af1c0c6b4..32c01e7f5 100644 --- a/composer.json +++ b/composer.json @@ -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", @@ -34,7 +34,8 @@ "chill-project/main": "dev-master" }, "require-dev": { - "doctrine/doctrine-fixtures-bundle": "~2.2@dev" + "doctrine/doctrine-fixtures-bundle": "~2.2@dev", + "chill-project/person": "dev-master@dev" }, "scripts": { "post-install-cmd": [ @@ -54,6 +55,9 @@ }, "extra": { "symfony-app-dir": "Tests/Fixtures/App/app", - "app-migrations-dir": "Tests/Fixtures/App/app/DoctrineMigrations" + "app-migrations-dir": "Tests/Fixtures/App/app/DoctrineMigrations", + "branch-alias": { + "dev-master": "fix_admin_interface-dev" + } } } From 4c328d0aae42524943c35dd6b3d4532e532c69f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 30 Nov 2015 22:12:59 +0100 Subject: [PATCH 34/54] remove dump informations --- Tests/Controller/CustomFieldsGroupControllerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Controller/CustomFieldsGroupControllerTest.php b/Tests/Controller/CustomFieldsGroupControllerTest.php index 920e02986..b6bc3bbee 100644 --- a/Tests/Controller/CustomFieldsGroupControllerTest.php +++ b/Tests/Controller/CustomFieldsGroupControllerTest.php @@ -52,7 +52,7 @@ class CustomFieldsGroupControllerTest extends WebTestCase { $crawler = $client->request('GET', '/fr/admin/customfieldsgroup/'); $crawler = $client->click($crawler->selectLink('modifier')->link()); - fwrite(STDOUT, $crawler->text()); + $form = $crawler->selectButton('Update')->form(array( 'custom_fields_group[name][fr]' => 'Foo', )); From 97475ca3b6c0f6be2c9db29c391045b2fae20eb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 30 Nov 2015 22:13:59 +0100 Subject: [PATCH 35/54] fix test for config according to new dev deps --- Tests/Config/ConfigCustomizablesEntitiesTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Config/ConfigCustomizablesEntitiesTest.php b/Tests/Config/ConfigCustomizablesEntitiesTest.php index deb9585e2..df66ab56c 100644 --- a/Tests/Config/ConfigCustomizablesEntitiesTest.php +++ b/Tests/Config/ConfigCustomizablesEntitiesTest.php @@ -43,7 +43,7 @@ class ConfigCustomizablesEntitiesTest extends KernelTestCase ->getParameter('chill_custom_fields.customizables_entities'); $this->assertInternalType('array', $customizableEntities); - $this->assertCount(0, $customizableEntities); + $this->assertCount(1, $customizableEntities); } /** @@ -59,7 +59,7 @@ class ConfigCustomizablesEntitiesTest extends KernelTestCase ->getParameter('chill_custom_fields.customizables_entities'); $this->assertInternalType('array', $customizableEntities); - $this->assertCount(1, $customizableEntities); + $this->assertCount(2, $customizableEntities); foreach($customizableEntities as $key => $config) { $this->assertInternalType('array', $config); From f18b384a0694435b4179cb59d70ddc70a1e8508f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 30 Nov 2015 22:33:15 +0100 Subject: [PATCH 36/54] remove 'empty_data' which cause conflict with transformer this blocked the possibility to uncheck the 'active' field on the choice. --- Form/Type/ChoicesListType.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Form/Type/ChoicesListType.php b/Form/Type/ChoicesListType.php index 7cd3c4c3d..120559920 100644 --- a/Form/Type/ChoicesListType.php +++ b/Form/Type/ChoicesListType.php @@ -25,8 +25,7 @@ class ChoicesListType extends AbstractType $builder->add('name', 'translatable_string') ->add('active', 'checkbox', array( - 'required' => false, - 'empty_data' => true + 'required' => false )) ->add('slug', 'hidden', array( From c4d2c5e6913120923e528357b0808f85b236cea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 30 Nov 2015 22:39:30 +0100 Subject: [PATCH 37/54] fix composer.json --- composer.json | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index 32c01e7f5..0e0224354 100644 --- a/composer.json +++ b/composer.json @@ -55,9 +55,6 @@ }, "extra": { "symfony-app-dir": "Tests/Fixtures/App/app", - "app-migrations-dir": "Tests/Fixtures/App/app/DoctrineMigrations", - "branch-alias": { - "dev-master": "fix_admin_interface-dev" - } + "app-migrations-dir": "Tests/Fixtures/App/app/DoctrineMigrations" } -} +} \ No newline at end of file From 57fbd54a9c98560b7ac6c23eb60a2a21a2e0c6ee Mon Sep 17 00:00:00 2001 From: Marc Ducobu Date: Tue, 8 Dec 2015 11:41:34 +0100 Subject: [PATCH 38/54] Removing the choice_with_other_widget that is alreay defined in the main bundle --- Resources/views/Form/fields.html.twig | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/Resources/views/Form/fields.html.twig b/Resources/views/Form/fields.html.twig index 04febae3c..f696dc057 100644 --- a/Resources/views/Form/fields.html.twig +++ b/Resources/views/Form/fields.html.twig @@ -25,11 +25,9 @@ {# CustomFields Choice #} {# render an alement in a choice list #} {% block cf_choices_list_widget %} - -{{ form_row(form.name) }} -{{ form_row(form.active) }} -{{ form_row(form.slug) }} - + {{ form_row(form.name) }} + {{ form_row(form.active) }} + {{ form_row(form.slug) }} {% endblock cf_choices_list_widget %} {# CFChoice : render the different elements in a choice list #} @@ -80,18 +78,6 @@ jQuery(document).ready(initializeCFChoiceOptionsChoices('{{ form.vars.id }}')); +{% endblock cf_choices_row %} -{% endblock cf_choices_row %} - -{% block choice_with_other_widget %} -
    -{%- for child in form.children._choices %} -{{- form_widget(child) -}} -{{- form_label(child) -}} -{%- if child.vars.value == '_other' -%} -{{- form_widget(form.children._other) -}} -{%- endif -%} -{% endfor -%} -
    - -{% endblock choice_with_other_widget %} \ No newline at end of file +{# The choice_with_other_widget widget is defined in the main bundle #} \ No newline at end of file From ebfb24a3ebaf323cdbfb094a0879fe9ee06f8677 Mon Sep 17 00:00:00 2001 From: Marc Ducobu Date: Tue, 8 Dec 2015 11:42:05 +0100 Subject: [PATCH 39/54] Refactoring CustomFields/CustomFieldChoice.php : removing useless linereturn --- CustomFields/CustomFieldChoice.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/CustomFields/CustomFieldChoice.php b/CustomFields/CustomFieldChoice.php index 304b33ef3..9bad639d6 100644 --- a/CustomFields/CustomFieldChoice.php +++ b/CustomFields/CustomFieldChoice.php @@ -20,14 +20,14 @@ namespace Chill\CustomFieldsBundle\CustomFields; +use Chill\CustomFieldsBundle\Form\Type\ChoicesListType; +use Chill\CustomFieldsBundle\Form\Type\ChoicesType; +use Chill\CustomFieldsBundle\Form\Type\ChoiceWithOtherType; use Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface; use Symfony\Component\Form\FormBuilderInterface; use Chill\CustomFieldsBundle\Entity\CustomField; -use Chill\CustomFieldsBundle\Form\Type\ChoicesType; use Symfony\Component\HttpFoundation\RequestStack; -use Chill\CustomFieldsBundle\Form\Type\ChoicesListType; use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldDataTransformer; -use Chill\CustomFieldsBundle\Form\Type\ChoiceWithOtherType; use Symfony\Bridge\Twig\TwigEngine; use Chill\MainBundle\Templating\TranslatableStringHelper; use Symfony\Component\Translation\Translator; @@ -122,9 +122,7 @@ class CustomFieldChoice implements CustomFieldInterface $builder->create($customField->getSlug(), 'choice', $options) ->addModelTransformer(new CustomFieldDataTransformer($this, $customField)) ); - } - } public function buildOptionsForm(FormBuilderInterface $builder) From 373edab629595e6f5edcf4f2bf111fe1be2174d8 Mon Sep 17 00:00:00 2001 From: Marc Ducobu Date: Tue, 8 Dec 2015 11:42:38 +0100 Subject: [PATCH 40/54] CustomFields/CustomFieldInterface.php : Improving the doc --- CustomFields/CustomFieldInterface.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/CustomFields/CustomFieldInterface.php b/CustomFields/CustomFieldInterface.php index 149e5500b..994172e41 100644 --- a/CustomFields/CustomFieldInterface.php +++ b/CustomFields/CustomFieldInterface.php @@ -13,7 +13,9 @@ interface CustomFieldInterface { /** - * + * Return a form type to edit the custom field. This form is shown to the + * user. + * * @param \Chill\CustomFieldsBundle\CustomField\FormBuilderInterface $builder * @param \Chill\CustomFieldsBundle\CustomField\CustomField $customField * @return \Symfony\Component\Form\FormTypeInterface the form type @@ -21,7 +23,7 @@ interface CustomFieldInterface public function buildForm(FormBuilderInterface $builder, CustomField $customField); /** - * transform the value into a format that can be stored in DB + * Transform the value into a format that can be stored in DB * * @param mixed $value * @param \Chill\CustomFieldsBundle\CustomField\CustomField $customField @@ -38,6 +40,7 @@ interface CustomFieldInterface public function deserialize($serialized, CustomField $customField); /** + * Return a repsentation of the value of the CustomField. * * @param mixed $value the raw value, **not deserialized** (= as stored in the db) * @param \Chill\CustomFieldsBundle\CustomField\CustomField $customField @@ -48,7 +51,7 @@ interface CustomFieldInterface public function getName(); /** - * return a formType which allow to edit option for the custom type. + * Return a formType which allow to edit option for the custom type. * This FormType is shown in admin * * @param \Chill\CustomFieldsBundle\CustomField\FormBuilderInterface $builder From 4f2b605efc3f867f1b075c830f64df24a08aee96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 8 Dec 2015 19:45:04 +0100 Subject: [PATCH 41/54] 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 --- CustomFields/CustomFieldNumber.php | 181 ++++++++++++++++++ Form/CustomFieldType.php | 1 + Form/Extension/PostTextExtension.php | 53 +++++ Form/Extension/PostTextIntegerExtension.php | 37 ++++ Form/Extension/PostTextNumberExtension.php | 34 ++++ Resources/config/services.yml | 18 ++ Resources/translations/messages.fr.yml | 6 + .../CustomFieldsRendering/number.html.twig | 1 + Resources/views/Form/fields.html.twig | 26 ++- Tests/CustomFields/CustomFieldsNumberTest.php | 143 ++++++++++++++ Tests/Fixtures/App/app/config/config.yml | 2 +- composer.json | 2 +- 12 files changed, 501 insertions(+), 3 deletions(-) create mode 100644 CustomFields/CustomFieldNumber.php create mode 100644 Form/Extension/PostTextExtension.php create mode 100644 Form/Extension/PostTextIntegerExtension.php create mode 100644 Form/Extension/PostTextNumberExtension.php create mode 100644 Resources/views/CustomFieldsRendering/number.html.twig create mode 100644 Tests/CustomFields/CustomFieldsNumberTest.php diff --git a/CustomFields/CustomFieldNumber.php b/CustomFields/CustomFieldNumber.php new file mode 100644 index 000000000..d880f8a17 --- /dev/null +++ b/CustomFields/CustomFieldNumber.php @@ -0,0 +1,181 @@ +, + * + * 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 . + */ + +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é + * @author Marc Ducobu + */ +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; + } + +} diff --git a/Form/CustomFieldType.php b/Form/CustomFieldType.php index 7130b8e60..9638cefca 100644 --- a/Form/CustomFieldType.php +++ b/Form/CustomFieldType.php @@ -87,6 +87,7 @@ class CustomFieldType extends AbstractType ->buildOptionsForm( $builder ->create('options', null, array('compound' => true)) + ->setRequired(false) ) ); } diff --git a/Form/Extension/PostTextExtension.php b/Form/Extension/PostTextExtension.php new file mode 100644 index 000000000..24cf4e4f4 --- /dev/null +++ b/Form/Extension/PostTextExtension.php @@ -0,0 +1,53 @@ + + * + * 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 . + */ + +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é + */ +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']; + } + } + +} diff --git a/Form/Extension/PostTextIntegerExtension.php b/Form/Extension/PostTextIntegerExtension.php new file mode 100644 index 000000000..1829501b8 --- /dev/null +++ b/Form/Extension/PostTextIntegerExtension.php @@ -0,0 +1,37 @@ + + * + * 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 . + */ + +namespace Chill\CustomFieldsBundle\Form\Extension; + +use Symfony\Component\Form\Extension\Core\Type\IntegerType; + +/** + * This class add the PostTextExtension to integer fields + * + * @author Julien Fastré + */ +class PostTextIntegerExtension extends PostTextExtension +{ + public function getExtendedType() + { + // return IntegerType::class; !! only for symfony 2.8 + return 'integer'; + } + +} diff --git a/Form/Extension/PostTextNumberExtension.php b/Form/Extension/PostTextNumberExtension.php new file mode 100644 index 000000000..5cbaeca34 --- /dev/null +++ b/Form/Extension/PostTextNumberExtension.php @@ -0,0 +1,34 @@ + + * + * 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 . + */ + +namespace Chill\CustomFieldsBundle\Form\Extension; + +/** + * This class add the PostTextExtension to number fields + * + * @author Julien Fastré + */ +class PostTextNumberExtension extends PostTextExtension +{ + public function getExtendedType() + { + return 'number'; + } + +} diff --git a/Resources/config/services.yml b/Resources/config/services.yml index 1f073c09b..4641910b2 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -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 diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index 77c13fd1c..2f4f55746 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -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 diff --git a/Resources/views/CustomFieldsRendering/number.html.twig b/Resources/views/CustomFieldsRendering/number.html.twig new file mode 100644 index 000000000..894d34fae --- /dev/null +++ b/Resources/views/CustomFieldsRendering/number.html.twig @@ -0,0 +1 @@ +{% if number is not empty %}{{ number|number_format(scale) }} {{ post|default('') }}{% endif %} diff --git a/Resources/views/Form/fields.html.twig b/Resources/views/Form/fields.html.twig index 04febae3c..b3d35ec94 100644 --- a/Resources/views/Form/fields.html.twig +++ b/Resources/views/Form/fields.html.twig @@ -94,4 +94,28 @@ {% endfor -%}
-{% endblock choice_with_other_widget %} \ No newline at end of file +{% 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-%} +
+{%- endif -%} +{{ block('form_widget') }} +{%- if post_text is defined and post_text is not empty-%} +{{ post_text }} +
+{%- 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-%} +
+{%- endif -%} +{{ block('form_widget') }} +{%- if post_text is defined and post_text is not empty-%} +{{ post_text }} +
+{%- endif -%} +{% endblock %} diff --git a/Tests/CustomFields/CustomFieldsNumberTest.php b/Tests/CustomFields/CustomFieldsNumberTest.php new file mode 100644 index 000000000..466e03ab4 --- /dev/null +++ b/Tests/CustomFields/CustomFieldsNumberTest.php @@ -0,0 +1,143 @@ + + * + * 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 . + */ + +namespace Chill\CustomFieldsBundle\Tests; + +use Chill\CustomFieldsBundle\CustomFields\CustomFieldNumber; +use Symfony\Component\Form\FormBuilderInterface; +use Chill\CustomFieldsBundle\Entity\CustomField; + +/** + * Test CustomFieldsNumber + * + * @author Julien Fastré + */ +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())); + } + + +} diff --git a/Tests/Fixtures/App/app/config/config.yml b/Tests/Fixtures/App/app/config/config.yml index 9fdeaf68d..48bd7abed 100644 --- a/Tests/Fixtures/App/app/config/config.yml +++ b/Tests/Fixtures/App/app/config/config.yml @@ -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: diff --git a/composer.json b/composer.json index 32c01e7f5..b32bfc99e 100644 --- a/composer.json +++ b/composer.json @@ -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", From 3230659a4ba77b394928aff3209cd08d4d1fc0bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 10 Dec 2015 17:16:59 +0100 Subject: [PATCH 42/54] add a required field to custom fields type ref Chill-project/Chill-CustomFields#17 --- CustomFields/CustomFieldChoice.php | 2 +- Entity/CustomField.php | 34 +++++++++++++ Form/CustomFieldType.php | 5 ++ Form/Type/CustomFieldType.php | 2 + Resources/config/doctrine/CustomField.orm.yml | 2 + .../migrations/Version20151210155904.php | 35 ++++++++++++++ Resources/translations/messages.fr.yml | 3 ++ Resources/views/CustomField/edit.html.twig | 1 + Resources/views/CustomField/new.html.twig | 1 + .../CustomFieldsGroupControllerTest.php | 5 +- Tests/CustomFields/CustomFieldsNumberTest.php | 48 +++++++++++++++++++ 11 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 Resources/migrations/Version20151210155904.php diff --git a/CustomFields/CustomFieldChoice.php b/CustomFields/CustomFieldChoice.php index 9bad639d6..6f23b6339 100644 --- a/CustomFields/CustomFieldChoice.php +++ b/CustomFields/CustomFieldChoice.php @@ -94,7 +94,7 @@ class CustomFieldChoice implements CustomFieldInterface $options = array( 'multiple' => $customFieldOptions[self::MULTIPLE], 'choices' => $choices, - 'required' => false, + 'required' => $customField->isRequired(), 'label' => $this->translatableStringHelper->localize($customField->getName())); //if allow_other = true diff --git a/Entity/CustomField.php b/Entity/CustomField.php index 2b45b498c..fe1a3bc89 100644 --- a/Entity/CustomField.php +++ b/Entity/CustomField.php @@ -60,6 +60,12 @@ class CustomField */ private $ordering; + /** + * + * @var bolean + */ + private $required = FALSE; + const ONE_TO_ONE = 1; const ONE_TO_MANY = 2; @@ -246,6 +252,34 @@ class CustomField $this->slug = $slug; return $this; } + + /** + * alias for isRequired + * + * @return boolean + */ + public function getRequired() + { + return $this->isRequired(); + } + + /** + * return true if the field required + * + * @return boolean + */ + public function isRequired() + { + return $this->required; + } + + public function setRequired($required) + { + $this->required = $required; + return $this; + } + + } diff --git a/Form/CustomFieldType.php b/Form/CustomFieldType.php index 9638cefca..1d3594718 100644 --- a/Form/CustomFieldType.php +++ b/Form/CustomFieldType.php @@ -66,6 +66,11 @@ class CustomFieldType extends AbstractType $builder ->add('ordering', 'number') + ->add('required', 'checkbox', array( + 'required' => false, + //'expanded' => TRUE, + 'label' => 'Required field' + )) ->add('type', 'hidden', array('data' => $options['type'])) ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { diff --git a/Form/Type/CustomFieldType.php b/Form/Type/CustomFieldType.php index 8a202e369..5e6ad0379 100644 --- a/Form/Type/CustomFieldType.php +++ b/Form/Type/CustomFieldType.php @@ -20,6 +20,7 @@ use Chill\CustomFieldsBundle\Service\CustomFieldProvider; use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldDataTransformer; use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; use Symfony\Component\OptionsResolver\OptionsResolver; +use Chill\CustomFieldsBundle\CustomFields\CustomFieldTitle; class CustomFieldType extends AbstractType { @@ -50,6 +51,7 @@ class CustomFieldType extends AbstractType $this->customFieldCompiler ->getCustomFieldByType($cf->getType()) ->buildForm($builder, $cf); + $builder->get($cf->getSlug())->setRequired($cf->isRequired()); } } diff --git a/Resources/config/doctrine/CustomField.orm.yml b/Resources/config/doctrine/CustomField.orm.yml index 595e96db5..5e6651158 100644 --- a/Resources/config/doctrine/CustomField.orm.yml +++ b/Resources/config/doctrine/CustomField.orm.yml @@ -22,6 +22,8 @@ Chill\CustomFieldsBundle\Entity\CustomField: type: float options: type: json_array + required: + type: boolean lifecycleCallbacks: { } manyToOne: customFieldGroup: diff --git a/Resources/migrations/Version20151210155904.php b/Resources/migrations/Version20151210155904.php new file mode 100644 index 000000000..f3d9eadf3 --- /dev/null +++ b/Resources/migrations/Version20151210155904.php @@ -0,0 +1,35 @@ +abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE customfield ADD required BOOLEAN DEFAULT FALSE'); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + // this down() migration is auto-generated, please modify it to your needs + $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE CustomField DROP required'); + + } +} diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index 2f4f55746..0c5965eb8 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -39,6 +39,9 @@ General informations: Informations générales Options: Options Custom fields group: Groupe de champ personnalisé Ordering: Ordre d'apparition +Required field: Champs requis +An answer is required: Une réponse est requise +Any answer is required: Aucune réponse n'est requise Back to the group: Retour au groupe de champs personnalisé Slug: Identifiant textuel The custom field has been created: Le champ personnalisé est créé diff --git a/Resources/views/CustomField/edit.html.twig b/Resources/views/CustomField/edit.html.twig index 08fbed2ce..019a02d95 100644 --- a/Resources/views/CustomField/edit.html.twig +++ b/Resources/views/CustomField/edit.html.twig @@ -29,6 +29,7 @@ {{ form_row(edit_form.customFieldsGroup) }} {% endif %} {{ form_row(edit_form.ordering) }} + {{ form_row(edit_form.required) }} {% if edit_form.options is not empty %}

{{ 'Options'|trans }}

{% for option in edit_form.options %} diff --git a/Resources/views/CustomField/new.html.twig b/Resources/views/CustomField/new.html.twig index 783cbb1d6..d06ee0cc3 100644 --- a/Resources/views/CustomField/new.html.twig +++ b/Resources/views/CustomField/new.html.twig @@ -30,6 +30,7 @@ {{ form_row(form.customFieldsGroup) }} {% endif %} {{ form_row(form.ordering) }} + {{ form_row(form.required) }} {% if form.options is not empty %}

{{ 'Options'|trans }}

{% for option in form.options %} diff --git a/Tests/Controller/CustomFieldsGroupControllerTest.php b/Tests/Controller/CustomFieldsGroupControllerTest.php index b6bc3bbee..420c4bf4c 100644 --- a/Tests/Controller/CustomFieldsGroupControllerTest.php +++ b/Tests/Controller/CustomFieldsGroupControllerTest.php @@ -51,7 +51,10 @@ class CustomFieldsGroupControllerTest extends WebTestCase private function editCustomFieldsGroup(Client $client) { $crawler = $client->request('GET', '/fr/admin/customfieldsgroup/'); - $crawler = $client->click($crawler->selectLink('modifier')->link()); + $links = $crawler->selectLink('modifier'); + $crawler = $client->click($links->last()->link()); + + $this->assertEquals(200, $client->getResponse()->getStatusCode()); $form = $crawler->selectButton('Update')->form(array( 'custom_fields_group[name][fr]' => 'Foo', diff --git a/Tests/CustomFields/CustomFieldsNumberTest.php b/Tests/CustomFields/CustomFieldsNumberTest.php index 466e03ab4..fb4d44a26 100644 --- a/Tests/CustomFields/CustomFieldsNumberTest.php +++ b/Tests/CustomFields/CustomFieldsNumberTest.php @@ -22,6 +22,8 @@ namespace Chill\CustomFieldsBundle\Tests; use Chill\CustomFieldsBundle\CustomFields\CustomFieldNumber; use Symfony\Component\Form\FormBuilderInterface; use Chill\CustomFieldsBundle\Entity\CustomField; +use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; +use Chill\CustomFieldsBundle\Form\CustomFieldsGroupType; /** * Test CustomFieldsNumber @@ -139,5 +141,51 @@ class CustomFieldsNumberTest extends \Symfony\Bundle\FrameworkBundle\Test\WebTes $this->assertEquals(1, count($form['default']->getErrors())); } + public function testRequiredFieldIsFalse() + { + $cf = $this->createCustomFieldNumber(array( + 'min' => 1000, + 'max' => null, + 'scale' => null, + 'post_text' => null + )); + $cf->setRequired(false); + + $cfGroup = (new \Chill\CustomFieldsBundle\Entity\CustomFieldsGroup()) + ->addCustomField($cf); + + $form = static::$kernel->getContainer()->get('form.factory') + ->createBuilder('custom_field', array(), array( + 'group' => $cfGroup + )) + ->getForm(); + + $this->assertFalse($form['default']->isRequired(), + "The field should not be required"); + } + + public function testRequiredFieldIsTrue() + { + $cf = $this->createCustomFieldNumber(array( + 'min' => 1000, + 'max' => null, + 'scale' => null, + 'post_text' => null + )); + $cf->setRequired(true); + + $cfGroup = (new \Chill\CustomFieldsBundle\Entity\CustomFieldsGroup()) + ->addCustomField($cf); + + $form = static::$kernel->getContainer()->get('form.factory') + ->createBuilder('custom_field', array(), array( + 'group' => $cfGroup + )) + ->getForm(); + + $this->assertTrue($form['default']->isRequired(), + "The field should be required"); + } + } From 4f13ec69597f525547b7a5fb3f6ffaa9e4fd76d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 11 Dec 2015 10:50:39 +0100 Subject: [PATCH 43/54] add a custom field long choice basic The `custom field long choice` aim to provide a way to deal with choices with a big possibilities. The `custom field long choice` allow : - to persist different options in the database ; - each option has a key, a text (translatable string), and eventually a parent, and an internal_key - every key can be activate or not. If the parent is inactivated, all childs are inactivated - the internal key have two purposes : - link to an external csv file, with their own key ; - add a special class to results, to allow custom layout. Currently, the field exists, but some elements are missing : - a script for CSV import - possibility to select multiple items - edition of options - handle of option without parents - tests are missing --- CustomFields/CustomFieldLongChoice.php | 156 ++++++++++++++++ DataFixtures/ORM/LoadOption.php | 172 ++++++++++++++++++ Entity/CustomFieldLongChoice/Option.php | 153 ++++++++++++++++ .../OptionRepository.php | 77 ++++++++ .../CustomFieldLongChoice.Option.orm.yml | 33 ++++ Resources/config/services.yml | 18 +- .../migrations/Version20151210205610.php | 47 +++++ Resources/translations/messages.fr.yml | 3 + .../choice_long.html.twig | 11 ++ composer.json | 5 +- 10 files changed, 672 insertions(+), 3 deletions(-) create mode 100644 CustomFields/CustomFieldLongChoice.php create mode 100644 DataFixtures/ORM/LoadOption.php create mode 100644 Entity/CustomFieldLongChoice/Option.php create mode 100644 EntityRepository/CustomFieldLongChoice/OptionRepository.php create mode 100644 Resources/config/doctrine/CustomFieldLongChoice.Option.orm.yml create mode 100644 Resources/migrations/Version20151210205610.php create mode 100644 Resources/views/CustomFieldsRendering/choice_long.html.twig diff --git a/CustomFields/CustomFieldLongChoice.php b/CustomFields/CustomFieldLongChoice.php new file mode 100644 index 000000000..a66de9dc2 --- /dev/null +++ b/CustomFields/CustomFieldLongChoice.php @@ -0,0 +1,156 @@ + + * + * 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 . + */ + +namespace Chill\CustomFieldsBundle\CustomFields; + +use Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface; +use Symfony\Component\Form\FormBuilderInterface; +use Chill\CustomFieldsBundle\Entity\CustomField; +use Chill\CustomFieldsBundle\EntityRepository\CustomFieldLongChoice\OptionRepository; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option; +use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldDataTransformer; +use Symfony\Bridge\Twig\TwigEngine; + +/** + * + * + * @author Julien Fastré + */ +class CustomFieldLongChoice implements CustomFieldInterface +{ + /** + * + * @var OptionRepository + */ + private $optionRepository; + + /** + * + * @var TranslatableStringHelper + */ + private $translatableStringHelper; + + /** + * @var TwigEngine + */ + private $templating; + + const KEY = 'key'; + + public function __construct(OptionRepository $optionRepository, + TranslatableStringHelper $translatableStringHelper, + TwigEngine $twigEngine) + { + $this->optionRepository = $optionRepository; + $this->translatableStringHelper = $translatableStringHelper; + $this->templating = $twigEngine; + } + + public function buildForm(FormBuilderInterface $builder, CustomField $customField) + { + $options = $customField->getOptions(); + $entries = $this->optionRepository->findFilteredByKey($options[self::KEY], + false, true); + //create a local copy of translatable string helper + $translatableStringHelper = $this->translatableStringHelper; + $builder->add($customField->getSlug(), 'select2_choice', array( + 'choices' => $entries, + 'choice_label' => function(Option $option) use ($translatableStringHelper) { + return $translatableStringHelper->localize($option->getText()); + }, + 'choice_value' => function ($key) use ($entries) { + if ($key === NULL) { + return null; + } + return $key->getId(); + }, + 'choices_as_values' => true, + 'multiple' => false, + 'expanded' => false, + 'group_by' => function(Option $option) use ($translatableStringHelper) { + if ($option->hasParent()) { + return $translatableStringHelper->localize($option->getParent()->getText()); + } else { + return $translatableStringHelper->localize($option->getText()); + } + }, + 'label' => $translatableStringHelper->localize($customField->getName()) + )); + $builder->get($customField->getSlug()) + ->addModelTransformer(new CustomFieldDataTransformer($this, $customField)); + + } + + public function buildOptionsForm(FormBuilderInterface $builder) + { + //create a selector between different keys + $keys = $this->optionRepository->getKeys(); + $choices = array(); + foreach ($keys as $key) { + $choices[$key] = $key; + } + + return $builder->add(self::KEY, 'choice', array( + 'choices' => $choices, + 'label' => 'Options key' + )); + + } + + public function deserialize($serialized, \Chill\CustomFieldsBundle\Entity\CustomField $customField) + { + if ($serialized === NULL) { + return NULL; + } + + + return $this->optionRepository->find($serialized); + } + + public function getName() + { + return 'Long Choice'; + } + + public function render($value, \Chill\CustomFieldsBundle\Entity\CustomField $customField, $documentType = 'html') + { + $option = $this->deserialize($value, $customField); + $template = 'ChillCustomFieldsBundle:CustomFieldsRendering:choice_long.' + .$documentType.'.twig'; + + return $this->templating + ->render($template, array( + 'values' => array($option) + )); + } + + public function serialize($value, \Chill\CustomFieldsBundle\Entity\CustomField $customField) + { + if (!$value instanceof Option) { + throw new \LogicException('the value should be an instance of ' + . 'Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option, ' + . is_object($value) ? get_class($value) : gettype($value).' given'); + } + + // we place the id in array, to allow in the future multiple select + return $value->getId(); + } + +} diff --git a/DataFixtures/ORM/LoadOption.php b/DataFixtures/ORM/LoadOption.php new file mode 100644 index 000000000..9dd9a5aaf --- /dev/null +++ b/DataFixtures/ORM/LoadOption.php @@ -0,0 +1,172 @@ + + * + * 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 . + */ + +namespace Chill\CustomFieldsBundle\DataFixtures\ORM; + +use Doctrine\Common\DataFixtures\AbstractFixture; +use Doctrine\Common\DataFixtures\OrderedFixtureInterface; +use Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option; + +/** + * Load some Options + * + * + * @author Julien Fastré + */ +class LoadOption extends AbstractFixture implements OrderedFixtureInterface +{ + /** + * + * @var \Faker\Generator + */ + public $fakerFr; + + /** + * + * @var \Faker\Generator + */ + public $fakerEn; + + /** + * + * @var \Faker\Generator + */ + public $fakerNl; + + public function __construct() + { + $this->fakerFr = \Faker\Factory::create('fr_FR'); + $this->fakerEn = \Faker\Factory::create('en_EN'); + $this->fakerNl = \Faker\Factory::create('nl_NL'); + } + + public function getOrder() + { + return 1000; + } + + public function load(\Doctrine\Common\Persistence\ObjectManager $manager) + { + echo "Loading Options \n"; + // load companies + $this->loadingCompanies($manager); + $this->loadingWords($manager); + + + $manager->flush(); + + } + + private function loadingWords(\Doctrine\Common\Persistence\ObjectManager $manager) + { + echo "Loading some words...\n"; + + $parents = array( + array( + 'fr' => 'Categorie 1', + 'nl' => 'Categorie 1', + 'en' => 'Category 1' + ), + array( + 'fr' => 'Categorie 2', + 'nl' => 'Categorie 2', + 'en' => 'Category 2' + ) + ); + + foreach ($parents as $text) { + $parent = (new Option()) + ->setText($text) + ->setKey('word') + ; + $manager->persist($parent); + //Load children + $expected_nb_children = rand(10, 50); + for ($i=0; $i < $expected_nb_children; $i++) { + $manager->persist($this->createChildOption($parent, array( + 'fr' => $this->fakerFr->word, + 'nl' => $this->fakerNl->word, + 'en' => $this->fakerEn->word + ))); + } + } + } + + private function loadingCompanies(\Doctrine\Common\Persistence\ObjectManager $manager) + { + echo "Loading companies \n"; + $companiesParents = array( + array( + 'fr' => 'Grandes Entreprises', + 'nl' => 'Grotes Bedrijven', + 'en' => 'Big Companies' + ), + array( + 'fr' => 'Moyennes Entreprises', + 'nl' => 'Middelbare Bedrijven', + 'en' => 'Middle Companies' + ), + array( + 'fr' => 'Petites Entreprises', + 'nl' => 'Kleine Bedrijven', + 'en' => 'Little Companies' + ) + ); + + + foreach ($companiesParents as $text) { + $parent = (new Option()) + ->setText($text) + ->setKey('company') + ; + $manager->persist($parent); + //Load children + $expected_nb_children = rand(10, 50); + for ($i=0; $i < $expected_nb_children; $i++) { + $companyName = $this->fakerFr->company; + $manager->persist($this->createChildOption($parent, array( + 'fr' => $companyName, + 'nl' => $companyName, + 'en' => $companyName + ))); + } + } + } + + private $counter = 0; + + /** + * + * @param Option $parent + * @param array $text + * @return Option + */ + private function createChildOption(Option $parent, array $text) + { + $this->counter ++; + + return (new Option()) + ->setText($text) + ->setParent($parent) + ->setActive(true) + ->setInternalKey($parent->getKey().'-'.$this->counter); + ; + } + +} diff --git a/Entity/CustomFieldLongChoice/Option.php b/Entity/CustomFieldLongChoice/Option.php new file mode 100644 index 000000000..9037ee117 --- /dev/null +++ b/Entity/CustomFieldLongChoice/Option.php @@ -0,0 +1,153 @@ + + * + * 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 . + */ + +namespace Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice; + +/** + * + * + * @author Julien Fastré + */ +class Option +{ + /** + * + * @var int + */ + private $id; + + /** + * + * @var string + */ + private $key; + + /** + * a json representation of text (multilingual) + * + * @var array + */ + private $text; + + /** + * + * @var \Doctrine\Common\Collections\Collection + */ + private $children; + + /** + * + * @var Option + */ + private $parent; + + /** + * + * @var string + */ + private $internalKey = ''; + + /** + * + * @var boolean + */ + private $active = true; + + public function getId() + { + return $this->id; + } + + public function getKey() + { + return $this->key; + } + + public function getText() + { + return $this->text; + } + + public function getChildren() + { + return $this->children; + } + + public function getParent() + { + return $this->parent; + } + + public function setKey($key) + { + $this->key = $key; + return $this; + } + + public function setText(array $text) + { + $this->text = $text; + return $this; + } + + public function setParent(Option $parent = null) + { + $this->parent = $parent; + $this->key = $parent->getKey(); + return $this; + } + + /** + * + * @return boolean + */ + public function hasParent() + { + return $this->parent === NULL ? false : true; + } + + public function getInternalKey() + { + return $this->internalKey; + } + + public function isActive() + { + return $this->active; + } + + public function getActive() + { + return $this->isActive(); + } + + public function setInternalKey($internal_key) + { + $this->internalKey = $internal_key; + return $this; + } + + public function setActive($active) + { + $this->active = $active; + return $this; + } + + +} diff --git a/EntityRepository/CustomFieldLongChoice/OptionRepository.php b/EntityRepository/CustomFieldLongChoice/OptionRepository.php new file mode 100644 index 000000000..58f8ee302 --- /dev/null +++ b/EntityRepository/CustomFieldLongChoice/OptionRepository.php @@ -0,0 +1,77 @@ + + * + * 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 . + */ + +namespace Chill\CustomFieldsBundle\EntityRepository\CustomFieldLongChoice; + +use Doctrine\ORM\EntityRepository; +use Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option; + +/** + * + * + * @author Julien Fastré + */ +class OptionRepository extends EntityRepository +{ + /** + * + * @param string $key + * @return Option[] + */ + public function findFilteredByKey($key, $includeParents = true, $active = true) + { + $qb = $this->createQueryBuilder('option'); + $qb->where('option.key = :key'); + + if ($active === true){ + $qb->andWhere('option.active = true'); + } + + if ($includeParents === false) { + $qb->andWhere('option.parent IS NOT NULL'); + + if ($active === TRUE) { + $qb->join('option.parent', 'p'); + $qb->andWhere('p.active = true'); + } + } + + $qb->setParameter('key', $key); + + return $qb->getQuery()->getResult(); + } + + /** + * + * @return string[] + */ + public function getKeys() + { + $keys = $this->createQueryBuilder('option') + ->select('option.key') + ->distinct() + ->getQuery() + ->getScalarResult(); + + return array_map(function($r) { + return $r['key']; + }, $keys); + } + +} diff --git a/Resources/config/doctrine/CustomFieldLongChoice.Option.orm.yml b/Resources/config/doctrine/CustomFieldLongChoice.Option.orm.yml new file mode 100644 index 000000000..3d0b8fbdc --- /dev/null +++ b/Resources/config/doctrine/CustomFieldLongChoice.Option.orm.yml @@ -0,0 +1,33 @@ +Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option: + type: entity + table: custom_field_long_choice_options + repositoryClass: Chill\CustomFieldsBundle\EntityRepository\CustomFieldLongChoice\OptionRepository + id: + id: + type: integer + id: true + generator: + strategy: AUTO + fields: + key: + type: string + length: 15 + text: + type: json_array + internalKey: + type: string + length: 50 + column: internal_key + active: + type: boolean + default: true + oneToMany: + children: + targetEntity: Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option + mappedBy: parent + manyToOne: + parent: + targetEntity: Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option + inversedBy: children + nullable: true + \ No newline at end of file diff --git a/Resources/config/services.yml b/Resources/config/services.yml index 4641910b2..e2c971c75 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -107,4 +107,20 @@ services: calls: - [setContainer, ["@service_container"]] tags: - - { name: twig.extension } \ No newline at end of file + - { name: twig.extension } + + chill.custom_field.custom_field_long_choice: + class: Chill\CustomFieldsBundle\CustomFields\CustomFieldLongChoice + arguments: + - "@chill.custom_field.custom_field_long_choice_option_repository" + - "@chill.main.helper.translatable_string" + - "@templating" + tags: + - { name: 'chill.custom_field', type: 'long_choice' } + + chill.custom_field.custom_field_long_choice_option_repository: + class: Chill\CustomFieldsBundle\EntityRepository\CustomFieldLongChoice\OptionRepository + factory: ["@doctrine", getRepository] + arguments: + - "Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option" + \ No newline at end of file diff --git a/Resources/migrations/Version20151210205610.php b/Resources/migrations/Version20151210205610.php new file mode 100644 index 000000000..01cb61728 --- /dev/null +++ b/Resources/migrations/Version20151210205610.php @@ -0,0 +1,47 @@ +abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('CREATE SEQUENCE custom_field_long_choice_options_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE TABLE custom_field_long_choice_options (id INT NOT NULL, ' + . 'parent_id INT DEFAULT NULL, ' + . 'key VARCHAR(15) NOT NULL, ' + . 'text jsonb NOT NULL, ' + . 'active boolean NOT NULL,' + . 'internal_key VARCHAR(50) NOT NULL DEFAULT \'\', ' + . 'PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_14BBB8E0727ACA70 ON custom_field_long_choice_options (parent_id)'); + $this->addSql('ALTER TABLE custom_field_long_choice_options ADD CONSTRAINT cf_long_choice_self_referencing ' + . 'FOREIGN KEY (parent_id) REFERENCES custom_field_long_choice_options (id) ' + . 'NOT DEFERRABLE INITIALLY IMMEDIATE'); + + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + // this down() migration is auto-generated, please modify it to your needs + $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE custom_field_long_choice_options DROP CONSTRAINT cf_long_choice_self_referencing'); + $this->addSql('DROP SEQUENCE custom_field_long_choice_options_id_seq CASCADE'); + $this->addSql('DROP TABLE custom_field_long_choice_options'); + } +} diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index 0c5965eb8..f77f08028 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -84,3 +84,6 @@ 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 + +#custom field long choice +Options key: Clé des options diff --git a/Resources/views/CustomFieldsRendering/choice_long.html.twig b/Resources/views/CustomFieldsRendering/choice_long.html.twig new file mode 100644 index 000000000..6849f1d0c --- /dev/null +++ b/Resources/views/CustomFieldsRendering/choice_long.html.twig @@ -0,0 +1,11 @@ +{% if values|length > 0 %} +
    + {%- for value in values -%} +
  • +  {{ value.text|localize_translatable_string }} +
  • + {%- endfor -%} +
+{% else %} +
{{ 'None'|trans }}
+{% endif %} \ No newline at end of file diff --git a/composer.json b/composer.json index 68f716242..9c1240b5a 100644 --- a/composer.json +++ b/composer.json @@ -34,8 +34,9 @@ "chill-project/main": "dev-master" }, "require-dev": { - "doctrine/doctrine-fixtures-bundle": "~2.2@dev", - "chill-project/person": "dev-master@dev" + "chill-project/person": "dev-master@dev", + "fzaninotto/faker": "~1", + "doctrine/doctrine-fixtures-bundle": "~2.2" }, "scripts": { "post-install-cmd": [ From 9ca2be78eb7e27df4643b41333d6380c4b7e3887 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 15 Dec 2015 10:06:05 +0100 Subject: [PATCH 44/54] use localize translatable string function to render label widget --- Resources/views/CustomField/render_label.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/views/CustomField/render_label.html.twig b/Resources/views/CustomField/render_label.html.twig index bf4b186fc..05bc19cc3 100644 --- a/Resources/views/CustomField/render_label.html.twig +++ b/Resources/views/CustomField/render_label.html.twig @@ -1 +1 @@ -{{ customField.name(app.request.locale) }} \ No newline at end of file +{{ customField.name|localize_translatable_string }} \ No newline at end of file From fe73a64e9d19d5bab09164331ed61cbc5c53a51c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 15 Dec 2015 11:11:36 +0100 Subject: [PATCH 45/54] Add possibility to hide empty value in customfield group view rendering A new parameter is defined : ``` chill_custom_fields: show_empty_values_in_views = true|false ``` A new method is added to CustomFieldInterface: `isEmptyValue`. To ease the dev of new classes, an AbstractCustomField class is created, which implements the most commons function (currently, only isEmptyValue). A new Twig Filter is added: `chill_custom_field_is_empty` The twig filter `chill_custom_fields_group_widget` has a new possibility in array option : `show_empty`. Default to chill_custom_fields.show_empty_values_in_view. May be forced by true/false. --- CustomFields/AbstractCustomField.php | 37 ++++++++++++++++++ CustomFields/CustomFieldChoice.php | 7 +++- CustomFields/CustomFieldInterface.php | 8 ++++ CustomFields/CustomFieldLongChoice.php | 2 +- CustomFields/CustomFieldNumber.php | 2 +- CustomFields/CustomFieldText.php | 2 +- CustomFields/CustomFieldTitle.php | 7 +++- .../ChillCustomFieldsExtension.php | 2 + DependencyInjection/Configuration.php | 38 +++++++++++-------- Resources/config/services.yml | 2 + .../views/CustomFieldsGroup/render.html.twig | 4 +- Service/CustomFieldsHelper.php | 18 +++++++-- Templating/Twig/CustomFieldRenderingTwig.php | 11 ++++++ .../Twig/CustomFieldsGroupRenderingTwig.php | 18 +++++++-- 14 files changed, 131 insertions(+), 27 deletions(-) create mode 100644 CustomFields/AbstractCustomField.php diff --git a/CustomFields/AbstractCustomField.php b/CustomFields/AbstractCustomField.php new file mode 100644 index 000000000..ddd019176 --- /dev/null +++ b/CustomFields/AbstractCustomField.php @@ -0,0 +1,37 @@ + + * + * 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 . + */ + +namespace Chill\CustomFieldsBundle\CustomFields; + +use Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface; +use Chill\CustomFieldsBundle\Entity\CustomField; + +/** + * + * + * @author Julien Fastré + */ +abstract class AbstractCustomField implements CustomFieldInterface +{ + public function isEmptyValue($value, CustomField $customField) + { + return (empty($value) and $value !== FALSE); + } + +} diff --git a/CustomFields/CustomFieldChoice.php b/CustomFields/CustomFieldChoice.php index 6f23b6339..8b0d0f647 100644 --- a/CustomFields/CustomFieldChoice.php +++ b/CustomFields/CustomFieldChoice.php @@ -38,7 +38,7 @@ use Symfony\Component\Translation\Translator; * @author Julien Fastré * @author Marc Ducobu */ -class CustomFieldChoice implements CustomFieldInterface +class CustomFieldChoice extends AbstractCustomField { const ALLOW_OTHER = 'other'; const OTHER_VALUE_LABEL = 'otherValueLabel'; @@ -174,6 +174,11 @@ class CustomFieldChoice implements CustomFieldInterface { return 'Choices'; } + + public function isEmptyValue($value, CustomField $customField) + { + return $value['_choices'] === NULL; + } /** * diff --git a/CustomFields/CustomFieldInterface.php b/CustomFields/CustomFieldInterface.php index 994172e41..ce341142d 100644 --- a/CustomFields/CustomFieldInterface.php +++ b/CustomFields/CustomFieldInterface.php @@ -58,4 +58,12 @@ interface CustomFieldInterface * @return \Symfony\Component\Form\FormTypeInterface|null the form type */ public function buildOptionsForm(FormBuilderInterface $builder); + + /** + * Return if the value can be considered as empty + * + * @param mixed $value the value passed throug the deserialize function + * @param CustomField $customField + */ + public function isEmptyValue($value, CustomField $customField); } diff --git a/CustomFields/CustomFieldLongChoice.php b/CustomFields/CustomFieldLongChoice.php index a66de9dc2..58285d132 100644 --- a/CustomFields/CustomFieldLongChoice.php +++ b/CustomFields/CustomFieldLongChoice.php @@ -33,7 +33,7 @@ use Symfony\Bridge\Twig\TwigEngine; * * @author Julien Fastré */ -class CustomFieldLongChoice implements CustomFieldInterface +class CustomFieldLongChoice extends AbstractCustomField { /** * diff --git a/CustomFields/CustomFieldNumber.php b/CustomFields/CustomFieldNumber.php index d880f8a17..b87dfe685 100644 --- a/CustomFields/CustomFieldNumber.php +++ b/CustomFields/CustomFieldNumber.php @@ -39,7 +39,7 @@ use Chill\MainBundle\Templating\TranslatableStringHelper; * @author Julien Fastré * @author Marc Ducobu */ -class CustomFieldNumber implements CustomFieldInterface +class CustomFieldNumber extends AbstractCustomField { /** * key for the minimal value of the field diff --git a/CustomFields/CustomFieldText.php b/CustomFields/CustomFieldText.php index a11705707..c2189bb88 100644 --- a/CustomFields/CustomFieldText.php +++ b/CustomFields/CustomFieldText.php @@ -33,7 +33,7 @@ use Chill\MainBundle\Templating\TranslatableStringHelper; * @author Julien Fastré * @author Marc Ducobu */ -class CustomFieldText implements CustomFieldInterface +class CustomFieldText extends AbstractCustomField { private $requestStack; diff --git a/CustomFields/CustomFieldTitle.php b/CustomFields/CustomFieldTitle.php index 6c15543eb..23f9f5e2b 100644 --- a/CustomFields/CustomFieldTitle.php +++ b/CustomFields/CustomFieldTitle.php @@ -28,7 +28,7 @@ use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Bundle\TwigBundle\TwigEngine; use Chill\MainBundle\Templating\TranslatableStringHelper; -class CustomFieldTitle implements CustomFieldInterface +class CustomFieldTitle extends AbstractCustomField { const TYPE = 'type'; const TYPE_TITLE = 'title'; @@ -92,6 +92,11 @@ class CustomFieldTitle implements CustomFieldInterface { return 'title'; } + + public function isEmptyValue($value, CustomField $customField) + { + return false; + } public function buildOptionsForm(FormBuilderInterface $builder) { diff --git a/DependencyInjection/ChillCustomFieldsExtension.php b/DependencyInjection/ChillCustomFieldsExtension.php index 3aaab5933..05c4108e4 100644 --- a/DependencyInjection/ChillCustomFieldsExtension.php +++ b/DependencyInjection/ChillCustomFieldsExtension.php @@ -33,6 +33,8 @@ class ChillCustomFieldsExtension extends Extension implements PrependExtensionIn $container->setParameter('chill_custom_fields.customizables_entities', $config['customizables_entities']); + $container->setParameter('chill_custom_fields.show_empty_values', + $config['show_empty_values_in_views']); } /* (non-PHPdoc) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 232a1a9a2..84c2147bb 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -35,27 +35,35 @@ class Configuration implements ConfigurationInterface ->defaultValue(array()) ->prototype('array') ->children() - ->scalarNode('class')->isRequired()->info($classInfo)->end() - ->scalarNode('name') ->isRequired()->info($nameInfo) ->end() + ->scalarNode('class')->isRequired()->info($classInfo) + ->end() + ->scalarNode('name') ->isRequired()->info($nameInfo) + ->end() ->arrayNode('options') - ->info($optionsInfo) - ->defaultValue(array()) - ->useAttributeAsKey('key') - ->prototype('array') - ->children() - ->scalarNode('form_type') - ->isRequired() - ->info($optionsFormType) - ->end() - ->variableNode('form_options') - ->info($optionsFormOptionsInfos) - ->defaultValue(array()) - ->end() + ->info($optionsInfo) + ->defaultValue(array()) + ->useAttributeAsKey('key') + ->prototype('array') + ->children() + ->scalarNode('form_type') + ->isRequired() + ->info($optionsFormType) ->end() + ->variableNode('form_options') + ->info($optionsFormOptionsInfos) + ->defaultValue(array()) + ->end() + ->end() ->end() ->end() ->end() ->end() + ->end() + ->booleanNode('show_empty_values_in_views') + ->info('Show the empty value for custom fields in the views, timeline, ...') + ->defaultValue(true) + ->end() + ->end() ; return $treeBuilder; diff --git a/Resources/config/services.yml b/Resources/config/services.yml index e2c971c75..1e03b8bf2 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -106,6 +106,8 @@ services: class: Chill\CustomFieldsBundle\Templating\Twig\CustomFieldsGroupRenderingTwig calls: - [setContainer, ["@service_container"]] + arguments: + - "%chill_custom_fields.show_empty_values%" tags: - { name: twig.extension } diff --git a/Resources/views/CustomFieldsGroup/render.html.twig b/Resources/views/CustomFieldsGroup/render.html.twig index a63183233..e325432a0 100644 --- a/Resources/views/CustomFieldsGroup/render.html.twig +++ b/Resources/views/CustomFieldsGroup/render.html.twig @@ -2,7 +2,9 @@ {% if customField.type == 'title' %} {{ chill_custom_field_widget(cFData , customField) }} {% else %} + {%- if show_empty == true or (chill_custom_field_is_empty(customField, cFData) == false) -%}
{{ chill_custom_field_label(customField) }}
{{ chill_custom_field_widget(cFData , customField) }}
- {% endif %} + {%- endif -%} + {%- endif -%} {% endfor %} \ No newline at end of file diff --git a/Service/CustomFieldsHelper.php b/Service/CustomFieldsHelper.php index 477c190ad..07c8c4f04 100644 --- a/Service/CustomFieldsHelper.php +++ b/Service/CustomFieldsHelper.php @@ -137,6 +137,17 @@ class CustomFieldsHelper : null; } + public function isEmptyValue(array $fields, $classOrCustomField, $slug = null) + { + $customField = ($classOrCustomField instanceof CustomField) ? $classOrCustomField : $this->getCustomField($classOrCustomField, $slug); + $slug = $customField->getSlug(); + $rawValue = (isset($fields[$slug])) ? $fields[$slug] : null; + + $customFieldType = $this->provider->getCustomFieldByType($customField->getType()); + + return $customFieldType->isEmptyValue($rawValue, $customField); + } + /** * Render the value of a custom field * @@ -144,16 +155,17 @@ class CustomFieldsHelper * @param CustomField|object|string $classOrCustomField the object OR the get_class($object) string OR The CustomField * @param string $documentType The type of document in which the rendered value is displayed ('html' or 'csv'). * @param string $slug The slug of the custom field to render. + * @param boolean $showIfEmpty If the widget must be rendered if the value is empty. An empty value is all values described as http://php.net/manual/fr/function.empty.php, except `FALSE` * @throws CustomFieldsHelperException if slug is missing * @return The representation of the value the customField. */ - public function renderCustomField(array $fields, $classOrCustomField, $documentType='html', $slug = null) + public function renderCustomField(array $fields, $classOrCustomField, $documentType='html', $slug = null, $showIfEmpty = true) { $customField = ($classOrCustomField instanceof CustomField) ? $classOrCustomField : $this->getCustomField($classOrCustomField, $slug); $slug = $customField->getSlug(); $rawValue = (isset($fields[$slug])) ? $fields[$slug] : null; + $customFieldType = $this->provider->getCustomFieldByType($customField->getType()); - return $this->provider->getCustomFieldByType($customField->getType()) - ->render($rawValue, $customField, $documentType); + return $customFieldType->render($rawValue, $customField, $documentType); } } \ No newline at end of file diff --git a/Templating/Twig/CustomFieldRenderingTwig.php b/Templating/Twig/CustomFieldRenderingTwig.php index be155abe3..8561d26f8 100644 --- a/Templating/Twig/CustomFieldRenderingTwig.php +++ b/Templating/Twig/CustomFieldRenderingTwig.php @@ -76,10 +76,21 @@ class CustomFieldRenderingTwig extends \Twig_Extension implements ContainerAware 'is_safe' => array( 'html' ) + )), + new \Twig_SimpleFunction('chill_custom_field_is_empty', array( + $this, + 'isEmptyValue' )) ]; } + + public function isEmptyValue($customFieldorClass, $fields, $slug = null) + { + return $this->container->get('chill.custom_field.helper') + ->isEmptyValue($fields, $customFieldorClass); + } + /* (non-PHPdoc) * @see Twig_ExtensionInterface::getName() */ diff --git a/Templating/Twig/CustomFieldsGroupRenderingTwig.php b/Templating/Twig/CustomFieldsGroupRenderingTwig.php index af6dbb585..a6b9305c0 100644 --- a/Templating/Twig/CustomFieldsGroupRenderingTwig.php +++ b/Templating/Twig/CustomFieldsGroupRenderingTwig.php @@ -37,15 +37,25 @@ use Chill\CustomFieldsBundle\Entity\CustomField; */ class CustomFieldsGroupRenderingTwig extends \Twig_Extension implements ContainerAwareInterface { - + /** @var Container $container The container */ private $container; /** @var array $defaultParams The default parameters */ private $defaultParams = array( - 'layout' => 'ChillCustomFieldsBundle:CustomFieldsGroup:render.html.twig' + 'layout' => 'ChillCustomFieldsBundle:CustomFieldsGroup:render.html.twig', + 'show_empty' => True ); + /** + * + * @param boolean $showEmptyValues whether the empty values must be rendered + */ + public function __construct($showEmptyValues) + { + $this->defaultParams['show_empty'] = $showEmptyValues; + } + /* * (non-PHPdoc) * @see \Symfony\Component\DependencyInjection\ContainerAwareInterface::setContainer() @@ -92,6 +102,7 @@ class CustomFieldsGroupRenderingTwig extends \Twig_Extension implements Containe * @param array $params The parameters for rendering : * - layout : allow to choose a different layout by default : * ChillCustomFieldsBundle:CustomFieldsGroup:render.html.twig + * - show_empty : force show empty field * @return string HTML representation of the custom field group value, as described in * the CustomFieldInterface. Is HTML safe */ @@ -102,6 +113,7 @@ class CustomFieldsGroupRenderingTwig extends \Twig_Extension implements Containe return $this->container->get('templating') ->render($resolvedParams['layout'], array( 'cFGroup' => $customFielsGroup, - 'cFData' => $fields)); + 'cFData' => $fields, + 'show_empty' => $resolvedParams['show_empty'])); } } \ No newline at end of file From 0a1898e9a78882a29ce7d4b9a5fa60bc0609252c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 16 Dec 2015 20:25:40 +0100 Subject: [PATCH 46/54] take into account the different type of choices in empty value --- CustomFields/CustomFieldChoice.php | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/CustomFields/CustomFieldChoice.php b/CustomFields/CustomFieldChoice.php index 8b0d0f647..a34968db3 100644 --- a/CustomFields/CustomFieldChoice.php +++ b/CustomFields/CustomFieldChoice.php @@ -177,7 +177,35 @@ class CustomFieldChoice extends AbstractCustomField public function isEmptyValue($value, CustomField $customField) { - return $value['_choices'] === NULL; + if ($value === NULL) { + return true; + } + + // if only one choice... + if (is_string($value)) { + return empty($value); + } + + // if multiple choice OR multiple/single choice with other + if (is_array($value)) + { + // if allow other + if (isset($value['_choices'])) { + if ($value['_choices'] === NULL) { + return true; + } + if (is_string($value['_choices'])) { + return empty($value); + } + if (is_array($value['_choices'])){ + return count($value['_choices']) > 0; + } + } else { // we do not have 'allow other' + return count($value) > .0; + } + } + + throw \LogicException("This case is not expected."); } /** From 9c622bc852664c2f039d50e85d28f9068d2ffb24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 17 Dec 2015 07:41:16 +0100 Subject: [PATCH 47/54] improve cfgroup rendering to show title only if necessary If the value `chill_custom_fields.show_empty_values_in_views` is false, the title is shown only if a field has been filled "below" the title. --- Resources/translations/messages.fr.yml | 4 ++ .../views/CustomFieldsGroup/render.html.twig | 39 +++++++++++++++++-- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index f77f08028..bf29b6e7b 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -2,6 +2,10 @@ 'Other value': 'Autre valeur' 'None': 'Pas spécifié' +#customfieldsgroup rendering +Empty data: Données vides +No data to show: Pas de valeurs à afficher + #customfieldsgroup administration CustomFieldsGroup list: Groupes de champs personnalisés CustomFieldsGroup creation: Nouveau groupe de champs personnalisés diff --git a/Resources/views/CustomFieldsGroup/render.html.twig b/Resources/views/CustomFieldsGroup/render.html.twig index e325432a0..fb293cf92 100644 --- a/Resources/views/CustomFieldsGroup/render.html.twig +++ b/Resources/views/CustomFieldsGroup/render.html.twig @@ -1,10 +1,43 @@ +{#- a customField element will be stored in title variable -#} +{%- set title = null -%} +{#- a customField element will be stored in subtitle variable -#} +{%- set subtitle = null -%} +{%- set type = constant('Chill\\CustomFieldsBundle\\CustomFields\\CustomFieldTitle::TYPE') -%} +{%- set type_subtitle = constant('Chill\\CustomFieldsBundle\\CustomFields\\CustomFieldTitle::TYPE_SUBTITLE') -%} +{%- set type_title = constant('Chill\\CustomFieldsBundle\\CustomFields\\CustomFieldTitle::TYPE_TITLE') -%} +{# a variable to store that "something has been printed #} +{%- set something_has_been_printed = false -%} {% for customField in cFGroup.activeCustomFields %} {% if customField.type == 'title' %} + {%- if show_empty == true %} {{ chill_custom_field_widget(cFData , customField) }} + {%- else -%} + {# we keep the customfield in memory, and print it only if 'something' has been filled after the title #} + {%- if customField.options[type] == type_title -%} + {%- set title = customField -%} + {# we have to reset the title hierarchy if we misused titles hierarchy #} + {%- set subtitle = null -%} + {%- elseif customField.options[type] == type_subtitle -%} + {%- set subtitle = customField -%} + {%- endif -%} + {%- endif -%} {% else %} {%- if show_empty == true or (chill_custom_field_is_empty(customField, cFData) == false) -%} -
{{ chill_custom_field_label(customField) }}
-
{{ chill_custom_field_widget(cFData , customField) }}
+ {%- if title is not empty -%} + {{ chill_custom_field_widget(cFData, title) }} + {%- set title = null -%} + {%- endif -%} + {%- if subtitle is not empty -%} + {{ chill_custom_field_widget(cFData, subtitle) }} + {%- set subtitle = null -%} + {%- endif -%} +
{{ chill_custom_field_label(customField) }}
+
{{ chill_custom_field_widget(cFData , customField) }}
+ {%- set something_has_been_printed = true -%} {%- endif -%} {%- endif -%} -{% endfor %} \ No newline at end of file +{% endfor %} +{% if something_has_been_printed == false %} +
{{ 'Empty data'|trans }}
+
{{ 'No data to show' | trans }}
+{% endif %} \ No newline at end of file From cbc66dc0f009f4a6d59103141596ca6522388c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 17 Dec 2015 22:07:28 +0100 Subject: [PATCH 48/54] allow choosing empty value in CFLongChoice --- CustomFields/CustomFieldLongChoice.php | 9 +++++++-- Resources/translations/messages.fr.yml | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CustomFields/CustomFieldLongChoice.php b/CustomFields/CustomFieldLongChoice.php index 58285d132..0b9100935 100644 --- a/CustomFields/CustomFieldLongChoice.php +++ b/CustomFields/CustomFieldLongChoice.php @@ -19,7 +19,6 @@ namespace Chill\CustomFieldsBundle\CustomFields; -use Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface; use Symfony\Component\Form\FormBuilderInterface; use Chill\CustomFieldsBundle\Entity\CustomField; use Chill\CustomFieldsBundle\EntityRepository\CustomFieldLongChoice\OptionRepository; @@ -84,6 +83,8 @@ class CustomFieldLongChoice extends AbstractCustomField 'choices_as_values' => true, 'multiple' => false, 'expanded' => false, + 'required' => $customField->isRequired(), + 'placeholder' => 'Choose a value', 'group_by' => function(Option $option) use ($translatableStringHelper) { if ($option->hasParent()) { return $translatableStringHelper->localize($option->getParent()->getText()); @@ -137,12 +138,16 @@ class CustomFieldLongChoice extends AbstractCustomField return $this->templating ->render($template, array( - 'values' => array($option) + 'values' => $option === NULL ? array() : array($option) )); } public function serialize($value, \Chill\CustomFieldsBundle\Entity\CustomField $customField) { + if ($value === NULL) { + return NULL; + } + if (!$value instanceof Option) { throw new \LogicException('the value should be an instance of ' . 'Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option, ' diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index bf29b6e7b..f71cbf98a 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -91,3 +91,4 @@ Text after the field: Texte après le champ #custom field long choice Options key: Clé des options +Choose a value: Choisissez une valeur From 60dc11caed7678d23be7800210140b5836d07e12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 17 Dec 2015 22:12:50 +0100 Subject: [PATCH 49/54] translation in choices name --- CustomFields/CustomFieldLongChoice.php | 2 +- CustomFields/CustomFieldNumber.php | 2 +- CustomFields/CustomFieldText.php | 2 +- CustomFields/CustomFieldTitle.php | 2 +- Resources/translations/messages.fr.yml | 6 ++++-- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/CustomFields/CustomFieldLongChoice.php b/CustomFields/CustomFieldLongChoice.php index 0b9100935..4d9f6400e 100644 --- a/CustomFields/CustomFieldLongChoice.php +++ b/CustomFields/CustomFieldLongChoice.php @@ -127,7 +127,7 @@ class CustomFieldLongChoice extends AbstractCustomField public function getName() { - return 'Long Choice'; + return 'Long choice field'; } public function render($value, \Chill\CustomFieldsBundle\Entity\CustomField $customField, $documentType = 'html') diff --git a/CustomFields/CustomFieldNumber.php b/CustomFields/CustomFieldNumber.php index b87dfe685..91ccac8d0 100644 --- a/CustomFields/CustomFieldNumber.php +++ b/CustomFields/CustomFieldNumber.php @@ -156,7 +156,7 @@ class CustomFieldNumber extends AbstractCustomField public function getName() { - return 'Number'; + return 'Number field'; } public function render($value, CustomField $customField, $documentType = 'html') diff --git a/CustomFields/CustomFieldText.php b/CustomFields/CustomFieldText.php index c2189bb88..1205d2c93 100644 --- a/CustomFields/CustomFieldText.php +++ b/CustomFields/CustomFieldText.php @@ -114,7 +114,7 @@ class CustomFieldText extends AbstractCustomField public function getName() { - return 'text field'; + return 'Text field'; } public function buildOptionsForm(FormBuilderInterface $builder) diff --git a/CustomFields/CustomFieldTitle.php b/CustomFields/CustomFieldTitle.php index 23f9f5e2b..11470df28 100644 --- a/CustomFields/CustomFieldTitle.php +++ b/CustomFields/CustomFieldTitle.php @@ -90,7 +90,7 @@ class CustomFieldTitle extends AbstractCustomField public function getName() { - return 'title'; + return 'Title'; } public function isEmptyValue($value, CustomField $customField) diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index f71cbf98a..a80f4ea08 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -54,9 +54,9 @@ The custom field has been updated: Le champ personnalisé a été mis à jour #custom field name choice: choix -title: titre +Title: Titre text: texte -text field: champ texte +Text field: Champ texte #custom field choice Multiplicity: Multiplicité @@ -88,7 +88,9 @@ 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 +Number field: Champ nombre #custom field long choice Options key: Clé des options Choose a value: Choisissez une valeur +Long choice field: Champ à choix pré-enregistrés From 9867cca632a3499b292d3b3573520444a0c287ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 17 Dec 2015 22:16:06 +0100 Subject: [PATCH 50/54] improve rendering of cfgroup index --- Resources/views/CustomFieldsGroup/index.html.twig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Resources/views/CustomFieldsGroup/index.html.twig b/Resources/views/CustomFieldsGroup/index.html.twig index 9a722b180..28ec9713a 100644 --- a/Resources/views/CustomFieldsGroup/index.html.twig +++ b/Resources/views/CustomFieldsGroup/index.html.twig @@ -45,12 +45,12 @@ {%- endif -%} -
    + From 24f9db6ae74cf66be9b0e5bee373ccb836fe2eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 17 Dec 2015 23:50:24 +0100 Subject: [PATCH 51/54] fix bug in changing custom field option bug description : > if you change the options of a custom field choice (i.e. from a > multiple to a single, removing or adding allow_other), the data > representation change and do not match with the expected > representation of the form. This commit fix this bug by switching the data representation to the current options. --- CustomFields/CustomFieldChoice.php | 88 +++++ Tests/CustomFields/CustomFieldsChoiceTest.php | 365 ++++++++++++++++++ 2 files changed, 453 insertions(+) create mode 100644 Tests/CustomFields/CustomFieldsChoiceTest.php diff --git a/CustomFields/CustomFieldChoice.php b/CustomFields/CustomFieldChoice.php index a34968db3..bc8c89d78 100644 --- a/CustomFields/CustomFieldChoice.php +++ b/CustomFields/CustomFieldChoice.php @@ -167,8 +167,96 @@ class CustomFieldChoice extends AbstractCustomField public function deserialize($serialized, CustomField $customField) { + // we always have to adapt to what the current data should be + $options = $customField->getOptions(); + + if ($options[self::MULTIPLE]) { + return $this->deserializeToMultiple($serialized, $options[self::ALLOW_OTHER]); + } else { + return $this->deserializeToUnique($serialized, $options[self::ALLOW_OTHER]); + } return $serialized; } + + private function deserializeToUnique($serialized, $allowOther) + { + $value = $this->guessValue($serialized); + + // set in a single value. We must have a single string + $fixedValue = is_array($value) ? + // check if the array has an element, if not replace by empty string + count($value) > 0 ? end($value) : '' + : + $value; + + if ($allowOther) { + return $this->deserializeWithAllowOther($serialized, $fixedValue); + } else { + return $fixedValue; + } + } + + /** + * deserialized the data from the database to a multiple + * field + * + * @param mixed $serialized + * @param boolean $allowOther + */ + private function deserializeToMultiple($serialized, $allowOther) + { + $value = $this->guessValue($serialized); + + // set in an array : we want a multiple + $fixedValue = is_array($value) ? $value : array($value); + + if ($allowOther) { + return $this->deserializeWithAllowOther($serialized, $fixedValue); + } else { + return $fixedValue; + } + } + + private function deserializeWithAllowOther($serialized, $value) + { + $existingOther = isset($serialized['_other']) ? $serialized['_other'] : ''; + + return array( + '_other' => $existingOther, + '_choices' => $value + ); + } + + /** + * Guess the value from the representation of it. + * + * If the value had an 'allow_other' = true option, the returned value + * **is not** the content of the _other field, but the `_other` string. + * + * @param array|string $value + * @return mixed + * @throws \LogicException if the case is not covered by this + */ + private function guessValue($value) + { + if ($value === NULL) { + return NULL; + } + + if (!is_array($value)) { + return $value; + } else { + // we have a field with "allow other" + if (isset($value['_choices'])) { + return $value['_choices']; + } else { + // we have a field with "multiple" + return $value; + } + } + + throw \LogicException("This case is not expected."); + } public function getName() { diff --git a/Tests/CustomFields/CustomFieldsChoiceTest.php b/Tests/CustomFields/CustomFieldsChoiceTest.php new file mode 100644 index 000000000..f01a283ee --- /dev/null +++ b/Tests/CustomFields/CustomFieldsChoiceTest.php @@ -0,0 +1,365 @@ + + * + * 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 . + */ + +namespace Chill\CustomFieldsBundle\Tests; + +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Chill\CustomFieldsBundle\Entity\CustomField; +use Chill\CustomFieldsBundle\CustomFields\CustomFieldChoice; + +/** + * This class cover the test of CustomFieldChoice. + * + * Function currently covered: + * + * - deserialize + * + * @author Julien Fastré + */ +class CustomFieldsChoiceTest extends KernelTestCase +{ + + /** + * + * @var \Chill\CustomFieldsBundle\Service\CustomFieldProvider + */ + private $cfProvider; + + /** + * + * @var \Chill\CustomFieldsBundle\CustomFields\CustomFieldChoice + */ + private $cfChoice; + + public function setUp() + { + static::bootKernel(); + + $this->cfProvider = static::$kernel->getContainer() + ->get('chill.custom_field.provider'); + $this->cfChoice = $this->cfProvider->getCustomFieldByType('choice'); + } + + public function tearDown() + { + parent::tearDown(); + } + + /** + * + * @param array $options + * @return CustomField + */ + private function generateCustomField($options) + { + return (new CustomField()) + ->setActive(true) + ->setSlug('slug') + ->setOptions($options) + ->setType('choice') + ; + } + + ///////////////////////////////////////// + // + // test function deserialize + // + //////////////////////////////////////// + + /** + * Test if the representation of the data is deserialized to a single text. + * + * If the value is in _other, the _other value should not be returned. + * + * @param type $data + * @dataProvider serializedRepresentationDataProvider + */ + public function testDeserializeSingleChoiceWithoutOther($data) + { + $customField = $this->generateCustomField(array( + CustomFieldChoice::ALLOW_OTHER => false, + CustomFieldChoice::MULTIPLE => false + )); + + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame('my-value', $deserialized); + } + + + public function testDeserializeSingleChoiceWithoutOtherDataIsNull() + { + $customField = $this->generateCustomField(array( + CustomFieldChoice::ALLOW_OTHER => false, + CustomFieldChoice::MULTIPLE => false + )); + + $deserialized = $this->cfChoice->deserialize(null, $customField); + + $this->assertSame(null, $deserialized); + + $deserialized = $this->cfChoice->deserialize('', $customField); + + $this->assertSame('', $deserialized); + } + + /** + * Test if the representation of the data is deserialized to a single text + * with an "allow_other" field. + * + * If the value is in _other, the _other value should be in the _other field. + * + * @param type $data + * @dataProvider serializedRepresentationDataProvider + */ + public function testDeserializeSingleChoiceWithOther($data) + { + $customField = $this->generateCustomField(array( + CustomFieldChoice::ALLOW_OTHER => true, + CustomFieldChoice::MULTIPLE => false + )); + + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame(array('_other' => '', '_choices' => 'my-value'), $deserialized); + } + + /** + * Other cases : + * + * - Test if the selected value is '_other + * - Test with null data + * + * @param type $data + */ + public function testDeserializeSingleChoiceWithOtherOtherCases() + { + $customField = $this->generateCustomField(array( + CustomFieldChoice::ALLOW_OTHER => true, + CustomFieldChoice::MULTIPLE => false + )); + + // from a single to a single + $data = array('_other' => 'something', '_choices' => '_other'); + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame(array('_other' => 'something', '_choices' => '_other'), $deserialized); + + + // from a multiple to a single + $data = array('_other' => 'something', '_choices' => array('some', '_other')); + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame(array('_other' => 'something', '_choices' => '_other'), $deserialized); + + //test with null data + //from a single to a single : + $data = array('_other' => 'something', '_choices' => null); + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame(array('_other' => 'something', '_choices' => null), $deserialized); + + $data = array('_other' => 'something', '_choices' => ''); + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame(array('_other' => 'something', '_choices' => ''), $deserialized); + + // from a multiple to a signle + $data = array('_other' => 'something', '_choices' => array()); + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame(array('_other' => 'something', '_choices' => ''), $deserialized); + + $data = array('_other' => 'something', '_choices' => array('')); + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame(array('_other' => 'something', '_choices' => ''), $deserialized); + + } + + /** + * Test if the representation of the data is deserialized to an array text + * with an "allow_other" field. + * + * This test does not covers the case when the selected value is `_other` + * + * @param type $data + * @dataProvider serializedRepresentationDataProvider + */ + public function testDeserializeMultipleChoiceWithOther($data) + { + $customField = $this->generateCustomField(array( + CustomFieldChoice::ALLOW_OTHER => true, + CustomFieldChoice::MULTIPLE => true + )); + + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame(array('_other' => '', '_choices' => array('my-value')), + $deserialized); + } + + /** + * Test if the representation of the data is deserialized to an array text + * with an "allow_other" field. + * + * This test covers : + * - the case when the selected value is `_other` + * - result is null + * + * @param type $data + */ + public function testDeserializeMultipleChoiceWithOtherOtherCases() + { + $customField = $this->generateCustomField(array( + CustomFieldChoice::ALLOW_OTHER => true, + CustomFieldChoice::MULTIPLE => true + )); + + // selected value is _other + // from single to multiple + $data = array('_other' => 'something', '_choices' => '_other'); + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame(array('_other' => 'something', '_choices' => array('_other')), + $deserialized); + + // from multiple to multiple + $data = array('_other' => 'something', '_choices' => array('_other', 'something')); + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame(array('_other' => 'something', '_choices' => array('_other', 'something')), + $deserialized); + + // test with null value + // from single to multiple + $data = array('_other' => '', '_choices' => ''); + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame(array('_other' => '', '_choices' => array('')), + $deserialized); + + // from multiple to multiple + $data = array('_other' => '', '_choices' => array()); + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame(array('_other' => '', '_choices' => array()), + $deserialized); + } + + /** + * Test if the representation of the data is deserialized to an array text + * **without** an "allow_other" field. + * + * + * @param type $data + * @dataProvider serializedRepresentationDataProvider + */ + public function testDeserializeMultipleChoiceWithoutOther($data) + { + $customField = $this->generateCustomField(array( + CustomFieldChoice::ALLOW_OTHER => false, + CustomFieldChoice::MULTIPLE => true + )); + + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame(array('my-value'), $deserialized); + } + + /** + * Test if the representation of the data is deserialized to an array text + * **without** an "allow_other" field. + * + * Covered cases : + * - NULL values + * + * + * @param type $data + */ + public function testDeserializeMultipleChoiceWithoutOtherOtherCases() + { + $customField = $this->generateCustomField(array( + CustomFieldChoice::ALLOW_OTHER => false, + CustomFieldChoice::MULTIPLE => true + )); + + // from single to multiple + $data = 'my-value'; + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame(array('my-value'), $deserialized); + + // from multiple to multiple + $data = array('my-value'); + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame(array('my-value'), $deserialized); + } + + public function serializedRepresentationDataProvider() + { + return array( + array( + // multiple => false, allow_other => false + 'my-value' + ), + array( + // multiple => true, allow_ther => false + array('my-value') + ), + array( + // multiple => false, allow_other => true, current value not in other + array('_other' => '', '_choices' => 'my-value') + ), + array( + // multiple => true, allow_other => true, current value not in other + array('_other' => '', '_choices'=> array('my-value')) + ), + ); + } + + + + ///////////////////////////////////////// + // + // test function isEmptyValue + // + //////////////////////////////////////// + + /** + * + * @param mixed $data + * @dataProvider serializedRepresentationDataProvider + */ + public function testIsEmptyValueNotEmpty($data) + { + $this->markTestSkipped("We have to improve the isEmptyFunction"); + $customField = $this->generateCustomField(array( + CustomFieldChoice::ALLOW_OTHER => false, + CustomFieldChoice::MULTIPLE => true + )); + + $deserialized = $this->cfChoice->deserialize($data, $customField); + $isEmpty = $this->cfChoice->isEmptyValue($deserialized, $customField); + + $this->assertFalse($isEmpty); + } + +} From 573697d8c7d3eb09bb4fe39f7cde2fe5ef5efac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 18 Dec 2015 00:22:09 +0100 Subject: [PATCH 52/54] improve function isEmptyValue + tests --- CustomFields/CustomFieldChoice.php | 18 ++--- Tests/CustomFields/CustomFieldsChoiceTest.php | 65 +++++++++++++++++-- 2 files changed, 66 insertions(+), 17 deletions(-) diff --git a/CustomFields/CustomFieldChoice.php b/CustomFields/CustomFieldChoice.php index bc8c89d78..782f5ab17 100644 --- a/CustomFields/CustomFieldChoice.php +++ b/CustomFields/CustomFieldChoice.php @@ -269,11 +269,6 @@ class CustomFieldChoice extends AbstractCustomField return true; } - // if only one choice... - if (is_string($value)) { - return empty($value); - } - // if multiple choice OR multiple/single choice with other if (is_array($value)) { @@ -282,17 +277,14 @@ class CustomFieldChoice extends AbstractCustomField if ($value['_choices'] === NULL) { return true; } - if (is_string($value['_choices'])) { - return empty($value); - } - if (is_array($value['_choices'])){ - return count($value['_choices']) > 0; - } + return empty($value['_choices']); } else { // we do not have 'allow other' - return count($value) > .0; + return empty($value); } + } else { + return empty($value); } - + throw \LogicException("This case is not expected."); } diff --git a/Tests/CustomFields/CustomFieldsChoiceTest.php b/Tests/CustomFields/CustomFieldsChoiceTest.php index f01a283ee..6fbc0b67e 100644 --- a/Tests/CustomFields/CustomFieldsChoiceTest.php +++ b/Tests/CustomFields/CustomFieldsChoiceTest.php @@ -344,22 +344,79 @@ class CustomFieldsChoiceTest extends KernelTestCase //////////////////////////////////////// /** + * test the not empty with the not-empty data provider * * @param mixed $data * @dataProvider serializedRepresentationDataProvider */ public function testIsEmptyValueNotEmpty($data) { - $this->markTestSkipped("We have to improve the isEmptyFunction"); + $customField = $this->generateCustomField(array( + CustomFieldChoice::ALLOW_OTHER => false, + CustomFieldChoice::MULTIPLE => true + )); + + $isEmpty = $this->cfChoice->isEmptyValue($data, $customField); + + $this->assertFalse($isEmpty); + } + + /** + * + * @dataProvider emptyDataProvider + * @param mixed $data + */ + public function testIsEmptyValueEmpty($data) + { $customField = $this->generateCustomField(array( CustomFieldChoice::ALLOW_OTHER => false, CustomFieldChoice::MULTIPLE => true )); - $deserialized = $this->cfChoice->deserialize($data, $customField); - $isEmpty = $this->cfChoice->isEmptyValue($deserialized, $customField); + $isEmpty = $this->cfChoice->isEmptyValue($data, $customField); - $this->assertFalse($isEmpty); + $this->assertTrue($isEmpty); + } + + /** + * provide empty data in different possible reprsentation + * + * @return array + */ + public function emptyDataProvider() + { + return array( + // 0 + array( + // signle + '' + ), + // 1 + array( + // single + null + ), + // 2 + array( + // signle with allow other + array('_other' => 'something', '_choices' => '') + ), + // 3 + array( + // multiple + array() + ), + // 4 + array( + // multiple with allow other + array('_other' => 'something', '_choices' => array()) + ), + // 5 + array( + // multiple with allow other + array('_other' => '', '_choices' => array()) + ), + ); } } From 3e5a90c36c5719b010b2ebde585e7d58d06090b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 23 Dec 2015 23:46:15 +0100 Subject: [PATCH 53/54] escaping argument --- Resources/config/services.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/config/services.yml b/Resources/config/services.yml index 1e03b8bf2..9af084616 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -124,5 +124,5 @@ services: class: Chill\CustomFieldsBundle\EntityRepository\CustomFieldLongChoice\OptionRepository factory: ["@doctrine", getRepository] arguments: - - "Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option" + - "Chill\\CustomFieldsBundle\\Entity\\CustomFieldLongChoice\\Option" \ No newline at end of file From 09a69765b98836bbfccfaf2695164fda55fa8b84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 23 Dec 2015 23:46:44 +0100 Subject: [PATCH 54/54] adding test for customFieldRendering function --- .../Twig/CustomFieldRenderingTwigTest.php | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 Tests/Templating/Twig/CustomFieldRenderingTwigTest.php diff --git a/Tests/Templating/Twig/CustomFieldRenderingTwigTest.php b/Tests/Templating/Twig/CustomFieldRenderingTwigTest.php new file mode 100644 index 000000000..7f4923349 --- /dev/null +++ b/Tests/Templating/Twig/CustomFieldRenderingTwigTest.php @@ -0,0 +1,105 @@ + + * + * 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 . + */ + +namespace Chill\CustomFields\Tests\Templating\Twig; + +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Chill\CustomFieldsBundle\Templating\Twig\CustomFieldRenderingTwig; +use Chill\CustomFieldsBundle\Entity\CustomField; +use Chill\CustomFieldsBundle\Service\CustomFieldProvider; + +/** + * Test the rendering of twig function which renders custom fields + * + * @author Julien Fastré + * @author Champs Libres + */ +class CustomFieldRenderingTwigTest extends KernelTestCase +{ + /** + * + * @var CustomFieldRenderingTwig + */ + private $cfRendering; + + /** + * + * @var CustomFieldProvider + */ + private $cfProvider; + + public function setUp() + { + self::bootKernel(); + $this->cfRendering = self::$kernel->getContainer() + ->get('chill.custom_field.twig.custom_fields_rendering') + ; + + $this->cfProvider = self::$kernel->getContainer() + ->get('chill.custom_field.provider'); + + // set locale to fr + $prophet = new \Prophecy\Prophet; + $request = $prophet->prophesize(); + $request->willExtend('Symfony\Component\HttpFoundation\Request'); + $request->getLocale()->willReturn('fr'); + self::$kernel->getContainer()->get('request_stack') + ->push($request->reveal()); + } + + /** + * + * @return CustomField + */ + private function getSimpleCustomFieldText() + { + return (new CustomField()) + ->setSlug('test') + ->setName(array('fr' => 'Test')) + ->setType('text') + ->setOrdering(10) + ->setOptions(array("maxLength" => 255)) + ->setActive(true) + ; + } + + public function testLabelRendering() + { + $cf = $this->getSimpleCustomFieldText(); + + $text = $this->cfRendering->renderLabel($cf); + + $this->assertContains('Test', $text, + "The rendering text should contains the 'test' text"); + } + + public function testWidgetRendering() + { + $cf = $this->getSimpleCustomFieldText(); + $fields = array( + 'test' => "My tailor is rich" + ); + + $text = $this->cfRendering->renderWidget($fields, $cf); + + $this->assertContains('My tailor is rich', $text, + "The rendering text should contains the 'test' text"); + } +}