diff --git a/Controller/PersonController.php b/Controller/PersonController.php
index 655bbad1b..cbe0212c5 100644
--- a/Controller/PersonController.php
+++ b/Controller/PersonController.php
@@ -130,36 +130,6 @@ class PersonController extends Controller
return $this->redirect($url);
}
}
-
- /**
- * Return a csv file with all the persons
- *
- * @return A csv file with all the persons
- */
- public function exportAction()
- {
- $em = $this->getDoctrine()->getManager();
- $chillSecurityHelper = $this->get('chill.main.security.authorization.helper');
- $user = $this->get('security.context')->getToken()->getUser();
-
- $reachableCenters = $chillSecurityHelper->getReachableCenters($user,
- new Role('CHILL_PERSON_SEE'));
-
- $personRepository = $em->getRepository('ChillPersonBundle:Person');
- $qb = $personRepository->createQueryBuilder('p');
- $qb->where($qb->expr()->in('p.center', ':centers'))
- ->setParameter('centers', $reachableCenters);
- $persons = $qb->getQuery()->getResult();
-
- $response = $this->render('ChillPersonBundle:Person:export.csv.twig',
- array(
- 'persons' => $persons,
- 'cf_group' => $this->getCFGroup()));
- $response->headers->set('Content-Type', 'text/csv; charset=utf-8');
- $response->headers->set('Content-Disposition', 'attachment; filename="export_person.csv"');
-
- return $response;
- }
public function newAction()
{
diff --git a/DependencyInjection/ChillPersonExtension.php b/DependencyInjection/ChillPersonExtension.php
index 4121c737b..5fecfa9d7 100644
--- a/DependencyInjection/ChillPersonExtension.php
+++ b/DependencyInjection/ChillPersonExtension.php
@@ -26,6 +26,7 @@ use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Chill\MainBundle\DependencyInjection\MissingBundleException;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
+use Chill\PersonBundle\Doctrine\DQL\AddressPart;
/**
* This is the class that loads and manages your bundle configuration
@@ -91,6 +92,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
{
$this->prependRoleHierarchy($container);
$this->prependHomepageWidget($container);
+ $this->prependDoctrineDQL($container);
$bundles = $container->getParameter('kernel.bundles');
//add ChillMain to assetic-enabled bundles
@@ -162,4 +164,33 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
)
));
}
+
+ /**
+ * Add DQL function linked with person
+ *
+ * @param ContainerBuilder $container
+ */
+ protected function prependDoctrineDQL(ContainerBuilder $container)
+ {
+ //add DQL function to ORM (default entity_manager)
+
+ $container->prependExtensionConfig('doctrine', array(
+ 'orm' => array(
+ 'dql' => array(
+ 'string_functions' => array(
+ 'GET_PERSON_ADDRESS_ADDRESS_ID' => AddressPart\AddressPartAddressId::class,
+ 'GET_PERSON_ADDRESS_STREET_ADDRESS_1' => AddressPart\AddressPartStreetAddress1::class,
+ 'GET_PERSON_ADDRESS_STREET_ADDRESS_2' => AddressPart\AddressPartStreetAddress2::class,
+ 'GET_PERSON_ADDRESS_VALID_FROM' => AddressPart\AddressPartValidFrom::class,
+ 'GET_PERSON_ADDRESS_POSTCODE_LABEL' => AddressPart\AddressPartPostCodeLabel::class,
+ 'GET_PERSON_ADDRESS_POSTCODE_CODE' => AddressPart\AddressPartPostCodeCode::class,
+ 'GET_PERSON_ADDRESS_POSTCODE_ID' => AddressPart\AddressPartPostCodeId::class,
+ 'GET_PERSON_ADDRESS_COUNTRY_NAME' => AddressPart\AddressPartCountryName::class,
+ 'GET_PERSON_ADDRESS_COUNTRY_CODE' => AddressPart\AddressPartCountryCode::class,
+ 'GET_PERSON_ADDRESS_COUNTRY_ID' => AddressPart\AddressPartCountryId::class
+ )
+ )
+ )
+ ));
+ }
}
diff --git a/Doctrine/DQL/AddressPart.php b/Doctrine/DQL/AddressPart.php
new file mode 100644
index 000000000..baa3863d1
--- /dev/null
+++ b/Doctrine/DQL/AddressPart.php
@@ -0,0 +1,103 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+namespace Chill\PersonBundle\Doctrine\DQL;
+
+use Doctrine\ORM\Query\AST\Functions\FunctionNode;
+use Doctrine\ORM\Query\Lexer;
+use Doctrine\ORM\Query\Parser;
+use Doctrine\ORM\Query\SqlWalker;
+
+/**
+ *
+ * USAGE GET_ADDRESS_(person.id, :date, 'postcode') where part
+ * should be replace by the part of the address.
+ *
+ * This function return the current address part at the given date, for the
+ * given person (identified by his id)
+ *
+ * The aim of this function is to be used within reports
+ *
+ * @author Julien Fastré
+ */
+abstract class AddressPart extends FunctionNode
+{
+ public $fields = array(
+ 'address_id',
+ 'streetaddress1',
+ 'streetaddress2',
+ 'validfrom',
+ 'postcode_label',
+ 'postcode_code',
+ 'postcode_id',
+ 'country_name',
+ 'country_code',
+ 'country_id'
+ );
+
+ /**
+ *
+ * @var \Doctrine\ORM\Query\AST\Node
+ */
+ private $pid;
+
+ /**
+ *
+ * @var \Doctrine\ORM\Query\AST\Node
+ */
+ private $date;
+
+ /**
+ *
+ * @var \Doctrine\ORM\Query\AST\Node
+ */
+ private $part;
+
+ /**
+ * return the part of the address
+ *
+ * Should be one value of the "public" amongst
+ * 'address_id', 'streetaddress1',
+ * 'streetaddress2', 'validfrom', 'postcode_label', 'postcode_code',
+ * 'postcode_id', 'country_name', 'country_code', 'country_id'
+ *
+ * @return string
+ */
+ abstract public function getPart();
+
+ public function getSql(SqlWalker $sqlWalker)
+ {
+ return sprintf(
+ 'get_last_address_%s(%s, %s)',
+ $this->getPart(),
+ $this->pid->dispatch($sqlWalker),
+ $this->date->dispatch($sqlWalker)
+ );
+ }
+
+ public function parse(Parser $parser)
+ {
+ $a = $parser->match(Lexer::T_IDENTIFIER);
+ $parser->match(Lexer::T_OPEN_PARENTHESIS);
+ // person id
+ $this->pid = $parser->SingleValuedPathExpression();
+ $parser->match(Lexer::T_COMMA);
+ // date
+ $this->date = $parser->ArithmeticPrimary();
+ $parser->match(Lexer::T_CLOSE_PARENTHESIS);
+ }
+}
diff --git a/Doctrine/DQL/AddressPart/AddressPartAddressId.php b/Doctrine/DQL/AddressPart/AddressPartAddressId.php
new file mode 100644
index 000000000..2f40796cf
--- /dev/null
+++ b/Doctrine/DQL/AddressPart/AddressPartAddressId.php
@@ -0,0 +1,33 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+namespace Chill\PersonBundle\Doctrine\DQL\AddressPart;
+
+use Chill\PersonBundle\Doctrine\DQL\AddressPart;
+
+/**
+ *
+ *
+ * @author Julien Fastré
+ */
+class AddressPartAddressId extends AddressPart
+{
+ public function getPart()
+ {
+ return 'address_id';
+ }
+}
diff --git a/Doctrine/DQL/AddressPart/AddressPartCountryCode.php b/Doctrine/DQL/AddressPart/AddressPartCountryCode.php
new file mode 100644
index 000000000..e997dbb91
--- /dev/null
+++ b/Doctrine/DQL/AddressPart/AddressPartCountryCode.php
@@ -0,0 +1,33 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+namespace Chill\PersonBundle\Doctrine\DQL\AddressPart;
+
+use Chill\PersonBundle\Doctrine\DQL\AddressPart;
+
+/**
+ *
+ *
+ * @author Julien Fastré
+ */
+class AddressPartCountryCode extends AddressPart
+{
+ public function getPart()
+ {
+ return 'country_code';
+ }
+}
diff --git a/Doctrine/DQL/AddressPart/AddressPartCountryId.php b/Doctrine/DQL/AddressPart/AddressPartCountryId.php
new file mode 100644
index 000000000..ab0ab0da2
--- /dev/null
+++ b/Doctrine/DQL/AddressPart/AddressPartCountryId.php
@@ -0,0 +1,33 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+namespace Chill\PersonBundle\Doctrine\DQL\AddressPart;
+
+use Chill\PersonBundle\Doctrine\DQL\AddressPart;
+
+/**
+ *
+ *
+ * @author Julien Fastré
+ */
+class AddressPartCountryId extends AddressPart
+{
+ public function getPart()
+ {
+ return 'country_id';
+ }
+}
diff --git a/Doctrine/DQL/AddressPart/AddressPartCountryName.php b/Doctrine/DQL/AddressPart/AddressPartCountryName.php
new file mode 100644
index 000000000..c37902909
--- /dev/null
+++ b/Doctrine/DQL/AddressPart/AddressPartCountryName.php
@@ -0,0 +1,33 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+namespace Chill\PersonBundle\Doctrine\DQL\AddressPart;
+
+use Chill\PersonBundle\Doctrine\DQL\AddressPart;
+
+/**
+ *
+ *
+ * @author Julien Fastré
+ */
+class AddressPartCountryName extends AddressPart
+{
+ public function getPart()
+ {
+ return 'country_name';
+ }
+}
diff --git a/Doctrine/DQL/AddressPart/AddressPartPostCodeCode.php b/Doctrine/DQL/AddressPart/AddressPartPostCodeCode.php
new file mode 100644
index 000000000..ce792cede
--- /dev/null
+++ b/Doctrine/DQL/AddressPart/AddressPartPostCodeCode.php
@@ -0,0 +1,33 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+namespace Chill\PersonBundle\Doctrine\DQL\AddressPart;
+
+use Chill\PersonBundle\Doctrine\DQL\AddressPart;
+
+/**
+ *
+ *
+ * @author Julien Fastré
+ */
+class AddressPartPostCodeCode extends AddressPart
+{
+ public function getPart()
+ {
+ return 'postcode_code';
+ }
+}
diff --git a/Doctrine/DQL/AddressPart/AddressPartPostCodeId.php b/Doctrine/DQL/AddressPart/AddressPartPostCodeId.php
new file mode 100644
index 000000000..5400a04a7
--- /dev/null
+++ b/Doctrine/DQL/AddressPart/AddressPartPostCodeId.php
@@ -0,0 +1,33 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+namespace Chill\PersonBundle\Doctrine\DQL\AddressPart;
+
+use Chill\PersonBundle\Doctrine\DQL\AddressPart;
+
+/**
+ *
+ *
+ * @author Julien Fastré
+ */
+class AddressPartPostCodeId extends AddressPart
+{
+ public function getPart()
+ {
+ return 'postcode_id';
+ }
+}
diff --git a/Doctrine/DQL/AddressPart/AddressPartPostCodeLabel.php b/Doctrine/DQL/AddressPart/AddressPartPostCodeLabel.php
new file mode 100644
index 000000000..ab36a8c46
--- /dev/null
+++ b/Doctrine/DQL/AddressPart/AddressPartPostCodeLabel.php
@@ -0,0 +1,33 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+namespace Chill\PersonBundle\Doctrine\DQL\AddressPart;
+
+use Chill\PersonBundle\Doctrine\DQL\AddressPart;
+
+/**
+ *
+ *
+ * @author Julien Fastré
+ */
+class AddressPartPostCodeLabel extends AddressPart
+{
+ public function getPart()
+ {
+ return 'postcode_label';
+ }
+}
diff --git a/Doctrine/DQL/AddressPart/AddressPartStreetAddress1.php b/Doctrine/DQL/AddressPart/AddressPartStreetAddress1.php
new file mode 100644
index 000000000..c06cf2b07
--- /dev/null
+++ b/Doctrine/DQL/AddressPart/AddressPartStreetAddress1.php
@@ -0,0 +1,33 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+namespace Chill\PersonBundle\Doctrine\DQL\AddressPart;
+
+use Chill\PersonBundle\Doctrine\DQL\AddressPart;
+
+/**
+ *
+ *
+ * @author Julien Fastré
+ */
+class AddressPartStreetAddress1 extends AddressPart
+{
+ public function getPart()
+ {
+ return 'streetaddress1';
+ }
+}
diff --git a/Doctrine/DQL/AddressPart/AddressPartStreetAddress2.php b/Doctrine/DQL/AddressPart/AddressPartStreetAddress2.php
new file mode 100644
index 000000000..739120e5e
--- /dev/null
+++ b/Doctrine/DQL/AddressPart/AddressPartStreetAddress2.php
@@ -0,0 +1,33 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+namespace Chill\PersonBundle\Doctrine\DQL\AddressPart;
+
+use Chill\PersonBundle\Doctrine\DQL\AddressPart;
+
+/**
+ *
+ *
+ * @author Julien Fastré
+ */
+class AddressPartStreetAddress2 extends AddressPart
+{
+ public function getPart()
+ {
+ return 'streetaddress2';
+ }
+}
diff --git a/Doctrine/DQL/AddressPart/AddressPartValidFrom.php b/Doctrine/DQL/AddressPart/AddressPartValidFrom.php
new file mode 100644
index 000000000..4a366bf1a
--- /dev/null
+++ b/Doctrine/DQL/AddressPart/AddressPartValidFrom.php
@@ -0,0 +1,33 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+namespace Chill\PersonBundle\Doctrine\DQL\AddressPart;
+
+use Chill\PersonBundle\Doctrine\DQL\AddressPart;
+
+/**
+ *
+ *
+ * @author Julien Fastré
+ */
+class AddressPartValidFrom extends AddressPart
+{
+ public function getPart()
+ {
+ return 'validfrom';
+ }
+}
diff --git a/Export/Export/ListPerson.php b/Export/Export/ListPerson.php
index 597ada954..1804a4895 100644
--- a/Export/Export/ListPerson.php
+++ b/Export/Export/ListPerson.php
@@ -15,7 +15,10 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
+use Chill\PersonBundle\Entity\Person;
+use Chill\CustomFieldsBundle\Entity\CustomField;
use Chill\MainBundle\Templating\TranslatableStringHelper;
+use Chill\CustomFieldsBundle\Service\CustomFieldProvider;
/**
* Render a list of peoples
@@ -37,26 +40,35 @@ class ListPerson implements ListInterface
protected $translator;
/**
- *
+ *
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
+ /**
+ *
+ * @var CustomFieldProvider
+ */
+ protected $customFieldProvider;
+
protected $fields = array(
'id', 'firstName', 'lastName', 'birthdate',
'placeOfBirth', 'gender', 'memo', 'email', 'phonenumber',
- 'countryOfBirth', 'nationality'
+ 'countryOfBirth', 'nationality', 'address_street_address_1',
+ 'address_street_address_2', 'address_valid_from', 'address_postcode_label',
+ 'address_postcode_code', 'address_country_name', 'address_country_code'
);
public function __construct(
EntityManagerInterface $em,
TranslatorInterface $translator,
- TranslatableStringHelper $translatableStringHelper
- )
- {
+ TranslatableStringHelper $translatableStringHelper,
+ CustomFieldProvider $customFieldProvider
+ ) {
$this->entityManager = $em;
$this->translator = $translator;
$this->translatableStringHelper = $translatableStringHelper;
+ $this->customFieldProvider = $customFieldProvider;
}
/**
@@ -66,11 +78,21 @@ class ListPerson implements ListInterface
*/
public function buildForm(FormBuilderInterface $builder)
{
+ $choices = array_combine($this->fields, $this->fields);
+
+ foreach ($this->getCustomFields() as $cf) {
+ $choices
+ [$this->translatableStringHelper->localize($cf->getName())]
+ =
+ $cf->getSlug();
+ }
+
$builder->add('fields', ChoiceType::class, array(
'multiple' => true,
'expanded' => true,
- 'choices' => array_combine($this->fields, $this->fields),
+ 'choices' => $choices,
+ 'choices_as_values' => true,
'label' => 'Fields to include in export',
'constraints' => [new Callback(array(
'callback' => function($selected, ExecutionContextInterface $context) {
@@ -84,6 +106,25 @@ class ListPerson implements ListInterface
));
}
+
+ /**
+ * Get custom fields associated with person
+ *
+ * @return CustomField[]
+ */
+ private function getCustomFields()
+ {
+ return $this->entityManager
+ ->createQuery("SELECT cf "
+ . "FROM ChillCustomFieldsBundle:CustomField cf "
+ . "JOIN cf.customFieldGroup g "
+ . "WHERE cf.type != :title AND g.entity LIKE :entity")
+ ->setParameters(array(
+ 'title' => 'title',
+ 'entity' => \addcslashes(Person::class, "\\")
+ ))
+ ->getResult();
+ }
/**
* {@inheritDoc}
@@ -163,13 +204,42 @@ class ListPerson implements ListInterface
return $this->translatableStringHelper->localize(
$country->getName());
};
- default:
+ case 'address_country_name':
return function($value) use ($key) {
- if ($value === '_header') { return \strtolower($key); }
+ if ($value === '_header') { return \strtolower($key); }
- return $value;
+ if ($value === NULL) {
+ return '';
+ }
+ return $this->translatableStringHelper->localize(json_decode($value, true));
+ };
+ default:
+ // for fields which are associated with person
+ if (in_array($key, $this->fields)) {
+ return function($value) use ($key) {
+ if ($value === '_header') { return \strtolower($key); }
+
+ return $value;
+
+ };
+ } else {
+ // for fields which are custom fields
+ /* @var $cf CustomField */
+ $cf = $this->entityManager
+ ->getRepository(CustomField::class)
+ ->findOneBy(array('slug' => $this->DQLToSlug($key)));
+
+ return function($value) use ($cf) {
+ if ($value === '_header') {
+ return $this->translatableStringHelper->localize($cf->getName());
+ }
+
+ return $this->customFieldProvider
+ ->getCustomFieldByType($cf->getType())
+ ->render(json_decode($value, true), $cf, 'csv');
};
+ }
}
}
@@ -182,7 +252,34 @@ class ListPerson implements ListInterface
*/
public function getQueryKeys($data)
{
- return $data['fields'];
+ $fields = array();
+
+ foreach ($data['fields'] as $key) {
+ if (in_array($key, $this->fields)) {
+ $fields[] = $key;
+ } else {
+ // this should be a slug from custom field, we have to clean it
+ $fields[] = $this->slugToDQL($key);
+ }
+ }
+
+ return $fields;
+ }
+
+ /**
+ * clean a slug to be usable by DQL
+ *
+ * @param string $slugsanitize
+ * @return string
+ */
+ private function slugToDQL($slug)
+ {
+ return "cf____".\str_replace("-", "____", $slug);
+ }
+
+ private function DQLToSlug($cleanedSlug)
+ {
+ return \str_replace("____", "-", \substr($cleanedSlug, 6));
}
/**
@@ -236,12 +333,38 @@ class ListPerson implements ListInterface
case 'nationality':
$qb->addSelect(sprintf('IDENTITY(person.%s) as %s', $f, $f));
break;
+ case 'address_street_address_1':
+ case 'address_street_address_2':
+ case 'address_valid_from':
+ case 'address_postcode_label':
+ case 'address_postcode_code':
+ case 'address_country_name':
+ case 'address_country_code':
+
+ $qb->addSelect(sprintf(
+ 'GET_PERSON_ADDRESS_%s(person.id, :address_date) AS %s',
+ // get the part after address_
+ strtoupper(substr($f, 8)),
+ $f));
+ $qb->setParameter('address_date', new \DateTime());
+ break;
default:
$qb->addSelect(sprintf('person.%s as %s', $f, $f));
}
}
}
+ foreach ($this->getCustomFields() as $cf) {
+ if (in_array($cf->getSlug(), $data['fields'])) {
+ $slug = $this->slugToDQL($cf->getSlug());
+ $qb->addSelect(
+ sprintf('GET_JSON_FIELD_BY_KEY(person.cFData, :slug%s) AS %s',
+ $slug, $slug));
+ $qb->setParameter(sprintf('slug%s', $slug), $cf->getSlug());
+ //$qb->setParameter(sprintf('name%s', $slug), $cf->getSlug());
+ }
+ }
+
$qb
->from('ChillPersonBundle:Person', 'person')
->join('person.center', 'center')
diff --git a/Resources/config/routing.yml b/Resources/config/routing.yml
index e377cf36c..6792ca184 100644
--- a/Resources/config/routing.yml
+++ b/Resources/config/routing.yml
@@ -92,15 +92,6 @@ chill_person_address_update:
path: /{_locale}/person/{person_id}/address/{address_id}/update
defaults: { _controller: ChillPersonBundle:PersonAddress:update }
-chill_person_export:
- path: /{_locale}/person/export/
- defaults: { _controller: ChillPersonBundle:Person:export }
- options:
- menus:
- export:
- order: 200
- label: Export persons
-
chill_person_timeline:
path: /{_locale}/person/{person_id}/timeline
defaults: { _controller: ChillPersonBundle:TimelinePerson:person }
diff --git a/Resources/config/services/exports.yml b/Resources/config/services/exports.yml
index b2fed1274..3d2fde74a 100644
--- a/Resources/config/services/exports.yml
+++ b/Resources/config/services/exports.yml
@@ -12,6 +12,7 @@ services:
- "@doctrine.orm.entity_manager"
- "@translator"
- "@chill.main.helper.translatable_string"
+ - "@chill.custom_field.provider"
tags:
- { name: chill.export, alias: list_person }
diff --git a/Resources/migrations/Version20170117131924.php b/Resources/migrations/Version20170117131924.php
new file mode 100644
index 000000000..5b6e9e68a
--- /dev/null
+++ b/Resources/migrations/Version20170117131924.php
@@ -0,0 +1,123 @@
+ 'integer',
+ 'streetaddress1' => 'varchar(255)',
+ 'streetaddress2' => 'varchar(255)',
+ 'validfrom' => 'date',
+ 'postcode_label' => 'varchar(255)',
+ 'postcode_code' => 'varchar(100)',
+ 'postcode_id' => 'integer',
+ 'country_name' => 'json',
+ 'country_code' => 'varchar(3)',
+ 'country_id' => 'integer'
+ );
+
+ /**
+ * @param Schema $schema
+ */
+ public function up(Schema $schema)
+ {
+ $this->addSql(<<<'SQL'
+CREATE OR REPLACE FUNCTION public.get_last_address (
+ pid integer,
+ before_date date)
+RETURNS TABLE(
+ person_id integer,
+ address_id integer,
+ streetaddress1 varchar(255),
+ streetaddress2 varchar(255),
+ validfrom date,
+ postcode_label varchar(255),
+ postcode_code varchar(100),
+ postcode_id integer,
+ country_name json,
+ country_code varchar(3),
+ country_id integer)
+ AS
+$BODY$
+SELECT
+ pid AS person_id,
+ chill_main_address.id AS address_id,
+ chill_main_address.streetaddress1,
+ chill_main_address.streetaddress2,
+ chill_main_address.validfrom,
+ chill_main_postal_code.label,
+ chill_main_postal_code.code,
+ chill_main_postal_code.id AS postal_code_id,
+ country.name,
+ country.countrycode,
+ country.id AS country_id
+FROM chill_main_address
+JOIN (
+ SELECT
+ chill_main_address.id AS address_id,
+ validfrom,
+ rank() OVER (PARTITION BY person_id ORDER BY validfrom DESC) as pos
+ FROM chill_person_persons_to_addresses
+ JOIN chill_main_address ON chill_person_persons_to_addresses.address_id = chill_main_address.id
+ WHERE person_id = pid
+ AND chill_main_address.validfrom <= before_date
+) AS ranking ON ranking.address_id = chill_main_address.id
+JOIN chill_main_postal_code ON chill_main_address.postcode_id = chill_main_postal_code.id
+JOIN country ON chill_main_postal_code.country_id = country.id
+WHERE ranking.pos = 1
+$BODY$
+LANGUAGE sql VOLATILE
+COST 100;
+SQL
+ );
+
+ // create function to get part of address
+ foreach ($this->fields as $var => $type) {
+ $this->addSql(sprintf(<<<'SQL'
+CREATE OR REPLACE FUNCTION get_last_address_%s (
+ pid integer,
+ before_date date)
+RETURNS %s AS
+$BODY$
+SELECT %s FROM get_last_address(pid, before_date)
+$BODY$
+LANGUAGE sql volatile
+COST 100;
+SQL
+ , $var, $type, $var));
+ }
+ }
+
+ /**
+ * @param Schema $schema
+ */
+ public function down(Schema $schema)
+ {
+ // drop function to get parts of address
+ foreach ($this->fields as $var => $type) {
+ $this->addSql(<<addSQL(<<,
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-namespace Chill\PersonBundle\Tests\Controller;
-
-use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
-use Symfony\Component\Security\Core\Role\Role;
-
-/**
- * Tests for the export of a person
- */
-
-class PersonControllerExportTest extends WebTestCase
-{
- /** @var \Doctrine\ORM\EntityManagerInterface The entity manager */
- private $em;
-
- /**
- * Prepare the client and the entity manager. The client send a Gest requestion
- * on the route chill_person_export.
- */
- protected function setUp()
- {
- $this->client = static::createClient(array(), array(
- 'PHP_AUTH_USER' => 'center a_social',
- 'PHP_AUTH_PW' => 'password',
- ));
-
- $exportUrl = $this->client->getContainer()->get('router')->generate('chill_person_export',
- array('_locale' => 'fr'));
-
- $this->client->request('GET', $exportUrl);
-
- $this->em = $this->client->getContainer()->get('doctrine.orm.entity_manager');
- }
-
- /**
- * Test the format of the exportAction :
- * - check if the file has the csv format
- * - check if each row as the same number of cell than the first row
- * - check if the number of row of the csv file is the same than the number of persons
- *
- * @return The content of the export
- */
- public function testExportActionFormat()
- {
- $response = $this->client->getResponse();
-
- $this->assertTrue(
- strpos($response->headers->get('Content-Type'),'text/csv') !== false,
- 'The csv file is well received');
-
- $content = $response->getContent();
- $rows = str_getcsv($content, "\n");
- $headerRow = array_pop($rows);
- $header = str_getcsv($headerRow);
- $headerSize = sizeof($header);
- $numberOfRows = 0;
-
- foreach ($rows as $row) {
- $rowContent = str_getcsv($row);
-
- $this->assertTrue(
- sizeof($rowContent) == $headerSize,
- 'Each row of the csv contains the good number of elements ('
- . 'regarding to the first row');
-
- $numberOfRows ++;
- }
-
-
- $chillSecurityHelper = $this->client->getContainer()->get('chill.main.security.authorization.helper');
- $user = $this->client->getContainer()->get('security.context')->getToken()->getUser();
-
- $reachableCenters = $chillSecurityHelper->getReachableCenters($user,
- new Role('CHILL_PERSON_SEE'));
-
- $personRepository = $this->em->getRepository('ChillPersonBundle:Person');
- $qb = $personRepository->createQueryBuilder('p');
- $qb->where($qb->expr()->in('p.center', ':centers'))
- ->setParameter('centers', $reachableCenters);
- $persons = $qb->getQuery()->getResult();
-
-
- $this->assertTrue(
- $numberOfRows == (sizeof($persons)),
- 'The csv file has a number of row equivalent than the number of '
- . 'person in the db'
- );
-
- return $content;
- }
-
-
- /**
- * Check that the export file do not contain a person form center B
- *
- * @depends testExportActionFormat
- */
- public function testExportActionNotContainingPersonFromCenterB($content)
- {
- $centerB = $this->em->getRepository('ChillMainBundle:Center')
- ->findOneBy(array('name' => 'Center B'));
-
- $person = $this->em->getRepository('ChillPersonBundle:Person')
- ->findOneBy(array('center' => $centerB));
-
- $this->assertFalse(strpos($person->getFirstName(), $content));
- }
-
- /**
- * Check that the export file contains information about a random person
- * of center A
- * @depends testExportActionFormat
- */
- public function testExportActionContainsARandomPersonFromCenterA($content)
- {
- $centerA = $this->em->getRepository('ChillMainBundle:Center')
- ->findOneBy(array('name' => 'Center A'));
-
- $person = $this->em->getRepository('ChillPersonBundle:Person')
- ->findOneBy(array('center' => $centerA));
-
- $this->assertContains($person->getFirstName(), $content);
- $this->assertContains($person->getLastName(), $content);
- $this->assertContains($person->getGender(), $content);
-
- $this->markTestIncomplete('Test other information of the person');
- }
-}
diff --git a/Tests/Export/Export/ListPersonTest.php b/Tests/Export/Export/ListPersonTest.php
index 837d0da5f..da546bddc 100644
--- a/Tests/Export/Export/ListPersonTest.php
+++ b/Tests/Export/Export/ListPersonTest.php
@@ -44,6 +44,15 @@ class ListPersonTest extends AbstractExportTest
$container = self::$kernel->getContainer();
$this->export = $container->get('chill.person.export.list_person');
+
+ // add a fake request with a default locale (used in translatable string)
+ $prophet = new \Prophecy\Prophet;
+ $request = $prophet->prophesize();
+ $request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
+ $request->getLocale()->willReturn('fr');
+
+ $container->get('request_stack')
+ ->push($request->reveal());
}
/**
@@ -62,7 +71,10 @@ class ListPersonTest extends AbstractExportTest
array('fields' => ['id', 'birthdate', 'gender', 'memo', 'email', 'phonenumber']),
array('fields' => ['firstName', 'lastName', 'phonenumber']),
array('fields' => ['id', 'nationality']),
- array('fields' => ['id', 'countryOfBirth'])
+ array('fields' => ['id', 'countryOfBirth']),
+ array('fields' => ['id', 'address_street_address_1',
+ 'address_street_address_2', 'address_valid_from', 'address_postcode_label',
+ 'address_postcode_code', 'address_country_name', 'address_country_code'])
);
}