mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-07-01 22:46:13 +00:00
Merge remote-tracking branch 'ChillCustomFields/sf4' into sf4
This commit is contained in:
commit
5ea4b4efe1
32
src/Bundle/ChillCustomFields/.gitignore
vendored
Normal file
32
src/Bundle/ChillCustomFields/.gitignore
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/web/bundles/
|
||||||
|
/app/cache/*
|
||||||
|
!/app/cache/dev/security/nonces/index
|
||||||
|
!/app/cache/prod/security/nonces/index
|
||||||
|
/app/logs/*
|
||||||
|
/vendor/
|
||||||
|
/app/config/parameters.ini
|
||||||
|
/app/config/parameters.yml
|
||||||
|
/app/bootstrap*
|
||||||
|
/src/Acme/
|
||||||
|
/output/
|
||||||
|
/web/uploads/images/*
|
||||||
|
!/web/uploads/images/index.html
|
||||||
|
/src/Progracqteur/WikipedaleBundle/DataFixtures/ORM/Files/*
|
||||||
|
.gitignore~
|
||||||
|
*~
|
||||||
|
composer.phar
|
||||||
|
composer.lock
|
||||||
|
/nbproject/private/
|
||||||
|
parameters.yml
|
||||||
|
app/config/parameters.yml
|
||||||
|
Tests/Fixtures/App/app/config/parameters.yml
|
||||||
|
.DS_Store
|
||||||
|
*bower_components
|
||||||
|
bin/*
|
||||||
|
/tmp/*
|
||||||
|
src/Chill/CustomFieldsBundle/vendor/*
|
||||||
|
bootstrap.php.cache
|
||||||
|
#the file created by composer to store creds
|
||||||
|
auth.json
|
||||||
|
Tests/Fixtures/App/app/config/parameters.yml
|
||||||
|
|
68
src/Bundle/ChillCustomFields/.gitlab-ci.yml
Normal file
68
src/Bundle/ChillCustomFields/.gitlab-ci.yml
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
.test_definition: &test_definition
|
||||||
|
services:
|
||||||
|
- chill/database:latest
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- echo "PHP version is $(php --version)"
|
||||||
|
- composer config github-oauth.github.com $GITHUB_TOKEN
|
||||||
|
- if [ $CI_BUILD_REF_NAME = "1.0" ] ; then export COMPOSER_ROOT_VERSION="1.0-dev"; else export COMPOSER_ROOT_VERSION="dev-master"; fi
|
||||||
|
- php -d memory_limit=-1 /usr/local/bin/composer install --no-interaction
|
||||||
|
- cp Resources/test/Fixtures/App/app/config/parameters.gitlab-ci.yml Resources/test/Fixtures/App/app/config/parameters.yml
|
||||||
|
- php Resources/test/Fixtures/App/app/console --env=test cache:warmup
|
||||||
|
- php Resources/test/Fixtures/App/app/console doctrine:migrations:migrate --env=test --no-interaction
|
||||||
|
- php Resources/test/Fixtures/App/app/console doctrine:fixtures:load --env=test --no-interaction
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- deploy
|
||||||
|
- test
|
||||||
|
- build-doc
|
||||||
|
- deploy-doc
|
||||||
|
|
||||||
|
test:php-7.2:
|
||||||
|
stage: test
|
||||||
|
image: chill/ci-image:php-7.2
|
||||||
|
<<: *test_definition
|
||||||
|
script: vendor/bin/phpunit
|
||||||
|
|
||||||
|
deploy-packagist:
|
||||||
|
stage: deploy
|
||||||
|
image: chill/ci-image:php-7.2
|
||||||
|
before_script:
|
||||||
|
# test that PACKAGIST USERNAME and PACKAGIST_TOKEN variable are set
|
||||||
|
- if [ -z ${PACKAGIST_USERNAME+x} ]; then echo "Please set PACKAGIST_USERNAME variable"; exit -1; fi
|
||||||
|
- if [ -z ${PACKAGIST_TOKEN+x} ]; then echo "Please set PACKAGIST_TOKEN variable"; exit -1; fi
|
||||||
|
script:
|
||||||
|
- STATUSCODE=$(curl -XPOST -H'content-type:application/json' "https://packagist.org/api/update-package?username=$PACKAGIST_USERNAME&apiToken=$PACKAGIST_TOKEN" -d"{\"repository\":{\"url\":\"$CI_PROJECT_URL.git\"}}" --silent --output /dev/stderr --write-out "%{http_code}")
|
||||||
|
- if [ $STATUSCODE = "202" ]; then exit 0; else exit $STATUSCODE; fi
|
||||||
|
|
||||||
|
# deploy documentation
|
||||||
|
api-doc-build:
|
||||||
|
stage: build-doc
|
||||||
|
environment: api-doc
|
||||||
|
image: chill/ci-image:php-7.2
|
||||||
|
before_script:
|
||||||
|
- mkdir api-doc
|
||||||
|
script: apigen generate --destination api-doc/$CI_BUILD_REF_NAME/$CI_PROJECT_NAME
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- "api-doc/"
|
||||||
|
name: api
|
||||||
|
expire_in: '2h'
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
- tags
|
||||||
|
|
||||||
|
api-doc-deploy:
|
||||||
|
stage: deploy-doc
|
||||||
|
image: pallet/swiftclient:latest
|
||||||
|
before_script:
|
||||||
|
# test that CONTAINER_API variable is set
|
||||||
|
- if [ -z ${CONTAINER_API+x} ]; then echo "Please set CONTAINER_API variable"; exit -1; fi
|
||||||
|
# go to api-doc to have and url with PROJECT/BUILD
|
||||||
|
- cd api-doc
|
||||||
|
# upload, and keep files during 1 year
|
||||||
|
script: "swift upload --header \"X-Delete-After: 31536000\" $CONTAINER_API $CI_BUILD_REF_NAME/$CI_PROJECT_NAME"
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
- tags
|
||||||
|
|
5
src/Bundle/ChillCustomFields/CHANGELOG.md
Normal file
5
src/Bundle/ChillCustomFields/CHANGELOG.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
Master branch
|
||||||
|
=============
|
||||||
|
|
||||||
|
- fix error on export: error when field definition has changed
|
||||||
|
|
15
src/Bundle/ChillCustomFields/ChillCustomFieldsBundle.php
Normal file
15
src/Bundle/ChillCustomFields/ChillCustomFieldsBundle.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||||
|
use Chill\CustomFieldsBundle\DependencyInjection\CustomFieldCompilerPass;
|
||||||
|
|
||||||
|
class ChillCustomFieldsBundle extends Bundle
|
||||||
|
{
|
||||||
|
public function build(\Symfony\Component\DependencyInjection\ContainerBuilder $container)
|
||||||
|
{
|
||||||
|
parent::build($container);
|
||||||
|
$container->addCompilerPass(new CustomFieldCompilerPass());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,264 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
* Copyright (C) 2014 Champs-Libres Coopérative <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Command;
|
||||||
|
|
||||||
|
use Chill\CustomFieldsBundle\Service\CustomFieldProvider;
|
||||||
|
use Doctrine\ORM\EntityManager;
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Helper\Table;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup;
|
||||||
|
use Symfony\Component\Console\Question\Question;
|
||||||
|
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||||
|
use Symfony\Component\Yaml\Parser;
|
||||||
|
use Symfony\Component\Yaml\Exception\ParseException;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for the command 'chill:custom_fields:populate_group' that
|
||||||
|
* Create custom fields from a yml file
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
* @author Marc Ducobu <marc.ducobu@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class CreateFieldsOnGroupCommand extends Command
|
||||||
|
{
|
||||||
|
const ARG_PATH = 'path';
|
||||||
|
const ARG_DELETE = 'delete';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var CustomFieldProvider
|
||||||
|
*/
|
||||||
|
private $customFieldProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var EntityManager
|
||||||
|
*/
|
||||||
|
private $entityManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ValidatorInterface
|
||||||
|
*/
|
||||||
|
private $validator;
|
||||||
|
|
||||||
|
private $availableLanguages;
|
||||||
|
private $customizablesEntities;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CreateFieldsOnGroupCommand constructor.
|
||||||
|
*
|
||||||
|
* @param CustomFieldProvider $customFieldProvider
|
||||||
|
* @param EntityManager $entityManager
|
||||||
|
* @param ValidatorInterface $validator
|
||||||
|
* @param $availableLanguages
|
||||||
|
* @param $customizablesEntities
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
CustomFieldProvider $customFieldProvider,
|
||||||
|
EntityManager $entityManager,
|
||||||
|
ValidatorInterface $validator,
|
||||||
|
$availableLanguages,
|
||||||
|
$customizablesEntities
|
||||||
|
) {
|
||||||
|
$this->customFieldProvider = $customFieldProvider;
|
||||||
|
$this->entityManager = $entityManager;
|
||||||
|
$this->validator = $validator;
|
||||||
|
$this->availableLanguages = $availableLanguages;
|
||||||
|
$this->customizablesEntities = $customizablesEntities;
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('chill:custom_fields:populate_group')
|
||||||
|
->setDescription('Create custom fields from a yml file')
|
||||||
|
->addArgument(self::ARG_PATH, InputOption::VALUE_REQUIRED,
|
||||||
|
'Path to description file')
|
||||||
|
->addOption(self::ARG_DELETE, null, InputOption::VALUE_NONE,
|
||||||
|
'If set, delete existing fields');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the existing custom fields for a given customFieldGroup
|
||||||
|
*
|
||||||
|
* @param CustomFieldsGroup $customFieldsGroup : The custom field group
|
||||||
|
*/
|
||||||
|
protected function deleteFieldsForCFGroup($customFieldsGroup)
|
||||||
|
{
|
||||||
|
$em = $this->entityManager;
|
||||||
|
|
||||||
|
foreach ($customFieldsGroup->getCustomFields() as $field) {
|
||||||
|
$em->remove($field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param InputInterface $input
|
||||||
|
* @param OutputInterface $output
|
||||||
|
* @return int|null|void
|
||||||
|
*/
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$helper = $this->getHelperSet()->get('question');
|
||||||
|
|
||||||
|
$em = $this->entityManager;
|
||||||
|
|
||||||
|
$customFieldsGroups = $em
|
||||||
|
->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup')
|
||||||
|
->findAll();
|
||||||
|
|
||||||
|
if (count($customFieldsGroups) === 0) {
|
||||||
|
$output->writeln('<error>There aren\'t any CustomFieldsGroup recorded'
|
||||||
|
. ' Please create at least one.</error>');
|
||||||
|
}
|
||||||
|
|
||||||
|
$table = new Table($output);
|
||||||
|
$table
|
||||||
|
->setHeaders(array_merge(
|
||||||
|
['id', 'entity'],
|
||||||
|
$this->availableLanguages
|
||||||
|
))
|
||||||
|
->setRows($this->_prepareRows($customFieldsGroups))
|
||||||
|
->render()
|
||||||
|
;
|
||||||
|
|
||||||
|
$question = new Question(
|
||||||
|
"Enter the customfieldGroup's id on which the custom fields should be added: ");
|
||||||
|
$question->setNormalizer(
|
||||||
|
function($answer) use ($customFieldsGroups) {
|
||||||
|
foreach ($customFieldsGroups as $customFieldsGroup) {
|
||||||
|
if ($answer == $customFieldsGroup->getId()) {
|
||||||
|
return $customFieldsGroup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new \RunTimeException('The id does not match an existing '
|
||||||
|
. 'CustomFieldsGroup');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
$customFieldsGroup = $helper->ask($input, $output, $question);
|
||||||
|
|
||||||
|
|
||||||
|
if ($input->getOption(self::ARG_DELETE)) {
|
||||||
|
$this->deleteFieldsForCFGroup($customFieldsGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
$fieldsInput = $this->_parse($input->getArgument(self::ARG_PATH),
|
||||||
|
$output);
|
||||||
|
|
||||||
|
$fields = $this->_addFields($customFieldsGroup, $fieldsInput, $output);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function _prepareRows ($customFieldsGroups)
|
||||||
|
{
|
||||||
|
$rows = array();
|
||||||
|
$languages = $this->availableLanguages;
|
||||||
|
//gather entitites and create an array to access them easily
|
||||||
|
$customizableEntities = array();
|
||||||
|
foreach ($this->customizablesEntities as $entry) {
|
||||||
|
$customizableEntities[$entry['class']] = $entry['name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
array_walk($customFieldsGroups,
|
||||||
|
function(CustomFieldsGroup $customFieldGroup, $key)
|
||||||
|
use ($languages, &$rows, $customizableEntities) {
|
||||||
|
//set id and entity
|
||||||
|
$row = array(
|
||||||
|
$customFieldGroup->getId(),
|
||||||
|
$customizableEntities[$customFieldGroup->getEntity()]
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($languages as $lang) {
|
||||||
|
//todo replace with service to find lang when available
|
||||||
|
$row[] = (isset($customFieldGroup->getName()[$lang])) ?
|
||||||
|
$customFieldGroup->getName()[$lang] :
|
||||||
|
'Not available in this language';
|
||||||
|
}
|
||||||
|
$rows[] = $row;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return $rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function _parse($path, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$parser = new Parser();
|
||||||
|
|
||||||
|
if (!file_exists($path)) {
|
||||||
|
throw new \RunTimeException("file does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$values = $parser->parse(file_get_contents($path));
|
||||||
|
} catch (ParseException $ex) {
|
||||||
|
throw new \RunTimeException("The yaml file is not valid", 0, $ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $values;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function _addFields(CustomFieldsGroup $group, $values, OutputInterface $output)
|
||||||
|
{
|
||||||
|
|
||||||
|
$em = $this->entityManager;
|
||||||
|
|
||||||
|
$languages = $this->availableLanguages;
|
||||||
|
|
||||||
|
foreach($values['fields'] as $slug => $field) {
|
||||||
|
//check the cf type exists
|
||||||
|
$cfType = $this->customFieldProvider->getCustomFieldByType($field['type']);
|
||||||
|
if ($cfType === NULL) {
|
||||||
|
throw new \RunTimeException('the type '.$field['type'].' '
|
||||||
|
. 'does not exists');
|
||||||
|
}
|
||||||
|
|
||||||
|
$cf = new CustomField();
|
||||||
|
$cf->setSlug($slug)
|
||||||
|
->setName($field['name'])
|
||||||
|
->setOptions(isset($field['options']) ? $field['options'] : array() )
|
||||||
|
->setOrdering($field['ordering'])
|
||||||
|
->setType($field['type'])
|
||||||
|
->setCustomFieldsGroup($group);
|
||||||
|
|
||||||
|
//add to table
|
||||||
|
$names = array();
|
||||||
|
foreach ($languages as $lang) {
|
||||||
|
//todo replace with service to find lang when available
|
||||||
|
$names[] = (isset($cf->getName()[$lang])) ?
|
||||||
|
$cf->getName()[$lang] :
|
||||||
|
'Not available in this language';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->validator->validate($cf)) {
|
||||||
|
$em->persist($cf);
|
||||||
|
$output->writeln("<info>Adding Custom Field of type "
|
||||||
|
.$cf->getType()."\t with slug ".$cf->getSlug().
|
||||||
|
"\t and names : ".implode($names, ', ')."</info>");
|
||||||
|
} else {
|
||||||
|
throw new \RunTimeException("Error in field ".$slug);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$em->flush();
|
||||||
|
}
|
||||||
|
}
|
38
src/Bundle/ChillCustomFields/Controller/AdminController.php
Normal file
38
src/Bundle/ChillCustomFields/Controller/AdminController.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
* Copyright (C) 2015 Champs Libres <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Controller;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class AdminController
|
||||||
|
* Controller for the custom fields configuration section (in admin section)
|
||||||
|
*
|
||||||
|
* @package Chill\CustomFieldsBundle\Controller
|
||||||
|
*/
|
||||||
|
class AdminController extends AbstractController
|
||||||
|
{
|
||||||
|
public function indexAction()
|
||||||
|
{
|
||||||
|
return $this->render('ChillCustomFieldsBundle:Admin:layout.html.twig');
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,199 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Controller;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomField;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup;
|
||||||
|
use Chill\CustomFieldsBundle\Form\CustomFieldType;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class CustomFieldController
|
||||||
|
*
|
||||||
|
* @package Chill\CustomFieldsBundle\Controller
|
||||||
|
*/
|
||||||
|
class CustomFieldController extends AbstractController
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new CustomField entity.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function createAction(Request $request)
|
||||||
|
{
|
||||||
|
$entity = new CustomField();
|
||||||
|
$form = $this->createCreateForm($entity, $request->query->get('type', null));
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
if ($form->isValid()) {
|
||||||
|
$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('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,
|
||||||
|
'form' => $form->createView(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a form to create a CustomField entity.
|
||||||
|
*
|
||||||
|
* @param CustomField $entity The entity
|
||||||
|
* @param string
|
||||||
|
* @return \Symfony\Component\Form\Form The form
|
||||||
|
*/
|
||||||
|
private function createCreateForm(CustomField $entity, $type)
|
||||||
|
{
|
||||||
|
$form = $this->createForm(CustomFieldType::class, $entity, array(
|
||||||
|
'action' => $this->generateUrl('customfield_create',
|
||||||
|
array('type' => $type)),
|
||||||
|
'method' => 'POST',
|
||||||
|
'type' => $type,
|
||||||
|
'group_widget' => ($entity->getCustomFieldsGroup()) ? 'hidden' :'entity'
|
||||||
|
));
|
||||||
|
|
||||||
|
$form->add('submit', SubmitType::class, array('label' => 'Create'));
|
||||||
|
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a form to create a new CustomField entity.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function newAction(Request $request)
|
||||||
|
{
|
||||||
|
$entity = new CustomField();
|
||||||
|
|
||||||
|
//add the custom field group if defined in URL
|
||||||
|
$cfGroupId = $request->query->get('customFieldsGroup', null);
|
||||||
|
|
||||||
|
if ($cfGroupId !== null) {
|
||||||
|
$cfGroup = $this->getDoctrine()->getManager()
|
||||||
|
->getRepository(CustomFieldsGroup::class)
|
||||||
|
->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(
|
||||||
|
'entity' => $entity,
|
||||||
|
'form' => $form->createView(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds and displays a CustomField entity.
|
||||||
|
*
|
||||||
|
* @deprecated is not used since there is no link to show action
|
||||||
|
*/
|
||||||
|
public function showAction($id)
|
||||||
|
{
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
|
$entity = $em->getRepository(CustomField::class)->find($id);
|
||||||
|
|
||||||
|
if (!$entity) {
|
||||||
|
throw $this->createNotFoundException('Unable to find CustomField entity.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('ChillCustomFieldsBundle:CustomField:show.html.twig', array(
|
||||||
|
'entity' => $entity, ));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a form to edit an existing CustomField entity.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function editAction($id)
|
||||||
|
{
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
|
$entity = $em->getRepository(CustomField::class)->find($id);
|
||||||
|
|
||||||
|
if (!$entity) {
|
||||||
|
throw $this->createNotFoundException('Unable to find CustomField entity.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$editForm = $this->createEditForm($entity, $entity->getType());
|
||||||
|
|
||||||
|
return $this->render('ChillCustomFieldsBundle:CustomField:edit.html.twig', array(
|
||||||
|
'entity' => $entity,
|
||||||
|
'edit_form' => $editForm->createView(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a form to edit a CustomField entity.
|
||||||
|
*
|
||||||
|
* @param CustomField $entity The entity
|
||||||
|
*
|
||||||
|
* @return \Symfony\Component\Form\Form The form
|
||||||
|
*/
|
||||||
|
private function createEditForm(CustomField $entity, $type)
|
||||||
|
{
|
||||||
|
$form = $this->createForm(CustomFieldType::class, $entity, array(
|
||||||
|
'action' => $this->generateUrl('customfield_update', array('id' => $entity->getId())),
|
||||||
|
'method' => 'PUT',
|
||||||
|
'type' => $type,
|
||||||
|
'group_widget' => 'hidden'
|
||||||
|
));
|
||||||
|
|
||||||
|
$form->add('submit', SubmitType::class, array('label' => 'Update'));
|
||||||
|
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Edits an existing CustomField entity.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function updateAction(Request $request, $id)
|
||||||
|
{
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
|
$entity = $em->getRepository('ChillCustomFieldsBundle:CustomField')->find($id);
|
||||||
|
|
||||||
|
if (!$entity) {
|
||||||
|
throw $this->createNotFoundException('Unable to find CustomField entity.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$editForm = $this->createEditForm($entity, $entity->getType());
|
||||||
|
$editForm->handleRequest($request);
|
||||||
|
|
||||||
|
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,
|
||||||
|
'edit_form' => $editForm->createView(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,429 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Controller;
|
||||||
|
|
||||||
|
use Chill\CustomFieldsBundle\Service\CustomFieldProvider;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
||||||
|
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;
|
||||||
|
use Chill\CustomFieldsBundle\Form\CustomFieldsGroupType;
|
||||||
|
use Chill\CustomFieldsBundle\Form\CustomFieldType;
|
||||||
|
use Chill\CustomFieldsBundle\Form\Type\CustomFieldType as FormTypeCustomField;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class CustomFieldsGroupController
|
||||||
|
*
|
||||||
|
* @package Chill\CustomFieldsBundle\Controller
|
||||||
|
*/
|
||||||
|
class CustomFieldsGroupController extends AbstractController
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var CustomFieldProvider
|
||||||
|
*/
|
||||||
|
private $customfieldProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var TranslatorInterface
|
||||||
|
*/
|
||||||
|
private $translator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CustomFieldsGroupController constructor.
|
||||||
|
*
|
||||||
|
* @param CustomFieldProvider $customFieldProvider
|
||||||
|
* @param TranslatorInterface $translator
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
CustomFieldProvider $customFieldProvider,
|
||||||
|
TranslatorInterface $translator
|
||||||
|
) {
|
||||||
|
$this->customfieldProvider = $customFieldProvider;
|
||||||
|
$this->translator = $translator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists all CustomFieldsGroup entities.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function indexAction()
|
||||||
|
{
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
|
$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' => $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 = null)
|
||||||
|
{
|
||||||
|
return $this->createFormBuilder($group, array(
|
||||||
|
'method' => 'POST',
|
||||||
|
'action' => $this->generateUrl('customfieldsgroup_makedefault')
|
||||||
|
))
|
||||||
|
->add('id', HiddenType::class)
|
||||||
|
->add('submit', SubmitType::class, array('label' => 'Make default'))
|
||||||
|
->getForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new CustomFieldsGroup entity.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function createAction(Request $request)
|
||||||
|
{
|
||||||
|
$entity = new CustomFieldsGroup();
|
||||||
|
$form = $this->createCreateForm($entity);
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
if ($form->isValid()) {
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
$em->persist($entity);
|
||||||
|
$em->flush();
|
||||||
|
|
||||||
|
$this->addFlash('success', $this->translator
|
||||||
|
->trans("The custom fields group has been created"));
|
||||||
|
|
||||||
|
return $this->redirect($this->generateUrl('customfieldsgroup_show', array('id' => $entity->getId())));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addFlash('error', $this->translator
|
||||||
|
->trans("The custom fields group form contains errors"));
|
||||||
|
|
||||||
|
return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:new.html.twig', array(
|
||||||
|
'entity' => $entity,
|
||||||
|
'form' => $form->createView(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a form to create a CustomFieldsGroup entity.
|
||||||
|
*
|
||||||
|
* @param CustomFieldsGroup $entity The entity
|
||||||
|
*
|
||||||
|
* @return \Symfony\Component\Form\Form The form
|
||||||
|
*/
|
||||||
|
private function createCreateForm(CustomFieldsGroup $entity)
|
||||||
|
{
|
||||||
|
$form = $this->createForm(CustomFieldsGroupType::class, $entity, array(
|
||||||
|
'action' => $this->generateUrl('customfieldsgroup_create'),
|
||||||
|
'method' => 'POST',
|
||||||
|
));
|
||||||
|
|
||||||
|
$form->add('submit', SubmitType::class, array('label' => 'Create'));
|
||||||
|
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a form to create a new CustomFieldsGroup entity.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function newAction()
|
||||||
|
{
|
||||||
|
$entity = new CustomFieldsGroup();
|
||||||
|
$form = $this->createCreateForm($entity);
|
||||||
|
|
||||||
|
return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:new.html.twig', array(
|
||||||
|
'entity' => $entity,
|
||||||
|
'form' => $form->createView(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds and displays a CustomFieldsGroup entity.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function showAction($id)
|
||||||
|
{
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
|
$entity = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup')->find($id);
|
||||||
|
|
||||||
|
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(),
|
||||||
|
'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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function editAction($id)
|
||||||
|
{
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
|
$entity = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup')->find($id);
|
||||||
|
|
||||||
|
if (!$entity) {
|
||||||
|
throw $this->createNotFoundException('Unable to find CustomFieldsGroup entity.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$editForm = $this->createEditForm($entity);
|
||||||
|
|
||||||
|
return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:edit.html.twig', array(
|
||||||
|
'entity' => $entity,
|
||||||
|
'edit_form' => $editForm->createView(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a form to edit a CustomFieldsGroup entity.
|
||||||
|
*
|
||||||
|
* @param CustomFieldsGroup $entity The entity
|
||||||
|
*
|
||||||
|
* @return \Symfony\Component\Form\Form The form
|
||||||
|
*/
|
||||||
|
private function createEditForm(CustomFieldsGroup $entity)
|
||||||
|
{
|
||||||
|
$form = $this->createForm(CustomFieldsGroupType::class, $entity, array(
|
||||||
|
'action' => $this->generateUrl('customfieldsgroup_update', array('id' => $entity->getId())),
|
||||||
|
'method' => 'PUT',
|
||||||
|
));
|
||||||
|
$form->add('submit', SubmitType::class, array('label' => 'Update'));
|
||||||
|
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createCreateFieldForm(CustomFieldsGroup $customFieldsGroup)
|
||||||
|
{
|
||||||
|
|
||||||
|
$fieldChoices = array();
|
||||||
|
foreach ($this->customfieldProvider->getAllFields()
|
||||||
|
as $key => $customType) {
|
||||||
|
$fieldChoices[$key] = $customType->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
$customfield = (new CustomField())
|
||||||
|
->setCustomFieldsGroup($customFieldsGroup);
|
||||||
|
|
||||||
|
$builder = $this->get('form.factory')
|
||||||
|
->createNamedBuilder(null, FormType::class, $customfield, array(
|
||||||
|
'method' => 'GET',
|
||||||
|
'action' => $this->generateUrl('customfield_new'),
|
||||||
|
'csrf_protection' => false
|
||||||
|
))
|
||||||
|
->add('type', ChoiceType::class, array(
|
||||||
|
'choices' => array_combine(array_values($fieldChoices),array_keys($fieldChoices)),
|
||||||
|
))
|
||||||
|
->add('customFieldsGroup', HiddenType::class)
|
||||||
|
->add('submit', SubmitType::class);
|
||||||
|
$builder->get('customFieldsGroup')
|
||||||
|
->addViewTransformer(new CustomFieldsGroupToIdTransformer(
|
||||||
|
$this->getDoctrine()->getManager()));
|
||||||
|
|
||||||
|
return $builder->getForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edits an existing CustomFieldsGroup entity.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function updateAction(Request $request, $id)
|
||||||
|
{
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
|
$entity = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup')->find($id);
|
||||||
|
|
||||||
|
if (!$entity) {
|
||||||
|
throw $this->createNotFoundException('Unable to find CustomFieldsGroup entity.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$editForm = $this->createEditForm($entity);
|
||||||
|
$editForm->handleRequest($request);
|
||||||
|
|
||||||
|
if ($editForm->isValid()) {
|
||||||
|
$em->flush();
|
||||||
|
|
||||||
|
$this->addFlash('success', $this->translator
|
||||||
|
->trans("The custom fields group has been updated"));
|
||||||
|
|
||||||
|
return $this->redirect($this->generateUrl('customfieldsgroup_edit', array('id' => $id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addFlash('error', $this->translator
|
||||||
|
->trans("The custom fields group form contains errors"));
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
$this->addFlash('success', $this->translator
|
||||||
|
->trans("The default custom fields group has been changed"));
|
||||||
|
|
||||||
|
return $this->redirect($this->generateUrl('customfieldsgroup'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function render the customFieldsGroup as a form.
|
||||||
|
*
|
||||||
|
* This function is for testing purpose !
|
||||||
|
*
|
||||||
|
* The route which call this action is not in Resources/config/routing.yml,
|
||||||
|
* but in Tests/Fixtures/App/app/config.yml
|
||||||
|
*
|
||||||
|
* @param int $id
|
||||||
|
*/
|
||||||
|
public function renderFormAction($id, Request $request)
|
||||||
|
{
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
|
$entity = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup')->find($id);
|
||||||
|
|
||||||
|
if (!$entity) {
|
||||||
|
throw $this->createNotFoundException('Unable to find CustomFieldsGroups entity.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$form = $this->createForm(FormTypeCustomField::class, null, array('group' => $entity));
|
||||||
|
$form->add('submit_dump', SubmitType::class, array('label' => 'POST AND DUMP'));
|
||||||
|
$form->add('submit_render', SubmitType::class, array('label' => 'POST AND RENDER'));
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
$this->get('twig.loader')
|
||||||
|
->addPath(__DIR__.'/../Tests/Fixtures/App/app/Resources/views/',
|
||||||
|
$namespace = 'test');
|
||||||
|
|
||||||
|
if ($form->isSubmitted()) {
|
||||||
|
if ($form->get('submit_render')->isClicked()) {
|
||||||
|
return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:render_for_test.html.twig', array(
|
||||||
|
'fields' => $form->getData(),
|
||||||
|
'customFieldsGroup' => $entity
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
//dump($form->getData());
|
||||||
|
//dump(json_enccode($form->getData()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return $this
|
||||||
|
->render('@test/CustomField/simple_form_render.html.twig', array(
|
||||||
|
'form' => $form->createView()
|
||||||
|
));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\CustomFields;
|
||||||
|
|
||||||
|
use Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
abstract class AbstractCustomField implements CustomFieldInterface
|
||||||
|
{
|
||||||
|
public function isEmptyValue($value, CustomField $customField)
|
||||||
|
{
|
||||||
|
return (empty($value) and $value !== FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
413
src/Bundle/ChillCustomFields/CustomFields/CustomFieldChoice.php
Normal file
413
src/Bundle/ChillCustomFields/CustomFields/CustomFieldChoice.php
Normal file
@ -0,0 +1,413 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\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 Symfony\Component\HttpFoundation\RequestStack;
|
||||||
|
use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldDataTransformer;
|
||||||
|
use Symfony\Bridge\Twig\TwigEngine;
|
||||||
|
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
|
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
* @author Marc Ducobu <marc@champs-libes.coop>
|
||||||
|
*/
|
||||||
|
class CustomFieldChoice extends AbstractCustomField
|
||||||
|
{
|
||||||
|
const ALLOW_OTHER = 'other';
|
||||||
|
const OTHER_VALUE_LABEL = 'otherValueLabel';
|
||||||
|
const MULTIPLE = 'multiple';
|
||||||
|
const EXPANDED = 'expanded';
|
||||||
|
const CHOICES = 'choices';
|
||||||
|
|
||||||
|
private $defaultLocales;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var TwigEngine
|
||||||
|
*/
|
||||||
|
private $templating;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var TranslatableStringHelper Helper that find the string in current locale from an array of translation
|
||||||
|
*/
|
||||||
|
private $translatableStringHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CustomFieldChoice constructor.
|
||||||
|
*
|
||||||
|
* @param TranslatorInterface $translator
|
||||||
|
* @param TwigEngine $templating
|
||||||
|
* @param TranslatableStringHelper $translatableStringHelper
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
TranslatorInterface $translator,
|
||||||
|
TwigEngine $templating,
|
||||||
|
TranslatableStringHelper $translatableStringHelper)
|
||||||
|
{
|
||||||
|
$this->defaultLocales = $translator->getFallbackLocales();
|
||||||
|
$this->templating = $templating;
|
||||||
|
$this->translatableStringHelper = $translatableStringHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder, CustomField $customField)
|
||||||
|
{
|
||||||
|
//prepare choices
|
||||||
|
$choices = array();
|
||||||
|
$customFieldOptions = $customField->getOptions();
|
||||||
|
|
||||||
|
foreach($customFieldOptions[self::CHOICES] as $persistedChoices) {
|
||||||
|
if ($persistedChoices['active']){
|
||||||
|
$choices[$persistedChoices['slug']] = $this->translatableStringHelper->localize($persistedChoices['name']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//prepare $options
|
||||||
|
$options = array(
|
||||||
|
'multiple' => $customFieldOptions[self::MULTIPLE],
|
||||||
|
'choices' => array_combine(array_values($choices),array_keys($choices)),
|
||||||
|
'required' => $customField->isRequired(),
|
||||||
|
'label' => $this->translatableStringHelper->localize($customField->getName())
|
||||||
|
);
|
||||||
|
|
||||||
|
//if allow_other = true
|
||||||
|
if ($customFieldOptions[self::ALLOW_OTHER] == true) {
|
||||||
|
$otherValueLabel = null;
|
||||||
|
if(array_key_exists(self::OTHER_VALUE_LABEL, $customFieldOptions)) {
|
||||||
|
$otherValueLabel = $this->translatableStringHelper->localize(
|
||||||
|
$customFieldOptions[self::OTHER_VALUE_LABEL]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$builder->add(
|
||||||
|
$builder
|
||||||
|
->create(
|
||||||
|
$customField->getSlug(),
|
||||||
|
ChoiceWithOtherType::class,
|
||||||
|
$options,
|
||||||
|
array('other_value_label'=> $otherValueLabel)
|
||||||
|
)
|
||||||
|
->addModelTransformer(new CustomFieldDataTransformer($this, $customField)));
|
||||||
|
|
||||||
|
} else { //if allow_other = false
|
||||||
|
//we add the 'expanded' to options
|
||||||
|
$options['expanded'] = $customFieldOptions[self::EXPANDED];
|
||||||
|
|
||||||
|
$builder->add(
|
||||||
|
$builder->create($customField->getSlug(), ChoiceType::class, $options)
|
||||||
|
->addModelTransformer(new CustomFieldDataTransformer($this, $customField))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildOptionsForm(FormBuilderInterface $builder)
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
->add(self::MULTIPLE, ChoiceType::class, array(
|
||||||
|
'expanded' => true,
|
||||||
|
'multiple' => false,
|
||||||
|
'choices' => array(
|
||||||
|
'Multiple' => '1',
|
||||||
|
'Unique' => '0'),
|
||||||
|
'empty_data' => '0',
|
||||||
|
'label' => 'Multiplicity'
|
||||||
|
))
|
||||||
|
->add(self::EXPANDED, ChoiceType::class, array(
|
||||||
|
'expanded' => true,
|
||||||
|
'multiple' => false,
|
||||||
|
'choices' => array(
|
||||||
|
'Expanded' => '1',
|
||||||
|
'Non expanded' => '0'),
|
||||||
|
'empty_data' => '0',
|
||||||
|
'label' => 'Choice display'
|
||||||
|
))
|
||||||
|
->add(self::ALLOW_OTHER, ChoiceType::class, array(
|
||||||
|
'label' => 'Allow other',
|
||||||
|
'choices' => array(
|
||||||
|
'No' => '0',
|
||||||
|
'Yes' => '1'),
|
||||||
|
'empty_data' => '0',
|
||||||
|
'expanded' => true,
|
||||||
|
'multiple' => false
|
||||||
|
))
|
||||||
|
->add(self::OTHER_VALUE_LABEL, TranslatableStringFormType::class, array(
|
||||||
|
'label' => 'Other value label (empty if use by default)'))
|
||||||
|
->add(self::CHOICES, ChoicesType::class, array(
|
||||||
|
'entry_type' => ChoicesListType::class,
|
||||||
|
'allow_add' => true
|
||||||
|
));
|
||||||
|
|
||||||
|
return $builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (array_key_exists('_choices', $value)) {
|
||||||
|
return $value['_choices'];
|
||||||
|
} else {
|
||||||
|
// we have a field with "multiple"
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw \LogicException("This case is not expected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Choices';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isEmptyValue($value, CustomField $customField)
|
||||||
|
{
|
||||||
|
if ($value === NULL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if multiple choice OR multiple/single choice with other
|
||||||
|
if (is_array($value))
|
||||||
|
{
|
||||||
|
// if allow other
|
||||||
|
if (array_key_exists('_choices', $value)) {
|
||||||
|
if ($value['_choices'] === NULL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return empty($value['_choices']);
|
||||||
|
} else { // we do not have 'allow other'
|
||||||
|
if (count($value) === 1){
|
||||||
|
return empty($value[0]);
|
||||||
|
} else {
|
||||||
|
return empty($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return empty($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw \LogicException("This case is not expected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @internal this function is able to receive data whichever is the value of "other", "multiple"
|
||||||
|
* @param mixed $value
|
||||||
|
* @param CustomField $customField
|
||||||
|
* @return string html representation
|
||||||
|
*/
|
||||||
|
public function render($value, CustomField $customField, $documentType = 'html')
|
||||||
|
{
|
||||||
|
//extract the data. They are under a _choice key if they are stored with allow_other
|
||||||
|
$data = (isset($value['_choices'])) ? $value['_choices'] : $value;
|
||||||
|
$selected = (is_array($data)) ? $data : array($data);
|
||||||
|
$choices = $customField->getOptions()[self::CHOICES];
|
||||||
|
|
||||||
|
if (in_array('_other', $selected)){
|
||||||
|
$choices[] = array('name' => $value['_other'], 'slug' => '_other');
|
||||||
|
}
|
||||||
|
|
||||||
|
$template = 'ChillCustomFieldsBundle:CustomFieldsRendering:choice.html.twig';
|
||||||
|
if($documentType == 'csv') {
|
||||||
|
$template = 'ChillCustomFieldsBundle:CustomFieldsRendering:choice.csv.twig';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->templating
|
||||||
|
->render($template,
|
||||||
|
array(
|
||||||
|
'choices' => $choices,
|
||||||
|
'selected' => $selected,
|
||||||
|
'multiple' => $customField->getOptions()[self::MULTIPLE],
|
||||||
|
'expanded' => $customField->getOptions()[self::EXPANDED],
|
||||||
|
'locales' => $this->defaultLocales
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function serialize($value, CustomField $customField)
|
||||||
|
{
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getChoices(CustomField $cf)
|
||||||
|
{
|
||||||
|
if ($cf->getOptions()[self::MULTIPLE]) {
|
||||||
|
$choices = array();
|
||||||
|
|
||||||
|
foreach ($cf->getOptions()[self::CHOICES] as $choice) {
|
||||||
|
if ($choices['active'] === false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$choices[$choice["slug"]] = $this->translatableStringHelper
|
||||||
|
->localize($choice["name"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->allowOtherChoice($cf)) {
|
||||||
|
$labels = $cf->getOptions()[self::OTHER_VALUE_LABEL];
|
||||||
|
if (!is_array($labels) or count($labels) === 0) {
|
||||||
|
$labels['back'] = 'other value';
|
||||||
|
}
|
||||||
|
$choices['_other'] = $this->translatableStringHelper
|
||||||
|
->localize($labels);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $choices;
|
||||||
|
} else {
|
||||||
|
return [
|
||||||
|
$cf->getSlug() => $this->translatableStringHelper->localize($cf->getName())
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the choice given in $choiceSlug is checked inside $data.
|
||||||
|
*
|
||||||
|
* Used in list exports.
|
||||||
|
*
|
||||||
|
* @param CustomField $cf
|
||||||
|
* @param string $choiceSlug the slug of the choice we want to know if it was checked
|
||||||
|
* @param array|string $data the data of the field
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function isChecked(CustomField $cf, $choiceSlug, $data)
|
||||||
|
{
|
||||||
|
if ($data === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($cf->getOptions()[self::MULTIPLE]) {
|
||||||
|
if ($cf->getOptions()[self::ALLOW_OTHER]) {
|
||||||
|
return \in_array($choiceSlug, $this->deserialize($data, $cf)['_choices']);
|
||||||
|
} else {
|
||||||
|
return \in_array($choiceSlug, $this->deserialize($data, $cf));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($cf->getOptions()[self::ALLOW_OTHER]) {
|
||||||
|
return $this->deserialize($data, $cf)['_choices'] === $choiceSlug;
|
||||||
|
} else {
|
||||||
|
return $this->deserialize($data, $cf) === $choiceSlug;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isMultiple(CustomField $cf)
|
||||||
|
{
|
||||||
|
return $cf->getOptions()[self::MULTIPLE];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function allowOtherChoice(CustomField $cf)
|
||||||
|
{
|
||||||
|
return $cf->getOptions()[self::ALLOW_OTHER];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function extractOtherValue(CustomField $cf, array $data = null)
|
||||||
|
{
|
||||||
|
return $data['_other'];
|
||||||
|
}
|
||||||
|
}
|
241
src/Bundle/ChillCustomFields/CustomFields/CustomFieldDate.php
Normal file
241
src/Bundle/ChillCustomFields/CustomFields/CustomFieldDate.php
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
|
||||||
|
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\CustomFields;
|
||||||
|
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomField;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\Validator\Constraints\GreaterThanOrEqual;
|
||||||
|
use Symfony\Component\Validator\Constraints\LessThanOrEqual;
|
||||||
|
use Symfony\Bundle\TwigBundle\TwigEngine;
|
||||||
|
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||||
|
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
|
use Symfony\Component\Validator\Constraints\Callback;
|
||||||
|
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldDataTransformer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a custom date number.
|
||||||
|
*
|
||||||
|
* The date may have a min and max value.
|
||||||
|
*
|
||||||
|
* The date is stored as an unix timestamp.
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class CustomFieldDate extends AbstractCustomField
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* key for the minimal value of the field
|
||||||
|
*/
|
||||||
|
const MIN = 'min';
|
||||||
|
const MAX = 'max';
|
||||||
|
const FORMAT = 'format';
|
||||||
|
const DATE_FORMAT = \DateTime::RFC3339;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @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)
|
||||||
|
{
|
||||||
|
$fieldOptions = $this->prepareFieldOptions($customField);
|
||||||
|
|
||||||
|
$builder->add(
|
||||||
|
$builder
|
||||||
|
->create(
|
||||||
|
$customField->getSlug(),
|
||||||
|
ChillDateType::class,
|
||||||
|
$fieldOptions)
|
||||||
|
->addModelTransformer(
|
||||||
|
new CustomFieldDataTransformer($this, $customField)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prepare the options'form field
|
||||||
|
*
|
||||||
|
* @param CustomField $customField
|
||||||
|
* @param string $type
|
||||||
|
* @return mixed[]
|
||||||
|
*/
|
||||||
|
private function prepareFieldOptions(CustomField $customField)
|
||||||
|
{
|
||||||
|
$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 Callback(
|
||||||
|
function($timestamp, ExecutionContextInterface $context) use ($options) {
|
||||||
|
if ($timestamp === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = \DateTime::createFromFormat(self::DATE_FORMAT, $timestamp);
|
||||||
|
$after = new \DateTime($options[self::MIN]);
|
||||||
|
|
||||||
|
if ($value < $after) {
|
||||||
|
$context
|
||||||
|
->buildViolation('This date must be after or equal to %date%', [
|
||||||
|
'%date%' => $after->format('d-m-Y')
|
||||||
|
])
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ($options[self::MAX] !== NULL) {
|
||||||
|
$fieldOptions['constraints'][] = new Callback(
|
||||||
|
function($timestamp, ExecutionContextInterface $context) use ($options) {
|
||||||
|
if ($timestamp === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = \DateTime::createFromFormat(self::DATE_FORMAT, $timestamp);
|
||||||
|
$before = new \DateTime($options[self::MAX]);
|
||||||
|
|
||||||
|
if ($value > $before) {
|
||||||
|
$context
|
||||||
|
->buildViolation('This date must be before or equal to %date%', [
|
||||||
|
'%date%' => $before->format('d-m-Y')
|
||||||
|
])
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $fieldOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildOptionsForm(FormBuilderInterface $builder)
|
||||||
|
{
|
||||||
|
$validatorFunction = function($value, ExecutionContextInterface $context) {
|
||||||
|
try {
|
||||||
|
$date = new \DateTime($value);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$context->buildViolation('The expression "%expression%" is invalid', [
|
||||||
|
'%expression%' => $value
|
||||||
|
])
|
||||||
|
->addViolation()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return $builder
|
||||||
|
->add(self::MIN, TextType::class, array(
|
||||||
|
'label' => 'Greater or equal than (expression like 1 day ago, 2 years ago, +1 month, today, tomorrow, or date with format YYYY-mm-dd)',
|
||||||
|
'required' => false,
|
||||||
|
'constraints' => [ new Callback($validatorFunction) ]
|
||||||
|
))
|
||||||
|
->add(self::MAX, TextType::class, array(
|
||||||
|
'label' => 'Lesser or equal than (expression like 1 day ago, 2 years ago, +1 month, today, tomorrow, or date with format YYYY-mm-dd)',
|
||||||
|
'required' => false,
|
||||||
|
'constraints' => [ new Callback($validatorFunction) ]
|
||||||
|
))
|
||||||
|
->add(self::FORMAT, ChoiceType::class, [
|
||||||
|
'label' => 'Format',
|
||||||
|
'choices' => [
|
||||||
|
'medium' => 'medium',
|
||||||
|
'long' => 'long',
|
||||||
|
'short' => 'short'
|
||||||
|
]
|
||||||
|
])
|
||||||
|
;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deserialize($serialized, CustomField $customField)
|
||||||
|
{
|
||||||
|
if (empty($serialized)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return \DateTime::createFromFormat(self::DATE_FORMAT, $serialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Date field';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render($value, CustomField $customField, $documentType = 'html')
|
||||||
|
{
|
||||||
|
switch ($documentType) {
|
||||||
|
case 'csv':
|
||||||
|
$date = $this->deserialize($value, $customField);
|
||||||
|
if (NULL === $date) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $date->format('Y-m-d');
|
||||||
|
default:
|
||||||
|
$template = 'ChillCustomFieldsBundle:CustomFieldsRendering:date.'
|
||||||
|
.$documentType.'.twig';
|
||||||
|
|
||||||
|
return $this->templating
|
||||||
|
->render($template, array(
|
||||||
|
'value' => $this->deserialize($value, $customField),
|
||||||
|
'format' => $customField->getOptions()[self::FORMAT]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function serialize($date, CustomField $customField)
|
||||||
|
{
|
||||||
|
if ($date === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $date->format(self::DATE_FORMAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\CustomFields;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
public function buildForm(FormBuilderInterface $builder, CustomField $customField);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform the value into a format that can be stored in DB
|
||||||
|
*
|
||||||
|
* @param mixed $value
|
||||||
|
* @param \Chill\CustomFieldsBundle\CustomField\CustomField $customField
|
||||||
|
*/
|
||||||
|
public function serialize($value, CustomField $customField);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform the representation of the value, stored in db, into the
|
||||||
|
* value which may be used in the process.
|
||||||
|
*
|
||||||
|
* @param mixed $value
|
||||||
|
* @param \Chill\CustomFieldsBundle\CustomField\CustomField $customField
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
* @return string an html representation of the value
|
||||||
|
*/
|
||||||
|
public function render($value, CustomField $customField, $documentType = 'html');
|
||||||
|
|
||||||
|
public function getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a formType which allow to edit option for the custom type.
|
||||||
|
* This FormType is shown in admin
|
||||||
|
*
|
||||||
|
* @param \Chill\CustomFieldsBundle\CustomField\FormBuilderInterface $builder
|
||||||
|
* @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);
|
||||||
|
}
|
@ -0,0 +1,162 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\CustomFields;
|
||||||
|
|
||||||
|
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;
|
||||||
|
use Chill\MainBundle\Form\Type\Select2ChoiceType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class CustomFieldLongChoice extends AbstractCustomField
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @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(), Select2ChoiceType::class, 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();
|
||||||
|
},
|
||||||
|
'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());
|
||||||
|
} 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, ChoiceType::class, array(
|
||||||
|
'choices' => array_combine(array_values($choices),array_keys($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 field';
|
||||||
|
}
|
||||||
|
|
||||||
|
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' => $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, '
|
||||||
|
. 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
186
src/Bundle/ChillCustomFields/CustomFields/CustomFieldNumber.php
Normal file
186
src/Bundle/ChillCustomFields/CustomFields/CustomFieldNumber.php
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
|
||||||
|
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\CustomFields;
|
||||||
|
|
||||||
|
use 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 Symfony\Component\Form\Extension\Core\Type\NumberType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
|
||||||
|
use Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomField;
|
||||||
|
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a custom field number.
|
||||||
|
*
|
||||||
|
* This number may have a min and max value, and a precision.
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
* @author Marc Ducobu <marc@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class CustomFieldNumber extends AbstractCustomField
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 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)?
|
||||||
|
IntegerType::class : NumberType::class;
|
||||||
|
//'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, NumberType::class, array(
|
||||||
|
'scale' => 2,
|
||||||
|
'label' => 'Greater or equal than',
|
||||||
|
'required' => false
|
||||||
|
))
|
||||||
|
->add(self::MAX, NumberType::class, array(
|
||||||
|
'scale' => 2,
|
||||||
|
'label' => 'Lesser or equal than',
|
||||||
|
'required' => false
|
||||||
|
))
|
||||||
|
->add(self::SCALE, IntegerType::class, array(
|
||||||
|
'scale' => 0,
|
||||||
|
'label' => 'Precision',
|
||||||
|
'constraints' => array(
|
||||||
|
new GreaterThanOrEqual(array('value' => 0))
|
||||||
|
)
|
||||||
|
))
|
||||||
|
->add(self::POST_TEXT, TextType::class, array(
|
||||||
|
'label' => 'Text after the field'
|
||||||
|
))
|
||||||
|
;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deserialize($serialized, CustomField $customField)
|
||||||
|
{
|
||||||
|
return $serialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Number field';
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
138
src/Bundle/ChillCustomFields/CustomFields/CustomFieldText.php
Normal file
138
src/Bundle/ChillCustomFields/CustomFields/CustomFieldText.php
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
|
||||||
|
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\CustomFields;
|
||||||
|
|
||||||
|
use Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomField;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
|
use Symfony\Bundle\TwigBundle\TwigEngine;
|
||||||
|
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
* @author Marc Ducobu <marc@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class CustomFieldText extends AbstractCustomField
|
||||||
|
{
|
||||||
|
|
||||||
|
private $requestStack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @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, TwigEngine $templating,
|
||||||
|
TranslatableStringHelper $translatableStringHelper)
|
||||||
|
{
|
||||||
|
$this->requestStack = $requestStack;
|
||||||
|
$this->templating = $templating;
|
||||||
|
$this->translatableStringHelper = $translatableStringHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_LENGTH = 'maxLength';
|
||||||
|
const MULTIPLE_CF_INLINE ='multipleCFInline';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a form according to the maxLength option
|
||||||
|
*
|
||||||
|
* if maxLength < 256 THEN the form type is 'text'
|
||||||
|
* if not, THEN the form type is textarea
|
||||||
|
*
|
||||||
|
* @param FormBuilderInterface $builder
|
||||||
|
* @param CustomField $customField
|
||||||
|
*/
|
||||||
|
public function buildForm(FormBuilderInterface $builder, CustomField $customField)
|
||||||
|
{
|
||||||
|
$options = $customField->getOptions();
|
||||||
|
|
||||||
|
$type = ($options[self::MAX_LENGTH] < 256) ? TextType::class
|
||||||
|
: TextareaType::class;
|
||||||
|
|
||||||
|
$attrArray = array();
|
||||||
|
|
||||||
|
if(array_key_exists(self::MULTIPLE_CF_INLINE, $options) and
|
||||||
|
$options[self::MULTIPLE_CF_INLINE]) {
|
||||||
|
$attrArray['class'] = 'multiple-cf-inline';
|
||||||
|
}
|
||||||
|
|
||||||
|
$builder->add($customField->getSlug(), $type, array(
|
||||||
|
'label' => $this->translatableStringHelper->localize($customField->getName()),
|
||||||
|
'required' => false,
|
||||||
|
'attr' => $attrArray
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render($value, CustomField $customField, $documentType = 'html')
|
||||||
|
{
|
||||||
|
$template = 'ChillCustomFieldsBundle:CustomFieldsRendering:text.html.twig';
|
||||||
|
if($documentType == 'csv') {
|
||||||
|
$template = 'ChillCustomFieldsBundle:CustomFieldsRendering:text.csv.twig';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->templating
|
||||||
|
->render($template, array('text' => $value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function serialize($value, CustomField $customField)
|
||||||
|
{
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deserialize($serialized, CustomField $customField)
|
||||||
|
{
|
||||||
|
return $serialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Text field';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildOptionsForm(FormBuilderInterface $builder)
|
||||||
|
{
|
||||||
|
return $builder
|
||||||
|
->add(self::MAX_LENGTH, IntegerType::class, array('empty_data' => 256))
|
||||||
|
->add(self::MULTIPLE_CF_INLINE, ChoiceType::class, array(
|
||||||
|
'choices' => array(
|
||||||
|
'Multiple boxes on the line' => '1',
|
||||||
|
'One box on the line' => '0'
|
||||||
|
),
|
||||||
|
'label' => 'Box appearance',
|
||||||
|
'expanded' => True
|
||||||
|
))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
115
src/Bundle/ChillCustomFields/CustomFields/CustomFieldTitle.php
Normal file
115
src/Bundle/ChillCustomFields/CustomFields/CustomFieldTitle.php
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\CustomFields;
|
||||||
|
|
||||||
|
use Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomField;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
|
use Symfony\Bundle\TwigBundle\TwigEngine;
|
||||||
|
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
|
use Chill\CustomFieldsBundle\Form\Type\CustomFieldsTitleType;
|
||||||
|
|
||||||
|
class CustomFieldTitle extends AbstractCustomField
|
||||||
|
{
|
||||||
|
const TYPE = 'type';
|
||||||
|
const TYPE_TITLE = 'title';
|
||||||
|
const TYPE_SUBTITLE = 'subtitle';
|
||||||
|
|
||||||
|
private $requestStack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @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, TwigEngine $templating,
|
||||||
|
TranslatableStringHelper $translatableStringHelper)
|
||||||
|
{
|
||||||
|
$this->requestStack = $requestStack;
|
||||||
|
$this->templating = $templating;
|
||||||
|
$this->translatableStringHelper = $translatableStringHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder, CustomField $customField)
|
||||||
|
{
|
||||||
|
$builder->add($customField->getSlug(), CustomFieldsTitleType::class, array(
|
||||||
|
'label' => false,
|
||||||
|
'attr' => array(
|
||||||
|
'class' => 'cf-title',
|
||||||
|
'title' => $this->translatableStringHelper->localize($customField->getName()),
|
||||||
|
self::TYPE => $customField->getOptions()[self::TYPE ]
|
||||||
|
)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render($value, CustomField $customField, $documentType = 'html')
|
||||||
|
{
|
||||||
|
return $this->templating
|
||||||
|
->render('ChillCustomFieldsBundle:CustomFieldsRendering:title.html.twig',
|
||||||
|
array(
|
||||||
|
'title' => $customField->getName(),
|
||||||
|
'type' => $customField->getOptions()[self::TYPE]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function serialize($value, CustomField $customField)
|
||||||
|
{
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deserialize($serialized, CustomField $customField)
|
||||||
|
{
|
||||||
|
return $serialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Title';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isEmptyValue($value, CustomField $customField)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildOptionsForm(FormBuilderInterface $builder)
|
||||||
|
{
|
||||||
|
return $builder->add(self::TYPE, ChoiceType::class,
|
||||||
|
array(
|
||||||
|
'choices' => array(
|
||||||
|
'Main title' => self::TYPE_TITLE,
|
||||||
|
'Subtitle' => self::TYPE_SUBTITLE
|
||||||
|
),
|
||||||
|
'label' => 'Title level',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
181
src/Bundle/ChillCustomFields/DataFixtures/ORM/LoadOption.php
Normal file
181
src/Bundle/ChillCustomFields/DataFixtures/ORM/LoadOption.php
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\DataFixtures\ORM;
|
||||||
|
|
||||||
|
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||||
|
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option;
|
||||||
|
use Doctrine\Persistence\ObjectManager;
|
||||||
|
|
||||||
|
error_reporting(0);
|
||||||
|
/**
|
||||||
|
* Load some Options
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
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(ObjectManager $manager)
|
||||||
|
{
|
||||||
|
echo "Loading Options \n";
|
||||||
|
|
||||||
|
// load companies
|
||||||
|
$this->loadingCompanies($manager);
|
||||||
|
$this->loadingWords($manager);
|
||||||
|
|
||||||
|
$manager->flush();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loadingWords(\Doctrine\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\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);
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\DependencyInjection;
|
||||||
|
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
use Symfony\Component\Config\FileLocator;
|
||||||
|
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||||
|
use Symfony\Component\DependencyInjection\Loader;
|
||||||
|
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the class that loads and manages your bundle configuration
|
||||||
|
*
|
||||||
|
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
|
||||||
|
*/
|
||||||
|
class ChillCustomFieldsExtension extends Extension implements PrependExtensionInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function load(array $configs, ContainerBuilder $container)
|
||||||
|
{
|
||||||
|
$configuration = new Configuration();
|
||||||
|
$config = $this->processConfiguration($configuration, $configs);
|
||||||
|
|
||||||
|
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config'));
|
||||||
|
$loader->load('services.yaml');
|
||||||
|
$loader->load('services/fixtures.yaml');
|
||||||
|
$loader->load('services/controller.yaml');
|
||||||
|
$loader->load('services/command.yaml');
|
||||||
|
|
||||||
|
//add at least a blank array at 'customizable_entities' options
|
||||||
|
//$customizable_entities = (isset($config['customizables_entities'])
|
||||||
|
// && $config['customizables_entities'] !== FALSE)
|
||||||
|
// ? $config['customizables_entities'] : array();
|
||||||
|
|
||||||
|
$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)
|
||||||
|
* @see \Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface::prepend()
|
||||||
|
*/
|
||||||
|
public function prepend(ContainerBuilder $container)
|
||||||
|
{
|
||||||
|
// add form layout to twig resources
|
||||||
|
$twigConfig['form_themes'][] = 'ChillCustomFieldsBundle:Form:fields.html.twig';
|
||||||
|
$container->prependExtensionConfig('twig', $twigConfig);
|
||||||
|
|
||||||
|
//add routes for custom bundle
|
||||||
|
$container->prependExtensionConfig('chill_main', array(
|
||||||
|
'routing' => array(
|
||||||
|
'resources' => array(
|
||||||
|
'@ChillCustomFieldsBundle/config/routes.yaml'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\DependencyInjection;
|
||||||
|
|
||||||
|
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||||
|
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the class that validates and merges configuration from
|
||||||
|
* your app/config files
|
||||||
|
*
|
||||||
|
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class}
|
||||||
|
*/
|
||||||
|
class Configuration implements ConfigurationInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getConfigTreeBuilder()
|
||||||
|
{
|
||||||
|
$treeBuilder = new TreeBuilder('chill_custom_fields');
|
||||||
|
$rootNode = $treeBuilder->getRootNode('chill_custom_fields');
|
||||||
|
|
||||||
|
$classInfo = "The class which may receive custom fields";
|
||||||
|
$nameInfo = "The name which will appears in the user interface. May be translatable";
|
||||||
|
$optionsInfo = "Options available for custom fields groups referencing this class";
|
||||||
|
$optionsFormType = "The name of the form to append";
|
||||||
|
$optionsFormOptionsInfos = "the arguments to pass the form";
|
||||||
|
$customizableEntitiesInfo = "A list of customizable entities";
|
||||||
|
|
||||||
|
$rootNode
|
||||||
|
->children()
|
||||||
|
->arrayNode('customizables_entities')
|
||||||
|
->info($customizableEntitiesInfo)
|
||||||
|
->defaultValue(array())
|
||||||
|
->prototype('array')
|
||||||
|
->children()
|
||||||
|
->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()
|
||||||
|
->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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\DependencyInjection;
|
||||||
|
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\Reference;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class CustomFieldCompilerPass implements CompilerPassInterface
|
||||||
|
{
|
||||||
|
public function process(ContainerBuilder $container)
|
||||||
|
{
|
||||||
|
if (!$container->hasDefinition('chill.custom_field.provider')) {
|
||||||
|
throw new \LogicException('service chill.custom_field.provider '
|
||||||
|
. 'is not defined.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$definition = $container->getDefinition(
|
||||||
|
'chill.custom_field.provider'
|
||||||
|
);
|
||||||
|
|
||||||
|
$taggedServices = $container->findTaggedServiceIds(
|
||||||
|
'chill.custom_field'
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($taggedServices as $id => $tagAttributes) {
|
||||||
|
foreach ($tagAttributes as $attributes) {
|
||||||
|
$definition->addMethodCall(
|
||||||
|
'addCustomField',
|
||||||
|
array(new Reference($id), $attributes["type"])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
312
src/Bundle/ChillCustomFields/Entity/CustomField.php
Normal file
312
src/Bundle/ChillCustomFields/Entity/CustomField.php
Normal file
@ -0,0 +1,312 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Entity;
|
||||||
|
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CustomField
|
||||||
|
*
|
||||||
|
* @ORM\Entity()
|
||||||
|
* @ORM\Table(name="customfield")
|
||||||
|
* @ORM\HasLifecycleCallbacks()
|
||||||
|
*/
|
||||||
|
class CustomField
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var integer
|
||||||
|
*
|
||||||
|
* @ORM\Id
|
||||||
|
* @ORM\Column(name="id", type="integer")
|
||||||
|
* @ORM\GeneratedValue(strategy="AUTO")
|
||||||
|
*/
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*
|
||||||
|
* @ORM\Column(type="string", length=255)
|
||||||
|
*/
|
||||||
|
private $slug;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*
|
||||||
|
* @ORM\Column(type="string", length=255)
|
||||||
|
*/
|
||||||
|
private $type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var boolean
|
||||||
|
*
|
||||||
|
* @ORM\Column(type="boolean")
|
||||||
|
*/
|
||||||
|
private $active = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*
|
||||||
|
* @ORM\Column(type="json_array")
|
||||||
|
*/
|
||||||
|
private $options = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*
|
||||||
|
* @ORM\Column(type="json_array")
|
||||||
|
*/
|
||||||
|
private $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*
|
||||||
|
* @ORM\Column(type="float")
|
||||||
|
*/
|
||||||
|
private $ordering;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var boolean
|
||||||
|
*
|
||||||
|
* @ORM\Column(type="boolean")
|
||||||
|
*/
|
||||||
|
private $required = FALSE;
|
||||||
|
|
||||||
|
const ONE_TO_ONE = 1;
|
||||||
|
const ONE_TO_MANY = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var CustomFieldsGroup
|
||||||
|
*
|
||||||
|
* @ORM\ManyToOne(
|
||||||
|
* targetEntity="Chill\CustomFieldsBundle\Entity\CustomFieldsGroup",
|
||||||
|
* inversedBy="customFields")
|
||||||
|
*/
|
||||||
|
private $customFieldGroup;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get id
|
||||||
|
*
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function getSlug()
|
||||||
|
{
|
||||||
|
return $this->slug;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getOptions()
|
||||||
|
{
|
||||||
|
return $this->options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set type
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* @return CustomField
|
||||||
|
*/
|
||||||
|
public function setType($type)
|
||||||
|
{
|
||||||
|
$this->type = $type;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get type
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getType()
|
||||||
|
{
|
||||||
|
return $this->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set active
|
||||||
|
*
|
||||||
|
* @param boolean $active
|
||||||
|
* @return CustomField
|
||||||
|
*/
|
||||||
|
public function setActive($active)
|
||||||
|
{
|
||||||
|
$this->active = $active;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the custom field is active
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function isActive()
|
||||||
|
{
|
||||||
|
return $this->active;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get customFieldGroup
|
||||||
|
*
|
||||||
|
* @return CustomFieldsGroup
|
||||||
|
*/
|
||||||
|
public function getCustomFieldsGroup()
|
||||||
|
{
|
||||||
|
return $this->customFieldGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set customFieldGroup
|
||||||
|
*
|
||||||
|
* @param CustomFieldsGroup $customFieldGroup
|
||||||
|
* @return CustomField
|
||||||
|
*/
|
||||||
|
public function setCustomFieldsGroup(CustomFieldsGroup $customFieldGroup = null)
|
||||||
|
{
|
||||||
|
$this->customFieldGroup = $customFieldGroup;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set name
|
||||||
|
*
|
||||||
|
* @param array $name
|
||||||
|
* @return CustomField
|
||||||
|
*/
|
||||||
|
public function setName($name)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get name
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getName($locale = null)
|
||||||
|
{
|
||||||
|
if ($locale) {
|
||||||
|
if (isset($this->name[$locale])) {
|
||||||
|
return $this->name[$locale];
|
||||||
|
} else {
|
||||||
|
foreach ($this->name as $name) {
|
||||||
|
if (!empty($name)) {
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return $this->name;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set order
|
||||||
|
*
|
||||||
|
* @param float $order
|
||||||
|
* @return CustomField
|
||||||
|
*/
|
||||||
|
public function setOrdering($order)
|
||||||
|
{
|
||||||
|
$this->ordering = $order;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get order
|
||||||
|
*
|
||||||
|
* @return float
|
||||||
|
*/
|
||||||
|
public function getOrdering()
|
||||||
|
{
|
||||||
|
return $this->ordering;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set options
|
||||||
|
*
|
||||||
|
* @param array $options
|
||||||
|
* @return CustomField
|
||||||
|
*/
|
||||||
|
public function setOptions(array $options)
|
||||||
|
{
|
||||||
|
$this->options = $options;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $slug
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setSlug($slug)
|
||||||
|
{
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,210 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice;
|
||||||
|
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Entity(
|
||||||
|
* repositoryClass="Chill\CustomFieldsBundle\EntityRepository\CustomFieldLongChoice\OptionRepository")
|
||||||
|
* @ORM\Table(name="custom_field_long_choice_options")
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class Option
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var integer
|
||||||
|
*
|
||||||
|
* @ORM\Id
|
||||||
|
* @ORM\Column(name="id", type="integer")
|
||||||
|
* @ORM\GeneratedValue(strategy="AUTO")
|
||||||
|
*/
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
* @ORM\Column(type="string", length=15)
|
||||||
|
*/
|
||||||
|
private $key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A json representation of text (multilingual)
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
* @ORM\Column(type="json_array")
|
||||||
|
*/
|
||||||
|
private $text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Collection
|
||||||
|
* @ORM\OneToMany(
|
||||||
|
* targetEntity="Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option",
|
||||||
|
* mappedBy="parent")
|
||||||
|
*/
|
||||||
|
private $children;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Option
|
||||||
|
* @ORM\ManyToOne(
|
||||||
|
* targetEntity="Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option",
|
||||||
|
* inversedBy="children")
|
||||||
|
* @ORM\JoinColumn(nullable=true)
|
||||||
|
*/
|
||||||
|
private $parent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
* @ORM\Column(type="string", length=50, name="internal_key")
|
||||||
|
*/
|
||||||
|
private $internalKey = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var boolean
|
||||||
|
* @ORM\Column(type="boolean")
|
||||||
|
*/
|
||||||
|
private $active = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getKey()
|
||||||
|
{
|
||||||
|
return $this->key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getText()
|
||||||
|
{
|
||||||
|
return $this->text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getChildren()
|
||||||
|
{
|
||||||
|
return $this->children;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Option
|
||||||
|
*/
|
||||||
|
public function getParent()
|
||||||
|
{
|
||||||
|
return $this->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $key
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setKey($key)
|
||||||
|
{
|
||||||
|
$this->key = $key;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $text
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setText(array $text)
|
||||||
|
{
|
||||||
|
$this->text = $text;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Option|null $parent
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getInternalKey()
|
||||||
|
{
|
||||||
|
return $this->internalKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isActive()
|
||||||
|
{
|
||||||
|
return $this->active;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getActive()
|
||||||
|
{
|
||||||
|
return $this->isActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $internal_key
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setInternalKey($internal_key)
|
||||||
|
{
|
||||||
|
$this->internalKey = $internal_key;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $active
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setActive($active)
|
||||||
|
{
|
||||||
|
$this->active = $active;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
120
src/Bundle/ChillCustomFields/Entity/CustomFieldsDefaultGroup.php
Normal file
120
src/Bundle/ChillCustomFields/Entity/CustomFieldsDefaultGroup.php
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Entity;
|
||||||
|
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CustomFieldsDefaultGroup
|
||||||
|
*
|
||||||
|
* @ORM\Entity()
|
||||||
|
* @ORM\Table(
|
||||||
|
* name="customfieldsdefaultgroup",
|
||||||
|
* uniqueConstraints={@ORM\UniqueConstraint(
|
||||||
|
* name="unique_entity",
|
||||||
|
* columns={"entity"}
|
||||||
|
* )})
|
||||||
|
*/
|
||||||
|
class CustomFieldsDefaultGroup
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var integer
|
||||||
|
*
|
||||||
|
* @ORM\Id
|
||||||
|
* @ORM\Column(name="id", type="integer")
|
||||||
|
* @ORM\GeneratedValue(strategy="AUTO")
|
||||||
|
*/
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*
|
||||||
|
* @ORM\Column(type="string", length=255)
|
||||||
|
*/
|
||||||
|
private $entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var CustomFieldsGroup
|
||||||
|
*
|
||||||
|
* @ORM\ManyToOne(
|
||||||
|
* targetEntity="Chill\CustomFieldsBundle\Entity\CustomFieldsGroup")
|
||||||
|
*
|
||||||
|
* sf4 check: option inversedBy="customFields" return inconsistent error mapping !!
|
||||||
|
*/
|
||||||
|
private $customFieldsGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get id
|
||||||
|
*
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set entity
|
||||||
|
*
|
||||||
|
* @param string $entity
|
||||||
|
* @return CustomFieldsDefaultGroup
|
||||||
|
*/
|
||||||
|
public function setEntity($entity)
|
||||||
|
{
|
||||||
|
$this->entity = $entity;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get entity
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getEntity()
|
||||||
|
{
|
||||||
|
return $this->entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set customFieldsGroup
|
||||||
|
*
|
||||||
|
* @param CustomFieldsGroup $customFieldsGroup *
|
||||||
|
* @return CustomFieldsDefaultGroup
|
||||||
|
*/
|
||||||
|
public function setCustomFieldsGroup($customFieldsGroup)
|
||||||
|
{
|
||||||
|
$this->customFieldsGroup = $customFieldsGroup;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get customFieldsGroup
|
||||||
|
*
|
||||||
|
* @return CustomFieldsGroup
|
||||||
|
*/
|
||||||
|
public function getCustomFieldsGroup()
|
||||||
|
{
|
||||||
|
return $this->customFieldsGroup;
|
||||||
|
}
|
||||||
|
}
|
239
src/Bundle/ChillCustomFields/Entity/CustomFieldsGroup.php
Normal file
239
src/Bundle/ChillCustomFields/Entity/CustomFieldsGroup.php
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Entity;
|
||||||
|
|
||||||
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CustomFieldGroup
|
||||||
|
*
|
||||||
|
* @ORM\Entity()
|
||||||
|
* @ORM\Table(name="customfieldsgroup")
|
||||||
|
*/
|
||||||
|
class CustomFieldsGroup
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var integer
|
||||||
|
*
|
||||||
|
* @ORM\Id
|
||||||
|
* @ORM\Column(name="id", type="integer")
|
||||||
|
* @ORM\GeneratedValue(strategy="AUTO")
|
||||||
|
*/
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*
|
||||||
|
* @ORM\Column(type="json_array")
|
||||||
|
*/
|
||||||
|
private $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*
|
||||||
|
* @ORM\Column(type="string", length=255)
|
||||||
|
*/
|
||||||
|
private $entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The custom fields of the group.
|
||||||
|
* The custom fields are asc-ordered regarding to their property "ordering".
|
||||||
|
*
|
||||||
|
* @var Collection $customFields
|
||||||
|
*
|
||||||
|
* @ORM\OneToMany(
|
||||||
|
* targetEntity="Chill\CustomFieldsBundle\Entity\CustomField",
|
||||||
|
* mappedBy="customFieldGroup")
|
||||||
|
* @ORM\OrderBy({"ordering" = "ASC"})
|
||||||
|
*/
|
||||||
|
private $customFields;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The custom fields of the group that are active.
|
||||||
|
* This variable if null, if this informations has not been computed.
|
||||||
|
*
|
||||||
|
* @var array|null
|
||||||
|
*/
|
||||||
|
private $activeCustomFields = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*
|
||||||
|
* @ORM\Column(type="json_array")
|
||||||
|
*/
|
||||||
|
private $options = array();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CustomFieldsGroup constructor.
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->customFields = new ArrayCollection();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add customField
|
||||||
|
*
|
||||||
|
* @param CustomField $customField
|
||||||
|
* @return CustomFieldsGroup
|
||||||
|
*/
|
||||||
|
public function addCustomField(CustomField $customField)
|
||||||
|
{
|
||||||
|
$this->customFields[] = $customField;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove customField
|
||||||
|
*
|
||||||
|
* @param CustomField $customField
|
||||||
|
*/
|
||||||
|
public function removeCustomField(CustomField $customField)
|
||||||
|
{
|
||||||
|
$this->customFields->removeElement($customField);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getCustomFields()
|
||||||
|
{
|
||||||
|
return $this->customFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the custom
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getActiveCustomFields()
|
||||||
|
{
|
||||||
|
if($this->activeCustomFields === null) {
|
||||||
|
$this->activeCustomFields = array();
|
||||||
|
foreach ($this->customFields as $cf) {
|
||||||
|
if($cf->isActive()) {
|
||||||
|
array_push($this->activeCustomFields, $cf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->activeCustomFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get id
|
||||||
|
*
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set name
|
||||||
|
*
|
||||||
|
* @param array $name
|
||||||
|
* @return CustomFieldsGroup
|
||||||
|
*/
|
||||||
|
public function setName($name)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get name
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getName($language = null)
|
||||||
|
{
|
||||||
|
//TODO set this in a service, PLUS twig function
|
||||||
|
if ($language) {
|
||||||
|
if (isset($this->name[$language])) {
|
||||||
|
return $this->name[$language];
|
||||||
|
} else {
|
||||||
|
foreach ($this->name as $name) {
|
||||||
|
if (!empty($name)) {
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set entity
|
||||||
|
*
|
||||||
|
* @param string $entity
|
||||||
|
* @return CustomFieldsGroup
|
||||||
|
*/
|
||||||
|
public function setEntity($entity)
|
||||||
|
{
|
||||||
|
$this->entity = $entity;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get entity
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getEntity()
|
||||||
|
{
|
||||||
|
return $this->entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get options array
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getOptions()
|
||||||
|
{
|
||||||
|
return $this->options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set options array
|
||||||
|
*
|
||||||
|
* @param array $options
|
||||||
|
* @return CustomFieldsGroup
|
||||||
|
*/
|
||||||
|
public function setOptions(array $options)
|
||||||
|
{
|
||||||
|
$this->options = $options;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\EntityRepository\CustomFieldLongChoice;
|
||||||
|
|
||||||
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
138
src/Bundle/ChillCustomFields/Form/CustomFieldType.php
Normal file
138
src/Bundle/ChillCustomFields/Form/CustomFieldType.php
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Form;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
|
||||||
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\NumberType;
|
||||||
|
use Symfony\Component\Form\FormEvent;
|
||||||
|
use Symfony\Component\Form\FormEvents;
|
||||||
|
use Doctrine\Persistence\ObjectManager;
|
||||||
|
use Chill\CustomFieldsBundle\Service\CustomFieldProvider;
|
||||||
|
use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldsGroupToIdTransformer;
|
||||||
|
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
|
||||||
|
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||||
|
|
||||||
|
|
||||||
|
class CustomFieldType extends AbstractType
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var CustomFieldProvider
|
||||||
|
*/
|
||||||
|
private $customFieldProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var TranslatableStringHelper
|
||||||
|
*/
|
||||||
|
private $translatableStringHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ObjectManager
|
||||||
|
*/
|
||||||
|
private $om;
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
CustomFieldProvider $compiler,
|
||||||
|
ObjectManager $om,
|
||||||
|
TranslatableStringHelper $translatableStringHelper
|
||||||
|
) {
|
||||||
|
$this->customFieldProvider = $compiler;
|
||||||
|
$this->om = $om;
|
||||||
|
$this->translatableStringHelper = $translatableStringHelper;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param FormBuilderInterface $builder
|
||||||
|
* @param array $options
|
||||||
|
*/
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
|
||||||
|
$customFieldsList = array();
|
||||||
|
|
||||||
|
foreach ($this->customFieldProvider->getAllFields() as $key => $field) {
|
||||||
|
$customFieldsList[$key] = $field->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
$builder
|
||||||
|
->add('name', TranslatableStringFormType::class)
|
||||||
|
->add('active', CheckboxType::class, array('required' => false));
|
||||||
|
|
||||||
|
if ($options['group_widget'] === 'entity') {
|
||||||
|
$builder->add('customFieldsGroup', EntityType::class, array(
|
||||||
|
'class' => 'ChillCustomFieldsBundle:CustomFieldsGroup',
|
||||||
|
'choice_label' => function($g) {
|
||||||
|
return $this->translatableStringHelper->localize($g->getName());
|
||||||
|
}
|
||||||
|
));
|
||||||
|
} elseif ($options['group_widget'] === 'hidden') {
|
||||||
|
$builder->add('customFieldsGroup', HiddenType::class);
|
||||||
|
$builder->get('customFieldsGroup')
|
||||||
|
->addViewTransformer(new CustomFieldsGroupToIdTransformer($this->om));
|
||||||
|
} else {
|
||||||
|
throw new \LogicException('The value of group_widget is not handled');
|
||||||
|
}
|
||||||
|
|
||||||
|
$builder
|
||||||
|
->add('ordering', NumberType::class)
|
||||||
|
->add('required', CheckboxType::class, array(
|
||||||
|
'required' => false,
|
||||||
|
//'expanded' => TRUE,
|
||||||
|
'label' => 'Required field'
|
||||||
|
))
|
||||||
|
->add('type', HiddenType::class, array('data' => $options['type']))
|
||||||
|
->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event)
|
||||||
|
{
|
||||||
|
$customField = $event->getData();
|
||||||
|
$form = $event->getForm();
|
||||||
|
|
||||||
|
// check if the customField object is "new"
|
||||||
|
// If no data is passed to the form, the data is "null".
|
||||||
|
// This should be considered a new "customField"
|
||||||
|
if (!$customField || null === $customField->getId()) {
|
||||||
|
$form->add('slug', TextType::class);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$builder->add(
|
||||||
|
$this->customFieldProvider
|
||||||
|
->getCustomFieldByType($options['type'])
|
||||||
|
->buildOptionsForm(
|
||||||
|
$builder
|
||||||
|
->create('options', null, array('compound' => true))
|
||||||
|
->setRequired(false)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param OptionsResolverInterface $resolver
|
||||||
|
*/
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver->setDefaults(array(
|
||||||
|
'data_class' => 'Chill\CustomFieldsBundle\Entity\CustomField'
|
||||||
|
));
|
||||||
|
|
||||||
|
$resolver->setRequired(array('type', 'group_widget'))
|
||||||
|
->addAllowedValues('type', array_keys($this->customFieldProvider->getAllFields()))
|
||||||
|
->addAllowedValues('group_widget', array('hidden', 'entity'))
|
||||||
|
->setDefault('group_widget', 'entity');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getBlockPrefix()
|
||||||
|
{
|
||||||
|
return 'custom_field_choice';
|
||||||
|
}
|
||||||
|
}
|
108
src/Bundle/ChillCustomFields/Form/CustomFieldsGroupType.php
Normal file
108
src/Bundle/ChillCustomFields/Form/CustomFieldsGroupType.php
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Form;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Translation\TranslatorInterface;
|
||||||
|
use Symfony\Component\Form\FormEvents;
|
||||||
|
use Symfony\Component\Form\FormEvent;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
|
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
|
||||||
|
|
||||||
|
|
||||||
|
class CustomFieldsGroupType extends AbstractType
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
private $customizableEntities; //TODO : add comment about this variable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Symfony\Component\Translation\TranslatorInterface
|
||||||
|
*/
|
||||||
|
private $translator;
|
||||||
|
|
||||||
|
public function __construct(array $customizableEntities, TranslatorInterface $translator)
|
||||||
|
{
|
||||||
|
$this->customizableEntities = $customizableEntities;
|
||||||
|
$this->translator = $translator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param FormBuilderInterface $builder
|
||||||
|
* @param array $options
|
||||||
|
*/
|
||||||
|
//TODO : details about the function
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
//prepare translation
|
||||||
|
$entities = array();
|
||||||
|
$customizableEntities = array(); //TODO : change name too close than $this->customizableEntities
|
||||||
|
|
||||||
|
foreach($this->customizableEntities as $key => $definition) {
|
||||||
|
$entities[$definition['class']] = $this->translator->trans($definition['name']);
|
||||||
|
$customizableEntities[$definition['class']] = $definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
$builder
|
||||||
|
->add('name', TranslatableStringFormType::class)
|
||||||
|
->add('entity', ChoiceType::class, array(
|
||||||
|
'choices' => array_combine(array_values($entities),array_keys($entities)),
|
||||||
|
))
|
||||||
|
;
|
||||||
|
|
||||||
|
$builder->addEventListener(FormEvents::POST_SET_DATA,
|
||||||
|
function(FormEvent $event) use ($customizableEntities, $builder){
|
||||||
|
$form = $event->getForm();
|
||||||
|
$group = $event->getData();
|
||||||
|
|
||||||
|
//stop the function if entity is not set
|
||||||
|
if ($group->getEntity() === NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($customizableEntities[$group->getEntity()]['options']) > 0) {
|
||||||
|
$optionBuilder = $builder
|
||||||
|
->getFormFactory()
|
||||||
|
->createBuilderForProperty(
|
||||||
|
'Chill\CustomFieldsBundle\Entity\CustomFieldsGroup',
|
||||||
|
'options'
|
||||||
|
)
|
||||||
|
->create('options', null, array(
|
||||||
|
'compound' => true,
|
||||||
|
'auto_initialize' => false,
|
||||||
|
'required' => false)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($customizableEntities[$group->getEntity()]['options'] as $key => $option) {
|
||||||
|
$optionBuilder
|
||||||
|
->add($key, $option['form_type'], $option['form_options'])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
if (isset($optionBuilder) && $optionBuilder->count() > 0) {
|
||||||
|
$form->add($optionBuilder->getForm());
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param OptionsResolverInterface $resolver
|
||||||
|
*/
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver->setDefaults(array(
|
||||||
|
'data_class' => 'Chill\CustomFieldsBundle\Entity\CustomFieldsGroup'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getBlockPrefix()
|
||||||
|
{
|
||||||
|
return 'custom_fields_group';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Form\DataTransformer;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\DataTransformerInterface;
|
||||||
|
use Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class CustomFieldDataTransformer implements DataTransformerInterface
|
||||||
|
{
|
||||||
|
private $customFieldDefinition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var \Chill\CustomFieldsBundle\Entity\CustomField
|
||||||
|
*/
|
||||||
|
private $customField;
|
||||||
|
|
||||||
|
public function __construct(CustomFieldInterface $customFieldDefinition,
|
||||||
|
CustomField $customField)
|
||||||
|
{
|
||||||
|
$this->customFieldDefinition = $customFieldDefinition;
|
||||||
|
$this->customField = $customField;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reverseTransform($value)
|
||||||
|
{
|
||||||
|
return $this->customFieldDefinition->serialize($value,
|
||||||
|
$this->customField);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function transform($value)
|
||||||
|
{
|
||||||
|
return $this->customFieldDefinition->deserialize($value,
|
||||||
|
$this->customField);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Form\DataTransformer;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\DataTransformerInterface;
|
||||||
|
use Symfony\Component\Form\Exception\TransformationFailedException;
|
||||||
|
use Doctrine\Persistence\ObjectManager;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup;
|
||||||
|
|
||||||
|
class CustomFieldsGroupToIdTransformer implements DataTransformerInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var ObjectManager
|
||||||
|
*/
|
||||||
|
private $om;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ObjectManager $om
|
||||||
|
*/
|
||||||
|
public function __construct(ObjectManager $om)
|
||||||
|
{
|
||||||
|
$this->om = $om;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms an custom_field_group to a string (id)
|
||||||
|
*
|
||||||
|
* @param CustomFieldsGroup|null $customFieldsGroup
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function transform($customFieldsGroup)
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms a string (id) to an object (CustomFieldsGroup).
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
* @return CustomFieldsGroup|null
|
||||||
|
* @throws TransformationFailedException if object (report) is not found.
|
||||||
|
*/
|
||||||
|
public function reverseTransform($id)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (null === $customFieldsGroup) {
|
||||||
|
throw new TransformationFailedException(sprintf(
|
||||||
|
'Le group avec le numéro "%s" ne peut pas être trouvé!',
|
||||||
|
$id
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $customFieldsGroup;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,145 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Form\DataTransformer;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\DataTransformerInterface;
|
||||||
|
use Doctrine\Persistence\ObjectManager;
|
||||||
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
|
|
||||||
|
class JsonCustomFieldToArrayTransformer implements DataTransformerInterface {
|
||||||
|
/**
|
||||||
|
* @var ObjectManager
|
||||||
|
*/
|
||||||
|
private $om;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ObjectManager $om
|
||||||
|
*/
|
||||||
|
public function __construct(ObjectManager $om)
|
||||||
|
{
|
||||||
|
$this->om = $om;
|
||||||
|
|
||||||
|
$customFields = $this->om
|
||||||
|
->getRepository('ChillCustomFieldsBundle:CustomField')
|
||||||
|
->findAll();
|
||||||
|
|
||||||
|
$customFieldsLablels = array_map(
|
||||||
|
function($e) { return $e->getLabel(); },
|
||||||
|
$customFields);
|
||||||
|
|
||||||
|
$customFieldsByLabel = array_combine($customFieldsLablels, $customFields);
|
||||||
|
|
||||||
|
$this->customField = $customFieldsByLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function transform($customFieldsJSON)
|
||||||
|
{
|
||||||
|
echo $customFieldsJSON;
|
||||||
|
|
||||||
|
if($customFieldsJSON === null) { // lors de la creation
|
||||||
|
$customFieldsArray = array();
|
||||||
|
} else {
|
||||||
|
$customFieldsArray = json_decode($customFieldsJSON,true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
echo "<br> - 4 - <br>";
|
||||||
|
|
||||||
|
var_dump($customFieldsArray);
|
||||||
|
|
||||||
|
echo "<br> - 5 - <br>";
|
||||||
|
*/
|
||||||
|
|
||||||
|
$customFieldsArrayRet = array();
|
||||||
|
|
||||||
|
foreach ($customFieldsArray as $key => $value) {
|
||||||
|
$traited = false;
|
||||||
|
if(array_key_exists($key, $this->customField)) {
|
||||||
|
$type = $this->customField[$key]->getType();
|
||||||
|
if(strpos($type,'ManyToOne') === 0) {
|
||||||
|
if(strpos($type,'ManyToOnePersist') ===0) {
|
||||||
|
$entityClass = substr($type, 17, -1);
|
||||||
|
} else {
|
||||||
|
$entityClass = substr($type, 10, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$customFieldsArrayRet[$key] = $this->om
|
||||||
|
->getRepository('ChillCustomFieldsBundle:' . $entityClass)
|
||||||
|
->findOneById($value);
|
||||||
|
$traited = true;
|
||||||
|
} else if ($type === 'ManyToMany(Adress)') {
|
||||||
|
$customFieldsArrayRet[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(! $traited) {
|
||||||
|
$customFieldsArrayRet[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump($customFieldsArrayRet);
|
||||||
|
|
||||||
|
return $customFieldsArrayRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reverseTransform($customFieldsArray)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
echo "<br> - - 7 - <br>";
|
||||||
|
|
||||||
|
|
||||||
|
var_dump(array_keys($customFieldsArray));
|
||||||
|
|
||||||
|
echo "<br> - - 8 - <br>";
|
||||||
|
|
||||||
|
var_dump(array_keys($this->customField));
|
||||||
|
|
||||||
|
echo "<br> - - 9 - <br>";
|
||||||
|
*/
|
||||||
|
|
||||||
|
//var_dump($customFieldsArray);
|
||||||
|
|
||||||
|
$customFieldsArrayRet = array();
|
||||||
|
|
||||||
|
foreach ($customFieldsArray as $key => $value) {
|
||||||
|
$traited = false;
|
||||||
|
if(array_key_exists($key, $this->customField)) {
|
||||||
|
$type = $this->customField[$key]->getType();
|
||||||
|
if(strpos($type,'ManyToOne') === 0) {
|
||||||
|
// pour le manytoone() faire
|
||||||
|
// un update du form en js ? : http://symfony.com/fr/doc/current/cookbook/form/form_collections.html
|
||||||
|
//
|
||||||
|
//$entityClass = substr($type, 10, -1);
|
||||||
|
//echo $entityClasss;
|
||||||
|
if(strpos($type, 'ManyToOnePersist') === 0) {
|
||||||
|
// PEUT ETRE A FAIRE SI SEULEMENT $value->getId() ne renvoie rien...
|
||||||
|
//
|
||||||
|
//
|
||||||
|
$this->om->persist($value); // pas bon ici
|
||||||
|
// LE PERSIST NE SERT QUE LA PREMIERE FOIS
|
||||||
|
// plutot le mettre dans une var temporaire de adress
|
||||||
|
// et faire le persist qd fait sur l'obj parent
|
||||||
|
// regarder : http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html
|
||||||
|
// ou : http://symfony.com/doc/current/cookbook/doctrine/event_listeners_subscribers.html
|
||||||
|
// dans yml :
|
||||||
|
// lifecycleCallbacks:
|
||||||
|
// prePersist: [ doStuffOnPrePersist, doOtherStuffOnPrePersist ]
|
||||||
|
$this->om->flush(); // sinon l'id pose pbm
|
||||||
|
}
|
||||||
|
|
||||||
|
$customFieldsArrayRet[$key] = $value->getId();
|
||||||
|
$traited = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(! $traited) {
|
||||||
|
$customFieldsArrayRet[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//echo json_encode($customFieldsArrayRet);
|
||||||
|
|
||||||
|
return json_encode($customFieldsArrayRet);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Form\Extension;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractTypeExtension;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Form\FormView;
|
||||||
|
use Symfony\Component\Form\FormInterface;
|
||||||
|
use Symfony\Component\PropertyAccess\PropertyAccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This extension create the possibility to add some text
|
||||||
|
* after the input.
|
||||||
|
*
|
||||||
|
* This can be used to print the units of the field, or some text.
|
||||||
|
*
|
||||||
|
* This class must be extended by Extension class specifics to each input.
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
abstract class PostTextExtension extends AbstractTypeExtension
|
||||||
|
{
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver->setDefined(array('post_text'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildView(FormView $view, FormInterface $form, array $options)
|
||||||
|
{
|
||||||
|
if (array_key_exists('post_text', $options)) {
|
||||||
|
//set the post text variable to the view
|
||||||
|
$view->vars['post_text'] = $options['post_text'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Form\Extension;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class add the PostTextExtension to integer fields
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class PostTextIntegerExtension extends PostTextExtension
|
||||||
|
{
|
||||||
|
public function getExtendedType()
|
||||||
|
{
|
||||||
|
return IntegerType::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Form\Extension;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\NumberType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class add the PostTextExtension to number fields
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class PostTextNumberExtension extends PostTextExtension
|
||||||
|
{
|
||||||
|
public function getExtendedType()
|
||||||
|
{
|
||||||
|
return NumberType::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
namespace Chill\CustomFieldsBundle\Form\Type;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a choice widget with an "other" option
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class ChoiceWithOtherType extends AbstractType
|
||||||
|
{
|
||||||
|
private $otherValueLabel = 'Other value';
|
||||||
|
|
||||||
|
/* (non-PHPdoc)
|
||||||
|
* @see \Symfony\Component\Form\AbstractType::buildForm()
|
||||||
|
*/
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
|
||||||
|
//add an 'other' entry in choices array
|
||||||
|
$options['choices'][$this->otherValueLabel] = '_other';
|
||||||
|
//ChoiceWithOther must always be expanded
|
||||||
|
$options['expanded'] = true;
|
||||||
|
// adding a default value for choice
|
||||||
|
$options['empty_data'] = null;
|
||||||
|
|
||||||
|
$builder
|
||||||
|
->add('_other', TextType::class, array('required' => false))
|
||||||
|
->add('_choices', ChoiceType::class, $options)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-PHPdoc)
|
||||||
|
* @see \Symfony\Component\Form\AbstractType::configureOptions()
|
||||||
|
*/
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver
|
||||||
|
->setRequired(array('choices'))
|
||||||
|
->setAllowedTypes('choices', array('array'))
|
||||||
|
->setDefaults(array(
|
||||||
|
'multiple' => false
|
||||||
|
))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBlockPrefix()
|
||||||
|
{
|
||||||
|
return 'choice_with_other';
|
||||||
|
}
|
||||||
|
}
|
55
src/Bundle/ChillCustomFields/Form/Type/ChoicesListType.php
Normal file
55
src/Bundle/ChillCustomFields/Form/Type/ChoicesListType.php
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
namespace Chill\CustomFieldsBundle\Form\Type;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\Form\FormEvent;
|
||||||
|
use Symfony\Component\Form\FormEvents;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
|
||||||
|
|
||||||
|
class ChoicesListType extends AbstractType
|
||||||
|
{
|
||||||
|
|
||||||
|
/* (non-PHPdoc)
|
||||||
|
* @see \Symfony\Component\Form\AbstractType::buildForm()
|
||||||
|
*/
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$builder->add('name', TranslatableStringFormType::class)
|
||||||
|
->add('active', CheckboxType::class, array(
|
||||||
|
'required' => false
|
||||||
|
))
|
||||||
|
->add('slug', HiddenType::class)
|
||||||
|
->addEventListener(FormEvents::SUBMIT, function(FormEvent $event) {
|
||||||
|
$form = $event->getForm();
|
||||||
|
$data = $event->getData();
|
||||||
|
|
||||||
|
$formData = $form->getData();
|
||||||
|
|
||||||
|
if (NULL === $formData['slug']) {
|
||||||
|
$slug = uniqid(rand(), true);
|
||||||
|
|
||||||
|
$data['slug'] = $slug;
|
||||||
|
$event->setData($data);
|
||||||
|
} else {
|
||||||
|
$data['slug'] = $formData['slug'];
|
||||||
|
$event->setData($data);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* @see \Symfony\Component\Form\FormTypeInterface::getName()
|
||||||
|
*/
|
||||||
|
public function getBlockPrefix()
|
||||||
|
{
|
||||||
|
return 'cf_choices_list';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
src/Bundle/ChillCustomFields/Form/Type/ChoicesType.php
Normal file
24
src/Bundle/ChillCustomFields/Form/Type/ChoicesType.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
namespace Chill\CustomFieldsBundle\Form\Type;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class ChoicesType extends AbstractType
|
||||||
|
{
|
||||||
|
public function getBlockPrefix()
|
||||||
|
{
|
||||||
|
return 'cf_choices';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getParent()
|
||||||
|
{
|
||||||
|
return CollectionType::class;
|
||||||
|
}
|
||||||
|
}
|
71
src/Bundle/ChillCustomFields/Form/Type/CustomFieldType.php
Normal file
71
src/Bundle/ChillCustomFields/Form/Type/CustomFieldType.php
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Form\Type;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Chill\CustomFieldsBundle\Form\DataTransformer\JsonCustomFieldToArrayTransformer;
|
||||||
|
use Doctrine\Persistence\ObjectManager;
|
||||||
|
use Chill\CustomFieldsBundle\Form\AdressType;
|
||||||
|
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
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ObjectManager
|
||||||
|
*/
|
||||||
|
private $om;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var CustomFieldCompiler
|
||||||
|
*/
|
||||||
|
private $customFieldCompiler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ObjectManager $om
|
||||||
|
*/
|
||||||
|
public function __construct(ObjectManager $om, CustomFieldProvider $compiler)
|
||||||
|
{
|
||||||
|
$this->om = $om;
|
||||||
|
$this->customFieldCompiler = $compiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
foreach ($options['group']->getActiveCustomFields() as $cf) {
|
||||||
|
$this->customFieldCompiler
|
||||||
|
->getCustomFieldByType($cf->getType())
|
||||||
|
->buildForm($builder, $cf);
|
||||||
|
$builder->get($cf->getSlug())->setRequired($cf->isRequired());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(\Symfony\Component\OptionsResolver\OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver
|
||||||
|
->setRequired(array('group'))
|
||||||
|
->addAllowedTypes('group', array('Chill\CustomFieldsBundle\Entity\CustomFieldsGroup'))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBlockPrefix()
|
||||||
|
{
|
||||||
|
return 'custom_field';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
namespace Chill\CustomFieldsBundle\Form\Type;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
|
class CustomFieldsTitleType extends AbstractType
|
||||||
|
{
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBlockPrefix()
|
||||||
|
{
|
||||||
|
return 'custom_field_title';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,138 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Champs-Libres Cooperative <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Form\Type;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\Form\FormEvent;
|
||||||
|
use Symfony\Component\Form\FormEvents;
|
||||||
|
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||||
|
use Symfony\Component\Form\FormInterface;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This type create a Choice field with custom fields as choices.
|
||||||
|
*
|
||||||
|
* This type can only be associated with a customFieldsGroup type. The field
|
||||||
|
* is populated when the data (a customFieldsGroup entity) is associated with
|
||||||
|
* the form
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class LinkedCustomFieldsType extends AbstractType
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var TranslatableStringHelper
|
||||||
|
*/
|
||||||
|
private $translatableStringHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name for the choice field
|
||||||
|
*
|
||||||
|
* Extracted from builder::getName
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $choiceName = 'choice';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the option of the form.
|
||||||
|
*
|
||||||
|
* @internal options are stored at the class level to be reused by appendChoice, after data are setted
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $options = array();
|
||||||
|
|
||||||
|
public function __construct(TranslatableStringHelper $helper)
|
||||||
|
{
|
||||||
|
$this->translatableStringHelper = $helper;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$this->choiceName = $builder->getName();
|
||||||
|
$this->options = $options;
|
||||||
|
|
||||||
|
$builder->addEventListener(FormEvents::POST_SET_DATA,
|
||||||
|
array($this, 'appendChoice'))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getParent()
|
||||||
|
{
|
||||||
|
return ChoiceType::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* append Choice on POST_SET_DATA event
|
||||||
|
*
|
||||||
|
* Choices are extracted from custom_field_group (the data associated
|
||||||
|
* with the root form)
|
||||||
|
*
|
||||||
|
* @param FormEvent $event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function appendChoice(FormEvent $event)
|
||||||
|
{
|
||||||
|
$rootForm = $this->getRootForm($event->getForm());
|
||||||
|
$group = $rootForm->getData();
|
||||||
|
|
||||||
|
if ($group === NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$choices = array();
|
||||||
|
foreach($group->getCustomFields() as $customFields) {
|
||||||
|
$choices[$customFields->getSlug()] =
|
||||||
|
$this->translatableStringHelper
|
||||||
|
->localize($customFields->getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
$options = array_merge($this->options, array(
|
||||||
|
'choices' => $choices,
|
||||||
|
));
|
||||||
|
|
||||||
|
$event->getForm()->getParent()->add($this->choiceName, ChoiceType::class,
|
||||||
|
$options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the root form (i.e. produced from CustomFieldsGroupType::getForm)
|
||||||
|
*
|
||||||
|
* @param FormInterface $form
|
||||||
|
* @return FormInterface
|
||||||
|
*/
|
||||||
|
private function getRootForm(FormInterface $form)
|
||||||
|
{
|
||||||
|
if ($form->getParent() === NULL) {
|
||||||
|
return $form;
|
||||||
|
} else {
|
||||||
|
return $this->getRootForm($form->getParent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBlockPrefix()
|
||||||
|
{
|
||||||
|
return 'custom_fields_group_linked_custom_fields';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
661
src/Bundle/ChillCustomFields/LICENSE.txt
Normal file
661
src/Bundle/ChillCustomFields/LICENSE.txt
Normal file
@ -0,0 +1,661 @@
|
|||||||
|
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 19 November 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU Affero General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works, specifically designed to ensure
|
||||||
|
cooperation with the community in the case of network server software.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
our General Public Licenses are intended to guarantee your freedom to
|
||||||
|
share and change all versions of a program--to make sure it remains free
|
||||||
|
software for all its users.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
Developers that use our General Public Licenses protect your rights
|
||||||
|
with two steps: (1) assert copyright on the software, and (2) offer
|
||||||
|
you this License which gives you legal permission to copy, distribute
|
||||||
|
and/or modify the software.
|
||||||
|
|
||||||
|
A secondary benefit of defending all users' freedom is that
|
||||||
|
improvements made in alternate versions of the program, if they
|
||||||
|
receive widespread use, become available for other developers to
|
||||||
|
incorporate. Many developers of free software are heartened and
|
||||||
|
encouraged by the resulting cooperation. However, in the case of
|
||||||
|
software used on network servers, this result may fail to come about.
|
||||||
|
The GNU General Public License permits making a modified version and
|
||||||
|
letting the public access it on a server without ever releasing its
|
||||||
|
source code to the public.
|
||||||
|
|
||||||
|
The GNU Affero General Public License is designed specifically to
|
||||||
|
ensure that, in such cases, the modified source code becomes available
|
||||||
|
to the community. It requires the operator of a network server to
|
||||||
|
provide the source code of the modified version running there to the
|
||||||
|
users of that server. Therefore, public use of a modified version, on
|
||||||
|
a publicly accessible server, gives the public access to the source
|
||||||
|
code of the modified version.
|
||||||
|
|
||||||
|
An older license, called the Affero General Public License and
|
||||||
|
published by Affero, was designed to accomplish similar goals. This is
|
||||||
|
a different license, not a version of the Affero GPL, but Affero has
|
||||||
|
released a new version of the Affero GPL which permits relicensing under
|
||||||
|
this license.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, if you modify the
|
||||||
|
Program, your modified version must prominently offer all users
|
||||||
|
interacting with it remotely through a computer network (if your version
|
||||||
|
supports such interaction) an opportunity to receive the Corresponding
|
||||||
|
Source of your version by providing access to the Corresponding Source
|
||||||
|
from a network server at no charge, through some standard or customary
|
||||||
|
means of facilitating copying of software. This Corresponding Source
|
||||||
|
shall include the Corresponding Source for any work covered by version 3
|
||||||
|
of the GNU General Public License that is incorporated pursuant to the
|
||||||
|
following paragraph.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the work with which it is combined will remain governed by version
|
||||||
|
3 of the GNU General Public License.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU Affero General Public License from time to time. Such new versions
|
||||||
|
will be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU Affero General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU Affero General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU Affero General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If your software can interact with users remotely through a computer
|
||||||
|
network, you should also make sure that it provides a way for users to
|
||||||
|
get its source. For example, if your program is a web application, its
|
||||||
|
interface could display a "Source" link that leads users to an archive
|
||||||
|
of the code. There are many ways you could offer source, and different
|
||||||
|
solutions will be better for different programs; see section 13 for the
|
||||||
|
specific requirements.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||||
|
<http://www.gnu.org/licenses/>.
|
9
src/Bundle/ChillCustomFields/README.md
Normal file
9
src/Bundle/ChillCustomFields/README.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
CustomFields
|
||||||
|
============
|
||||||
|
|
||||||
|
The bundle for adding custom fields to Chill. This bundle is part of the Chill project.
|
||||||
|
|
||||||
|
Documentation & installation
|
||||||
|
============================
|
||||||
|
|
||||||
|
Read documentation here : http://chill.readthedocs.org
|
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Symfony\Component\HttpKernel\Kernel;
|
||||||
|
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||||
|
|
||||||
|
class AppKernel extends Kernel
|
||||||
|
{
|
||||||
|
public function registerBundles()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
|
||||||
|
new Chill\CustomFieldsBundle\ChillCustomFieldsBundle(),
|
||||||
|
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
|
||||||
|
new Symfony\Bundle\MonologBundle\MonologBundle(),
|
||||||
|
new Symfony\Bundle\TwigBundle\TwigBundle(),
|
||||||
|
new \Symfony\Bundle\AsseticBundle\AsseticBundle(),
|
||||||
|
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
|
||||||
|
new \Chill\MainBundle\ChillMainBundle,
|
||||||
|
new \Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle(),
|
||||||
|
new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(),
|
||||||
|
new Chill\PersonBundle\ChillPersonBundle(),
|
||||||
|
#add here all the required bundle (some bundle are not required)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function registerContainerConfiguration(LoaderInterface $loader)
|
||||||
|
{
|
||||||
|
$loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getCacheDir()
|
||||||
|
{
|
||||||
|
return sys_get_temp_dir().'/CustomFieldsBundle/cache';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getLogDir()
|
||||||
|
{
|
||||||
|
return $this->getRootDir().'/../logs';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
2
src/Bundle/ChillCustomFields/Resources/test/Fixtures/App/app/DoctrineMigrations/.gitignore
vendored
Normal file
2
src/Bundle/ChillCustomFields/Resources/test/Fixtures/App/app/DoctrineMigrations/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*
|
||||||
|
!.gitignore
|
@ -0,0 +1,7 @@
|
|||||||
|
{% if inputKeys is defined %}
|
||||||
|
{% for key in inputKeys %}
|
||||||
|
{{ form_row(form[key]) }}
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
{{ form(form) }}
|
||||||
|
{% endif %}
|
@ -0,0 +1,14 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>{% block title %}Welcome!{% endblock %}</title>
|
||||||
|
{% block stylesheets %}{% endblock %}
|
||||||
|
<link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" />
|
||||||
|
{% block javascripts_head %}<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% block body %}{% endblock %}
|
||||||
|
{% block javascripts %}{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Doctrine\Common\Annotations\AnnotationRegistry;
|
||||||
|
use Composer\Autoload\ClassLoader;
|
||||||
|
|
||||||
|
/** @var ClassLoader $loader */
|
||||||
|
$loader = require __DIR__.'/../../../../../vendor/autoload.php';
|
||||||
|
|
||||||
|
AnnotationRegistry::registerLoader(array($loader, 'loadClass'));
|
||||||
|
|
||||||
|
return $loader;
|
@ -0,0 +1,76 @@
|
|||||||
|
imports:
|
||||||
|
- { resource: parameters.yml }
|
||||||
|
|
||||||
|
framework:
|
||||||
|
secret: Not very secret
|
||||||
|
router: { resource: "%kernel.root_dir%/config/routing.yml" }
|
||||||
|
form: true
|
||||||
|
csrf_protection: true
|
||||||
|
session: ~
|
||||||
|
default_locale: fr
|
||||||
|
translator: { fallback: fr }
|
||||||
|
profiler: { only_exceptions: false }
|
||||||
|
templating:
|
||||||
|
engines: ['twig']
|
||||||
|
|
||||||
|
doctrine:
|
||||||
|
dbal:
|
||||||
|
driver: pdo_pgsql
|
||||||
|
host: "%database_host%"
|
||||||
|
port: "%database_port%"
|
||||||
|
dbname: "%database_name%"
|
||||||
|
user: "%database_user%"
|
||||||
|
password: "%database_password%"
|
||||||
|
charset: UTF8
|
||||||
|
orm:
|
||||||
|
auto_generate_proxy_classes: "%kernel.debug%"
|
||||||
|
auto_mapping: true
|
||||||
|
|
||||||
|
# Assetic Configuration
|
||||||
|
assetic:
|
||||||
|
debug: "%kernel.debug%"
|
||||||
|
use_controller: false
|
||||||
|
bundles: [ ]
|
||||||
|
#java: /usr/bin/java
|
||||||
|
filters:
|
||||||
|
cssrewrite: ~
|
||||||
|
|
||||||
|
chill_main:
|
||||||
|
available_languages: [ fr, nl, en ]
|
||||||
|
|
||||||
|
security:
|
||||||
|
providers:
|
||||||
|
chain_provider:
|
||||||
|
chain :
|
||||||
|
providers: [in_memory, users]
|
||||||
|
in_memory:
|
||||||
|
memory:
|
||||||
|
users:
|
||||||
|
admin: { password: olala, roles: 'ROLE_ADMIN' }
|
||||||
|
users:
|
||||||
|
entity:
|
||||||
|
class: Chill\MainBundle\Entity\User
|
||||||
|
property: username
|
||||||
|
|
||||||
|
encoders:
|
||||||
|
Chill\MainBundle\Entity\User:
|
||||||
|
algorithm: bcrypt
|
||||||
|
Symfony\Component\Security\Core\User\User: plaintext
|
||||||
|
|
||||||
|
firewalls:
|
||||||
|
dev:
|
||||||
|
pattern: ^/(_(profiler|wdt)|css|images|js)/
|
||||||
|
security: false
|
||||||
|
|
||||||
|
default:
|
||||||
|
anonymous: ~
|
||||||
|
form_login:
|
||||||
|
csrf_parameter: _csrf_token
|
||||||
|
csrf_token_id: authenticate
|
||||||
|
csrf_provider: form.csrf_provider
|
||||||
|
logout: ~
|
||||||
|
access_control:
|
||||||
|
#disable authentication for tests
|
||||||
|
#- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||||
|
#- { path: ^/admin, roles: ROLE_ADMIN }
|
||||||
|
#- { path: ^/, roles: ROLE_USER }
|
@ -0,0 +1,11 @@
|
|||||||
|
imports:
|
||||||
|
- { resource: config.yml } #here we import a config.yml file, this is not required
|
||||||
|
|
||||||
|
framework:
|
||||||
|
test: ~
|
||||||
|
session:
|
||||||
|
storage_id: session.storage.filesystem
|
||||||
|
|
||||||
|
chill_custom_fields:
|
||||||
|
customizables_entities:
|
||||||
|
- { class: TEST, name: test }
|
@ -0,0 +1,8 @@
|
|||||||
|
# config/config_test.yml
|
||||||
|
imports:
|
||||||
|
- { resource: config.yml } #here we import a config.yml file, this is not required
|
||||||
|
|
||||||
|
framework:
|
||||||
|
test: ~
|
||||||
|
session:
|
||||||
|
storage_id: session.storage.filesystem
|
@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
#required by ConfigCustomizablesEntitiesTest::testNotEmptyConfig
|
||||||
|
|
||||||
|
imports:
|
||||||
|
- { resource: config_test.yml }
|
||||||
|
|
||||||
|
chill_custom_fields:
|
||||||
|
customizables_entities:
|
||||||
|
- { class: Test\With\A\Dummy\Entity, name: test }
|
@ -0,0 +1,7 @@
|
|||||||
|
parameters:
|
||||||
|
database_host: chill__database
|
||||||
|
database_port: 5432
|
||||||
|
database_name: postgres
|
||||||
|
database_user: postgres
|
||||||
|
database_password: postgres
|
||||||
|
locale: fr
|
@ -0,0 +1,7 @@
|
|||||||
|
parameters:
|
||||||
|
database_host: 127.0.0.1
|
||||||
|
database_port: 5434
|
||||||
|
database_name: symfony
|
||||||
|
database_user: symfony
|
||||||
|
database_password: symfony
|
||||||
|
locale: fr
|
@ -0,0 +1,10 @@
|
|||||||
|
cl_custom_fields:
|
||||||
|
resource: .
|
||||||
|
type: chill_routes
|
||||||
|
|
||||||
|
chill_main:
|
||||||
|
resource: "@ChillMainBundle/Resources/config/routing.yml"
|
||||||
|
|
||||||
|
test_custom_field_form_render:
|
||||||
|
path: /customfieldsgroup/test/render/{id}
|
||||||
|
defaults: { _controller: ChillCustomFieldsBundle:CustomFieldsGroup:renderForm }
|
@ -0,0 +1,27 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
||||||
|
use Symfony\Component\Console\Input\ArgvInput;
|
||||||
|
use Symfony\Component\Debug\Debug;
|
||||||
|
|
||||||
|
// if you don't want to setup permissions the proper way, just uncomment the following PHP line
|
||||||
|
// read https://symfony.com/doc/current/setup.html#checking-symfony-application-configuration-and-setup
|
||||||
|
// for more information
|
||||||
|
//umask(0000);
|
||||||
|
|
||||||
|
set_time_limit(0);
|
||||||
|
|
||||||
|
require __DIR__.'/autoload.php';
|
||||||
|
|
||||||
|
$input = new ArgvInput();
|
||||||
|
$env = $input->getParameterOption(array('--env', '-e'), getenv('SYMFONY_ENV') ?: 'dev');
|
||||||
|
$debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(array('--no-debug', '')) && $env !== 'prod';
|
||||||
|
|
||||||
|
if ($debug) {
|
||||||
|
Debug::enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
$kernel = new AppKernel($env, $debug);
|
||||||
|
$application = new Application($kernel);
|
||||||
|
$application->run($input);
|
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\Debug\Debug;
|
||||||
|
|
||||||
|
// If you don't want to setup permissions the proper way, just uncomment the following PHP line
|
||||||
|
// read http://symfony.com/doc/current/book/installation.html#configuration-and-setup for more information
|
||||||
|
//umask(0000);
|
||||||
|
|
||||||
|
// This check prevents access to debug front controllers that are deployed by accident to production servers.
|
||||||
|
// Feel free to remove this, extend it, or make something more sophisticated.
|
||||||
|
if (isset($_SERVER['HTTP_CLIENT_IP'])
|
||||||
|
|| isset($_SERVER['HTTP_X_FORWARDED_FOR'])
|
||||||
|
|| !(in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', 'fe80::1', '::1')) || php_sapi_name() === 'cli-server')
|
||||||
|
) {
|
||||||
|
header('HTTP/1.0 403 Forbidden');
|
||||||
|
exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$loader = require_once __DIR__.'/../app/bootstrap.php.cache';
|
||||||
|
Debug::enable();
|
||||||
|
|
||||||
|
require_once __DIR__.'/../app/AppKernel.php';
|
||||||
|
|
||||||
|
$kernel = new AppKernel('dev', true);
|
||||||
|
$kernel->loadClassCache();
|
||||||
|
$request = Request::createFromGlobals();
|
||||||
|
$response = $kernel->handle($request);
|
||||||
|
$response->send();
|
||||||
|
$kernel->terminate($request, $response);
|
@ -0,0 +1,31 @@
|
|||||||
|
{#
|
||||||
|
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
|
||||||
|
<info@champs-libres.coop> / <http://www.champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#}
|
||||||
|
|
||||||
|
{% extends "@ChillMain/Admin/layoutWithVerticalMenu.html.twig" %}
|
||||||
|
|
||||||
|
{% block vertical_menu_content %}
|
||||||
|
{{ chill_menu('admin_custom_fields', {
|
||||||
|
'layout': '@ChillCustomFields/Admin/menu.html.twig',
|
||||||
|
}) }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block layout_wvm_content %}
|
||||||
|
{% block admin_content %}<!-- block personcontent empty -->
|
||||||
|
<h1>{{ 'CustomFields configuration' |trans }}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,20 @@
|
|||||||
|
{#
|
||||||
|
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
|
||||||
|
<info@champs-libres.coop> / <http://www.champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#}
|
||||||
|
|
||||||
|
{% extends "@ChillMain/Menu/verticalMenu.html.twig" %}
|
||||||
|
{% block v_menu_title %}{{ 'Custom fields configuration menu'|trans }}{% endblock %}
|
@ -0,0 +1,49 @@
|
|||||||
|
{#
|
||||||
|
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#}
|
||||||
|
{% extends "@ChillCustomFields/Admin/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% block title %}{{ 'CustomField edit'|trans }}{% endblock title %}
|
||||||
|
|
||||||
|
{% block admin_content %}
|
||||||
|
<h1>{{ 'CustomField edit'|trans }}</h1>
|
||||||
|
|
||||||
|
<h2>{{ 'General informations'|trans }}</h2>
|
||||||
|
{{ 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) }}
|
||||||
|
{{ form_row(edit_form.required) }}
|
||||||
|
{% if edit_form.options is not empty %}
|
||||||
|
<h2>{{ 'Options'|trans }}</h2>
|
||||||
|
{% 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) }}
|
||||||
|
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('customfieldsgroup_show', { 'id': entity.customFieldsGroup.id }) }}" class="sc-button btn-reset">
|
||||||
|
{{ 'Back to the group'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,7 @@
|
|||||||
|
{% extends '::base.html.twig' %}
|
||||||
|
|
||||||
|
{% block javascripts_head %}<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>{% endblock %}
|
||||||
|
|
||||||
|
{% block body -%}
|
||||||
|
{{ form(form) }}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,56 @@
|
|||||||
|
{#
|
||||||
|
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#}
|
||||||
|
{% extends "@ChillCustomFields/Admin/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% block title %}{{ 'CustomField creation'|trans }}{% endblock title %}
|
||||||
|
|
||||||
|
{% block admin_content %}
|
||||||
|
<h1>{{ 'CustomField creation'|trans }}</h1>
|
||||||
|
|
||||||
|
<h2>{{ 'General informations'|trans }}</h2>
|
||||||
|
{{ 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) }}
|
||||||
|
{{ form_row(form.required) }}
|
||||||
|
{% if form.options is not empty %}
|
||||||
|
<h2>{{ 'Options'|trans }}</h2>
|
||||||
|
{% for option in form.options %}
|
||||||
|
{{ form_row(option) }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{{ form_row(form.submit, {'attr': { 'class': 'sc-button btn-create' } } ) }}
|
||||||
|
{{ form_end(form) }}
|
||||||
|
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
{% if entity.customFieldsGroup is not null %}
|
||||||
|
<a href="{{ path('customfieldsgroup_show', { 'id': entity.customFieldsGroup.id }) }}" class="sc-button btn-reset">
|
||||||
|
{{ 'Back to the group'|trans }}
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ path('customfieldsgroup') }}" class="sc-button btn-reset">
|
||||||
|
{{ 'Back to the list'|trans }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
@ -0,0 +1 @@
|
|||||||
|
{{ customField.name|localize_translatable_string }}
|
@ -0,0 +1,56 @@
|
|||||||
|
{#
|
||||||
|
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#}
|
||||||
|
{% extends "@ChillCustomFields/Admin/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% block admin_content %}
|
||||||
|
<h1>CustomField</h1>
|
||||||
|
|
||||||
|
<table class="record_properties">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th>Id</th>
|
||||||
|
<td>{{ entity.id }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Label</th>
|
||||||
|
<td>{{ entity.name(app.request.locale) }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Type</th>
|
||||||
|
<td>{{ entity.type }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Active</th>
|
||||||
|
<td>{{ entity.active }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('customfield') }}">
|
||||||
|
Back to the list
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('customfield_edit', { 'id': entity.id }) }}">
|
||||||
|
Edit
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>{{ form(delete_form) }}</li>
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,45 @@
|
|||||||
|
{#
|
||||||
|
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#}
|
||||||
|
{% extends "@ChillCustomFields/Admin/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% block title %}{{ 'CustomFieldsGroup edit'|trans }}{% endblock %}
|
||||||
|
|
||||||
|
{% block admin_content %}
|
||||||
|
<h1>{{ 'CustomFieldsGroup edit'|trans }}</h1>
|
||||||
|
|
||||||
|
{{ 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) }}
|
||||||
|
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('customfieldsgroup') }}" class="sc-button bt-cancel">
|
||||||
|
{{ 'Back to the list'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('customfieldsgroup_show', { 'id' : entity.id }) }}" class="sc-button bt-cancel">
|
||||||
|
{{ 'show'|trans|capitalize }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,67 @@
|
|||||||
|
{#
|
||||||
|
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#}
|
||||||
|
{% extends "@ChillCustomFields/Admin/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% block title %}{{ 'CustomFieldsGroup list'|trans }}{% endblock %}
|
||||||
|
|
||||||
|
{% block admin_content %}
|
||||||
|
<h1>{{ 'CustomFieldsGroup list'|trans }}</h1>
|
||||||
|
|
||||||
|
<table class="records_list">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ 'Name'|trans }}</th>
|
||||||
|
<th>{{ 'Entity'|trans }}</th>
|
||||||
|
<th>{{ 'Is default ?'|trans }} <i class="fa fa-info-circle" title="{{ 'Some module select default groups for some usage. Example: the default person group is shown under person page.'|trans|escape('html_attr') }}"></i></th>
|
||||||
|
<th>{{ 'Actions'|trans }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for entity in entities %}
|
||||||
|
<tr>
|
||||||
|
<td><a href="{{ path('customfieldsgroup_show', { 'id': entity.id }) }}">{{ entity.name|localize_translatable_string }}</a></td>
|
||||||
|
<td>{{ entity.entity|trans }}</td>
|
||||||
|
<td style="text-align: center;">
|
||||||
|
{%- if entity.id in default_groups -%}
|
||||||
|
<i class="fa fa-star"></i>
|
||||||
|
{%- 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 -%}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('customfieldsgroup_show', { 'id': entity.id }) }}" class="sc-button">{{ 'show'|trans|capitalize }}</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('customfieldsgroup_edit', { 'id': entity.id }) }}" class="sc-button btn-edit">{{ 'edit'|trans|capitalize }}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a href="{{ path('customfieldsgroup_new') }}" class="sc-button bt-create">
|
||||||
|
{{ 'Create a new group'|trans }}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,32 @@
|
|||||||
|
{#
|
||||||
|
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#}
|
||||||
|
{% extends "@ChillCustomFields/Admin/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% block admin_content %}
|
||||||
|
<h1>{{ 'CustomFieldsGroup creation'|trans }}</h1>
|
||||||
|
|
||||||
|
{{ form_start(form) }}
|
||||||
|
{{ form_row(form.name) }}
|
||||||
|
{{ form_row(form.entity) }}
|
||||||
|
<p>
|
||||||
|
{{ form_widget(form.submit, { 'attr' : { 'class': 'sc-button bt-create' } } ) }}
|
||||||
|
<a href="{{ path('customfieldsgroup') }}" class="sc-button bt-cancel">
|
||||||
|
{{ 'Back to the list'|trans }}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
{{ form_end(form) }}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,86 @@
|
|||||||
|
{#- 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 -%}
|
||||||
|
{%- set title_div_opened = false -%}
|
||||||
|
{%- set subtitle_div_opened = false -%}
|
||||||
|
{% for customField in cFGroup.activeCustomFields %}
|
||||||
|
{% if customField.type == 'title' %}
|
||||||
|
{%- if show_empty == true %}
|
||||||
|
{%- if customField.options[type] == type_title -%}
|
||||||
|
{%- if title_div_opened == false -%}
|
||||||
|
<div class="cf_title_box">
|
||||||
|
{%- set title_div_opened = true -%}
|
||||||
|
{%- else -%}
|
||||||
|
{%- if subtitle_div_opened == true -%}
|
||||||
|
</div> <!-- closing cf_subtitle_box -->
|
||||||
|
{%- set title_div_opened = false -%}
|
||||||
|
{%- endif -%}
|
||||||
|
</div><div class="cf_title_box">
|
||||||
|
{%- endif -%}
|
||||||
|
{%- else -%}
|
||||||
|
{%- if subtitle_div_opened == false -%}
|
||||||
|
<div class="cf_subtitle_box">
|
||||||
|
{%- set subtitle_div_opened = true -%}
|
||||||
|
{%- else -%}
|
||||||
|
</div><div class="cf_subtitle_box">
|
||||||
|
{%- endif -%}
|
||||||
|
{%- endif -%}
|
||||||
|
{{ 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(cFData, customField) == false) -%}
|
||||||
|
{%- if title is not empty -%}
|
||||||
|
{%- if title_div_opened == false -%}
|
||||||
|
<div class="cf_title_box">
|
||||||
|
{%- set title_div_opened = true -%}
|
||||||
|
{%- else -%}
|
||||||
|
{%- if subtitle_div_opened == true -%}
|
||||||
|
</div> <!-- closing cf_subtitle_box -->
|
||||||
|
{%- set title_div_opened = false -%}
|
||||||
|
{%- endif -%}
|
||||||
|
</div><div class="cf_title_box">
|
||||||
|
{%- endif -%}
|
||||||
|
{{ chill_custom_field_widget(cFData, title) }}
|
||||||
|
{%- set title = null -%}
|
||||||
|
{%- endif -%}
|
||||||
|
{%- if subtitle is not empty -%}
|
||||||
|
{%- if subtitle_div_opened == false -%}
|
||||||
|
<div class="cf_subtitle_box">
|
||||||
|
{%- set subtitle_div_opened = true -%}
|
||||||
|
{%- else -%}
|
||||||
|
</div><div class="cf_subtitle_box">
|
||||||
|
{%- endif -%}
|
||||||
|
{{ chill_custom_field_widget(cFData, subtitle) }}
|
||||||
|
{%- set subtitle = null -%}
|
||||||
|
{%- endif -%}
|
||||||
|
<dt class="custom_fields_group_rendering">{{ chill_custom_field_label(customField) }}</dt>
|
||||||
|
<dd class="custom_fields_group_rendering">{{ chill_custom_field_widget(cFData , customField) }}</dd>
|
||||||
|
{%- set something_has_been_printed = true -%}
|
||||||
|
{%- endif -%}
|
||||||
|
{%- endif -%}
|
||||||
|
{% endfor %}
|
||||||
|
{%- if subtitle_div_opened == true -%}
|
||||||
|
</div> <!-- closing cf_subtitle_box -->
|
||||||
|
{%- endif -%}
|
||||||
|
{%- if title_div_opened == true -%}
|
||||||
|
</div> <!-- closing cf_title_box -->
|
||||||
|
{%- endif -%}
|
||||||
|
{% if something_has_been_printed == false %}
|
||||||
|
<dt class="custom_field_no_data custom_fields_group_rendering">{{ 'Empty data'|trans }}</dt>
|
||||||
|
<dd class="custom_field_no_data custom_fields_group_rendering">{{ 'No data to show' | trans }}</dd>
|
||||||
|
{% endif %}
|
@ -0,0 +1,7 @@
|
|||||||
|
<dl class="custom_fields_group_rendering">
|
||||||
|
<span class="custom_fields_group_name">{{ customFieldsGroup.name(app.request.locale) }}</span>
|
||||||
|
{% for customField in customFieldsGroup.customFields %}
|
||||||
|
<dt>{{ chill_custom_field_label(customField) }}</dt>
|
||||||
|
<dd>{{ chill_custom_field_widget(fields, customField) }}</dd>
|
||||||
|
{% endfor %}
|
||||||
|
</dl>
|
@ -0,0 +1,116 @@
|
|||||||
|
{#
|
||||||
|
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#}
|
||||||
|
{% extends "@ChillCustomFields/Admin/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% block title %}{{ 'CustomFieldsGroup details'|trans }}{% endblock %}
|
||||||
|
|
||||||
|
{% block admin_content %}
|
||||||
|
<h1>{{ 'CustomFieldsGroup details'|trans }}</h1>
|
||||||
|
|
||||||
|
<table class="record_properties">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th>{{ 'Name'|trans }}</th>
|
||||||
|
<td>{{ entity.getName|localize_translatable_string }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{{ 'Entity'|trans }}</th>
|
||||||
|
<td>{{ entity.entity|trans }}</td>
|
||||||
|
</tr>
|
||||||
|
{%- for key in options -%}
|
||||||
|
<tr>
|
||||||
|
<th>{{ key ~ '_label'|trans }}</th>
|
||||||
|
<td>
|
||||||
|
{%- 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 -%}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{%- else -%}
|
||||||
|
<!-- no option available for this entity -->
|
||||||
|
{%- endfor -%}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('customfieldsgroup') }}" class="sc-button bt-cancel">
|
||||||
|
{{ 'Back to the list'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('customfieldsgroup_edit', { 'id': entity.id }) }}" class="sc-button bt-edit">
|
||||||
|
{{ 'Edit'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>{{ 'Fields associated with this group'|trans }}</h2>
|
||||||
|
|
||||||
|
{%- if entity.customFields|length > 0 -%}
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ 'ordering'|trans|capitalize }}</th>
|
||||||
|
<th>{{ 'label_field'|trans|capitalize }}</th>
|
||||||
|
<th>{{ 'type'|trans|capitalize }}</th>
|
||||||
|
<th>{{ 'active'|trans|capitalize }}</th>
|
||||||
|
<th> </th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{%- for field in entity.customFields -%}
|
||||||
|
<tr>
|
||||||
|
<td>{{ field.ordering }}</td>
|
||||||
|
<td>{{ field.name|localize_translatable_string }}</td>
|
||||||
|
<td>{{ field.type|trans }}</td>
|
||||||
|
<td style="text-align:center;">
|
||||||
|
{%- if field.active -%}
|
||||||
|
<i class="fa fa-check-square-o"></i>
|
||||||
|
{%- else -%}
|
||||||
|
<i class="fa fa-square-o"></i>
|
||||||
|
{%- endif -%}
|
||||||
|
</td>
|
||||||
|
<td style="text-align:center">
|
||||||
|
<a href="{{ path('customfield_edit', { 'id' : field.id }) }}" class="sc-button bt-edit">{{ 'edit'|trans|capitalize }}</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{%- endfor -%}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{{ form_start(create_field_form) }}
|
||||||
|
<div class="grid-4">
|
||||||
|
{{ form_widget(create_field_form.type) }}
|
||||||
|
</div>
|
||||||
|
{{ form_widget(create_field_form.submit, { 'attr': { 'class': 'sc-button bt-create' }, 'label': 'Add a new field' } ) }}
|
||||||
|
{{ form_end(create_field_form) }}
|
||||||
|
{%- else -%}
|
||||||
|
<p>
|
||||||
|
{{ 'Any field is currently associated with this group'|trans }}
|
||||||
|
</p>
|
||||||
|
{{ form_start(create_field_form) }}
|
||||||
|
<div class="grid-4">
|
||||||
|
{{ form_widget(create_field_form.type) }}
|
||||||
|
</div>
|
||||||
|
{{ form_widget(create_field_form.submit, { 'attr': { 'class': 'sc-button bt-create' }, 'label': 'Create a new field' } ) }}
|
||||||
|
{{ form_end(create_field_form) }}
|
||||||
|
{%- endif -%}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,13 @@
|
|||||||
|
{% if selected|length > 0 %}
|
||||||
|
{%- for choice in choices -%}
|
||||||
|
{% if choice['slug'] in selected %}
|
||||||
|
{%- if choice['slug'] is not same as('_other') -%}
|
||||||
|
{{ choice['name']|localize_translatable_string|csv_cell }}
|
||||||
|
{%- else -%}
|
||||||
|
{{ choice['name']|csv_cell }}
|
||||||
|
{%- endif -%}
|
||||||
|
{% endif %}
|
||||||
|
{%- endfor -%}
|
||||||
|
{% else %}
|
||||||
|
{{ 'None'|trans }}
|
||||||
|
{% endif %}
|
@ -0,0 +1,29 @@
|
|||||||
|
{% if selected|length > 0 %}
|
||||||
|
<ul class="custom_fields choice">
|
||||||
|
{%- for choice in choices -%}
|
||||||
|
{% if choice['slug'] in selected %}
|
||||||
|
{%- set is_selected = true -%}
|
||||||
|
{%- else -%}
|
||||||
|
{%- set is_selected = false -%}
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
|
{%- if is_selected -%}
|
||||||
|
<li class="{% if is_selected or expanded == 1 %} selected {% endif %}">
|
||||||
|
{%- if is_selected -%}
|
||||||
|
<i class="fa fa-check-square-o"></i>
|
||||||
|
{%- else -%}
|
||||||
|
<i class="fa fa-square-o"></i>
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
|
{%- if choice['slug'] is not same as('_other') -%}
|
||||||
|
{{ choice['name']|localize_translatable_string }}
|
||||||
|
{%- else -%}
|
||||||
|
{{ choice['name'] }}
|
||||||
|
{%- endif -%}
|
||||||
|
</li>
|
||||||
|
{%- endif -%}
|
||||||
|
{%- endfor -%}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<div class="custom_fields_choice empty">{{ 'None'|trans }}</div>
|
||||||
|
{% endif %}
|
@ -0,0 +1 @@
|
|||||||
|
{% if values|length == 1 %}{{ values[0].text|localize_translatable_string|default("")|csv_cell }}{% elseif values|length ==0 %}{{ 'emtpy'|csv_cell }}{% else %}{{ 'pas de rendu multiple'|csv_cell }}{% endif %}
|
@ -0,0 +1,11 @@
|
|||||||
|
{% if values|length > 0 %}
|
||||||
|
<ul class="custom_fields long_choice {% if values|length == 1 %}unique{% endif %}">
|
||||||
|
{%- for value in values -%}
|
||||||
|
<li class="long_choice_item long_choice-key-{{ value.key }} long_choice-ikey-{{ value.internalKey }} long_choice-parent-ikey-{{ value.parent.internalKey }}">
|
||||||
|
<i class="fa fa-check-square-o"></i> {{ value.text|localize_translatable_string }}
|
||||||
|
</li>
|
||||||
|
{%- endfor -%}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<div class="custom_fields_choice long_choice empty">{{ 'None'|trans }}</div>
|
||||||
|
{% endif %}
|
@ -0,0 +1 @@
|
|||||||
|
{% if value is not empty %}{{ value|format_date(format)}}{% endif %}
|
@ -0,0 +1 @@
|
|||||||
|
{% if number is not empty %}{{ number|number_format(scale)|csv_cell }}{% endif %}
|
@ -0,0 +1 @@
|
|||||||
|
{% if number is not empty %}{{ number|number_format(scale) }} {{ post|default('') }}{% endif %}
|
@ -0,0 +1 @@
|
|||||||
|
{% if text is not empty %}{{ text|csv_cell}}{% else %}{{ 'None'|trans }}{% endif %}
|
@ -0,0 +1 @@
|
|||||||
|
{% if text is not empty %}{{ text|nl2br }}{% else %}<span class="custom_fields_text empty">{{ 'None'|trans }}</span>{% endif %}
|
@ -0,0 +1,5 @@
|
|||||||
|
{% if type == "title"%}
|
||||||
|
<h2>{{ title | localize_translatable_string }}</h2>
|
||||||
|
{% else %}
|
||||||
|
<h3>{{ title | localize_translatable_string }}</h3>
|
||||||
|
{% endif %}
|
@ -0,0 +1,111 @@
|
|||||||
|
{#
|
||||||
|
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#}
|
||||||
|
|
||||||
|
{# CustomFields Title #}
|
||||||
|
{% block custom_field_title_widget %}
|
||||||
|
<span class="cf-{{ form.vars.attr.type }}">
|
||||||
|
{{ form.vars.attr.title }}
|
||||||
|
</span>
|
||||||
|
{% endblock custom_field_title_widget %}
|
||||||
|
|
||||||
|
{# 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) }}
|
||||||
|
{% endblock cf_choices_list_widget %}
|
||||||
|
|
||||||
|
{# CFChoice : render the different elements in a choice list #}
|
||||||
|
{% block cf_choices_row %}
|
||||||
|
<h3>{{ 'Choices'|trans }}</h3>
|
||||||
|
|
||||||
|
<div id="{{ form.vars.id }}" data-prototype="{{- form_row(form.vars.prototype.children.name)
|
||||||
|
~ form_row(form.vars.prototype.children.active)
|
||||||
|
~ form_row(form.vars.prototype.children.slug) -}}">
|
||||||
|
<table><tbody>
|
||||||
|
{% for choice in form %}
|
||||||
|
<tr><td>
|
||||||
|
{{ form_row(choice.name) }}
|
||||||
|
{{ form_row(choice.active) }}
|
||||||
|
{{ form_row(choice.slug) }}
|
||||||
|
</td></tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody></table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{# we use javascrit to add an additional element. All functions are personnalized with the id ( = form.vars.id) #}
|
||||||
|
<script type="text/javascript">
|
||||||
|
function addElementInDiv(div_id) {
|
||||||
|
var div = $('#' + div_id);console.log(div);
|
||||||
|
var prototype = div.data('prototype');console.log(prototype);
|
||||||
|
var index = div.data('index');console.log(index);
|
||||||
|
var add_element_link = $('#' + div_id + '_add_element_link');
|
||||||
|
var new_fields = prototype.replace(/__name__label__/g, index);
|
||||||
|
var new_fields = prototype.replace(/__name__/g, index);
|
||||||
|
|
||||||
|
div.data('index', index + 1);
|
||||||
|
console.log(index);
|
||||||
|
add_element_link.before(new_fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initializeCFChoiceOptionsChoices(div_id) {
|
||||||
|
var add_element_link = $('<a id="' + div_id + '_add_element_link"" href="#" class="sc-button bt-submit">{{ 'Add an element'|trans }}</a>');
|
||||||
|
var div = $('#' + div_id);
|
||||||
|
div.append(add_element_link);
|
||||||
|
div.data('index', div.find('td').length);
|
||||||
|
console.log(div.data('index'));
|
||||||
|
|
||||||
|
add_element_link.on('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
addElementInDiv(div_id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function(event) {
|
||||||
|
jQuery(document).ready(initializeCFChoiceOptionsChoices('{{ form.vars.id }}'));
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock cf_choices_row %}
|
||||||
|
|
||||||
|
{# extend the number type to add post_text extension #}
|
||||||
|
{% block number_widget %}
|
||||||
|
{%- if post_text is defined and post_text is not empty-%}
|
||||||
|
<div class="input_with_post_text">
|
||||||
|
{%- endif -%}
|
||||||
|
{{ block('form_widget') }}
|
||||||
|
{%- if post_text is defined and post_text is not empty-%}
|
||||||
|
<span class="post_text">{{ post_text }}</span>
|
||||||
|
</div>
|
||||||
|
{%- endif -%}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{# extend the number type to add post_text extension #}
|
||||||
|
{% block integer_widget %}
|
||||||
|
{%- if post_text is defined and post_text is not empty-%}
|
||||||
|
<div class="input_with_post_text">
|
||||||
|
{%- endif -%}
|
||||||
|
{{ block('form_widget') }}
|
||||||
|
{%- if post_text is defined and post_text is not empty-%}
|
||||||
|
<span class="post_text">{{ post_text }}</span>
|
||||||
|
</div>
|
||||||
|
{%- endif -%}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{# The choice_with_other_widget widget is defined in the main bundle #}
|
||||||
|
|
103
src/Bundle/ChillCustomFields/Service/CustomFieldProvider.php
Normal file
103
src/Bundle/ChillCustomFields/Service/CustomFieldProvider.php
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
|
||||||
|
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Service;
|
||||||
|
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive all the services tagged with 'chill.custom_field'.
|
||||||
|
*
|
||||||
|
* The services tagged with 'chill.custom_field' are services used to declare
|
||||||
|
* a new custom field type. The tag must contain a 'type' variable (that must
|
||||||
|
* be unique), this type is used to identify this custom field in the form
|
||||||
|
* declration
|
||||||
|
*
|
||||||
|
* For example (in services.yml) :
|
||||||
|
* services:
|
||||||
|
* chill.icp2.type:
|
||||||
|
* tags:
|
||||||
|
* - { name: 'chill.custom_field', type: 'ICPC2' }
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class CustomFieldProvider implements ContainerAwareInterface
|
||||||
|
{
|
||||||
|
/** @var array $servicesByType The services indexes by the type */
|
||||||
|
private $servicesByType = array();
|
||||||
|
|
||||||
|
/** @var Container $container The container */
|
||||||
|
private $container;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new custom field to the provider
|
||||||
|
*
|
||||||
|
* @param type $serviceName The name of the service (declared in service.yml)
|
||||||
|
* @param type $type The type of the service (that is used in the form to
|
||||||
|
* add this type)
|
||||||
|
*/
|
||||||
|
public function addCustomField($serviceName, $type)
|
||||||
|
{
|
||||||
|
$this->servicesByType[$type] = $serviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a custom field stored in the provider. The custom field is identified
|
||||||
|
* by its type.
|
||||||
|
*
|
||||||
|
* @param string $type The type of the wanted service
|
||||||
|
* @return CustomFieldInterface
|
||||||
|
*/
|
||||||
|
public function getCustomFieldByType($type)
|
||||||
|
{
|
||||||
|
if (isset($this->servicesByType[$type])) {
|
||||||
|
return $this->servicesByType[$type];
|
||||||
|
} else {
|
||||||
|
throw new \LogicException('the custom field with type '.$type.' '
|
||||||
|
. 'is not found');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Symfony\Component\DependencyInjection\ContainerAwareInterface::setContainer()
|
||||||
|
*/
|
||||||
|
public function setContainer(ContainerInterface $container = null)
|
||||||
|
{
|
||||||
|
if ($container === null) {
|
||||||
|
throw new \LogicException('container should not be null');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->container = $container;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the custom fields known by the provider
|
||||||
|
*
|
||||||
|
* @return array Array of the known custom fields indexed by the type.
|
||||||
|
*/
|
||||||
|
public function getAllFields()
|
||||||
|
{
|
||||||
|
return $this->servicesByType;
|
||||||
|
}
|
||||||
|
}
|
90
src/Bundle/ChillCustomFields/Service/CustomFieldsHelper.php
Normal file
90
src/Bundle/ChillCustomFields/Service/CustomFieldsHelper.php
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
|
||||||
|
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Service;
|
||||||
|
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Chill\CustomFieldsBundle\Service\CustomFieldProvider;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helpers for manipulating custom fields.
|
||||||
|
*
|
||||||
|
* Herlpers for getting a certain custom field, for getting the raw value
|
||||||
|
* of a custom field and for rendering the value of a custom field.
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class CustomFieldsHelper
|
||||||
|
{
|
||||||
|
/** @var EntityManagerInterface $em The entity manager */
|
||||||
|
private $em;
|
||||||
|
|
||||||
|
/** @var CustomFieldProvider $provider Provider of all the declared custom
|
||||||
|
* fields */
|
||||||
|
private $provider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param EntityManagerInterface $em The entity manager
|
||||||
|
* @param CustomFieldProvider $provider The customfield provider that
|
||||||
|
* contains all the declared custom fields
|
||||||
|
*/
|
||||||
|
public function __construct(EntityManagerInterface $em,
|
||||||
|
CustomFieldProvider $provider)
|
||||||
|
{
|
||||||
|
$this->em = $em;
|
||||||
|
$this->provider = $provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isEmptyValue(array $fields, CustomField $customField)
|
||||||
|
{
|
||||||
|
$slug = $customField->getSlug();
|
||||||
|
$rawValue = (isset($fields[$slug])) ? $fields[$slug] : null;
|
||||||
|
$customFieldType = $this->provider->getCustomFieldByType($customField->getType());
|
||||||
|
|
||||||
|
$deserializedValue = $customFieldType->deserialize($rawValue, $customField);
|
||||||
|
|
||||||
|
return $customFieldType->isEmptyValue($deserializedValue, $customField);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the value of a custom field
|
||||||
|
*
|
||||||
|
* @param array $fields the **raw** array, as stored in the db
|
||||||
|
* @param CustomField $customField the customField entity
|
||||||
|
* @param string $documentType The type of document in which the rendered value is displayed ('html' or 'csv').
|
||||||
|
* @throws CustomFieldsHelperException if slug is missing
|
||||||
|
* @return The representation of the value the customField.
|
||||||
|
*/
|
||||||
|
public function renderCustomField(array $fields, CustomField $customField, $documentType='html')
|
||||||
|
{
|
||||||
|
$slug = $customField->getSlug();
|
||||||
|
$rawValue = (isset($fields[$slug])) ? $fields[$slug] : null;
|
||||||
|
$customFieldType = $this->provider->getCustomFieldByType($customField->getType());
|
||||||
|
|
||||||
|
return $customFieldType->render($rawValue, $customField, $documentType);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
|
||||||
|
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Service;
|
||||||
|
|
||||||
|
class CustomFieldsHelperException extends \Exception
|
||||||
|
{
|
||||||
|
public static function customFieldsGroupNotFound($entity)
|
||||||
|
{
|
||||||
|
return new CustomFieldsHelperException("The customFieldsGroups associated with $entity are not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function slugIsMissing()
|
||||||
|
{
|
||||||
|
return new CustomFieldsHelperException("The slug is missing");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,146 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
|
||||||
|
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Templating\Twig;
|
||||||
|
|
||||||
|
use Chill\CustomFieldsBundle\Service\CustomFieldsHelper;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\Container;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomField;
|
||||||
|
use Twig\Extension\AbstractExtension;
|
||||||
|
use Twig\TwigFunction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the following Twig Extension :
|
||||||
|
* * chill_custom_field_widget : to render the value of the custom field,
|
||||||
|
* * chill_custom_field_label : to render the label of the custom field,
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class CustomFieldRenderingTwig extends AbstractExtension implements ContainerAwareInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/** @var Container $container The container */
|
||||||
|
private $container;
|
||||||
|
|
||||||
|
/** @var array $defaultParams The default parameters */
|
||||||
|
private $defaultParams = array(
|
||||||
|
'label_layout' => 'ChillCustomFieldsBundle:CustomField:render_label.html.twig'
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var CustomFieldsHelper
|
||||||
|
*/
|
||||||
|
private $customFieldsHelper;
|
||||||
|
|
||||||
|
public function __construct(CustomFieldsHelper $customFieldsHelper)
|
||||||
|
{
|
||||||
|
$this->customFieldsHelper = $customFieldsHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Symfony\Component\DependencyInjection\ContainerAwareInterface::setContainer()
|
||||||
|
*/
|
||||||
|
public function setContainer(ContainerInterface $container = null)
|
||||||
|
{
|
||||||
|
$this->container = $container;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see Twig_Extension::getFunctions()
|
||||||
|
*/
|
||||||
|
public function getFunctions()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
new TwigFunction('chill_custom_field_widget', array(
|
||||||
|
$this,
|
||||||
|
'renderWidget'
|
||||||
|
), array(
|
||||||
|
'is_safe' => array(
|
||||||
|
'html'
|
||||||
|
)
|
||||||
|
)),
|
||||||
|
new TwigFunction('chill_custom_field_label', array(
|
||||||
|
$this,
|
||||||
|
'renderLabel'
|
||||||
|
), array(
|
||||||
|
'is_safe' => array(
|
||||||
|
'html'
|
||||||
|
)
|
||||||
|
)),
|
||||||
|
new TwigFunction('chill_custom_field_is_empty', array(
|
||||||
|
$this,
|
||||||
|
'isEmptyValue'
|
||||||
|
))
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function isEmptyValue($fields, CustomField $customField)
|
||||||
|
{
|
||||||
|
return $this->customFieldsHelper
|
||||||
|
->isEmptyValue($fields, $customField);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-PHPdoc)
|
||||||
|
* @see Twig_ExtensionInterface::getName()
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'chill_custom_fields_rendering';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Twig Extension that is used to render the label of a custom field.
|
||||||
|
*
|
||||||
|
* @param CustomField $customField Either a customField OR a customizable_entity OR the FQDN of the entity
|
||||||
|
* @param array $params The parameters for rendering. Currently, 'label_layout' allow to choose a different label. Default is 'ChillCustomFieldsBundle:CustomField:render_label.html.twig'
|
||||||
|
* @return string HTML representation of the custom field label.
|
||||||
|
*/
|
||||||
|
public function renderLabel(CustomField $customField, array $params = array())
|
||||||
|
{
|
||||||
|
$resolvedParams = array_merge($this->defaultParams, $params);
|
||||||
|
|
||||||
|
return $this->container->get('templating')
|
||||||
|
->render($resolvedParams['label_layout'], array('customField' => $customField));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Twig extension that is used to render the value of a custom field.
|
||||||
|
*
|
||||||
|
* The presentation of the value is influenced by the document type.
|
||||||
|
*
|
||||||
|
* @param array $fields The array raw, as stored in the db
|
||||||
|
* @param CustomField $customField Either a customField OR a customizable_entity OR the FQDN of the entity
|
||||||
|
* @param string $documentType The type of the document (csv, html)
|
||||||
|
* @param string $slug The slug of the custom field ONLY necessary if the first argument is NOT a CustomField instance
|
||||||
|
* @return string HTML representation of the custom field value, as described in the CustomFieldInterface. Is HTML safe
|
||||||
|
*/
|
||||||
|
public function renderWidget(array $fields, CustomField $customField, $documentType='html')
|
||||||
|
{
|
||||||
|
return $this->customFieldsHelper
|
||||||
|
->renderCustomField($fields, $customField, $documentType);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,120 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
|
||||||
|
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Templating\Twig;
|
||||||
|
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\Container;
|
||||||
|
use Twig\Extension\AbstractExtension;
|
||||||
|
use Twig\TwigFunction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the following Twig Extension :
|
||||||
|
* * chill_custom_fields_group_widget : to render the value of a custom field
|
||||||
|
* * group
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
* @author Marc Ducobu <marc.ducobu@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class CustomFieldsGroupRenderingTwig extends AbstractExtension implements ContainerAwareInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/** @var Container $container The container */
|
||||||
|
private $container;
|
||||||
|
|
||||||
|
/** @var array $defaultParams The default parameters */
|
||||||
|
private $defaultParams = array(
|
||||||
|
'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()
|
||||||
|
*/
|
||||||
|
public function setContainer(ContainerInterface $container = null)
|
||||||
|
{
|
||||||
|
$this->container = $container;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see Twig_Extension::getFunctions()
|
||||||
|
*/
|
||||||
|
public function getFunctions()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
new TwigFunction('chill_custom_fields_group_widget', array(
|
||||||
|
$this,
|
||||||
|
'renderWidget'
|
||||||
|
), array(
|
||||||
|
'is_safe' => array(
|
||||||
|
'html'
|
||||||
|
)
|
||||||
|
)),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-PHPdoc)
|
||||||
|
* @see Twig_ExtensionInterface::getName()
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'chill_custom_fields_group_rendering';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Twig extension that is used to render the value of a custom field group.
|
||||||
|
*
|
||||||
|
* The presentation of the value is influenced by the document type.
|
||||||
|
*
|
||||||
|
* @param array $fields The array raw, as stored in the db
|
||||||
|
* @param CustomFieldsGroud $customFielsGroup The custom field group
|
||||||
|
* @param string $documentType The type of the document (csv, html)
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
public function renderWidget(array $fields, $customFielsGroup, $documentType='html', array $params = array())
|
||||||
|
{
|
||||||
|
$resolvedParams = array_merge($this->defaultParams, $params);
|
||||||
|
|
||||||
|
return $this->container->get('templating')
|
||||||
|
->render($resolvedParams['layout'], array(
|
||||||
|
'cFGroup' => $customFielsGroup,
|
||||||
|
'cFData' => $fields,
|
||||||
|
'show_empty' => $resolvedParams['show_empty']));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Tests\Config;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the option Customizables_entities
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class ConfigCustomizablesEntitiesTest extends KernelTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Test that the config does work if the option
|
||||||
|
* chill_custom_fields.customizables_entities IS NOT present
|
||||||
|
*
|
||||||
|
* In this case, parameter 'chill_custom_fields.customizables_entities'
|
||||||
|
* should be an empty array in container
|
||||||
|
*/
|
||||||
|
public function testNotPresentInConfig()
|
||||||
|
{
|
||||||
|
self::bootKernel(array('environment' => 'test'));
|
||||||
|
$customizableEntities = static::$kernel->getContainer()
|
||||||
|
->getParameter('chill_custom_fields.customizables_entities');
|
||||||
|
|
||||||
|
$this->assertInternalType('array', $customizableEntities);
|
||||||
|
$this->assertCount(1, $customizableEntities);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that the 'chill_custom_fields.customizables_entities' is filled
|
||||||
|
* correctly with a minimal configuration.
|
||||||
|
*
|
||||||
|
* @internal use a custom config environment
|
||||||
|
*/
|
||||||
|
public function testNotEmptyConfig()
|
||||||
|
{
|
||||||
|
self::bootKernel(array('environment' => 'test_customizable_entities_test_not_empty_config'));
|
||||||
|
$customizableEntities = static::$kernel->getContainer()
|
||||||
|
->getParameter('chill_custom_fields.customizables_entities');
|
||||||
|
|
||||||
|
$this->assertInternalType('array', $customizableEntities);
|
||||||
|
$this->assertCount(2, $customizableEntities);
|
||||||
|
|
||||||
|
foreach($customizableEntities as $key => $config) {
|
||||||
|
$this->assertInternalType('array', $config);
|
||||||
|
$this->assertArrayHasKey('name', $config);
|
||||||
|
$this->assertArrayHasKey('class', $config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Tests\Controller;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
|
|
||||||
|
class CustomFieldControllerTest extends WebTestCase
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
public function testCompleteScenario()
|
||||||
|
{
|
||||||
|
// Create a new client to browse the application
|
||||||
|
$client = static::createClient();
|
||||||
|
|
||||||
|
// Create a new entry in the database
|
||||||
|
$crawler = $client->request('GET', '/customfield/');
|
||||||
|
$this->assertEquals(200, $client->getResponse()->getStatusCode(), "Unexpected HTTP status code for GET /customfield/");
|
||||||
|
$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_customfield[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_customfield[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());
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Tests\Controller;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Client;
|
||||||
|
|
||||||
|
class CustomFieldsGroupControllerTest extends WebTestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public function testCompleteScenario()
|
||||||
|
{
|
||||||
|
self::bootKernel(array('environment' => '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/');
|
||||||
|
$links = $crawler->selectLink('Modifier');
|
||||||
|
|
||||||
|
$this->assertGreaterThan(0, $links->count(),
|
||||||
|
"We can't find a 'Modifier' link on the index page");
|
||||||
|
$crawler = $client->click($links->last()->link());
|
||||||
|
|
||||||
|
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||||
|
|
||||||
|
$form = $crawler->selectButton('Mettre à jour')->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"]');
|
||||||
|
}
|
||||||
|
}
|
86
src/Bundle/ChillCustomFields/Tests/CustomFieldTestHelper.php
Normal file
86
src/Bundle/ChillCustomFields/Tests/CustomFieldTestHelper.php
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
* Copyright (C) 2014 Champs-Libres Coopérative <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Tests;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomField;
|
||||||
|
use Symfony\Component\HttpKernel\KernelInterface;
|
||||||
|
use Symfony\Component\DomCrawler\Crawler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Give useful method to prepare tests regarding custom fields
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
trait CustomFieldTestHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare a crawler containing the rendering of a customField
|
||||||
|
*
|
||||||
|
* @internal This method will mock a customFieldGroup containing $field, and
|
||||||
|
* rendering the customfield, using Type\CustomFieldType, to a simple form row
|
||||||
|
*
|
||||||
|
* @param CustomField $field
|
||||||
|
* @param KernelTestCase $testCase
|
||||||
|
* @param KernelInterface $kernel
|
||||||
|
* @param type $locale
|
||||||
|
* @return Crawler
|
||||||
|
*/
|
||||||
|
public function getCrawlerForField(CustomField $field, $locale = 'en')
|
||||||
|
{
|
||||||
|
$kernel = static::$kernel;
|
||||||
|
|
||||||
|
//check a kernel is accessible
|
||||||
|
$customFieldsGroup = $this->createMock('Chill\CustomFieldsBundle\Entity\CustomFieldsGroup');
|
||||||
|
$customFieldsGroup->expects($this->once())
|
||||||
|
->method('getActiveCustomFields')
|
||||||
|
->will($this->returnValue(array($field)));
|
||||||
|
|
||||||
|
$request = $this->createMock('Symfony\Component\HttpFoundation\Request');
|
||||||
|
$request->expects($this->any())
|
||||||
|
->method('getLocale')
|
||||||
|
->will($this->returnValue($locale));
|
||||||
|
|
||||||
|
$kernel->getContainer()->get('request_stack')->push($request);
|
||||||
|
|
||||||
|
$builder = $kernel->getContainer()->get('form.factory')->createBuilder();
|
||||||
|
$form = $builder->add('tested', 'custom_field',
|
||||||
|
array('group' => $customFieldsGroup))
|
||||||
|
->getForm();
|
||||||
|
|
||||||
|
$kernel->getContainer()->get('twig.loader')
|
||||||
|
->addPath($kernel->getContainer()->getParameter('kernel.root_dir').
|
||||||
|
'/Resources/views/', $namespace = 'test');
|
||||||
|
|
||||||
|
$content = $kernel
|
||||||
|
->getContainer()->get('templating')
|
||||||
|
->render('@test/CustomField/simple_form_render.html.twig', array(
|
||||||
|
'form' => $form->createView(),
|
||||||
|
'inputKeys' => array('tested')
|
||||||
|
));
|
||||||
|
|
||||||
|
$crawler = new Crawler();
|
||||||
|
$crawler->addHtmlContent($content);
|
||||||
|
|
||||||
|
return $crawler;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,468 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Tests;
|
||||||
|
|
||||||
|
use 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é <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
|
||||||
|
$deserialized = $this->cfChoice->deserialize(array(null), $customField);
|
||||||
|
$this->assertSame(null, $deserialized);
|
||||||
|
|
||||||
|
$deserialized = $this->cfChoice->deserialize(array('_other' => null, '_choices' => null), $customField);
|
||||||
|
$this->assertSame(null, $deserialized);
|
||||||
|
|
||||||
|
$deserialized = $this->cfChoice->deserialize(array('_other' => null, '_choices' => ''), $customField);
|
||||||
|
$this->assertSame('', $deserialized);
|
||||||
|
|
||||||
|
$deserialized = $this->cfChoice->deserialize(array(null), $customField);
|
||||||
|
$this->assertSame(null, $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);
|
||||||
|
|
||||||
|
$deserialized = $this->cfChoice->deserialize(array('_other' => null, '_choices' => null), $customField);
|
||||||
|
$this->assertSame(array('_other' => '', '_choices' => null), $deserialized);
|
||||||
|
|
||||||
|
$deserialized = $this->cfChoice->deserialize(array('_other' => null, '_choices' => ''), $customField);
|
||||||
|
$this->assertSame(array('_other' => '', '_choices' => ''), $deserialized);
|
||||||
|
|
||||||
|
$deserialized = $this->cfChoice->deserialize(array(null), $customField);
|
||||||
|
$this->assertSame(array('_other' => '', '_choices' => null), $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);
|
||||||
|
|
||||||
|
$deserialized = $this->cfChoice->deserialize(array('_other' => null, '_choices' => null), $customField);
|
||||||
|
$this->assertSame(array('_other' => '', '_choices' => array(null)), $deserialized);
|
||||||
|
|
||||||
|
$deserialized = $this->cfChoice->deserialize(array('_other' => null, '_choices' => ''), $customField);
|
||||||
|
$this->assertSame(array('_other' => '', '_choices' => array('')), $deserialized);
|
||||||
|
|
||||||
|
$deserialized = $this->cfChoice->deserialize(array(null), $customField);
|
||||||
|
$this->assertSame(array('_other' => '', '_choices' => array(null)), $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);
|
||||||
|
|
||||||
|
// from multiple
|
||||||
|
$data = array(null);
|
||||||
|
$deserialized = $this->cfChoice->deserialize($data, $customField);
|
||||||
|
$this->assertSame(array(null), $deserialized);
|
||||||
|
|
||||||
|
$data = array('_other' => null, '_choices' => array(null));
|
||||||
|
$deserialized = $this->cfChoice->deserialize($data, $customField);
|
||||||
|
$this->assertSame(array(null), $deserialized);
|
||||||
|
|
||||||
|
//from single
|
||||||
|
$data = array('_other' => null, '_choices' => null);
|
||||||
|
$deserialized = $this->cfChoice->deserialize($data, $customField);
|
||||||
|
$this->assertSame(array(null), $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
|
||||||
|
//
|
||||||
|
////////////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test the not empty with the not-empty data provider
|
||||||
|
*
|
||||||
|
* @param mixed $data
|
||||||
|
* @dataProvider serializedRepresentationDataProvider
|
||||||
|
*/
|
||||||
|
public function testIsEmptyValueNotEmpty($data)
|
||||||
|
{
|
||||||
|
$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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @dataProvider emptyDataProvider
|
||||||
|
* @param mixed $data deserialized data
|
||||||
|
*/
|
||||||
|
public function testIsEmptyValueEmpty($data)
|
||||||
|
{
|
||||||
|
$customField = $this->generateCustomField(array(
|
||||||
|
CustomFieldChoice::ALLOW_OTHER => false,
|
||||||
|
CustomFieldChoice::MULTIPLE => true
|
||||||
|
));
|
||||||
|
|
||||||
|
$isEmpty = $this->cfChoice->isEmptyValue($data, $customField);
|
||||||
|
|
||||||
|
$this->assertTrue($isEmpty);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* provide empty data in different possible representations.
|
||||||
|
* Those data are supposed to be deserialized.
|
||||||
|
*
|
||||||
|
* @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())
|
||||||
|
),
|
||||||
|
// 6
|
||||||
|
array(
|
||||||
|
// empty
|
||||||
|
array('_other' => null, '_choices' => null)
|
||||||
|
),
|
||||||
|
// 7
|
||||||
|
array(
|
||||||
|
// empty
|
||||||
|
array(null)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,191 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Tests;
|
||||||
|
|
||||||
|
use Chill\CustomFieldsBundle\CustomFields\CustomFieldNumber;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomField;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup;
|
||||||
|
use Chill\CustomFieldsBundle\Form\CustomFieldsGroupType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test CustomFieldsNumber
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class CustomFieldsNumberTest extends \Symfony\Bundle\FrameworkBundle\Test\WebTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var CustomFieldNumber
|
||||||
|
*/
|
||||||
|
private $customFieldNumber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var FormBuilderInterface
|
||||||
|
*/
|
||||||
|
private $formBuilder;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
|
||||||
|
$this->customFieldNumber = self::$kernel->getContainer()
|
||||||
|
->get('chill.custom_field.number');
|
||||||
|
|
||||||
|
$this->formBuilder = self::$kernel->getContainer()
|
||||||
|
->get('form.factory')
|
||||||
|
->createBuilder('form', null, array(
|
||||||
|
'csrf_protection' => false,
|
||||||
|
'csrf_field_name' => '_token'
|
||||||
|
));
|
||||||
|
|
||||||
|
$request = new \Symfony\Component\HttpFoundation\Request();
|
||||||
|
$request->setLocale('fr');
|
||||||
|
|
||||||
|
self::$kernel->getContainer()
|
||||||
|
->get('request_stack')
|
||||||
|
->push($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param mixed[] $options
|
||||||
|
* @return CustomField
|
||||||
|
*/
|
||||||
|
private function createCustomFieldNumber($options)
|
||||||
|
{
|
||||||
|
return (new CustomField())
|
||||||
|
->setType('number')
|
||||||
|
->setActive(true)
|
||||||
|
->setOrdering(10)
|
||||||
|
->setSlug('default')
|
||||||
|
->setName(array('fr' => 'default'))
|
||||||
|
->setOptions($options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateValidForm()
|
||||||
|
{
|
||||||
|
$cf = $this->createCustomFieldNumber(array(
|
||||||
|
'min' => null,
|
||||||
|
'max' => null,
|
||||||
|
'scale' => null,
|
||||||
|
'post_text' => null
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->customFieldNumber->buildForm($this->formBuilder, $cf);
|
||||||
|
|
||||||
|
$form = $this->formBuilder->getForm();
|
||||||
|
|
||||||
|
$form->submit(array('default' => 10));
|
||||||
|
|
||||||
|
$this->assertTrue($form->isSynchronized());
|
||||||
|
$this->assertEquals(10, $form['default']->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateInvalidFormValueGreaterThanMaximum()
|
||||||
|
{
|
||||||
|
$cf = $this->createCustomFieldNumber(array(
|
||||||
|
'min' => null,
|
||||||
|
'max' => 10,
|
||||||
|
'scale' => null,
|
||||||
|
'post_text' => null
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->customFieldNumber->buildForm($this->formBuilder, $cf);
|
||||||
|
|
||||||
|
$form = $this->formBuilder->getForm();
|
||||||
|
|
||||||
|
$form->submit(array('default' => 100));
|
||||||
|
|
||||||
|
$this->assertTrue($form->isSynchronized());
|
||||||
|
$this->assertFalse($form->isValid());
|
||||||
|
$this->assertEquals(1, count($form['default']->getErrors()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateInvalidFormValueLowerThanMinimum()
|
||||||
|
{
|
||||||
|
$cf = $this->createCustomFieldNumber(array(
|
||||||
|
'min' => 1000,
|
||||||
|
'max' => null,
|
||||||
|
'scale' => null,
|
||||||
|
'post_text' => null
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->customFieldNumber->buildForm($this->formBuilder, $cf);
|
||||||
|
|
||||||
|
$form = $this->formBuilder->getForm();
|
||||||
|
|
||||||
|
$form->submit(array('default' => 100));
|
||||||
|
|
||||||
|
$this->assertTrue($form->isSynchronized());
|
||||||
|
$this->assertFalse($form->isValid());
|
||||||
|
$this->assertEquals(1, count($form['default']->getErrors()));
|
||||||
|
}
|
||||||
|
|
||||||
|
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(\Chill\CustomFieldsBundle\Form\Type\CustomFieldType::class, 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(\Chill\CustomFieldsBundle\Form\Type\CustomFieldType::class, array(), array(
|
||||||
|
'group' => $cfGroup
|
||||||
|
))
|
||||||
|
->getForm();
|
||||||
|
|
||||||
|
$this->assertTrue($form['default']->isRequired(),
|
||||||
|
"The field should be required");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,106 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
* Copyright (C) 2014 Champs-Libres.coop
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Tests;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomField;
|
||||||
|
use Chill\CustomFieldsBundle\CustomFields\CustomFieldText;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
|
use Symfony\Component\DomCrawler\Crawler;
|
||||||
|
use Chill\CustomFieldsBundle\Tests\CustomFieldTestHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class CustomFieldsTextTest extends WebTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var \Chill\CustomFieldsBundle\Service\CustomFieldProvider
|
||||||
|
*/
|
||||||
|
private $customFieldProvider;
|
||||||
|
|
||||||
|
use CustomFieldTestHelper;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
static::bootKernel();
|
||||||
|
$this->customFieldProvider = static::$kernel->getContainer()
|
||||||
|
->get('chill.custom_field.provider');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCustomFieldsTextExists()
|
||||||
|
{
|
||||||
|
$customField = $this->customFieldProvider->getCustomFieldByType('text');
|
||||||
|
|
||||||
|
$this->assertInstanceOf('Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface',
|
||||||
|
$customField);
|
||||||
|
$this->assertInstanceOf('Chill\CustomFieldsBundle\CustomFields\CustomFieldText',
|
||||||
|
$customField);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPublicFormRenderingLengthLessThan256()
|
||||||
|
{
|
||||||
|
$customField = new CustomField();
|
||||||
|
$customField->setType('text')
|
||||||
|
->setOptions(array(CustomFieldText::MAX_LENGTH => 255))
|
||||||
|
->setSlug('slug')
|
||||||
|
->setOrdering(10)
|
||||||
|
->setActive(true)
|
||||||
|
->setName(array('en' => 'my label'));
|
||||||
|
|
||||||
|
$crawler = $this->getCrawlerForField($customField);
|
||||||
|
|
||||||
|
$this->assertCount(1, $crawler->filter("input[type=text]"));
|
||||||
|
$this->assertCount(1, $crawler->filter("label:contains('my label')"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPublicFormRenderingLengthMoreThan25()
|
||||||
|
{
|
||||||
|
$customField = new CustomField();
|
||||||
|
$customField->setType('text')
|
||||||
|
->setOptions(array(CustomFieldText::MAX_LENGTH => 256))
|
||||||
|
->setSlug('slug')
|
||||||
|
->setOrdering(10)
|
||||||
|
->setActive(true)
|
||||||
|
->setName(array('en' => 'my label'));
|
||||||
|
|
||||||
|
$crawler = $this->getCrawlerForField($customField);
|
||||||
|
|
||||||
|
$this->assertCount(1, $crawler->filter("textarea"));
|
||||||
|
$this->assertCount(1, $crawler->filter("label:contains('my label')"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFormTextNew()
|
||||||
|
{
|
||||||
|
$client = static::createClient();
|
||||||
|
|
||||||
|
$crawler = $client->request('GET', '/fr/admin/customfield/new?type=text');
|
||||||
|
|
||||||
|
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||||
|
|
||||||
|
$form = $crawler->selectButton('custom_field_choice_submit')->form();
|
||||||
|
$this->assertTrue($form->has('custom_field_choice[options][maxLength]'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Champs-Libres <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFields\Tests\Form\Extension;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the post-text extension
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class PostTextIntegerExtensionTest extends KernelTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var \Symfony\Component\Form\FormBuilderInterface
|
||||||
|
*/
|
||||||
|
private $formBuilder;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
|
||||||
|
$container = self::$kernel->getContainer();
|
||||||
|
|
||||||
|
$this->formBuilder = $container->get('form.factory')
|
||||||
|
->createBuilder('form', null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateView()
|
||||||
|
{
|
||||||
|
$form = $this->formBuilder->add('test', IntegerType::class, array(
|
||||||
|
'post_text' => 'my text'
|
||||||
|
))->getForm();
|
||||||
|
|
||||||
|
$view = $form->createView();
|
||||||
|
|
||||||
|
$this->assertEquals('my text', $view['test']->vars['post_text']);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Champs-Libres <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFields\Tests\Form\Extension;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\NumberType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the post-text extension
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class PostTextNumberExtensionTest extends KernelTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var \Symfony\Component\Form\FormBuilderInterface
|
||||||
|
*/
|
||||||
|
private $formBuilder;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
|
||||||
|
$container = self::$kernel->getContainer();
|
||||||
|
|
||||||
|
$this->formBuilder = $container->get('form.factory')
|
||||||
|
->createBuilder('form', null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateView()
|
||||||
|
{
|
||||||
|
$form = $this->formBuilder->add('test', NumberType::class, array(
|
||||||
|
'post_text' => 'my text'
|
||||||
|
))->getForm();
|
||||||
|
|
||||||
|
$view = $form->createView();
|
||||||
|
|
||||||
|
$this->assertEquals('my text', $view['test']->vars['post_text']);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFieldsBundle\Tests;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that routes are correctly loaded
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class RoutingLoaderTest extends WebTestCase
|
||||||
|
{
|
||||||
|
public function testRoutesAreLoaded()
|
||||||
|
{
|
||||||
|
$client = static::createClient();
|
||||||
|
|
||||||
|
$client->request('GET','/fr/admin/customfield/');
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
Response::HTTP_OK,
|
||||||
|
$client->getResponse()->getStatusCode()
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
* Copyright (C) 2015 Champs Libres <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFields\Tests\Service;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||||
|
use Chill\CustomFieldsBundle\Service\CustomFieldsHelper;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for custom fields helper
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
* @author Champs Libres <info@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class CustomFieldsHelperTest extends KernelTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var CustomFieldsHelper
|
||||||
|
*/
|
||||||
|
private $cfHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var CustomField
|
||||||
|
*/
|
||||||
|
private $randomCFText;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
|
||||||
|
$container = self::$kernel->getContainer();
|
||||||
|
|
||||||
|
$this->cfHelper = $container->get('chill.custom_field.helper');
|
||||||
|
|
||||||
|
$this->randomCFText = (new CustomField())
|
||||||
|
->setSlug('my-slug')
|
||||||
|
->setActive(true)
|
||||||
|
->setName(array('fr' => 'my cf'))
|
||||||
|
->setOptions(array('maxLength' => 1000))
|
||||||
|
->setType('text')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRenderCustomField()
|
||||||
|
{
|
||||||
|
$data = array(
|
||||||
|
$this->randomCFText->getSlug() => 'Sample text'
|
||||||
|
);
|
||||||
|
|
||||||
|
$text = $this->cfHelper->renderCustomField($data, $this->randomCFText);
|
||||||
|
|
||||||
|
$this->assertContains('Sample text', $text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsEmptyValue()
|
||||||
|
{
|
||||||
|
// not empty value
|
||||||
|
$data = array(
|
||||||
|
$this->randomCFText->getSlug() => 'Sample text'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse($this->cfHelper->isEmptyValue($data, $this->randomCFText));
|
||||||
|
|
||||||
|
//empty value
|
||||||
|
$data = array(
|
||||||
|
$this->randomCFText->getSlug() => ''
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertTrue($this->cfHelper->isEmptyValue($data, $this->randomCFText));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,128 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
* Copyright (C) 2015 Champs Libres <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\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é <julien.fastre@champs-libres.coop>
|
||||||
|
* @author Champs Libres <info@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsEmpty()
|
||||||
|
{
|
||||||
|
$cf = $this->getSimpleCustomFieldText();
|
||||||
|
|
||||||
|
// value is not empty
|
||||||
|
$fields = array(
|
||||||
|
'test' => "My tailor is rich"
|
||||||
|
);
|
||||||
|
|
||||||
|
$result = $this->cfRendering->isEmptyValue($fields, $cf);
|
||||||
|
|
||||||
|
$this->assertFalse($result);
|
||||||
|
|
||||||
|
// value is empty
|
||||||
|
$fields = array(
|
||||||
|
'text' => ''
|
||||||
|
);
|
||||||
|
|
||||||
|
$result = $this->cfRendering->isEmptyValue($fields, $cf);
|
||||||
|
|
||||||
|
$this->assertTrue($result);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,130 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
* Copyright (C) 2015 Champs Libres <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CustomFields\Tests\Templating\Twig;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||||
|
use Chill\CustomFieldsBundle\Templating\Twig\CustomFieldsGroupRenderingTwig;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomField;
|
||||||
|
use Chill\CustomFieldsBundle\Service\CustomFieldProvider;
|
||||||
|
use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the rendering of a custom fields group through
|
||||||
|
* the `chill_custom_fields_group_widget`
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
* @author Champs Libres <info@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class CustomFieldsGroupRenderingTwigTest extends KernelTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var CustomFieldsGroupRenderingTwig
|
||||||
|
*/
|
||||||
|
private $cfRendering;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var CustomFieldProvider
|
||||||
|
*/
|
||||||
|
private $cfProvider;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
$this->cfRendering = self::$kernel->getContainer()
|
||||||
|
->get('chill.custom_field.twig.custom_fields_group_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($slug, $name)
|
||||||
|
{
|
||||||
|
return (new CustomField())
|
||||||
|
->setSlug($slug)
|
||||||
|
->setName(array('fr' => $name))
|
||||||
|
->setType('text')
|
||||||
|
->setOrdering(10)
|
||||||
|
->setOptions(array("maxLength" => 255))
|
||||||
|
->setActive(true)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return CustomFieldsGroup
|
||||||
|
*/
|
||||||
|
private function getCustomFieldsGroup()
|
||||||
|
{
|
||||||
|
return (new CustomFieldsGroup())
|
||||||
|
->setEntity('\Dummy')
|
||||||
|
->setName(array("fr" => "A cf group"))
|
||||||
|
->addCustomField($this->getSimpleCustomFieldText("horses", "Do you like horses ?."))
|
||||||
|
->addCustomField($this->getSimpleCustomFieldText("sure", "Are you sure ?"))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRenderingWidget()
|
||||||
|
{
|
||||||
|
$cfGroup = $this->getCustomFieldsGroup();
|
||||||
|
|
||||||
|
$text = $this->cfRendering->renderWidget(array(
|
||||||
|
'horses' => 'I like horses',
|
||||||
|
'sure' => 'Yes !'
|
||||||
|
), $cfGroup);
|
||||||
|
|
||||||
|
$this->assertContains('Do you like horses', $text);
|
||||||
|
$this->assertContains('I like horses', $text);
|
||||||
|
$this->assertContains('Are you sure', $text);
|
||||||
|
$this->assertContains('Yes', $text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRenderingWidgetDoNotShowEmpty()
|
||||||
|
{
|
||||||
|
$cfGroup = $this->getCustomFieldsGroup();
|
||||||
|
$cfGroup->addCustomField($this->getSimpleCustomFieldText('empty', 'Do not answer'));
|
||||||
|
|
||||||
|
$text = $this->cfRendering->renderWidget(array(
|
||||||
|
'horses' => 'I like horses',
|
||||||
|
'sure' => 'Yes !'
|
||||||
|
), $cfGroup, 'html', array('show_empty' => false));
|
||||||
|
|
||||||
|
$this->assertContains('Do you like horses', $text);
|
||||||
|
$this->assertContains('I like horses', $text);
|
||||||
|
$this->assertContains('Are you sure', $text);
|
||||||
|
$this->assertContains('Yes', $text);
|
||||||
|
$this->assertNotContains('Do not answer', $text);
|
||||||
|
}
|
||||||
|
}
|
8
src/Bundle/ChillCustomFields/Tests/bootstrap.php
Normal file
8
src/Bundle/ChillCustomFields/Tests/bootstrap.php
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!is_file($autoloadFile = __DIR__.'/../vendor/autoload.php')) {
|
||||||
|
throw new \LogicException('Could not find autoload.php in vendor/. Did you run "composer install --dev"?');
|
||||||
|
}
|
||||||
|
|
||||||
|
require $autoloadFile;
|
||||||
|
|
15
src/Bundle/ChillCustomFields/apigen.neon
Normal file
15
src/Bundle/ChillCustomFields/apigen.neon
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# configuration for apigen
|
||||||
|
|
||||||
|
|
||||||
|
source:
|
||||||
|
- .
|
||||||
|
|
||||||
|
accessLevels: ["public", "protected"]
|
||||||
|
|
||||||
|
exclude:
|
||||||
|
- vendor/*
|
||||||
|
- Resources/test/*
|
||||||
|
- Tests/Fixtures/*
|
||||||
|
|
||||||
|
title: Chill CustomFields Bundle
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user