`_ is present.
+
+Error `An exception has been thrown during the rendering of a template ("Asset manifest file "/var/www/app/web/build/manifest.json" does not exist.").` on first run
+====================================================================================================================================================================
+
+Run :code:`make build-assets`
+
+Running in production
+*********************
+
+Currently, to run this software in production, the *state of the art* is the following :
+
+1. Run the software locally and tweak the configuration to your needs ;
+2. Build the image and store them into a private container registry. This can be done using :code:`make build-and-push-image`.
+
+ To be sure to target the correct container registry, you have to adapt the values ``IMAGE_NGINX`` and ``IMAGE_PHP`` date in the ``.env`` file.
+3. Run the image on your production server, using docker-compose or eventually docker stack. You have to customize the variable set in docker-compose.
+
+ See also the :ref:`running-production-tips-and-tricks` below.
+
+.. warning::
+
+ In production, you **must** set those variables:
+
+ * ``APP_ENV`` to ``prod``
+ * ``APP_DEBUG`` to ``false``
+
+ There are security issues if you keep the same variable than for production.
+
+
+.. _running-production-tips-and-tricks:
+
+Tips and tricks
+===============
+
+Operation on database (backups, running custom sql, replication) are easier to set when run outside of a container. If you run into a container, take care of the volume where data are stored.
+
+The PHP sessions are stored inside redis. This is useful if you distribute the traffic amongst different php server: they will share same sessions if a request goes into a different instance of the container.
+
+When the PHP servers are shared across multiple instances, take care that some data is stored into redis: the same redis server should be reachable by all instances.
+
+It is worth having an eye on the configuration of logstash container.
+
+
+Design principles
+*****************
+
+Why the DB URL is set in environment, and not in parameters.yml ?
+=================================================================
+
+Because, at startup, a script does check the db is up and, if not, wait for a couple of seconds before running ``entrypoint.sh``. For avoiding double configuration, the configuration of the PHP app takes his configuration from environment also (and it will be standard in future releases, with symfony 4.0).
+
diff --git a/src/Bundle/ChillActivityBundle/Form/ActivityType.php b/src/Bundle/ChillActivityBundle/Form/ActivityType.php
index ad0e55aa7..3a9a307fd 100644
--- a/src/Bundle/ChillActivityBundle/Form/ActivityType.php
+++ b/src/Bundle/ChillActivityBundle/Form/ActivityType.php
@@ -15,7 +15,6 @@ use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTra
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
-use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Chill\ActivityBundle\Form\Type\TranslatableActivityType;
use Chill\ActivityBundle\Form\Type\TranslatableActivityReason;
use Chill\MainBundle\Form\Type\UserPickerType;
diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/list.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/list.html.twig
index fa20d33fc..94a9d9a82 100644
--- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/list.html.twig
+++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/list.html.twig
@@ -46,12 +46,7 @@
| {{ activity.durationTime|date('H:i') }} |
{% if activity.comment.comment is not empty %}
-
- {{ activity.comment.comment|slice(0, 250) }} {#
- sf4 check: if 'slice' could replace 'truncate' filter ?
- truncate come with twig-extensions, in conflict with twig 3
- #}
-
+ {{ activity.comment|chill_entity_render_box( { 'limit_lines': 3, 'metadata': false } ) }}
{% endif %}
{%- if activity.reasons is empty -%}
{{ 'No reason associated'|trans }}
diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Timeline/activity_person_context.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Timeline/activity_person_context.html.twig
index d788c1cf3..dddd05cf7 100644
--- a/src/Bundle/ChillActivityBundle/Resources/views/Timeline/activity_person_context.html.twig
+++ b/src/Bundle/ChillActivityBundle/Resources/views/Timeline/activity_person_context.html.twig
@@ -13,7 +13,7 @@
{% if is_granted(constant('Chill\\ActivityBundle\\Security\\Authorization\\ActivityVoter::SEE_DETAILS'), activity) %}
- - {% if activity.comment.comment is empty %}{{ 'No comments'|trans }}{% else %}
{{ activity.comment.comment|nl2br }} {% endif %}
+ - {% if activity.comment.comment is empty %}{{ 'No comments'|trans }}{% else %}{{ activity.comment|chill_entity_render_box({'metadata': false}) }}{% endif %}
- {{ 'Reasons'|trans }}
{%- if activity.reasons is empty -%}
diff --git a/src/Bundle/ChillDocStoreBundle/Form/PersonDocumentType.php b/src/Bundle/ChillDocStoreBundle/Form/PersonDocumentType.php
index 184bbbe33..1629410af 100644
--- a/src/Bundle/ChillDocStoreBundle/Form/PersonDocumentType.php
+++ b/src/Bundle/ChillDocStoreBundle/Form/PersonDocumentType.php
@@ -4,7 +4,6 @@ namespace Chill\DocStoreBundle\Form;
use Chill\DocStoreBundle\Entity\Document;
-use Chill\DocStoreBundle\Entity\DocumentCategory;
use Chill\DocStoreBundle\Entity\PersonDocument;
use Chill\MainBundle\Entity\User;
use Symfony\Component\Form\AbstractType;
@@ -12,15 +11,13 @@ use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Doctrine\ORM\EntityRepository;
-use Chill\MainBundle\Form\Type\AppendScopeChoiceTypeTrait;
-use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Doctrine\Persistence\ObjectManager;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\MainBundle\Form\Type\ScopePickerType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
-use Symfony\Component\Form\Extension\Core\Type\TextareaType;
+use Chill\MainBundle\Form\Type\ChillTextareaType;
class PersonDocumentType extends AbstractType
@@ -62,7 +59,7 @@ class PersonDocumentType extends AbstractType
{
$builder
->add('title', TextType::class)
- ->add('description', TextareaType::class, [
+ ->add('description', ChillTextareaType::class, [
'required' => false
])
->add('object', StoredObjectType::class, [
diff --git a/src/Bundle/ChillDocStoreBundle/Resources/public/module/async_upload/uploader.js b/src/Bundle/ChillDocStoreBundle/Resources/public/module/async_upload/uploader.js
index 9e96070bb..3fcfb0a42 100644
--- a/src/Bundle/ChillDocStoreBundle/Resources/public/module/async_upload/uploader.js
+++ b/src/Bundle/ChillDocStoreBundle/Resources/public/module/async_upload/uploader.js
@@ -1,5 +1,5 @@
var algo = 'AES-CBC';
-var Dropzone = require('dropzone');
+import Dropzone from 'dropzone';
var initializeDownload = require('./downloader.js');
@@ -121,7 +121,7 @@ var createZone = (zone, zoneData) => {
created.classList.add('dropzone');
initMessage.classList.add('dz-message');
initMessage.appendChild(document.createTextNode(initContent));
-
+ console.log(Dropzone);
dropzoneI = new Dropzone(created, {
url: function(files) {
return getUploadUrl(zoneData, files);
diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/show.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/show.html.twig
index ac1b18601..1761b4db7 100644
--- a/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/show.html.twig
+++ b/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/show.html.twig
@@ -45,7 +45,7 @@
{{ 'Any description'|trans }}
{% else %}
- {{ document.description }}
+ {{ document.description|chill_markdown_to_html }}
{% endif %}
diff --git a/src/Bundle/ChillMainBundle/Controller/PermissionsGroupController.php b/src/Bundle/ChillMainBundle/Controller/PermissionsGroupController.php
index 148a1fe35..0a46c4496 100644
--- a/src/Bundle/ChillMainBundle/Controller/PermissionsGroupController.php
+++ b/src/Bundle/ChillMainBundle/Controller/PermissionsGroupController.php
@@ -14,6 +14,7 @@ use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Security\Core\Role\RoleHierarchy;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Form\Type\ComposedRoleScopeType;
+use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
@@ -43,6 +44,11 @@ class PermissionsGroupController extends AbstractController
*/
private $translator;
+ /**
+ * @var ValidatorInterface
+ */
+ private $validator;
+
/**
* PermissionsGroupController constructor.
*
@@ -50,18 +56,21 @@ class PermissionsGroupController extends AbstractController
* @param RoleProvider $roleProvider
* @param RoleHierarchy $roleHierarchy
* @param TranslatorInterface $translator
+ * @param ValidatorInterface $validator
*/
public function __construct(
TranslatableStringHelper $translatableStringHelper,
RoleProvider $roleProvider,
RoleHierarchy $roleHierarchy,
- TranslatorInterface $translator
+ TranslatorInterface $translator,
+ ValidatorInterface $validator
)
{
$this->translatableStringHelper = $translatableStringHelper;
$this->roleProvider = $roleProvider;
$this->roleHierarchy = $roleHierarchy;
$this->translator = $translator;
+ $this->validator = $validator;
}
/**
@@ -452,7 +461,7 @@ class PermissionsGroupController extends AbstractController
);
$permissionsGroup->addRoleScope($roleScope);
- $violations = $this->get('validator')->validate($permissionsGroup);
+ $violations = $this->validator->validate($permissionsGroup);
if ($violations->count() === 0) {
$em->flush();
diff --git a/src/Bundle/ChillMainBundle/Controller/UserController.php b/src/Bundle/ChillMainBundle/Controller/UserController.php
index 93ed2fa62..7de280d1d 100644
--- a/src/Bundle/ChillMainBundle/Controller/UserController.php
+++ b/src/Bundle/ChillMainBundle/Controller/UserController.php
@@ -11,6 +11,7 @@ use Chill\MainBundle\Form\UserType;
use Chill\MainBundle\Entity\GroupCenter;
use Chill\MainBundle\Form\Type\ComposedGroupCenterType;
use Chill\MainBundle\Form\UserPasswordType;
+use Symfony\Component\Validator\Validator\ValidatorInterface;
/**
@@ -28,14 +29,21 @@ class UserController extends AbstractController
*/
private $logger;
+ /**
+ * @var ValidatorInterface
+ */
+ private $validator;
+
/**
* UserController constructor.
*
* @param LoggerInterface $logger
+ * @param ValidatorInterface $validator
*/
- public function __construct(LoggerInterface $logger)
+ public function __construct(LoggerInterface $logger, ValidatorInterface $validator)
{
$this->logger = $logger;
+ $this->validator = $validator;
}
/**
@@ -258,7 +266,7 @@ class UserController extends AbstractController
$form[self::FORM_GROUP_CENTER_COMPOSED]->getData());
$user->addGroupCenter($groupCenter);
- if ($this->get('validator')->validate($user)->count() === 0) {
+ if ($this->validator->validate($user)->count() === 0) {
$em->flush();
$this->addFlash('success', $this->get('translator')->trans('The '
@@ -267,7 +275,7 @@ class UserController extends AbstractController
return $this->redirect($this->generateUrl('admin_user_edit',
array('id' => $uid)));
} else {
- foreach($this->get('validator')->validate($user) as $error)
+ foreach($this->validator->validate($user) as $error)
$this->addFlash('error', $error->getMessage());
}
}
@@ -380,7 +388,7 @@ class UserController extends AbstractController
// logging for prod
$this->logger->info('update password for an user', [
- 'by' => $this->getUser()->getUsername(),
+ 'by' => $this->getUser()->getUsername(),
'user' => $user->getUsername()
]);
diff --git a/src/Bundle/ChillMainBundle/Form/Extension/CKEditorExtension.php b/src/Bundle/ChillMainBundle/Form/Extension/CKEditorExtension.php
deleted file mode 100644
index 96751d746..000000000
--- a/src/Bundle/ChillMainBundle/Form/Extension/CKEditorExtension.php
+++ /dev/null
@@ -1,38 +0,0 @@
-setDefaults([
- 'attr' => [
- 'class' => 'ckeditor snippet-markdown'
- ]
- ]);
- }
-}
\ No newline at end of file
diff --git a/src/Bundle/ChillMainBundle/Form/Type/ChillTextareaType.php b/src/Bundle/ChillMainBundle/Form/Type/ChillTextareaType.php
new file mode 100644
index 000000000..37c436f7c
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Form/Type/ChillTextareaType.php
@@ -0,0 +1,57 @@
+
+ *
+ * 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\MainBundle\Form\Type;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\Extension\Core\Type\TextareaType;
+use Symfony\Component\OptionsResolver\OptionsResolver;
+use Symfony\Component\Form\FormView;
+use Symfony\Component\Form\FormInterface;
+
+/**
+ * Create a Textarea
+ *
+ * By default, add a WYSIWYG editor.
+ *
+ * Options:
+ *
+ * * `disable_editor`: set true to disable editor
+ *
+ */
+final class ChillTextareaType extends AbstractType
+{
+ public function getParent()
+ {
+ return TextareaType::class;
+ }
+
+ public function configureOptions(OptionsResolver $resolver)
+ {
+ $resolver
+ ->setDefined('disable_editor')
+ ->setDefault('disable_editor', false)
+ ->setAllowedTypes('disable_editor', 'bool');
+ }
+
+ public function buildView(FormView $view, FormInterface $form, array $options)
+ {
+ if (!$options['disable_editor']) {
+ $view->vars['attr']['ckeditor'] = true;
+ }
+ }
+}
diff --git a/src/Bundle/ChillMainBundle/Form/Type/CommentType.php b/src/Bundle/ChillMainBundle/Form/Type/CommentType.php
index a088af573..a6e664769 100644
--- a/src/Bundle/ChillMainBundle/Form/Type/CommentType.php
+++ b/src/Bundle/ChillMainBundle/Form/Type/CommentType.php
@@ -20,7 +20,7 @@ namespace Chill\MainBundle\Form\Type;
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
-use Symfony\Component\Form\Extension\Core\Type\TextareaType;
+use Chill\MainBundle\Form\Type\ChillTextareaType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
@@ -44,8 +44,8 @@ class CommentType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
- ->add('comment', TextareaType::class, [
-
+ ->add('comment', ChillTextareaType::class, [
+ 'disable_editor' => $options['disable_editor']
])
;
@@ -72,8 +72,12 @@ class CommentType extends AbstractType
public function configureOptions(OptionsResolver $resolver)
{
- $resolver->setDefaults([
- 'data_class' => CommentEmbeddable::class,
- ]);
+ $resolver
+ ->setDefined('disable_editor')
+ ->setAllowedTypes('disable_editor', 'bool')
+ ->setDefaults([
+ 'data_class' => CommentEmbeddable::class,
+ 'disable_editor' => false
+ ]);
}
}
diff --git a/src/Bundle/ChillMainBundle/Phonenumber/PhonenumberHelper.php b/src/Bundle/ChillMainBundle/Phonenumber/PhonenumberHelper.php
index c29ac27be..c2ab59442 100644
--- a/src/Bundle/ChillMainBundle/Phonenumber/PhonenumberHelper.php
+++ b/src/Bundle/ChillMainBundle/Phonenumber/PhonenumberHelper.php
@@ -26,146 +26,168 @@ use Psr\Cache\CacheItemPoolInterface;
/**
* Helper to some task linked to phonenumber.
- *
- * Currently, only Twilio is supported (https://www.twilio.com/lookup). A method
+ *
+ * Currently, only Twilio is supported (https://www.twilio.com/lookup). A method
* allow to check if the helper is configured for validation. This should be used
* before doing some validation.
- *
+ *
*
*/
class PhonenumberHelper
{
/**
- *
- * @var Client
+ * Twilio client
*/
- protected $twilioClient;
+ protected Client $twilioClient;
/**
- *
- * @var LoggerInterface
+ * TRUE if the client is properly configured
*/
- protected $logger;
-
- /**
- *
- * @var CacheItemPoolInterface
- */
- protected $cachePool;
-
+ protected bool $isConfigured = false;
+
+ protected LoggerInterface $logger;
+
+ protected CacheItemPoolInterface $cachePool;
+
const LOOKUP_URI = 'https://lookups.twilio.com/v1/PhoneNumbers/%s';
const FORMAT_URI = 'https://lookups.twilio.com/v1/PhoneNumbers/%s';
-
-
+
public function __construct(
CacheItemPoolInterface $cachePool,
- $config,
+ $config,
LoggerInterface $logger
) {
$this->logger = $logger;
$this->cachePool = $cachePool;
-
- if (\array_key_exists('twilio_sid', $config)
+
+ if (\array_key_exists('twilio_sid', $config)
&& !empty($config['twilio_sid'])
- && \array_key_exists('twilio_secret', $config)
- && !empty($config['twilio_secret'])) {
-
+ && strlen($config['twilio_sid']) > 2
+ && \array_key_exists('twilio_secret', $config)
+ && !empty($config['twilio_secret'])
+ && strlen($config['twilio_secret']) > 2
+ ) {
+
$this->twilioClient = new Client([
'auth' => [ $config['twilio_sid'], $config['twilio_secret'] ]
]);
- }
+ $this->isConfigured = TRUE;
+ }
}
-
+
/**
* Return true if the validation is configured and available.
- *
+ *
* @return bool
*/
public function isPhonenumberValidationConfigured() : bool
{
- return NULL !== $this->twilioClient;
+ return $this->isConfigured;
}
-
+
/**
- * REturn true if the phoennumber is a mobile phone. Return always false
+ * REturn true if the phoennumber is a mobile phone. Return always true
* if the validation is not configured.
- *
+ *
* @param string $phonenumber
* @return bool
*/
public function isValidPhonenumberMobile($phonenumber) : bool
{
- $validation = $this->performTwilioLookup($phonenumber);
-
- if (NULL === $validation) {
- return false;
+ if (FALSE === $this->isPhonenumberValidationConfigured()) {
+ return true;
}
+ $validation = $this->performTwilioLookup($phonenumber);
+
+ if (NULL === $validation) {
+ return true;
+ }
+
return $validation === 'mobile';
}
-
+
/**
- * Return true if the phonenumber is a landline or voip phone. Return always false
+ * Return true if the phonenumber is a landline or voip phone. Return always true
* if the validation is not configured.
- *
+ *
* @param string $phonenumber
* @return bool
*/
public function isValidPhonenumberLandOrVoip($phonenumber) : bool
{
- $validation = $this->performTwilioLookup($phonenumber);
-
- if (NULL === $validation) {
- return false;
+ if (FALSE === $this->isPhonenumberValidationConfigured()) {
+ return true;
}
+ $validation = $this->performTwilioLookup($phonenumber);
+
+ if (NULL === $validation) {
+ return true;
+ }
+
return \in_array($validation, [ 'landline', 'voip' ]);
}
-
+
/**
- * Return true if the phonenumber is a landline or voip phone. Return always false
+ * Return true if the phonenumber is a landline or voip phone. Return always true
* if the validation is not configured.
- *
+ *
* @param string $phonenumber
* @return bool
*/
public function isValidPhonenumberAny($phonenumber) : bool
{
+ if (FALSE === $this->isPhonenumberValidationConfigured()) {
+ return true;
+ }
$validation = $this->performTwilioLookup($phonenumber);
-
+;
if (NULL === $validation) {
return false;
}
-
+
return \in_array($validation, [ 'landline', 'voip', 'mobile' ]);
}
-
+
+ /**
+ * Get type (mobile, landline, ...) for phone number
+ *
+ * @param string $phonenumber
+ *
+ * @return string
+ */
+ public function getType(string $phonenumber): string
+ {
+ return $this->performTwilioLookup($phonenumber) ?? 'unknown';
+ }
+
public function format($phonenumber)
{
return $this->performTwilioFormat($phonenumber);
}
-
+
protected function performTwilioFormat($phonenumber)
{
if (FALSE === $this->isPhonenumberValidationConfigured()) {
return $phonenumber;
}
-
+
// filter only number
$filtered = \preg_replace("/[^0-9]/", "", $phonenumber);
-
+
$item = $this->cachePool->getItem('pnum_format_nat_'.$filtered);
-
+
if ($item->isHit()) {
return $item->get();
}
-
+
try {
$response = $this->twilioClient->get(sprintf(self::FORMAT_URI, '+'.$filtered), [
'http_errors' => true,
]);
-
+
} catch (ClientException $e) {
$response = $e->getResponse();
$this->logger->error("[phonenumber helper] Could not format number "
@@ -174,7 +196,7 @@ class PhonenumberHelper
"status_code" => $response->getStatusCode(),
"phonenumber" => $phonenumber
]);
-
+
return $phonenumber;
} catch (ServerException $e) {
$response = $e->getResponse();
@@ -184,7 +206,7 @@ class PhonenumberHelper
"status_code" => $response->getStatusCode(),
"phonenumber" => $phonenumber
]);
-
+
return null;
} catch (ConnectException $e) {
$this->logger->error("[phonenumber helper] Could not format number "
@@ -192,38 +214,38 @@ class PhonenumberHelper
"message" => $e->getMessage(),
"phonenumber" => $phonenumber
]);
-
+
return null;
}
-
+
$format = \json_decode($response->getBody())->national_format;
-
+
$item
->set($format)
// expires after 3d
->expiresAfter(3600 * 24 * 3)
;
-
+
$this->cachePool->save($item);
-
+
return $format;
}
-
+
protected function performTwilioLookup($phonenumber)
{
if (FALSE === $this->isPhonenumberValidationConfigured()) {
return null;
}
-
+
// filter only number
$filtered = \preg_replace("/[^0-9]/", "", $phonenumber);
-
+
$item = $this->cachePool->getItem('pnum_'.$filtered);
-
+
if ($item->isHit()) {
- return $item->get();
+ //return $item->get();
}
-
+
try {
$response = $this->twilioClient->get(sprintf(self::LOOKUP_URI, '+'.$filtered), [
'http_errors' => true,
@@ -241,7 +263,7 @@ class PhonenumberHelper
"status_code" => $response->getStatusCode(),
"phonenumber" => $phonenumber
]);
-
+
return null;
} catch (ConnectException $e) {
$this->logger->error("[phonenumber helper] Could not format number "
@@ -249,20 +271,20 @@ class PhonenumberHelper
"message" => $e->getMessage(),
"phonenumber" => $phonenumber
]);
-
+
return null;
}
-
+
$validation = \json_decode($response->getBody())->carrier->type;
-
+
$item
->set($validation)
// expires after 12h
->expiresAfter(3600 * 12)
;
-
+
$this->cachePool->save($item);
-
+
return $validation;
}
}
diff --git a/src/Bundle/ChillMainBundle/Resources/public/main.js b/src/Bundle/ChillMainBundle/Resources/public/main.js
index 8deae49cc..83221da35 100644
--- a/src/Bundle/ChillMainBundle/Resources/public/main.js
+++ b/src/Bundle/ChillMainBundle/Resources/public/main.js
@@ -33,6 +33,7 @@ require('./modules/breadcrumb/index.js');
require('./modules/download-report/index.js');
require('./modules/select_interactive_loading/index.js');
require('./modules/export-list/export-list.scss');
+require('./modules/entity/index.js');
/*
* load img
diff --git a/src/Bundle/ChillMainBundle/Resources/public/modules/ckeditor5/index.js b/src/Bundle/ChillMainBundle/Resources/public/modules/ckeditor5/index.js
index 4e91411b5..678f418b0 100644
--- a/src/Bundle/ChillMainBundle/Resources/public/modules/ckeditor5/index.js
+++ b/src/Bundle/ChillMainBundle/Resources/public/modules/ckeditor5/index.js
@@ -1,39 +1,24 @@
import ClassicEditorBase from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
import EssentialsPlugin from '@ckeditor/ckeditor5-essentials/src/essentials';
import MarkdownPlugin from '@ckeditor/ckeditor5-markdown-gfm/src/markdown';
-//import UploadAdapterPlugin from '@ckeditor/ckeditor5-adapter-ckfinder/src/uploadadapter';
-//import AutoformatPlugin from '@ckeditor/ckeditor5-autoformat/src/autoformat';
import BoldPlugin from '@ckeditor/ckeditor5-basic-styles/src/bold';
import ItalicPlugin from '@ckeditor/ckeditor5-basic-styles/src/italic';
import BlockQuotePlugin from '@ckeditor/ckeditor5-block-quote/src/blockquote';
-//import EasyImagePlugin from '@ckeditor/ckeditor5-easy-image/src/easyimage';
import HeadingPlugin from '@ckeditor/ckeditor5-heading/src/heading';
-//import ImagePlugin from '@ckeditor/ckeditor5-image/src/image';
-//import ImageCaptionPlugin from '@ckeditor/ckeditor5-image/src/imagecaption';
-//import ImageStylePlugin from '@ckeditor/ckeditor5-image/src/imagestyle';
-//import ImageToolbarPlugin from '@ckeditor/ckeditor5-image/src/imagetoolbar';
-//import ImageUploadPlugin from '@ckeditor/ckeditor5-image/src/imageupload';
import LinkPlugin from '@ckeditor/ckeditor5-link/src/link';
import ListPlugin from '@ckeditor/ckeditor5-list/src/list';
import ParagraphPlugin from '@ckeditor/ckeditor5-paragraph/src/paragraph';
+import "./index.scss";
export default class ClassicEditor extends ClassicEditorBase {}
ClassicEditor.builtinPlugins = [
EssentialsPlugin,
MarkdownPlugin,
-// UploadAdapterPlugin,
-// AutoformatPlugin,
BoldPlugin,
ItalicPlugin,
BlockQuotePlugin,
-// EasyImagePlugin,
HeadingPlugin,
-// ImagePlugin,
-// ImageCaptionPlugin,
-// ImageStylePlugin,
-// ImageToolbarPlugin,
-// ImageUploadPlugin,
LinkPlugin,
ListPlugin,
ParagraphPlugin
@@ -49,27 +34,19 @@ ClassicEditor.defaultConfig = {
'link',
'bulletedList',
'numberedList',
-// 'uploadImage',
'blockQuote',
'undo',
'redo'
]
},
-// image: {
-// toolbar: [
-// 'imageStyle:full',
-// 'imageStyle:side',
-// '|',
-// 'imageTextAlternative'
-// ]
-// },
language: 'fr'
};
let Fields = [];
-Fields.push.apply(Fields, document.querySelectorAll('textarea.ckeditor'));
-Fields.push.apply(Fields, document.querySelectorAll('.cf-fields textarea'));
+Fields.push.apply(Fields, document.querySelectorAll('textarea[ckeditor]'));
+// enable for custom fields
+//Fields.push.apply(Fields, document.querySelectorAll('.cf-fields textarea'));
Fields.forEach(function(field) {
ClassicEditor
@@ -81,4 +58,4 @@ Fields.forEach(function(field) {
console.error( error.stack );
})
;
-})
\ No newline at end of file
+});
\ No newline at end of file
diff --git a/src/Bundle/ChillMainBundle/Resources/public/modules/ckeditor5/index.scss b/src/Bundle/ChillMainBundle/Resources/public/modules/ckeditor5/index.scss
new file mode 100644
index 000000000..5fceab7bc
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Resources/public/modules/ckeditor5/index.scss
@@ -0,0 +1,8 @@
+// set min height for ckeditor
+.ck-editor__editable {
+ min-height: 150px;
+}
+
+.ck-editor.ck-reset {
+ margin-bottom: 1.5em;
+}
\ No newline at end of file
diff --git a/src/Bundle/ChillMainBundle/Resources/public/modules/entity/comment_embeddable.scss b/src/Bundle/ChillMainBundle/Resources/public/modules/entity/comment_embeddable.scss
new file mode 100644
index 000000000..e45173e56
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Resources/public/modules/entity/comment_embeddable.scss
@@ -0,0 +1,6 @@
+.chill-entity__comment-embeddable {
+ .chill-entity__comment-embeddable__metadata {
+ font-size: smaller;
+ color: var(--chill-light-gray);
+ }
+}
\ No newline at end of file
diff --git a/src/Bundle/ChillMainBundle/Resources/public/modules/entity/index.js b/src/Bundle/ChillMainBundle/Resources/public/modules/entity/index.js
new file mode 100644
index 000000000..c739899a5
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Resources/public/modules/entity/index.js
@@ -0,0 +1,2 @@
+// css classes to render entities
+require('./comment_embeddable.scss');
diff --git a/src/Bundle/ChillMainBundle/Resources/public/modules/scratch/_custom.scss b/src/Bundle/ChillMainBundle/Resources/public/modules/scratch/_custom.scss
index 3d7ce19af..0fe6bd846 100644
--- a/src/Bundle/ChillMainBundle/Resources/public/modules/scratch/_custom.scss
+++ b/src/Bundle/ChillMainBundle/Resources/public/modules/scratch/_custom.scss
@@ -157,16 +157,27 @@ dl.chill_view_data {
}
-blockquote.chill-user-quote {
+blockquote.chill-user-quote,
+div.chill-user-quote {
border-left: 10px solid $chill-yellow;
margin: 1.5em 10px;
padding: 0.5em 10px;
quotes: "\201C""\201D""\2018""\2019";
background-color: $chill-llight-gray;
-
-
- p { display: inline; }
-
+
+ blockquote {
+ margin: 1.5em 10px;
+ padding: 0.5em 10px;
+ }
+
+ blockquote:before {
+ color: #ccc;
+ content: open-quote;
+ font-size: 4em;
+ line-height: 0.1em;
+ margin-right: 0.25em;
+ vertical-align: -0.4em;
+ }
}
.chill-no-data-statement {
diff --git a/src/Bundle/ChillMainBundle/Resources/public/modules/scratch/modules/_forms.scss b/src/Bundle/ChillMainBundle/Resources/public/modules/scratch/modules/_forms.scss
index b01c802b6..dcffddec9 100644
--- a/src/Bundle/ChillMainBundle/Resources/public/modules/scratch/modules/_forms.scss
+++ b/src/Bundle/ChillMainBundle/Resources/public/modules/scratch/modules/_forms.scss
@@ -148,7 +148,6 @@ form {
li {
label {
display: inline-block;
- font-weight: normal;
}
}
}
diff --git a/src/Bundle/ChillMainBundle/Resources/views/Entity/CommentEmbeddable.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Entity/CommentEmbeddable.html.twig
new file mode 100644
index 000000000..c9b76451c
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Resources/views/Entity/CommentEmbeddable.html.twig
@@ -0,0 +1,36 @@
+{{ opening_box|raw }}
+
+
+
+{% if options['metadata'] %}
+
+{% endif %}
+{{ closing_box|raw }}
\ No newline at end of file
diff --git a/src/Bundle/ChillMainBundle/Templating/ChillMarkdownRenderExtension.php b/src/Bundle/ChillMainBundle/Templating/ChillMarkdownRenderExtension.php
new file mode 100644
index 000000000..4db950e6c
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Templating/ChillMarkdownRenderExtension.php
@@ -0,0 +1,54 @@
+
+ *
+ * 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\MainBundle\Templating;
+
+use Twig\Extension\AbstractExtension;
+use Twig\TwigFilter;
+
+use Parsedown;
+
+/**
+ * Render markdown
+ */
+final class ChillMarkdownRenderExtension extends AbstractExtension
+{
+ /**
+ * @var Parsedown
+ */
+ protected $parsedown;
+
+ public function __construct()
+ {
+ $this->parsedown = new Parsedown();
+ $this->parsedown->setSafeMode(true);
+ }
+
+ public function getFilters(): array
+ {
+ return [
+ new TwigFilter('chill_markdown_to_html', [$this, 'renderMarkdownToHtml'], [
+ 'is_safe' => [ 'html' ]
+ ])
+ ];
+ }
+
+ public function renderMarkdownToHtml(string $var): string
+ {
+ return $this->parsedown->parse($var);
+ }
+}
diff --git a/src/Bundle/ChillMainBundle/Templating/Entity/CommentRender.php b/src/Bundle/ChillMainBundle/Templating/Entity/CommentRender.php
index d5fce5749..9ff0ca90c 100644
--- a/src/Bundle/ChillMainBundle/Templating/Entity/CommentRender.php
+++ b/src/Bundle/ChillMainBundle/Templating/Entity/CommentRender.php
@@ -21,9 +21,9 @@
namespace Chill\MainBundle\Templating\Entity;
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
-use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Repository\UserRepository;
use Chill\MainBundle\Templating\Entity\AbstractChillEntityRender;
+use Symfony\Component\Templating\EngineInterface;
class CommentRender extends AbstractChillEntityRender
{
@@ -31,10 +31,19 @@ class CommentRender extends AbstractChillEntityRender
* @var \Chill\MainBundle\Repository\UserRepository
*/
private $userRepository;
+
+ /**
+ *
+ * @var EngineInterface
+ */
+ private $engine;
- public function __construct(UserRepository $userRepository)
- {
+ public function __construct(
+ UserRepository $userRepository,
+ EngineInterface $engine
+ ) {
$this->userRepository = $userRepository;
+ $this->engine = $engine;
}
/**
@@ -45,35 +54,29 @@ class CommentRender extends AbstractChillEntityRender
*/
public function renderBox($entity, array $options): string
{
- $username = '';
-
+ // default options
+ $options = \array_merge([
+ 'user' => [],
+ 'disable_markdown' => false,
+ 'limit_lines' => null,
+ 'metadata' => true
+ ], $options);
+
if ($entity->getUserId()) {
$user = $this->userRepository->find($entity->getUserId());
- if ($user instanceof User) {
- $username = $user->getUsername();
- }
}
-
- $str = $this->getDefaultOpeningBox('comment-embeddable').
- '';
-
- if ($entity->getDate() instanceof \DateTime) {
- $str .= '';
- }
-
- if (strlen($username) > 0) {
- $str .= '';
- }
-
- $str .= $this->getDefaultClosingBox();
-
- return $str;
+
+ return $this->engine
+ ->render(
+ '@ChillMain/Entity/CommentEmbeddable.html.twig',
+ [
+ 'opening_box' => $this->getDefaultOpeningBox('comment-embeddable'),
+ 'closing_box' => $this->getDefaultClosingBox(),
+ 'user' => $user ?? NULL,
+ 'comment' => $entity,
+ 'options' => $options
+ ]
+ );
}
/**
diff --git a/src/Bundle/ChillMainBundle/Tests/Templating/ChillMarkdownRenderExtensionTest.php b/src/Bundle/ChillMainBundle/Tests/Templating/ChillMarkdownRenderExtensionTest.php
new file mode 100644
index 000000000..d95969b9d
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Tests/Templating/ChillMarkdownRenderExtensionTest.php
@@ -0,0 +1,76 @@
+
+ *
+ * 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\MainBundle\Tests\Templating;
+
+use PHPUnit\Framework\TestCase;
+use Chill\MainBundle\Templating\ChillMarkdownRenderExtension;
+
+/**
+ * Test the service ChillMarkdownRenderExtension
+ *
+ * @internal we do not want to test the markdown transformation. We just want to
+ * test that the markdown is correctly transformed into html, and that the html
+ * is safe.
+ */
+class ChillMarkdownRenderExtensionTest extends TestCase
+{
+
+ private const SIMPLE_MARKDOWN = <<test
+Text.
+HTML;
+
+ private const UNAUTHORIZED_MARKDOWN = <<alert("ok");
+MD;
+
+ private const UNAUTHORIZED_HTML = <<<script>alert("ok");</script>
+HTML;
+
+ /**
+ * Test that the markdown input is transformed into html
+ */
+ public function testRendering()
+ {
+ $extension = new ChillMarkdownRenderExtension();
+
+ $this->assertEquals(self::SIMPLE_HTML,
+ $extension->renderMarkdownToHtml(self::SIMPLE_MARKDOWN));
+ }
+
+ /**
+ * Test that the output of the markdown content is sanitized
+ */
+ public function testSecurity()
+ {
+ $extension = new ChillMarkdownRenderExtension();
+
+ $this->assertEquals(self::UNAUTHORIZED_HTML,
+ $extension->renderMarkdownToHtml(self::UNAUTHORIZED_MARKDOWN));
+ }
+}
diff --git a/src/Bundle/ChillMainBundle/chill.webpack.config.js b/src/Bundle/ChillMainBundle/chill.webpack.config.js
index fdbe37a22..f3e2999ca 100644
--- a/src/Bundle/ChillMainBundle/chill.webpack.config.js
+++ b/src/Bundle/ChillMainBundle/chill.webpack.config.js
@@ -7,9 +7,8 @@ buildCKEditor = function(encore)
.addPlugin( new CKEditorWebpackPlugin( {
language: 'fr',
addMainLanguageTranslationsToAllAssets: true,
- verbose: true,
- strict: true,
- //additionalLanguages: ['en', 'nl', 'es'],
+ verbose: !encore.isProduction(),
+ strict: true
} ) )
// Use raw-loader for CKEditor 5 SVG files.
@@ -35,7 +34,7 @@ buildCKEditor = function(encore)
} )
} )
;
-}
+};
// Compile and loads all assets from the Chill Main Bundle
module.exports = function(encore, entries)
@@ -61,8 +60,8 @@ module.exports = function(encore, entries)
encore.addEntry('bootstrap', __dirname + '/Resources/public/modules/bootstrap/index.js');
// CKEditor5
- //buildCKEditor(encore);
- //encore.addEntry('ckeditor5', __dirname + '/Resources/public/modules/ckeditor5/index.js');
+ buildCKEditor(encore);
+ encore.addEntry('ckeditor5', __dirname + '/Resources/public/modules/ckeditor5/index.js');
-};
\ No newline at end of file
+};
diff --git a/src/Bundle/ChillMainBundle/config/services/controller.yaml b/src/Bundle/ChillMainBundle/config/services/controller.yaml
index 90630ff03..5fb542786 100644
--- a/src/Bundle/ChillMainBundle/config/services/controller.yaml
+++ b/src/Bundle/ChillMainBundle/config/services/controller.yaml
@@ -1,16 +1,16 @@
services:
-
+
Chill\MainBundle\Controller\:
autowire: true
resource: '../../Controller'
tags: ['controller.service_arguments']
-
+
Chill\MainBundle\Controller\PasswordController:
autowire: true
arguments:
$chillLogger: '@monolog.logger.chill'
tags: ['controller.service_arguments']
-
+
Chill\MainBundle\Controller\SearchController:
arguments:
$searchProvider: '@chill_main.search_provider'
@@ -24,9 +24,11 @@ services:
$roleProvider: '@chill.main.role_provider'
$roleHierarchy: '@security.role_hierarchy'
$translator: '@Symfony\Contracts\Translation\TranslatorInterface'
+ $validator: '@Symfony\Component\Validator\Validator\ValidatorInterface'
tags: ['controller.service_arguments']
Chill\MainBundle\Controller\UserController:
arguments:
$logger: '@Psr\Log\LoggerInterface'
- tags: ['controller.service_arguments']
\ No newline at end of file
+ $validator: '@Symfony\Component\Validator\Validator\ValidatorInterface'
+ tags: ['controller.service_arguments']
diff --git a/src/Bundle/ChillMainBundle/config/services/form.yaml b/src/Bundle/ChillMainBundle/config/services/form.yaml
index d3a01ff5d..513553194 100644
--- a/src/Bundle/ChillMainBundle/config/services/form.yaml
+++ b/src/Bundle/ChillMainBundle/config/services/form.yaml
@@ -138,10 +138,6 @@ services:
tags:
- { name: form.type }
- Chill\MainBundle\Form\Extension\CKEditorExtension:
- tags:
- - { name: form.type_extension, extended_type: Symfony\Component\Form\Extension\Core\Type\TextareaType }
-
chill.main.form.type.comment:
class: Chill\MainBundle\Form\Type\CommentType
arguments:
diff --git a/src/Bundle/ChillMainBundle/config/services/templating.yaml b/src/Bundle/ChillMainBundle/config/services/templating.yaml
index 0dfb92380..29dc676d1 100644
--- a/src/Bundle/ChillMainBundle/config/services/templating.yaml
+++ b/src/Bundle/ChillMainBundle/config/services/templating.yaml
@@ -34,5 +34,10 @@ services:
Chill\MainBundle\Templating\Entity\CommentRender:
arguments:
- '@chill.main.user_repository'
+ - '@Symfony\Component\Templating\EngineInterface'
tags:
- { name: 'chill.render_entity' }
+
+ Chill\MainBundle\Templating\ChillMarkdownRenderExtension:
+ tags:
+ - { name: twig.extension }
diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml
index b19feb69c..a7b71a072 100644
--- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml
+++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml
@@ -35,6 +35,9 @@ This form contains errors: Ce formulaire contient des erreurs
Choose an user: Choisir un utilisateur
'You are going to leave a page with unsubmitted data. Are you sure you want to leave ?': "Vous allez quitter la page alors que des données n'ont pas été enregistrées. Êtes vous sûr de vouloir partir ?"
No value: Aucune information
+Last updated by: Dernière mise à jour par
+Last updated on: Dernière mise à jour le
+on: le
Edit: Modifier
Update: Mettre à jour
diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodController.php
index 2f6925373..2b51e9191 100644
--- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodController.php
+++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodController.php
@@ -3,7 +3,7 @@
/*
* Chill is a software for social workers
*
- * Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
+ * Copyright (C) 2014-2021, Champs Libres Cooperative SCRLFS,
* ,
*
* This program is free software: you can redistribute it and/or modify
@@ -23,6 +23,7 @@
namespace Chill\PersonBundle\Controller;
use Chill\PersonBundle\Privacy\PrivacyEvent;
+use Doctrine\DBAL\Exception;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Form\AccompanyingPeriodType;
@@ -32,6 +33,8 @@ use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Validator\ConstraintViolationListInterface;
+use Symfony\Component\Validator\Validator\ValidatorInterface;
/**
* Class AccompanyingPeriodController
@@ -46,57 +49,54 @@ class AccompanyingPeriodController extends AbstractController
protected $eventDispatcher;
/**
- * ReportController constructor.
+ * @var ValidatorInterface
+ */
+ protected $validator;
+
+ /**
+ * AccompanyingPeriodController constructor.
*
* @param EventDispatcherInterface $eventDispatcher
+ * @param ValidatorInterface $validator
*/
- public function __construct(EventDispatcherInterface $eventDispatcher)
+ public function __construct(EventDispatcherInterface $eventDispatcher, ValidatorInterface $validator)
{
$this->eventDispatcher = $eventDispatcher;
+ $this->validator = $validator;
}
- /**
- * @param $person_id
- * @return Response
- */
- public function listAction($person_id){
-
+ public function listAction(int $person_id): Response
+ {
$person = $this->_getPerson($person_id);
- $event = new PrivacyEvent($person, array(
+ $event = new PrivacyEvent($person, [
'element_class' => AccompanyingPeriod::class,
'action' => 'list'
- ));
+ ]);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
- return $this->render('ChillPersonBundle:AccompanyingPeriod:list.html.twig',
- array('accompanying_periods' => $person->getAccompanyingPeriodsOrdered(),
- 'person' => $person));
+ return $this->render('ChillPersonBundle:AccompanyingPeriod:list.html.twig', [
+ 'accompanying_periods' => $person->getAccompanyingPeriodsOrdered(),
+ 'person' => $person
+ ]);
}
- /**
- * @param $person_id
- * @param Request $request
- * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response
- */
- public function createAction($person_id, Request $request)
+ public function createAction(int $person_id, Request $request): Response
{
-
$person = $this->_getPerson($person_id);
$this->denyAccessUnlessGranted(PersonVoter::UPDATE, $person,
'You are not allowed to update this person');
- $accompanyingPeriod = new AccompanyingPeriod(new \DateTime());
- $accompanyingPeriod->setClosingDate(new \DateTime());
-
- $person->addAccompanyingPeriod(
- $accompanyingPeriod);
-
+ $accompanyingPeriod = new AccompanyingPeriod(new \DateTimeImmutable('now'));
+ $accompanyingPeriod->setClosingDate(new \DateTimeImmutable('now'));
+
+ $accompanyingPeriod->addPerson($person);
+ //or $person->addAccompanyingPeriod($accompanyingPeriod);
+
$form = $this->createForm(
AccompanyingPeriodType::class,
- $accompanyingPeriod,
- [
+ $accompanyingPeriod, [
'period_action' => 'create',
'center' => $person->getCenter()
]);
@@ -106,7 +106,7 @@ class AccompanyingPeriodController extends AbstractController
$errors = $this->_validatePerson($person);
$flashBag = $this->get('session')->getFlashBag();
- if ($form->isValid(array('Default', 'closed'))
+ if ($form->isValid(['Default', 'closed'])
&& count($errors) === 0) {
$em = $this->getDoctrine()->getManager();
@@ -116,8 +116,11 @@ class AccompanyingPeriodController extends AbstractController
$this->get('translator')->trans(
'A period has been created.'));
- return $this->redirect($this->generateUrl('chill_person_accompanying_period_list',
- array('person_id' => $person->getId())));
+ return $this->redirect(
+ $this->generateUrl('chill_person_accompanying_period_list', [
+ 'person_id' => $person->getId()
+ ]));
+
} else {
$flashBag->add('error', $this->get('translator')
->trans('Error! Period not created!'));
@@ -128,57 +131,64 @@ class AccompanyingPeriodController extends AbstractController
}
}
- return $this->render('ChillPersonBundle:AccompanyingPeriod:form.html.twig',
- array(
- 'form' => $form->createView(),
- 'person' => $person,
- 'accompanying_period' => $accompanyingPeriod
- )
- );
+ return $this->render('ChillPersonBundle:AccompanyingPeriod:form.html.twig', [
+ 'form' => $form->createView(),
+ 'person' => $person,
+ 'accompanying_period' => $accompanyingPeriod
+ ]);
}
/**
- * @param $person_id
- * @param $period_id
- * @param Request $request
- * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response|\Symfony\Component\HttpKernel\Exception\NotFoundHttpException
+ * @throws Exception
*/
- public function updateAction($person_id, $period_id, Request $request){
+ public function updateAction(int $person_id, int $period_id, Request $request): Response
+ {
$em = $this->getDoctrine()->getManager();
- $accompanyingPeriod = $em->getRepository('ChillPersonBundle:AccompanyingPeriod')
- ->find($period_id);
+ /** @var AccompanyingPeriod $accompanyingPeriod */
+ $accompanyingPeriod = $em->getRepository(AccompanyingPeriod::class)->find($period_id);
if ($accompanyingPeriod === null) {
- return $this->createNotFoundException("Period with id ".$period_id.
- " is not found");
+ throw $this->createNotFoundException("Period with id " . $period_id . " is not found");
}
- $person = $accompanyingPeriod->getPerson();
+ /** @var Person $person */
+ $person = $this->_getPerson($person_id);
+
+ // CHECK
+ if (! $accompanyingPeriod->containsPerson($person)) {
+ throw new Exception("Accompanying period " . $period_id . " does not contain person " . $person_id);
+ }
$this->denyAccessUnlessGranted(PersonVoter::UPDATE, $person,
'You are not allowed to update this person');
$form = $this->createForm(AccompanyingPeriodType::class,
- $accompanyingPeriod, array('period_action' => 'update',
- 'center' => $person->getCenter()));
+ $accompanyingPeriod, [
+ 'period_action' => 'update',
+ 'center' => $person->getCenter()
+ ]);
if ($request->getMethod() === 'POST') {
$form->handleRequest($request);
$errors = $this->_validatePerson($person);
$flashBag = $this->get('session')->getFlashBag();
- if ($form->isValid(array('Default', 'closed'))
+ if ($form->isValid(['Default', 'closed'])
&& count($errors) === 0) {
+
$em->flush();
$flashBag->add('success',
- $this->get('translator')->trans(
- 'An accompanying period has been updated.'));
+ $this->get('translator')->trans('An accompanying period has been updated.'));
- return $this->redirect($this->generateUrl('chill_person_accompanying_period_list',
- array('person_id' => $person->getId())));
+ return $this->redirect(
+ $this->generateUrl('chill_person_accompanying_period_list', [
+ 'person_id' => $person->getId()
+ ]));
+
} else {
+
$flashBag->add('error', $this->get('translator')
->trans('Error when updating the period'));
@@ -188,46 +198,42 @@ class AccompanyingPeriodController extends AbstractController
}
}
- return $this->render('ChillPersonBundle:AccompanyingPeriod:form.html.twig',
- array(
- 'form' => $form->createView(),
- 'person' => $person,
- 'accompanying_period' => $accompanyingPeriod
- ) );
+ return $this->render('ChillPersonBundle:AccompanyingPeriod:form.html.twig', [
+ 'form' => $form->createView(),
+ 'person' => $person,
+ 'accompanying_period' => $accompanyingPeriod
+ ]);
}
/**
- * @param $person_id
- * @param Request $request
- * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response
* @throws \Exception
*/
- public function closeAction($person_id, Request $request)
+ public function closeAction(int $person_id, Request $request): Response
{
$person = $this->_getPerson($person_id);
- $this->denyAccessUnlessGranted(PersonVoter::UPDATE, $person,
- 'You are not allowed to update this person');
+ $this->denyAccessUnlessGranted(PersonVoter::UPDATE, $person, 'You are not allowed to update this person');
if ($person->isOpen() === false) {
+
$this->get('session')->getFlashBag()
->add('error', $this->get('translator')
- ->trans('Beware period is closed',
- array('%name%' => $person->__toString())));
+ ->trans('Beware period is closed', ['%name%' => $person->__toString()]
+ ));
return $this->redirect(
- $this->generateUrl('chill_person_accompanying_period_list', array(
- 'person_id' => $person->getId()
- )));
+ $this->generateUrl('chill_person_accompanying_period_list', [
+ 'person_id' => $person->getId()
+ ]));
}
$current = $person->getCurrentAccompanyingPeriod();
- $form = $this->createForm(AccompanyingPeriodType::class, $current, array(
+ $form = $this->createForm(AccompanyingPeriodType::class, $current, [
'period_action' => 'close',
'center' => $person->getCenter()
- ));
+ ]);
if ($request->getMethod() === 'POST') {
$form->handleRequest($request);
@@ -239,16 +245,18 @@ class AccompanyingPeriodController extends AbstractController
if (count($errors) === 0) {
$this->get('session')->getFlashBag()
->add('success', $this->get('translator')
- ->trans('An accompanying period has been closed.',
- array('%name%' => $person->__toString())));
+ ->trans('An accompanying period has been closed.', [
+ '%name%' => $person->__toString()
+ ]));
$this->getDoctrine()->getManager()->flush();
return $this->redirect(
- $this->generateUrl('chill_person_accompanying_period_list', array(
- 'person_id' => $person->getId()
- ))
- );
+ $this->generateUrl('chill_person_accompanying_period_list', [
+ 'person_id' => $person->getId()
+ ])
+ );
+
} else {
$this->get('session')->getFlashBag()
->add('error', $this->get('translator')
@@ -259,6 +267,7 @@ class AccompanyingPeriodController extends AbstractController
->add('info', $error->getMessage());
}
}
+
} else { //if form is not valid
$this->get('session')->getFlashBag()
->add('error',
@@ -273,37 +282,34 @@ class AccompanyingPeriodController extends AbstractController
}
}
- return $this->render('ChillPersonBundle:AccompanyingPeriod:form.html.twig',
- array(
- 'form' => $form->createView(),
- 'person' => $person,
- 'accompanying_period' => $current
- ));
+ return $this->render('ChillPersonBundle:AccompanyingPeriod:form.html.twig', [
+ 'form' => $form->createView(),
+ 'person' => $person,
+ 'accompanying_period' => $current
+ ]);
}
- /**
- * @param Person $person
- * @return \Symfony\Component\Validator\ConstraintViolationListInterface
- */
- private function _validatePerson(Person $person) {
- $errors = $this->get('validator')->validate($person, null,
- array('Default'));
- $errors_accompanying_period = $this->get('validator')->validate($person, null,
- array('accompanying_period_consistent'));
+ private function _validatePerson(Person $person): ConstraintViolationListInterface
+ {
+ $errors = $this->validator->validate($person, null,
+ ['Default']);
- foreach($errors_accompanying_period as $error ) {
- $errors->add($error);
+ // Can be disabled with config
+ if (false === $this->container->getParameter('chill_person.allow_multiple_simultaneous_accompanying_periods')) {
+
+ $errors_accompanying_period = $this->validator->validate($person, null,
+ ['accompanying_period_consistent']);
+
+ foreach($errors_accompanying_period as $error ) {
+ $errors->add($error);
+ }
}
return $errors;
}
- /**
- * @param $person_id
- * @param Request $request
- * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response
- */
- public function openAction($person_id, Request $request) {
+ public function openAction(int $person_id, Request $request): Response
+ {
$person = $this->_getPerson($person_id);
$this->denyAccessUnlessGranted(PersonVoter::UPDATE, $person,
@@ -314,19 +320,22 @@ class AccompanyingPeriodController extends AbstractController
$this->get('session')->getFlashBag()
->add('error', $this->get('translator')
->trans('Error! Period %name% is not closed ; it can be open',
- array('%name%' => $person->__toString())));
+ ['%name%' => $person->__toString()]
+ ));
return $this->redirect(
- $this->generateUrl('chill_person_accompanying_period_list', array(
- 'person_id' => $person->getId()
- )));
+ $this->generateUrl('chill_person_accompanying_period_list', [
+ 'person_id' => $person->getId()
+ ]));
}
$accompanyingPeriod = new AccompanyingPeriod(new \DateTime());
$form = $this->createForm(AccompanyingPeriodType::class,
- $accompanyingPeriod, array('period_action' => 'open',
- 'center' => $person->getCenter()));
+ $accompanyingPeriod, [
+ 'period_action' => 'open',
+ 'center' => $person->getCenter()
+ ]);
if ($request->getMethod() === 'POST') {
$form->handleRequest($request);
@@ -338,16 +347,18 @@ class AccompanyingPeriodController extends AbstractController
if (count($errors) <= 0) {
$this->get('session')->getFlashBag()
- ->add('success', $this->get('translator')
- ->trans('An accompanying period has been opened.',
- array('%name%' => $person->__toString())));
+ ->add('success', $this->get('translator')
+ ->trans('An accompanying period has been opened.',
+ ['%name%' => $person->__toString()]
+ ));
$this->getDoctrine()->getManager()->flush();
return $this->redirect(
- $this->generateUrl('chill_person_accompanying_period_list', array(
+ $this->generateUrl('chill_person_accompanying_period_list', [
'person_id' => $person->getId()
- )));
+ ]));
+
} else {
$this->get('session')->getFlashBag()
->add('error', $this->get('translator')
@@ -358,27 +369,25 @@ class AccompanyingPeriodController extends AbstractController
->add('info', $error->getMessage());
}
}
+
} else { // if errors in forms
$this->get('session')->getFlashBag()
- ->add('error', $this->get('translator')
- ->trans('Period not opened : form is invalid'));
+ ->add('error', $this->get('translator')
+ ->trans('Period not opened : form is invalid')
+ );
}
}
- return $this->render('ChillPersonBundle:AccompanyingPeriod:form.html.twig',
- array('form' => $form->createView(),
- 'person' => $person,
- 'accompanying_period' => $accompanyingPeriod));
+ return $this->render('ChillPersonBundle:AccompanyingPeriod:form.html.twig', [
+ 'form' => $form->createView(),
+ 'person' => $person,
+ 'accompanying_period' => $accompanyingPeriod
+ ]);
}
- /**
- * @param $person_id
- * @param $period_id
- * @param Request $request
- * @return object|\Symfony\Component\HttpFoundation\RedirectResponse|Response
- */
- public function reOpenAction($person_id, $period_id, Request $request)
+ public function reOpenAction(int $person_id, int $period_id, Request $request): Response
{
+ /** @var Person $person */
$person = $this->_getPerson($person_id);
$criteria = Criteria::create();
@@ -395,7 +404,7 @@ class AccompanyingPeriodController extends AbstractController
$confirm = $request->query->getBoolean('confirm', false);
- if ($confirm === true && $period->canBeReOpened()) {
+ if ($confirm === true && $period->canBeReOpened($person)) {
$period->reOpen();
$this->_validatePerson($person);
@@ -405,13 +414,16 @@ class AccompanyingPeriodController extends AbstractController
$this->addFlash('success', $this->get('translator')->trans(
'The period has been re-opened'));
- return $this->redirectToRoute('chill_person_accompanying_period_list',
- array('person_id' => $person->getId()));
- } elseif ($confirm === false && $period->canBeReOpened()) {
- return $this->render('ChillPersonBundle:AccompanyingPeriod:re_open.html.twig', array(
+ return $this->redirectToRoute('chill_person_accompanying_period_list', [
+ 'person_id' => $person->getId()
+ ]);
+
+ } elseif ($confirm === false && $period->canBeReOpened($person)) {
+ return $this->render('ChillPersonBundle:AccompanyingPeriod:re_open.html.twig', [
'period' => $period,
'person' => $person
- ));
+ ]);
+
} else {
return (new Response())
->setStatusCode(Response::HTTP_BAD_REQUEST)
@@ -420,12 +432,10 @@ class AccompanyingPeriodController extends AbstractController
}
/**
- *
- * @param int $id
- * @return Person
- * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the person is not found
+ * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
*/
- private function _getPerson($id) {
+ private function _getPerson(int $id) : Person
+ {
$person = $this->getDoctrine()->getManager()
->getRepository('ChillPersonBundle:Person')->find($id);
diff --git a/src/Bundle/ChillPersonBundle/Controller/PersonAddressController.php b/src/Bundle/ChillPersonBundle/Controller/PersonAddressController.php
index fb8a80da1..f68e1ee9b 100644
--- a/src/Bundle/ChillPersonBundle/Controller/PersonAddressController.php
+++ b/src/Bundle/ChillPersonBundle/Controller/PersonAddressController.php
@@ -29,6 +29,7 @@ use Chill\MainBundle\Form\Type\AddressType;
use Chill\MainBundle\Entity\Address;
use Doctrine\Common\Collections\Criteria;
use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Validator\Validator\ValidatorInterface;
/**
* Class PersonAddressController
@@ -40,7 +41,21 @@ use Symfony\Component\HttpFoundation\Request;
*/
class PersonAddressController extends AbstractController
{
-
+ /**
+ * @var ValidatorInterface
+ */
+ protected $validator;
+
+ /**
+ * PersonAddressController constructor.
+ *
+ * @param ValidatorInterface $validator
+ */
+ public function __construct(ValidatorInterface $validator)
+ {
+ $this->validator = $validator;
+ }
+
public function listAction($person_id)
{
$person = $this->getDoctrine()->getManager()
@@ -302,9 +317,9 @@ class PersonAddressController extends AbstractController
*/
private function validatePerson(Person $person)
{
- $errors = $this->get('validator')
+ $errors = $this->validator
->validate($person, null, array('Default'));
- $errors_addresses_consistent = $this->get('validator')
+ $errors_addresses_consistent = $this->validator
->validate($person, null, array('addresses_consistent'));
foreach($errors_addresses_consistent as $error) {
diff --git a/src/Bundle/ChillPersonBundle/Controller/PersonController.php b/src/Bundle/ChillPersonBundle/Controller/PersonController.php
index 28a960520..db2b8b9d1 100644
--- a/src/Bundle/ChillPersonBundle/Controller/PersonController.php
+++ b/src/Bundle/ChillPersonBundle/Controller/PersonController.php
@@ -38,6 +38,7 @@ use Symfony\Component\Translation\TranslatorInterface;
use Chill\MainBundle\Search\SearchProvider;
use Chill\PersonBundle\Repository\PersonRepository;
use Chill\PersonBundle\Config\ConfigPersonAltNamesHelper;
+use Symfony\Component\Validator\Validator\ValidatorInterface;
/**
* Class PersonController
@@ -51,25 +52,24 @@ class PersonController extends AbstractController
* @var SimilarPersonMatcher
*/
protected $similarPersonMatcher;
-
+
/**
*
* @var TranslatorInterface
*/
protected $translator;
-
-
+
/**
* @var EventDispatcherInterface
*/
protected $eventDispatcher;
-
+
/**
*
* @var PersonRepository;
*/
protected $personRepository;
-
+
/**
*
* @var ConfigPersonAltNamesHelper
@@ -80,6 +80,11 @@ class PersonController extends AbstractController
* @var \Psr\Log\LoggerInterface
*/
private $logger;
+
+ /**
+ * @var ValidatorInterface
+ */
+ private $validator;
public function __construct(
SimilarPersonMatcher $similarPersonMatcher,
@@ -87,7 +92,8 @@ class PersonController extends AbstractController
EventDispatcherInterface $eventDispatcher,
PersonRepository $personRepository,
ConfigPersonAltNamesHelper $configPersonAltNameHelper,
- LoggerInterface $logger
+ LoggerInterface $logger,
+ ValidatorInterface $validator
) {
$this->similarPersonMatcher = $similarPersonMatcher;
$this->translator = $translator;
@@ -95,6 +101,7 @@ class PersonController extends AbstractController
$this->configPersonAltNameHelper = $configPersonAltNameHelper;
$this->personRepository = $personRepository;
$this->logger = $logger;
+ $this->validator = $validator;
}
public function getCFGroup()
@@ -120,13 +127,13 @@ class PersonController extends AbstractController
throw $this->createNotFoundException("Person with id $person_id not"
. " found on this server");
}
-
+
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person,
"You are not allowed to see this person.");
-
+
$event = new PrivacyEvent($person);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
-
+
return $this->render('ChillPersonBundle:Person:view.html.twig',
array(
"person" => $person,
@@ -267,14 +274,14 @@ class PersonController extends AbstractController
*/
private function _validatePersonAndAccompanyingPeriod(Person $person)
{
- $errors = $this->get('validator')
+ $errors = $this->validator
->validate($person, null, array('creation'));
//validate accompanying periods
$periods = $person->getAccompanyingPeriods();
foreach ($periods as $period) {
- $period_errors = $this->get('validator')
+ $period_errors = $this->validator
->validate($period);
//group errors :
@@ -293,7 +300,7 @@ class PersonController extends AbstractController
$r->setStatusCode(400);
return $r;
}
-
+
$form = $this->createForm(
//CreationPersonType::NAME,
CreationPersonType::class,
@@ -306,7 +313,7 @@ class PersonController extends AbstractController
$form->handleRequest($request);
$person = $this->_bindCreationForm($form);
-
+
$errors = $this->_validatePersonAndAccompanyingPeriod($person);
$this->logger->info(sprintf('Person created with %d errors ', count($errors)));
diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPeople.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPeople.php
index 0977eef2c..fa20d3457 100644
--- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPeople.php
+++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPeople.php
@@ -21,6 +21,7 @@
namespace Chill\PersonBundle\DataFixtures\ORM;
+use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
@@ -195,6 +196,9 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con
case 'maritalStatus':
$value = $this->getReference($value);
break;
+ case 'accompanyingPeriods':
+ $this->addAccompanyingPeriods($p, $value, $manager);
+ break;
}
//try to add the data using the setSomething function,
@@ -230,15 +234,15 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con
private function getRandomAddress()
{
return (new Address())
- ->setStreetAddress1($this->faker->streetAddress)
- ->setStreetAddress2(
- rand(0,9) > 5 ? $this->faker->streetAddress : ''
- )
- ->setPostcode($this->getReference(
- LoadPostalCodes::$refs[array_rand(LoadPostalCodes::$refs)]
- ))
- ->setValidFrom($this->faker->dateTimeBetween('-5 years'))
- ;
+ ->setStreetAddress1($this->faker->streetAddress)
+ ->setStreetAddress2(
+ rand(0,9) > 5 ? $this->faker->streetAddress : ''
+ )
+ ->setPostcode($this->getReference(
+ LoadPostalCodes::$refs[array_rand(LoadPostalCodes::$refs)]
+ ))
+ ->setValidFrom($this->faker->dateTimeBetween('-5 years'))
+ ;
}
private function getCountry($countryCode)
@@ -251,25 +255,25 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con
->findOneByCountryCode($countryCode);
}
- private $maritalStatusRef = ['ms_single', 'ms_married', 'ms_widow', 'ms_separat',
+ private $maritalStatusRef = ['ms_single', 'ms_married', 'ms_widow', 'ms_separat',
'ms_divorce', 'ms_legalco', 'ms_unknown'];
- private $firstNamesMale = array("Jean", "Mohamed", "Alfred", "Robert",
- "Compère", "Jean-de-Dieu",
- "Charles", "Pierre", "Luc", "Mathieu", "Alain", "Etienne", "Eric",
- "Corentin", "Gaston", "Spirou", "Fantasio", "Mahmadou", "Mohamidou",
- "Vursuv" );
- private $firstNamesFemale = array("Svedana", "Sevlatina","Irène", "Marcelle",
- "Corentine", "Alfonsine","Caroline","Solange","Gostine", "Fatoumata",
- "Groseille", "Chana", "Oxana", "Ivana");
+ private $firstNamesMale = array("Jean", "Mohamed", "Alfred", "Robert", "Justin", "Brian",
+ "Compère", "Jean-de-Dieu", "Charles", "Pierre", "Luc", "Mathieu", "Alain", "Etienne", "Eric",
+ "Corentin", "Gaston", "Spirou", "Fantasio", "Mahmadou", "Mohamidou", "Vursuv", "Youssef" );
+
+ private $firstNamesFemale = array("Svedana", "Sevlatina", "Irène", "Marcelle",
+ "Corentine", "Alfonsine", "Caroline", "Solange", "Gostine", "Fatoumata", "Nicole",
+ "Groseille", "Chana", "Oxana", "Ivana", "Julie", "Tina", "Adèle" );
+
+ private $lastNames = array("Diallo", "Bah", "Gaillot", "Martin");
- private $lastNames = array("Diallo", "Bah", "Gaillot");
private $lastNamesTrigrams = array("fas", "tré", "hu", 'blart', 'van', 'der', 'lin', 'den',
- 'ta', 'mi', 'gna', 'bol', 'sac', 'ré', 'jo', 'du', 'pont', 'cas', 'tor', 'rob', 'al',
- 'ma', 'gone', 'car',"fu", "ka", "lot", "no", "va", "du", "bu", "su",
+ 'ta', 'mi', 'net', 'gna', 'bol', 'sac', 'ré', 'jo', 'du', 'pont', 'cas', 'tor', 'rob', 'al',
+ 'ma', 'gone', 'car',"fu", "ka", "lot", "no", "va", "du", "bu", "su", "jau", "tte", 'sir',
"lo", 'to', "cho", "car", 'mo','zu', 'qi', 'mu');
- private $genders = array(Person::MALE_GENDER, Person::FEMALE_GENDER);
+ private $genders = array(Person::MALE_GENDER, Person::FEMALE_GENDER);
private $years = array();
@@ -279,48 +283,101 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con
private $peoples = array(
array(
- 'FirstName' => "Depardieu",
- 'LastName' => "Gérard",
+ 'LastName' => "Depardieu",
+ 'FirstName' => "Gérard",
'Birthdate' => "1948-12-27",
'PlaceOfBirth' => "Châteauroux",
'Gender' => Person::MALE_GENDER,
'CountryOfBirth' => 'FR',
'Nationality' => 'RU',
'center' => 'centerA',
- 'maritalStatus' => 'ms_divorce'
+ 'maritalStatus' => 'ms_divorce',
+ 'accompanyingPeriods' => [
+ [
+ 'from' => '2015-02-01',
+ 'to' => '2015-10-30',
+ 'remark' => 'oops',
+ ],[
+ 'from' => '2017-06-01',
+ 'to' => '2018-03-30',
+ 'remark' => 'argg',
+ ],[
+ 'from' => '2019-01-01',
+ 'to' => '2019-12-31',
+ 'remark' => 'blob',
+ ]
+ ]
),
- array(
- //to have a person with same firstname as Gérard Depardieu
- 'FirstName' => "Depardieu",
- 'LastName' => "Jean",
+ array(
+ //to have a person with same firstname as Gérard Depardieu
+ 'LastName' => "Depardieu",
+ 'FirstName' => "Jean",
'Birthdate' => "1960-10-12",
'CountryOfBirth' => 'FR',
'Nationality' => 'FR',
'center' => 'centerA',
'maritalStatus' => 'ms_divorce'
),
- array(
- //to have a person with same birthdate of Gérard Depardieu
- 'FirstName' => 'Van Snick',
- 'LastName' => 'Bart',
- 'Birthdate' => '1948-12-27',
- 'center' => 'centerA',
- 'maritalStatus' => 'ms_legalco'
- ),
- array(
- //to have a woman with Depardieu as FirstName
- 'FirstName' => 'Depardieu',
- 'LastName' => 'Charline',
- 'Gender' => Person::FEMALE_GENDER,
- 'center' => 'centerA',
- 'maritalStatus' => 'ms_legalco'
- ),
- array(
- //to have a special character in lastName
- 'FirstName' => 'Manço',
- 'LastName' => 'Étienne',
- 'center' => 'centerA',
- 'maritalStatus' => 'ms_unknown'
- )
+ array(
+ //to have a person with same birthdate of Gérard Depardieu
+ 'LastName' => 'Van Snick',
+ 'FirstName' => 'Bart',
+ 'Birthdate' => '1948-12-27',
+ 'center' => 'centerA',
+ 'maritalStatus' => 'ms_legalco'
+ ),
+ array(
+ //to have a woman with Depardieu as FirstName
+ 'LastName' => 'Depardieu',
+ 'FirstName' => 'Charline',
+ 'Gender' => Person::FEMALE_GENDER,
+ 'center' => 'centerA',
+ 'maritalStatus' => 'ms_legalco'
+ ),
+ array(
+ //to have a special character in lastName
+ 'LastName' => 'Manço',
+ 'FirstName' => 'Étienne',
+ 'center' => 'centerA',
+ 'maritalStatus' => 'ms_unknown'
+ ),
+ array(
+ //to have true duplicate person
+ 'LastName' => "Depardieu",
+ 'FirstName' => "Jean",
+ 'Birthdate' => "1960-10-12",
+ 'CountryOfBirth' => 'FR',
+ 'Nationality' => 'FR',
+ 'center' => 'centerA',
+ 'maritalStatus' => 'ms_divorce'
+ ),
+ array(
+ //to have false duplicate person
+ 'LastName' => "Depardieu",
+ 'FirstName' => "Jeanne",
+ 'Birthdate' => "1966-11-13",
+ 'CountryOfBirth' => 'FR',
+ 'Nationality' => 'FR',
+ 'center' => 'centerA',
+ 'maritalStatus' => 'ms_legalco'
+ ),
);
+
+
+ private function addAccompanyingPeriods(Person $person, array $periods, ObjectManager $manager)
+ {
+ foreach ($periods as $period) {
+
+ echo "adding new past Accompanying Period..\n";
+
+ /** @var AccompanyingPeriod $accompanyingPeriod */
+ $accompanyingPeriod = new AccompanyingPeriod(new \DateTime($period['from']));
+ $accompanyingPeriod
+ ->setClosingDate(new \DateTime($period['to']))
+ ->setRemark($period['remark'])
+ ;
+
+ $person->addAccompanyingPeriod($accompanyingPeriod);
+ }
+ }
}
diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPersonACL.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPersonACL.php
index 0e3cb6dc9..a3f42ced9 100644
--- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPersonACL.php
+++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPersonACL.php
@@ -50,24 +50,36 @@ class LoadPersonACL extends AbstractFixture implements OrderedFixtureInterface
case 'social':
case 'direction':
printf("Adding CHILL_PERSON_UPDATE & CHILL_PERSON_CREATE to %s permission group \n", $permissionsGroup->getName());
+
$roleScopeUpdate = (new RoleScope())
->setRole('CHILL_PERSON_UPDATE')
->setScope(null);
$permissionsGroup->addRoleScope($roleScopeUpdate);
+
$roleScopeCreate = (new RoleScope())
->setRole('CHILL_PERSON_CREATE')
->setScope(null);
$permissionsGroup->addRoleScope($roleScopeCreate);
+
+ $roleScopeDuplicate = (new RoleScope())
+ ->setRole('CHILL_PERSON_DUPLICATE')
+ ->setScope(null);
+ $permissionsGroup->addRoleScope($roleScopeDuplicate);
+
$roleScopeList = (new RoleScope())
->setRole(PersonVoter::LISTS)
->setScope(null);
$permissionsGroup->addRoleScope($roleScopeList);
+
$roleScopeStats = (new RoleScope())
->setRole(PersonVoter::STATS)
->setScope(null);
$permissionsGroup->addRoleScope($roleScopeStats);
+
$manager->persist($roleScopeUpdate);
$manager->persist($roleScopeCreate);
+ $manager->persist($roleScopeDuplicate);
+
break;
case 'administrative':
printf("Adding CHILL_PERSON_SEE to %s permission group \n", $permissionsGroup->getName());
diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php
index c1ea40486..f8e8173de 100644
--- a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php
+++ b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php
@@ -56,6 +56,9 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
$this->handlePersonFieldsParameters($container, $config['person_fields']);
$this->handleAccompanyingPeriodsFieldsParameters($container, $config['accompanying_periods_fields']);
+
+ $container->setParameter('chill_person.allow_multiple_simultaneous_accompanying_periods',
+ $config['allow_multiple_simultaneous_accompanying_periods']);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config'));
$loader->load('services.yaml');
@@ -140,7 +143,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
}
$container->prependExtensionConfig('chill_custom_fields',
- array('customizables_entities' =>
+ array('customizables_entities' =>
array(
array('class' => 'Chill\PersonBundle\Entity\Person', 'name' => 'PersonEntity')
)
@@ -152,7 +155,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
* @param ContainerBuilder $container
* @throws MissingBundleException
*/
- public function prepend(ContainerBuilder $container)
+ public function prepend(ContainerBuilder $container)
{
$this->prependRoleHierarchy($container);
$this->prependHomepageWidget($container);
@@ -189,7 +192,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
/**
* Add a widget "add a person" on the homepage, automatically
- *
+ *
* @param \Chill\PersonBundle\DependencyInjection\containerBuilder $container
*/
protected function prependHomepageWidget(containerBuilder $container)
@@ -208,7 +211,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
/**
* Add role hierarchy.
- *
+ *
* @param ContainerBuilder $container
*/
protected function prependRoleHierarchy(ContainerBuilder $container)
@@ -217,7 +220,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
'role_hierarchy' => array(
'CHILL_PERSON_UPDATE' => array('CHILL_PERSON_SEE'),
'CHILL_PERSON_CREATE' => array('CHILL_PERSON_SEE'),
- PersonVoter::LISTS => [ ChillExportVoter::EXPORT ],
+ PersonVoter::LISTS => [ ChillExportVoter::EXPORT ],
PersonVoter::STATS => [ ChillExportVoter::EXPORT ]
)
));
@@ -225,7 +228,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
/**
* Add DQL function linked with person
- *
+ *
* @param ContainerBuilder $container
*/
protected function prependDoctrineDQL(ContainerBuilder $container)
diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php
index 9784e8523..3ebe3ceb1 100644
--- a/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php
+++ b/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php
@@ -104,8 +104,21 @@ class Configuration implements ConfigurationInterface
->canBeDisabled()
->children()
->append($this->addFieldNode('user'))
+ ->append($this->addFieldNode('createdBy'))
+ ->append($this->addFieldNode('step'))
+ ->append($this->addFieldNode('origin'))
+ ->append($this->addFieldNode('intensity'))
+ ->append($this->addFieldNode('scopes'))
+ ->append($this->addFieldNode('requestor'))
+ ->append($this->addFieldNode('anonymous'))
+ ->append($this->addFieldNode('emergency'))
+ ->append($this->addFieldNode('confidential'))
->end() //children for 'accompanying_person_fields', parent = array 'person_fields'
->end() // paccompanying_person_fields, parent = children of root
+ ->booleanNode('allow_multiple_simultaneous_accompanying_periods')
+ ->info('Can we have more than one simultaneous accompanying period in the same time. Default false.')
+ ->defaultValue(false)
+ ->end()
->end() // children of 'root', parent = root
;
diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php
index 255cf056f..a7311f838 100644
--- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php
+++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php
@@ -3,7 +3,7 @@
/*
* Chill is a software for social workers
*
- * Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
+ * Copyright (C) 2014-2021, Champs Libres Cooperative SCRLFS,
* ,
*
* This program is free software: you can redistribute it and/or modify
@@ -22,18 +22,28 @@
namespace Chill\PersonBundle\Entity;
+use Chill\MainBundle\Entity\Scope;
+use Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive;
+use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment;
+use Chill\PersonBundle\Entity\AccompanyingPeriod\Origin;
+use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource;
+use Chill\ThirdPartyBundle\Entity\ThirdParty;
+use Doctrine\Common\Collections\ArrayCollection;
+use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Chill\MainBundle\Entity\User;
/**
- * AccompanyingPeriod
+ * AccompanyingPeriod Class
*
- * @ORM\Entity()
+ * @ORM\Entity(repositoryClass="Chill\PersonBundle\Repository\AccompanyingPeriodRepository")
* @ORM\Table(name="chill_person_accompanying_period")
*/
class AccompanyingPeriod
{
+ const INTENSITY = ['occasional', 'regular'];
+
/**
* @var integer
*
@@ -63,16 +73,24 @@ class AccompanyingPeriod
* @ORM\Column(type="text")
*/
private $remark = '';
-
+
/**
- * @var Person
+ * @var Collection
*
- * @ORM\ManyToOne(
- * targetEntity="Chill\PersonBundle\Entity\Person",
- * inversedBy="accompanyingPeriods",
- * cascade={"refresh"})
+ * @ORM\OneToMany(targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod\Comment",
+ * mappedBy="accompanyingPeriod"
+ * )
*/
- private $person;
+ private $comments;
+
+ /**
+ * @var Collection
+ *
+ * @ORM\OneToMany(targetEntity=AccompanyingPeriodParticipation::class,
+ * mappedBy="accompanyingPeriod",
+ * cascade={"persist", "remove", "merge", "detach"})
+ */
+ private $participations;
/**
* @var AccompanyingPeriod\ClosingMotive
@@ -84,14 +102,88 @@ class AccompanyingPeriod
private $closingMotive = null;
/**
- * The user making the accompanying
- * @var User
- *
- * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
+ * @ORM\ManyToOne(targetEntity=User::class)
* @ORM\JoinColumn(nullable=true)
*/
private $user;
+ /**
+ * @ORM\ManyToOne(targetEntity=User::class)
+ * @ORM\JoinColumn(nullable=true)
+ */
+ private $createdBy;
+
+ /**
+ * @var string
+ * @ORM\Column(type="string", length=32, nullable=true)
+ */
+ private $step = 'DRAFT';
+
+ /**
+ * @ORM\ManyToOne(targetEntity=Origin::class)
+ * @ORM\JoinColumn(nullable=true)
+ */
+ private $origin;
+
+ /**
+ * @var string
+ * @ORM\Column(type="string", nullable=true)
+ */
+ private $intensity;
+
+ /**
+ * @var Collection
+ * @ORM\ManyToMany(
+ * targetEntity=Scope::class,
+ * cascade={}
+ * )
+ * @ORM\JoinTable(
+ * name="accompanying_periods_scopes",
+ * joinColumns={@ORM\JoinColumn(name="accompanying_period_id", referencedColumnName="id")},
+ * inverseJoinColumns={@ORM\JoinColumn(name="scope_id", referencedColumnName="id")}
+ * )
+ */
+ private $scopes;
+
+ /**
+ * @ORM\ManyToOne(targetEntity=Person::class)
+ * @ORM\JoinColumn(nullable=true)
+ */
+ private $requestorPerson;
+
+ /**
+ * @ORM\ManyToOne(targetEntity=ThirdParty::class)
+ * @ORM\JoinColumn(nullable=true)
+ */
+ private $requestorThirdParty;
+
+ /**
+ * @var bool
+ * @ORM\Column(type="boolean")
+ */
+ private $requestorAnonymous = false;
+
+ /**
+ * @var bool
+ * @ORM\Column(type="boolean")
+ */
+ private $emergency = false;
+
+ /**
+ * @var bool
+ * @ORM\Column(type="boolean")
+ */
+ private $confidential = false;
+
+ /**
+ * @var Collection
+ *
+ * @ORM\OneToMany(
+ * targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod\Resource",
+ * mappedBy="accompanyingPeriod"
+ * )
+ */
+ private $resources;
/**
* AccompanyingPeriod constructor.
@@ -101,12 +193,14 @@ class AccompanyingPeriod
*/
public function __construct(\DateTime $dateOpening) {
$this->setOpeningDate($dateOpening);
+ $this->participations = new ArrayCollection();
+ $this->scopes = new ArrayCollection();
}
/**
* Get id
*
- * @return integer
+ * @return integer
*/
public function getId()
{
@@ -129,7 +223,7 @@ class AccompanyingPeriod
/**
* Get openingDate
*
- * @return \DateTime
+ * @return \DateTime
*/
public function getOpeningDate()
{
@@ -138,12 +232,12 @@ class AccompanyingPeriod
/**
* Set closingDate
- *
+ *
* For closing a Person file, you should use Person::setClosed instead.
*
* @param \DateTime $dateClosing
* @return AccompanyingPeriod
- *
+ *
*/
public function setClosingDate($closingDate)
{
@@ -155,7 +249,7 @@ class AccompanyingPeriod
/**
* Get closingDate
*
- * @return \DateTime
+ * @return \DateTime
*/
public function getClosingDate()
{
@@ -165,26 +259,20 @@ class AccompanyingPeriod
/**
* @return boolean
*/
- public function isOpen(): bool
+ public function isOpen(): bool
{
- if ($this->getOpeningDate() > new \DateTime('now')) {
+ if ($this->getOpeningDate() > new \DateTimeImmutable('now')) {
return false;
}
if ($this->getClosingDate() === null) {
return true;
- } else {
- return false;
}
+
+ return false;
}
-
- /**
- * Set remark
- *
- * @param string $remark
- * @return AccompanyingPeriod
- */
- public function setRemark($remark)
+
+ public function setRemark(string $remark): self
{
if ($remark === null) {
$remark = '';
@@ -194,83 +282,123 @@ class AccompanyingPeriod
return $this;
}
-
- /**
- * Get remark
- *
- * @return string
- */
- public function getRemark()
+
+ public function getRemark(): string
{
return $this->remark;
}
-
- /**
- * Set person.
- *
- * For consistency, you should use Person::addAccompanyingPeriod instead.
- *
- * @param Person $person
- * @return AccompanyingPeriod
- * @see Person::addAccompanyingPeriod
- */
- public function setPerson(Person $person = null)
+
+ public function getComments(): Collection
{
- $this->person = $person;
+ return $this->comments;
+ }
+
+ public function addComment(Comment $comment): self
+ {
+ $this->comments[] = $comment;
+
+ return $this;
+ }
+
+ public function removeComment(Comment $comment): void
+ {
+ $this->comments->removeElement($comment);
+ }
+
+ /**
+ * Get Participations Collection
+ */
+ public function getParticipations(): Collection
+ {
+ return $this->participations;
+ }
+
+ /**
+ * This private function scan Participations Collection,
+ * searching for a given Person
+ */
+ private function participationsContainsPerson(Person $person): ?AccompanyingPeriodParticipation
+ {
+ foreach ($this->participations as $participation) {
+ /** @var AccompanyingPeriodParticipation $participation */
+ if ($person === $participation->getPerson()) {
+ return $participation;
+ }}
+
+ return null;
+ }
+
+ /**
+ * This public function is the same but return only true or false
+ */
+ public function containsPerson(Person $person): bool
+ {
+ return ($this->participationsContainsPerson($person) === null) ? false : true;
+ }
+
+ /**
+ * Add Person
+ */
+ public function addPerson(Person $person = null): self
+ {
+ $participation = new AccompanyingPeriodParticipation($this, $person);
+ $this->participations[] = $participation;
return $this;
}
-
- /**
- * Get person
- *
- * @return Person
- */
- public function getPerson()
- {
- return $this->person;
- }
/**
- * @return AccompanyingPeriod\ClosingMotive
+ * Remove Person
*/
- public function getClosingMotive()
+ public function removePerson(Person $person): void
+ {
+ $participation = $this->participationsContainsPerson($person);
+
+ if (! null === $participation) {
+ $participation->setEndDate(new \DateTimeImmutable('now'));
+ $this->participations->removeElement($participation);
+ }
+ }
+
+
+ public function getClosingMotive(): ?ClosingMotive
{
return $this->closingMotive;
}
- /**
- * @param AccompanyingPeriod\ClosingMotive|null $closingMotive
- * @return $this
- */
- public function setClosingMotive(AccompanyingPeriod\ClosingMotive $closingMotive = null)
+ public function setClosingMotive(ClosingMotive $closingMotive = null): self
{
$this->closingMotive = $closingMotive;
+
return $this;
}
/**
* If the period can be reopened.
- *
- * This function test if the period is closed and if the period is the last
- * for the associated person
- *
- * @return boolean
+ *
+ * This function test if the period is closed and if the period is the last
+ * for the given person
*/
- public function canBeReOpened()
+ public function canBeReOpened(Person $person): bool
{
if ($this->isOpen() === true) {
return false;
}
- $periods = $this->getPerson()->getAccompanyingPeriodsOrdered();
+ $participation = $this->participationsContainsPerson($person);
+ if (!null === $participation)
+ {
+ $person = $participation->getPerson();
+ $periods = $person->getAccompanyingPeriodsOrdered();
+ return end($periods) === $this;
+ }
- return end($periods) === $this;
+ return false;
}
/**
*/
- public function reOpen()
+ public function reOpen(): void
{
$this->setClosingDate(null);
$this->setClosingMotive(null);
@@ -294,7 +422,7 @@ class AccompanyingPeriod
/**
* Returns true if the closing date is after the opening date.
- *
+ *
* @return boolean
*/
public function isClosingAfterOpening()
@@ -308,23 +436,165 @@ class AccompanyingPeriod
}
}
- /**
- * @return User|null
- */
function getUser(): ?User
{
return $this->user;
}
- /**
- * @param User $user
- * @return AccompanyingPeriod
- */
function setUser(User $user): self
{
$this->user = $user;
return $this;
}
+
+ public function getOrigin(): Origin
+ {
+ return $this->origin;
+ }
+
+ public function setOrigin(Origin $origin): self
+ {
+ $this->origin = $origin;
+
+ return $this;
+ }
+
+ public function getRequestorPerson(): ?Person
+ {
+ return $this->requestorPerson;
+ }
+
+ public function setRequestorPerson(Person $requestorPerson): self
+ {
+ $this->requestorPerson = ($this->requestorThirdParty === null) ? $requestorPerson : null;
+
+ return $this;
+ }
+
+ public function getRequestorThirdParty(): ?ThirdParty
+ {
+ return $this->requestorThirdParty;
+ }
+
+ public function setRequestorThirdParty(ThirdParty $requestorThirdParty): self
+ {
+ $this->requestorThirdParty = ($this->requestorPerson === null) ? $requestorThirdParty : null;
+
+ return $this;
+ }
+
+ /**
+ * @return Person|ThirdParty
+ */
+ public function getRequestor()
+ {
+ return $this->requestorPerson ?? $this->requestorThirdParty;
+ }
+
+ public function isRequestorAnonymous(): bool
+ {
+ return $this->requestorAnonymous;
+ }
+
+ public function setRequestorAnonymous(bool $requestorAnonymous): self
+ {
+ $this->requestorAnonymous = $requestorAnonymous;
+
+ return $this;
+ }
+
+ public function isEmergency(): bool
+ {
+ return $this->emergency;
+ }
+
+ public function setEmergency(bool $emergency): self
+ {
+ $this->emergency = $emergency;
+
+ return $this;
+ }
+
+ public function isConfidential(): bool
+ {
+ return $this->confidential;
+ }
+
+ public function setConfidential(bool $confidential): self
+ {
+ $this->confidential = $confidential;
+
+ return $this;
+ }
+
+ public function getCreatedBy(): ?User
+ {
+ return $this->createdBy;
+ }
+
+ public function setCreatedBy(User $createdBy): self
+ {
+ $this->createdBy = $createdBy;
+ return $this;
+ }
+
+ public function getStep(): string
+ {
+ return $this->step;
+ }
+
+ public function setStep(string $step): self
+ {
+ $this->step = $step;
+
+ return $this;
+ }
+
+ public function getIntensity(): string
+ {
+ return $this->intensity;
+ }
+
+ public function setIntensity(string $intensity): self
+ {
+ $this->intensity = $intensity;
+
+ return $this;
+ }
+
+ public function getScopes(): Collection
+ {
+ return $this->scopes;
+ }
+
+ public function addScope(Scope $scope): self
+ {
+ $this->scopes[] = $scope;
+
+ return $this;
+ }
+
+ public function removeScope(Scope $scope): void
+ {
+ $this->scopes->removeElement($scope);
+ }
+
+ public function getResources(): Collection
+ {
+ return $this->resources;
+ }
+
+ public function addResource(Resource $resource): self
+ {
+ $this->resources[] = $resource;
+
+ return $this;
+ }
+
+ public function removeResource(Resource $resource): void
+ {
+ $this->resources->removeElement($resource);
+ }
}
diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/ClosingMotive.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/ClosingMotive.php
index 05149e23f..1bb48da00 100644
--- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/ClosingMotive.php
+++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/ClosingMotive.php
@@ -1,19 +1,21 @@
- *
+ * Chill is a software for social workers
+ *
+ * Copyright (C) 2014-2021, Champs Libres Cooperative SCRLFS,
+ * ,
+ *
* This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
+ * 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.
- *
+ * 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 .
*/
@@ -28,8 +30,8 @@ use Doctrine\Common\Collections\ArrayCollection;
* ClosingMotive give an explanation why we closed the Accompanying period
*
* @ORM\Entity(
- * repositoryClass="Chill\PersonBundle\Repository\ClosingMotiveRepository")
- * @ORM\Table(name="chill_person_closingmotive")
+ * repositoryClass="Chill\PersonBundle\Repository\AccompanyingPeriod\ClosingMotiveRepository")
+ * @ORM\Table(name="chill_person_accompanying_period_closingmotive")
*/
class ClosingMotive
{
diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Comment.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Comment.php
new file mode 100644
index 000000000..e8ecf3248
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Comment.php
@@ -0,0 +1,154 @@
+,
+ *
+ * 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\Entity\AccompanyingPeriod;
+
+use Chill\PersonBundle\Repository\AccompanyingPeriod\CommentRepository;
+use Chill\MainBundle\Entity\User;
+use Chill\PersonBundle\Entity\AccompanyingPeriod;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity(repositoryClass=CommentRepository::class)
+ * @ORM\Table(name="chill_person_accompanying_period_comment")
+ */
+class Comment
+{
+ /**
+ * @ORM\Id
+ * @ORM\GeneratedValue
+ * @ORM\Column(type="integer")
+ */
+ private $id;
+
+ /**
+ * @ORM\ManyToOne(
+ * targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod",
+ * inversedBy="comments")
+ * @ORM\JoinColumn(nullable=false)
+ */
+ private $accompanyingPeriod;
+
+ /**
+ * @ORM\ManyToOne(targetEntity=User::class)
+ * @ORM\JoinColumn(nullable=false)
+ */
+ private $creator;
+
+ /**
+ * @ORM\Column(type="datetime")
+ */
+ private $createdAt;
+
+ /**
+ * @ORM\Column(type="datetime")
+ */
+ private $updatedAt;
+
+ /**
+ * @ORM\ManyToOne(targetEntity=User::class)
+ * @ORM\JoinColumn(nullable=false)
+ */
+ private $updatedBy;
+
+ /**
+ * @ORM\Column(type="text")
+ */
+ private $content;
+
+ public function getId(): ?int
+ {
+ return $this->id;
+ }
+
+ public function getAccompanyingPeriod(): ?AccompanyingPeriod
+ {
+ return $this->accompanyingPeriod;
+ }
+
+ public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self
+ {
+ $this->accompanyingPeriod = $accompanyingPeriod;
+
+ return $this;
+ }
+
+ public function getCreator(): ?User
+ {
+ return $this->creator;
+ }
+
+ public function setCreator(?User $creator): self
+ {
+ $this->creator = $creator;
+
+ return $this;
+ }
+
+ public function getCreatedAt(): ?\DateTimeInterface
+ {
+ return $this->createdAt;
+ }
+
+ public function setCreatedAt(\DateTimeInterface $createdAt): self
+ {
+ $this->createdAt = $createdAt;
+
+ return $this;
+ }
+
+ public function getUpdatedAt(): ?\DateTimeInterface
+ {
+ return $this->updatedAt;
+ }
+
+ public function setUpdatedAt(\DateTimeInterface $updatedAt): self
+ {
+ $this->updatedAt = $updatedAt;
+
+ return $this;
+ }
+
+ public function getUpdatedBy(): ?User
+ {
+ return $this->updatedBy;
+ }
+
+ public function setUpdatedBy(?User $updatedBy): self
+ {
+ $this->updatedBy = $updatedBy;
+
+ return $this;
+ }
+
+ public function getContent(): ?string
+ {
+ return $this->content;
+ }
+
+ public function setContent(string $content): self
+ {
+ $this->content = $content;
+
+ return $this;
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Origin.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Origin.php
new file mode 100644
index 000000000..4016cd833
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Origin.php
@@ -0,0 +1,79 @@
+,
+ *
+ * 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\Entity\AccompanyingPeriod;
+
+use Chill\PersonBundle\Entity\AccompanyingPeriod\OriginRepository;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity(repositoryClass=OriginRepository::class)
+ * @ORM\Table(name="chill_person_accompanying_period_origin")
+ */
+class Origin
+{
+ /**
+ * @ORM\Id
+ * @ORM\GeneratedValue
+ * @ORM\Column(type="integer")
+ */
+ private $id;
+
+ /**
+ * @ORM\Column(type="string", length=255)
+ */
+ private $label;
+
+ /**
+ * @ORM\Column(type="date_immutable", nullable=true)
+ */
+ private $noActiveAfter;
+
+ public function getId(): ?int
+ {
+ return $this->id;
+ }
+
+ public function getLabel(): ?string
+ {
+ return $this->label;
+ }
+
+ public function setLabel(string $label): self
+ {
+ $this->label = $label;
+
+ return $this;
+ }
+
+ public function getNoActiveAfter(): ?\DateTimeImmutable
+ {
+ return $this->noActiveAfter;
+ }
+
+ public function setNoActiveAfter(?\DateTimeImmutable $noActiveAfter): self
+ {
+ $this->noActiveAfter = $noActiveAfter;
+
+ return $this;
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Resource.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Resource.php
new file mode 100644
index 000000000..ec13fcad6
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Resource.php
@@ -0,0 +1,132 @@
+,
+ *
+ * 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\Entity\AccompanyingPeriod;
+
+use Chill\PersonBundle\Repository\AccompanyingPeriod\ResourceRepository;
+use Chill\PersonBundle\Entity\AccompanyingPeriod;
+use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment;
+use Chill\PersonBundle\Entity\Person;
+use Chill\ThirdPartyBundle\Entity\ThirdParty;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Entity(repositoryClass=ResourceRepository::class)
+ * @ORM\Table(name="chill_person_accompanying_period_resource")
+ */
+class Resource
+{
+ /**
+ * @ORM\Id
+ * @ORM\GeneratedValue
+ * @ORM\Column(type="integer")
+ */
+ private $id;
+
+ /**
+ * @ORM\ManyToOne(
+ * targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod",
+ * inversedBy="resources"
+ * )
+ * @ORM\JoinColumn(nullable=false)
+ */
+ private $accompanyingPeriod;
+
+ /**
+ * @ORM\ManyToOne(targetEntity=ThirdParty::class)
+ * @ORM\JoinColumn(nullable=true)
+ */
+ private $thirdParty;
+
+ /**
+ * @ORM\ManyToOne(targetEntity=Person::class)
+ * @ORM\JoinColumn(nullable=true)
+ */
+ private $person;
+
+ /**
+ * @ORM\ManyToOne(targetEntity=Comment::class)
+ * @ORM\JoinColumn(nullable=true)
+ */
+ private $comment;
+
+ public function getId(): ?int
+ {
+ return $this->id;
+ }
+
+ public function getAccompanyingPeriod(): ?AccompanyingPeriod
+ {
+ return $this->accompanyingPeriod;
+ }
+
+ public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self
+ {
+ $this->accompanyingPeriod = $accompanyingPeriod;
+
+ return $this;
+ }
+
+ public function getThirdParty(): ?ThirdParty
+ {
+ return $this->thirdParty;
+ }
+
+ public function setThirdParty(?ThirdParty $thirdParty): self
+ {
+ $this->thirdParty = $thirdParty;
+
+ return $this;
+ }
+
+ public function getPerson(): ?Person
+ {
+ return $this->person;
+ }
+
+ public function setPerson(?Person $person): self
+ {
+ $this->person = $person;
+
+ return $this;
+ }
+
+ public function getComment(): ?Comment
+ {
+ return $this->comment;
+ }
+
+ public function setComment(?Comment $comment): self
+ {
+ $this->comment = $comment;
+
+ return $this;
+ }
+
+ /**
+ * @return Person|ThirdParty
+ */
+ public function getResource()
+ {
+ return $this->person ?? $this->thirdParty;
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriodParticipation.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriodParticipation.php
new file mode 100644
index 000000000..9a807b179
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriodParticipation.php
@@ -0,0 +1,124 @@
+,
+ *
+ * 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\Entity;
+
+use Chill\PersonBundle\Repository\AccompanyingPeriodParticipationRepository;
+use Chill\PersonBundle\Entity\AccompanyingPeriod;
+use Chill\PersonBundle\Entity\Person;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * AccompanyingPeriodParticipation Class
+ *
+ * @package Chill\PersonBundle\Entity
+ * @ORM\Entity(repositoryClass=AccompanyingPeriodParticipationRepository::class)
+ * @ORM\Table(name="chill_person_accompanying_period_participation")
+ */
+class AccompanyingPeriodParticipation
+{
+ /**
+ * @ORM\Id
+ * @ORM\GeneratedValue
+ * @ORM\Column(type="integer")
+ */
+ private $id;
+
+ /**
+ * @ORM\ManyToOne(targetEntity=Person::class, inversedBy="accompanyingPeriodParticipations")
+ * @ORM\JoinColumn(name="person_id", referencedColumnName="id", nullable=false)
+ */
+ private $person;
+
+ /**
+ * @ORM\ManyToOne(targetEntity=AccompanyingPeriod::class, inversedBy="participations")
+ * @ORM\JoinColumn(name="accompanyingperiod_id", referencedColumnName="id", nullable=false)
+ */
+ private $accompanyingPeriod;
+
+ /**
+ * @ORM\Column(type="date", nullable=false)
+ */
+ private $startDate;
+
+ /**
+ * @ORM\Column(type="date", nullable=true)
+ */
+ private $endDate = null;
+
+ public function __construct(AccompanyingPeriod $accompanyingPeriod, Person $person)
+ {
+ $this->startDate = new \DateTimeImmutable('now');
+ $this->accompanyingPeriod = $accompanyingPeriod;
+ $this->person = $person;
+ }
+
+ public function getId(): ?int
+ {
+ return $this->id;
+ }
+
+ public function getPerson(): ?Person
+ {
+ return $this->person;
+ }
+
+ public function setPerson(?Person $person): self
+ {
+ $this->person = $person;
+
+ return $this;
+ }
+
+ public function getAccompanyingPeriod(): ?AccompanyingPeriod
+ {
+ return $this->accompanyingPeriod;
+ }
+
+ public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self
+ {
+ $this->accompanyingPeriod = $accompanyingPeriod;
+
+ return $this;
+ }
+
+ public function getStartDate(): ?\DateTimeInterface
+ {
+ return $this->startDate;
+ }
+
+ /*
+ * public function setStartDate(\DateTimeInterface $startDate): self { $this->startDate = $startDate; return $this; }
+ */
+
+ public function getEndDate(): ?\DateTimeInterface
+ {
+ return $this->endDate;
+ }
+
+ public function setEndDate(?\DateTimeInterface $endDate): self
+ {
+ $this->endDate = $endDate;
+
+ return $this;
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/Entity/Person.php b/src/Bundle/ChillPersonBundle/Entity/Person.php
index 36993ce3b..b493975cf 100644
--- a/src/Bundle/ChillPersonBundle/Entity/Person.php
+++ b/src/Bundle/ChillPersonBundle/Entity/Person.php
@@ -42,7 +42,6 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
* name="person_names",
* columns={"firstName", "lastName"}
* )})
- * sf4 check index name
* @ORM\HasLifecycleCallbacks()
*/
class Person implements HasCenterInterface
@@ -72,7 +71,7 @@ class Person implements HasCenterInterface
* @ORM\Column(type="string", length=255)
*/
private $lastName;
-
+
/**
* @var Collection
*
@@ -177,6 +176,18 @@ class Person implements HasCenterInterface
*/
private $mobilenumber = '';
+ /**
+ * @var Collection
+ *
+ * @ORM\OneToMany(
+ * targetEntity="Chill\PersonBundle\Entity\PersonPhone",
+ * mappedBy="person",
+ * cascade={"persist", "remove", "merge", "detach"},
+ * orphanRemoval=true
+ * )
+ */
+ private $otherPhoneNumbers;
+
//TO-ADD caseOpeningDate
//TO-ADD nativeLanguag
@@ -204,14 +215,13 @@ class Person implements HasCenterInterface
/**
* The person's accompanying periods (when the person was accompanied by the center)
- * @var ArrayCollection
+ * @var Collection
*
- * @ORM\OneToMany(
- * targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod",
+ * @ORM\OneToMany(targetEntity=AccompanyingPeriodParticipation::class,
* mappedBy="person",
* cascade={"persist", "remove", "merge", "detach"})
*/
- private $accompanyingPeriods; //TO-CHANGE in accompanyingHistory
+ private $accompanyingPeriodParticipations;
/**
* A remark over the person
@@ -248,15 +258,14 @@ class Person implements HasCenterInterface
* @ORM\OrderBy({"validFrom" = "DESC"})
*/
private $addresses;
-
+
/**
* @var string
*
* @ORM\Column(type="text", nullable=true)
*/
private $fullnameCanonical;
-
-
+
/**
* Person constructor.
*
@@ -264,10 +273,11 @@ class Person implements HasCenterInterface
*/
public function __construct(\DateTime $opening = null)
{
- $this->accompanyingPeriods = new ArrayCollection();
+ $this->accompanyingPeriodParticipations = new ArrayCollection();
$this->spokenLanguages = new ArrayCollection();
$this->addresses = new ArrayCollection();
$this->altNames = new ArrayCollection();
+ $this->otherPhoneNumbers = new ArrayCollection();
if ($opening === null) {
$opening = new \DateTime();
@@ -275,23 +285,54 @@ class Person implements HasCenterInterface
$this->open(new AccompanyingPeriod($opening));
}
-
+
/**
- * @param AccompanyingPeriod $accompanyingPeriod
- * @uses AccompanyingPeriod::setPerson
+ * This private function scan accompanyingPeriodParticipations Collection,
+ * searching for a given AccompanyingPeriod
*/
- public function addAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod)
+ private function participationsContainAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): ?AccompanyingPeriodParticipation
{
- $accompanyingPeriod->setPerson($this);
- $this->accompanyingPeriods->add($accompanyingPeriod);
+ foreach ($this->accompanyingPeriodParticipations as $participation) {
+ /** @var AccompanyingPeriodParticipation $participation */
+ if ($accompanyingPeriod === $participation->getAccompanyingPeriod()) {
+ return $participation;
+ }}
+
+ return null;
}
/**
- * @param AccompanyingPeriod $accompanyingPeriod
+ * This public function is the same but return only true or false
*/
- public function removeAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod)
+ public function containsAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): bool
{
- $this->accompanyingPeriods->remove($accompanyingPeriod);
+ return ($this->participationsContainAccompanyingPeriod($accompanyingPeriod)) ? false : true;
+ }
+
+ /**
+ * Add AccompanyingPeriodParticipation
+ *
+ * @uses AccompanyingPeriod::addPerson
+ */
+ public function addAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): self
+ {
+ $participation = new AccompanyingPeriodParticipation($accompanyingPeriod, $this);
+ $this->accompanyingPeriodParticipations->add($participation);
+
+ return $this;
+ }
+
+ /**
+ * Remove AccompanyingPeriod
+ */
+ public function removeAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod) : void
+ {
+ $participation = $this->participationsContainAccompanyingPeriod($accompanyingPeriod);
+
+ if (! null === $participation) {
+ $participation->setEndDate(\DateTimeImmutable::class);
+ $this->accompanyingPeriodParticipations->removeElement($participation);
+ }
}
/**
@@ -303,10 +344,8 @@ class Person implements HasCenterInterface
* For closing a file, @see this::close
*
* To check if the Person and its accompanying period is consistent, use validation.
- *
- * @param AccompanyingPeriod $accompanyingPeriod
*/
- public function open(AccompanyingPeriod $accompanyingPeriod)
+ public function open(AccompanyingPeriod $accompanyingPeriod) : void
{
$this->proxyAccompanyingPeriodOpenState = true;
$this->addAccompanyingPeriod($accompanyingPeriod);
@@ -320,28 +359,26 @@ class Person implements HasCenterInterface
*
* To check if the Person and its accompanying period are consistent, use validation.
*
- * @param accompanyingPeriod
* @throws \Exception if two lines of the accompanying period are open.
*/
- public function close(AccompanyingPeriod $accompanyingPeriod = null)
+ public function close(AccompanyingPeriod $accompanyingPeriod = null) : void
{
$this->proxyAccompanyingPeriodOpenState = false;
}
/**
* Return the opened accompanying period.
- *
- * @return AccompanyingPeriod
*/
- public function getOpenedAccompanyingPeriod()
+ public function getOpenedAccompanyingPeriod() : AccompanyingPeriod
{
if ($this->isOpen() === false) {
return null;
}
- foreach ($this->accompanyingPeriods as $period) {
- if ($period->isOpen()) {
- return $period;
+ foreach ($this->accompanyingPeriodParticipations as $participation) {
+ /** @var AccompanyingPeriodParticipation $participation */
+ if ($participation->getAccompanyingPeriod()->isOpen()) {
+ return $participation->getAccompanyingPeriod();
}
}
}
@@ -349,31 +386,41 @@ class Person implements HasCenterInterface
/**
* Returns the opened accompanying period.
*
- * @return AccompanyingPeriod
* @deprecated since 1.1 use `getOpenedAccompanyingPeriod instead
*/
- public function getCurrentAccompanyingPeriod()
+ public function getCurrentAccompanyingPeriod() : AccompanyingPeriod
{
return $this->getOpenedAccompanyingPeriod();
}
/**
- * @return ArrayCollection
+ * Get AccompanyingPeriods array
*/
- public function getAccompanyingPeriods()
+ public function getAccompanyingPeriods(): array
{
- return $this->accompanyingPeriods;
+ $accompanyingPeriods = [];
+ foreach ($this->accompanyingPeriodParticipations as $participation)
+ {
+ /** @var AccompanyingPeriodParticipation $participation */
+ $accompanyingPeriods[] = $participation->getAccompanyingPeriod();
+ }
+ return $accompanyingPeriods;
+ }
+
+ /**
+ * Get AccompanyingPeriodParticipations Collection
+ */
+ public function getAccompanyingPeriodParticipations(): Collection
+ {
+ return $this->accompanyingPeriodParticipations;
}
/**
- * Get the accompanying periods of a give person with the
- * chronological order.
- *
- * @return AccompanyingPeriod[]
+ * Get the accompanying periods of a give person with the chronological order.
*/
- public function getAccompanyingPeriodsOrdered()
+ public function getAccompanyingPeriodsOrdered(): array
{
- $periods = $this->getAccompanyingPeriods()->toArray();
+ $periods = $this->getAccompanyingPeriods();
//order by date :
usort($periods, function($a, $b) {
@@ -406,11 +453,9 @@ class Person implements HasCenterInterface
}
/**
- * check if the person is opened
- *
- * @return boolean
+ * Check if the person is opened
*/
- public function isOpen()
+ public function isOpen() : bool
{
foreach ($this->getAccompanyingPeriods() as $period) {
if ($period->isOpen()) {
@@ -476,7 +521,7 @@ class Person implements HasCenterInterface
{
return $this->lastName;
}
-
+
/**
* @return Collection
*/
@@ -484,7 +529,7 @@ class Person implements HasCenterInterface
{
return $this->altNames;
}
-
+
/**
* @param Collection $altNames
* @return $this
@@ -492,10 +537,10 @@ class Person implements HasCenterInterface
public function setAltNames(Collection $altNames)
{
$this->altNames = $altNames;
-
+
return $this;
}
-
+
/**
* @param PersonAltName $altName
* @return $this
@@ -506,24 +551,24 @@ class Person implements HasCenterInterface
$this->altNames->add($altName);
$altName->setPerson($this);
}
-
+
return $this;
}
-
+
/**
* @param PersonAltName $altName
* @return $this
*/
- public function removeAltName(PersonAltName $altName)
+ public function removeAltName(PersonAltName $altName)
{
if ($this->altNames->contains($altName)) {
$altName->setPerson(null);
$this->altNames->removeElement($altName);
}
-
+
return $this;
}
-
+
/**
* Set birthdate
*
@@ -760,7 +805,7 @@ class Person implements HasCenterInterface
{
return $this->nationality;
}
-
+
/**
* @return string
*/
@@ -863,7 +908,53 @@ class Person implements HasCenterInterface
{
return $this->mobilenumber;
}
-
+
+ /**
+ * @return Collection
+ */
+ public function getOtherPhoneNumbers(): Collection
+ {
+ return $this->otherPhoneNumbers;
+ }
+
+ /**
+ * @param Collection $otherPhoneNumbers
+ * @return $this
+ */
+ public function setOtherPhoneNumbers(Collection $otherPhoneNumbers)
+ {
+ $this->otherPhoneNumbers = $otherPhoneNumbers;
+
+ return $this;
+ }
+
+ /**
+ * @param PersonPhone $otherPhoneNumber
+ * @return $this
+ */
+ public function addOtherPhoneNumber(PersonPhone $otherPhoneNumber)
+ {
+ if (false === $this->otherPhoneNumbers->contains($otherPhoneNumber)) {
+ $otherPhoneNumber->setPerson($this);
+ $this->otherPhoneNumbers->add($otherPhoneNumber);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param PersonPhone $otherPhoneNumber
+ * @return $this
+ */
+ public function removeOtherPhoneNumber(PersonPhone $otherPhoneNumber)
+ {
+ if ($this->otherPhoneNumbers->contains($otherPhoneNumber)) {
+ $this->otherPhoneNumbers->removeElement($otherPhoneNumber);
+ }
+
+ return $this;
+ }
+
/**
* @return string
*/
@@ -894,7 +985,7 @@ class Person implements HasCenterInterface
{
return $this->spokenLanguages;
}
-
+
/**
* @param Address $address
* @return $this
@@ -905,7 +996,7 @@ class Person implements HasCenterInterface
return $this;
}
-
+
/**
* @param Address $address
*/
@@ -924,7 +1015,7 @@ class Person implements HasCenterInterface
{
return $this->addresses;
}
-
+
/**
* @param \DateTime|null $date
* @return null
@@ -1051,4 +1142,15 @@ class Person implements HasCenterInterface
return true;
}
+
+ public function getFullnameCanonical() : string
+ {
+ return $this->fullnameCanonical;
+ }
+
+ public function setFullnameCanonical($fullnameCanonical) : Person
+ {
+ $this->fullnameCanonical = $fullnameCanonical;
+ return $this;
+ }
}
diff --git a/src/Bundle/ChillPersonBundle/Entity/PersonPhone.php b/src/Bundle/ChillPersonBundle/Entity/PersonPhone.php
new file mode 100644
index 000000000..4a2ffaf28
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Entity/PersonPhone.php
@@ -0,0 +1,115 @@
+date = new \DateTime();
+ }
+
+ public function getId(): int
+ {
+ return $this->id;
+ }
+
+ public function getPerson(): Person
+ {
+ return $this->person;
+ }
+
+ public function setPerson(Person $person): void
+ {
+ $this->person = $person;
+ }
+
+ public function getType(): string
+ {
+ return $this->type;
+ }
+
+ public function setType(string $type): void
+ {
+ $this->type = $type;
+ }
+
+ public function getPhonenumber(): string
+ {
+ return $this->phonenumber;
+ }
+
+ public function setPhonenumber(string $phonenumber): void
+ {
+ $this->phonenumber = $phonenumber;
+ }
+
+ public function getDescription(): ?string
+ {
+ return $this->description;
+ }
+
+ public function setDescription(?string $description): void
+ {
+ $this->description = $description;
+ }
+
+ public function getDate(): \DateTime
+ {
+ return $this->date;
+ }
+
+ public function setDate(\DateTime $date): void
+ {
+ $this->date = $date;
+ }
+
+ public function isEmpty(): bool
+ {
+ return empty($this->getDescription()) && empty($this->getPhonenumber());
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/Form/AccompanyingPeriodType.php b/src/Bundle/ChillPersonBundle/Form/AccompanyingPeriodType.php
index 2de2011a1..b4c146960 100644
--- a/src/Bundle/ChillPersonBundle/Form/AccompanyingPeriodType.php
+++ b/src/Bundle/ChillPersonBundle/Form/AccompanyingPeriodType.php
@@ -6,17 +6,16 @@ use Chill\MainBundle\Entity\Center;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
-use Symfony\Component\Form\FormEvents;
-use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
-use Symfony\Component\Form\Extension\Core\Type\TextareaType;
+use Chill\MainBundle\Form\Type\ChillTextareaType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Chill\MainBundle\Form\Type\UserPickerType;
use Symfony\Component\Security\Core\Role\Role;
use Chill\PersonBundle\Form\Type\ClosingMotivePickerType;
+
/**
* Class AccompanyingPeriodType
*
@@ -89,7 +88,7 @@ class AccompanyingPeriodType extends AbstractType
]);
}
- $builder->add('remark', TextareaType::class, [
+ $builder->add('remark', ChillTextareaType::class, [
'required' => false
]);
}
diff --git a/src/Bundle/ChillPersonBundle/Form/PersonType.php b/src/Bundle/ChillPersonBundle/Form/PersonType.php
index 7cf24a836..d87fe0196 100644
--- a/src/Bundle/ChillPersonBundle/Form/PersonType.php
+++ b/src/Bundle/ChillPersonBundle/Form/PersonType.php
@@ -21,21 +21,24 @@
namespace Chill\PersonBundle\Form;
+use Chill\CustomFieldsBundle\Form\Type\CustomFieldType;
+use Chill\MainBundle\Form\Type\ChillCollectionType;
+use Chill\MainBundle\Form\Type\ChillTextareaType;
+use Chill\MainBundle\Form\Type\Select2CountryType;
+use Chill\MainBundle\Form\Type\Select2LanguageType;
+use Chill\PersonBundle\Config\ConfigPersonAltNamesHelper;
+use Chill\PersonBundle\Form\Type\GenderType;
+use Chill\PersonBundle\Form\Type\PersonAltNameType;
+use Chill\PersonBundle\Form\Type\PersonPhoneType;
+use Chill\PersonBundle\Entity\PersonPhone;
+use Chill\PersonBundle\Form\Type\Select2MaritalStatusType;
use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\FormBuilderInterface;
-use Symfony\Component\OptionsResolver\OptionsResolver;
-use Symfony\Component\Form\Extension\Core\Type\TextareaType;
-use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\TelType;
-use Chill\PersonBundle\Form\Type\GenderType;
-use Chill\MainBundle\Form\Type\Select2CountryType;
-use Chill\MainBundle\Form\Type\Select2LanguageType;
-use Chill\CustomFieldsBundle\Form\Type\CustomFieldType;
-use Chill\PersonBundle\Form\Type\Select2MaritalStatusType;
-use Chill\PersonBundle\Config\ConfigPersonAltNamesHelper;
-use Chill\PersonBundle\Form\Type\PersonAltNameType;
+use Symfony\Component\Form\Extension\Core\Type\TextType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\OptionsResolver\OptionsResolver;
class PersonType extends AbstractType
{
@@ -48,7 +51,7 @@ class PersonType extends AbstractType
* @var string[]
*/
protected $config = array();
-
+
/**
*
* @var ConfigPersonAltNamesHelper
@@ -80,16 +83,16 @@ class PersonType extends AbstractType
->add('gender', GenderType::class, array(
'required' => true
));
-
+
if ($this->configAltNamesHelper->hasAltNames()) {
$builder->add('altNames', PersonAltNameType::class, [
'by_reference' => false
]);
}
-
+
if ($this->config['memo'] === 'visible') {
$builder
- ->add('memo', TextareaType::class, array('required' => false))
+ ->add('memo', ChillTextareaType::class, array('required' => false))
;
}
@@ -98,17 +101,31 @@ class PersonType extends AbstractType
}
if ($this->config['contact_info'] === 'visible') {
- $builder->add('contactInfo', TextareaType::class, array('required' => false));
+ $builder->add('contactInfo', ChillTextareaType::class, array('required' => false));
}
if ($this->config['phonenumber'] === 'visible') {
$builder->add('phonenumber', TelType::class, array('required' => false));
}
-
+
if ($this->config['mobilenumber'] === 'visible') {
$builder->add('mobilenumber', TelType::class, array('required' => false));
}
+ $builder->add('otherPhoneNumbers', ChillCollectionType::class, [
+ 'entry_type' => PersonPhoneType::class,
+ 'button_add_label' => 'Add new phone',
+ 'button_remove_label' => 'Remove phone',
+ 'required' => false,
+ 'allow_add' => true,
+ 'allow_delete' => true,
+ 'by_reference' => false,
+ 'label' => false,
+ 'delete_empty' => function(PersonPhone $pp = null) {
+ return NULL === $pp || $pp->isEmpty();
+ }
+ ]);
+
if ($this->config['email'] === 'visible') {
$builder->add('email', EmailType::class, array('required' => false));
}
@@ -153,7 +170,7 @@ class PersonType extends AbstractType
{
$resolver->setDefaults(array(
'data_class' => 'Chill\PersonBundle\Entity\Person',
- 'validation_groups' => array('general', 'creation')
+ 'validation_groups' => array('general', 'creation'),
));
$resolver->setRequired(array(
diff --git a/src/Bundle/ChillPersonBundle/Form/Type/ClosingMotivePickerType.php b/src/Bundle/ChillPersonBundle/Form/Type/ClosingMotivePickerType.php
index aa7e47583..d2f85c924 100644
--- a/src/Bundle/ChillPersonBundle/Form/Type/ClosingMotivePickerType.php
+++ b/src/Bundle/ChillPersonBundle/Form/Type/ClosingMotivePickerType.php
@@ -11,7 +11,7 @@ use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive;
use Chill\MainBundle\Templating\Entity\ChillEntityRenderExtension;
use Symfony\Component\OptionsResolver\Options;
-use Chill\PersonBundle\Repository\ClosingMotiveRepository;
+use Chill\PersonBundle\Repository\AccompanyingPeriod\ClosingMotiveRepository;
/**
* Class ClosingMotivePickerType
diff --git a/src/Bundle/ChillPersonBundle/Form/Type/PersonPhoneType.php b/src/Bundle/ChillPersonBundle/Form/Type/PersonPhoneType.php
new file mode 100644
index 000000000..f06d5cd72
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Form/Type/PersonPhoneType.php
@@ -0,0 +1,65 @@
+phonenumberHelper = $phonenumberHelper;
+ $this->em = $em;
+ }
+
+ public function buildForm(FormBuilderInterface $builder, array $options)
+ {
+ $builder->add('phonenumber', TelType::class, [
+ 'label' => 'Other phonenumber',
+ 'required' => true,
+ ]);
+
+ $builder->add('description', TextType::class, [
+ 'required' => false,
+ ]);
+
+ $builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) {
+ if (NULL === $event->getData()) {
+ return;
+ }
+
+ $oldPersonPhone = $this->em->getUnitOfWork()
+ ->getOriginalEntityData($event->getData());
+
+ if ($oldPersonPhone['phonenumber'] ?? null !== $event->getForm()->getData()->getPhonenumber()) {
+ $type = $this->phonenumberHelper->getType($event->getData()->getPhonenumber());
+ $event->getData()->setType($type);
+ }
+ });
+ }
+
+ public function configureOptions(OptionsResolver $resolver)
+ {
+ $resolver
+ ->setDefaults([
+ 'data_class' => PersonPhone::class,
+ 'validation_groups' => ['general', 'creation'],
+ ])
+ ;
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/Repository/ClosingMotiveRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ClosingMotiveRepository.php
similarity index 73%
rename from src/Bundle/ChillPersonBundle/Repository/ClosingMotiveRepository.php
rename to src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ClosingMotiveRepository.php
index c3519796d..ef1130b62 100644
--- a/src/Bundle/ChillPersonBundle/Repository/ClosingMotiveRepository.php
+++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ClosingMotiveRepository.php
@@ -1,11 +1,15 @@
+ * Chill is a software for social workers
+ *
+ * Copyright (C) 2014-2021, Champs Libres Cooperative SCRLFS,
+ * ,
*
* This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
+ * 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
@@ -15,7 +19,8 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-namespace Chill\PersonBundle\Repository;
+
+namespace Chill\PersonBundle\Repository\AccompanyingPeriod;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
@@ -39,13 +44,13 @@ class ClosingMotiveRepository extends EntityRepository
$rsm->addRootEntityFromClassMetadata($this->getClassName(), 'cm');
$sql = "SELECT ".(string) $rsm."
- FROM chill_person_closingmotive AS cm
+ FROM chill_person_accompanying_period_closingmotive AS cm
WHERE
active IS TRUE ";
if ($onlyLeaf) {
$sql .= "AND cm.id NOT IN (
- SELECT DISTINCT parent_id FROM chill_person_closingmotive WHERE parent_id IS NOT NULL
+ SELECT DISTINCT parent_id FROM chill_person_accompanying_period_closingmotive WHERE parent_id IS NOT NULL
)";
}
diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/CommentRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/CommentRepository.php
new file mode 100644
index 000000000..b41e77591
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/CommentRepository.php
@@ -0,0 +1,42 @@
+,
+ *
+ * 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\Repository\AccompanyingPeriod;
+
+use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment;
+use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
+use Doctrine\Persistence\ManagerRegistry;
+
+/**
+ * @method Comment|null find($id, $lockMode = null, $lockVersion = null)
+ * @method Comment|null findOneBy(array $criteria, array $orderBy = null)
+ * @method Comment[] findAll()
+ * @method Comment[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
+ */
+class CommentRepository extends ServiceEntityRepository
+{
+ public function __construct(ManagerRegistry $registry)
+ {
+ parent::__construct($registry, Comment::class);
+ }
+
+}
diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/OriginRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/OriginRepository.php
new file mode 100644
index 000000000..6a5b28901
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/OriginRepository.php
@@ -0,0 +1,42 @@
+,
+ *
+ * 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\Repository\AccompanyingPeriod;
+
+use Chill\PersonBundle\Entity\AccompanyingPeriod\Origin;
+use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
+use Doctrine\Persistence\ManagerRegistry;
+
+/**
+ * @method Origin|null find($id, $lockMode = null, $lockVersion = null)
+ * @method Origin|null findOneBy(array $criteria, array $orderBy = null)
+ * @method Origin[] findAll()
+ * @method Origin[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
+ */
+class OriginRepository extends ServiceEntityRepository
+{
+ public function __construct(ManagerRegistry $registry)
+ {
+ parent::__construct($registry, Origin::class);
+ }
+
+}
diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ResourceRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ResourceRepository.php
new file mode 100644
index 000000000..46eaaaaa0
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ResourceRepository.php
@@ -0,0 +1,42 @@
+,
+ *
+ * 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\Repository\AccompanyingPeriod;
+
+use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource;
+use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
+use Doctrine\Persistence\ManagerRegistry;
+
+/**
+ * @method Resource|null find($id, $lockMode = null, $lockVersion = null)
+ * @method Resource|null findOneBy(array $criteria, array $orderBy = null)
+ * @method Resource[] findAll()
+ * @method Resource[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
+ */
+class ResourceRepository extends ServiceEntityRepository
+{
+ public function __construct(ManagerRegistry $registry)
+ {
+ parent::__construct($registry, Resource::class);
+ }
+
+}
diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodParticipationRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodParticipationRepository.php
new file mode 100644
index 000000000..fbe957ecf
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodParticipationRepository.php
@@ -0,0 +1,42 @@
+,
+ *
+ * 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\Repository;
+
+use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
+use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
+use Doctrine\Persistence\ManagerRegistry;
+
+/**
+ * @method AccompanyingPeriodParticipation|null find($id, $lockMode = null, $lockVersion = null)
+ * @method AccompanyingPeriodParticipation|null findOneBy(array $criteria, array $orderBy = null)
+ * @method AccompanyingPeriodParticipation[] findAll()
+ * @method AccompanyingPeriodParticipation[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
+ */
+class AccompanyingPeriodParticipationRepository extends ServiceEntityRepository
+{
+ public function __construct(ManagerRegistry $registry)
+ {
+ parent::__construct($registry, AccompanyingPeriodParticipation::class);
+ }
+
+}
diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodRepository.php
new file mode 100644
index 000000000..4bc9f92db
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodRepository.php
@@ -0,0 +1,42 @@
+,
+ *
+ * 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\Repository;
+
+use Chill\PersonBundle\Entity\AccompanyingPeriod;
+use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
+use Doctrine\Persistence\ManagerRegistry;
+
+/**
+ * @method AccompanyingPeriod|null find($id, $lockMode = null, $lockVersion = null)
+ * @method AccompanyingPeriod|null findOneBy(array $criteria, array $orderBy = null)
+ * @method AccompanyingPeriod[] findAll()
+ * @method AccompanyingPeriod[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
+ */
+class AccompanyingPeriodRepository extends ServiceEntityRepository
+{
+ public function __construct(ManagerRegistry $registry)
+ {
+ parent::__construct($registry, AccompanyingPeriod::class);
+ }
+
+}
diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriod/list.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriod/list.html.twig
index 4d82813d0..c0c50dbab 100644
--- a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriod/list.html.twig
+++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriod/list.html.twig
@@ -5,6 +5,9 @@
{% block title %}{{ 'Person accompanying period - %name%'|trans({ '%name%' : person.__toString}) }}{% endblock title %}
{% block personcontent %}
+
+{{ 'Accompanying period list'|trans }}
+
@@ -48,8 +51,13 @@
{% endif %}
-
- {{ accompanying_period.remark|chill_print_or_message('No remark', 'blockquote') }}
+ {% if accompanying_period is not empty %}
+
+ {{ accompanying_period.remark|chill_markdown_to_html }}
+
+ {% else %}
+ {{ null|chill_print_or_message('No remark', 'blockquote') }}
+ {% endif %}
|
@@ -63,7 +71,7 @@
{% endif %}
- {% if accompanying_period.canBeReOpened == true %}
+ {% if accompanying_period.canBeReOpened(person) == true %}
-
{{'Re-open accompanying period'|trans }}
diff --git a/src/Bundle/ChillPersonBundle/Resources/views/Person/edit.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/Person/edit.html.twig
index 62cc0c259..4546cc56d 100644
--- a/src/Bundle/ChillPersonBundle/Resources/views/Person/edit.html.twig
+++ b/src/Bundle/ChillPersonBundle/Resources/views/Person/edit.html.twig
@@ -83,6 +83,9 @@
{%- if form.mobilenumber is defined -%}
{{ form_row(form.mobilenumber, {'label': 'Mobilenumber'}) }}
{%- endif -%}
+ {%- if form.otherPhoneNumbers is defined -%}
+ {{ form_widget(form.otherPhoneNumbers) }}
+ {%- endif -%}
{%- if form.contactInfo is defined -%}
{{ form_row(form.contactInfo, {'label': 'Notes on contact information'}) }}
{%- endif -%}
diff --git a/src/Bundle/ChillPersonBundle/Resources/views/Person/view.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/Person/view.html.twig
index e3d6f233a..796a7f82e 100644
--- a/src/Bundle/ChillPersonBundle/Resources/views/Person/view.html.twig
+++ b/src/Bundle/ChillPersonBundle/Resources/views/Person/view.html.twig
@@ -48,20 +48,9 @@ This view should receive those arguments:
{#
{{ person.memo|nl2br }} #}
-
+
+ {{ person.memo|chill_markdown_to_html }}
- {% apply markdown_to_html %}
- {{ person.memo }}
- {% endapply %}
- {% apply markdown_to_html %}
-## Marc est down
-
-**michel** _ça va_
-
-> une citation
-
-Sit amet nisl ~~purus~~ in mollis.
- {% endapply %}
{% endif %}
@@ -223,7 +212,7 @@ Sit amet nisl ~~purus~~ in mollis.
{%- if chill_person.fields.email == 'visible' -%}
- {{ 'Email'|trans }} :
- - {% if person.email is not empty %}
{{ person.email|nl2br }} {% else %}{{ 'No data given'|trans }}{% endif %}
+ - {% if person.email is not empty %}{{ person.email }}{% else %}{{ 'No data given'|trans }}{% endif %}
{%- endif -%}
{%- if chill_person.fields.phonenumber == 'visible' -%}
@@ -238,10 +227,29 @@ Sit amet nisl ~~purus~~ in mollis.
- {% if person.mobilenumber is not empty %}
{{ person.mobilenumber|chill_format_phonenumber }}{% else %}{{ 'No data given'|trans }}{% endif %}
{% endif %}
+ {% for pp in person.otherPhoneNumbers %}
+ - {{ 'Other phonenumber'|trans }} :
+ -
+
{{ pp.phoneNumber|chill_format_phonenumber }}
+ {% if pp.description is not empty %}
+
+ {{ pp.description|nl2br }}
+ {% endif %}
+
+
+ {% endfor %}
{%- if chill_person.fields.contact_info == 'visible' -%}
- {{ 'Notes on contact information'|trans }} :
- - {% if person.contactInfo is not empty %}{{ person.contactInfo|nl2br }}{% else %}{{ 'No data given'|trans }}{% endif %}
+ -
+ {% if person.contactInfo is not empty %}
+
+ {{ person.contactInfo|chill_markdown_to_html }}
+
+ {% else %}
+ {{ 'No data given'|trans }}
+ {% endif %}
+
{%- endif -%}
diff --git a/src/Bundle/ChillPersonBundle/config/services/controller.yaml b/src/Bundle/ChillPersonBundle/config/services/controller.yaml
index 13713f3fd..812440bee 100644
--- a/src/Bundle/ChillPersonBundle/config/services/controller.yaml
+++ b/src/Bundle/ChillPersonBundle/config/services/controller.yaml
@@ -7,6 +7,7 @@ services:
$personRepository: '@Chill\PersonBundle\Repository\PersonRepository'
$configPersonAltNameHelper: '@Chill\PersonBundle\Config\ConfigPersonAltNamesHelper'
$logger: '@Psr\Log\LoggerInterface'
+ $validator: '@Symfony\Component\Validator\Validator\ValidatorInterface'
tags: ['controller.service_arguments']
Chill\PersonBundle\Controller\TimelinePersonController:
@@ -19,6 +20,12 @@ services:
Chill\PersonBundle\Controller\AccompanyingPeriodController:
arguments:
$eventDispatcher: '@Symfony\Component\EventDispatcher\EventDispatcherInterface'
+ $validator: '@Symfony\Component\Validator\Validator\ValidatorInterface'
+ tags: ['controller.service_arguments']
+
+ Chill\PersonBundle\Controller\PersonAddressController:
+ arguments:
+ $validator: '@Symfony\Component\Validator\Validator\ValidatorInterface'
tags: ['controller.service_arguments']
Chill\PersonBundle\Controller\AdminController: ~
diff --git a/src/Bundle/ChillPersonBundle/config/services/form.yaml b/src/Bundle/ChillPersonBundle/config/services/form.yaml
index 659421c8a..aa6f36b28 100644
--- a/src/Bundle/ChillPersonBundle/config/services/form.yaml
+++ b/src/Bundle/ChillPersonBundle/config/services/form.yaml
@@ -19,10 +19,10 @@ services:
arguments:
$translatableStringHelper: '@Chill\MainBundle\Templating\TranslatableStringHelper'
$chillEntityRenderExtension: '@Chill\MainBundle\Templating\Entity\ChillEntityRenderExtension'
- $closingMotiveRepository: '@Chill\PersonBundle\Repository\ClosingMotiveRepository'
+ $closingMotiveRepository: '@Chill\PersonBundle\Repository\AccompanyingPeriod\ClosingMotiveRepository'
tags:
- { name: form.type, alias: closing_motive }
-
+
Chill\PersonBundle\Form\AccompanyingPeriodType:
arguments:
$config: "%chill_person.accompanying_period_fields%"
@@ -39,10 +39,17 @@ services:
- '@Symfony\Component\Translation\TranslatorInterface'
tags:
- { name: form.type }
-
+
Chill\PersonBundle\Form\Type\PersonAltNameType:
arguments:
$configHelper: '@Chill\PersonBundle\Config\ConfigPersonAltNamesHelper'
$translatableStringHelper: '@chill.main.helper.translatable_string'
tags:
- { name: form.type }
+
+ Chill\PersonBundle\Form\Type\PersonPhoneType:
+ arguments:
+ $phonenumberHelper: '@Chill\MainBundle\Phonenumber\PhonenumberHelper'
+ $em: '@Doctrine\ORM\EntityManagerInterface'
+ tags:
+ - { name: form.type }
diff --git a/src/Bundle/ChillPersonBundle/config/services/repository.yaml b/src/Bundle/ChillPersonBundle/config/services/repository.yaml
index ee945def7..8cfaa8471 100644
--- a/src/Bundle/ChillPersonBundle/config/services/repository.yaml
+++ b/src/Bundle/ChillPersonBundle/config/services/repository.yaml
@@ -6,9 +6,15 @@ services:
arguments:
- 'Chill\PersonBundle\Entity\Person'
Chill\PersonBundle\Repository\PersonRepository: '@chill.person.repository.person'
-
- Chill\PersonBundle\Repository\ClosingMotiveRepository:
- class: Chill\PersonBundle\Repository\ClosingMotiveRepository
+
+ Chill\PersonBundle\Repository\AccompanyingPeriod\ClosingMotiveRepository:
+ class: Chill\PersonBundle\Repository\AccompanyingPeriod\ClosingMotiveRepository
factory: ['@doctrine.orm.entity_manager', getRepository]
arguments:
- 'Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive'
+
+ Chill\PersonBundle\Repository\AccompanyingPeriodRepository:
+ class: Chill\PersonBundle\Repository\AccompanyingPeriodRepository
+ tags: [ doctrine.repository_service ]
+ arguments:
+ - '@Doctrine\Persistence\ManagerRegistry'
diff --git a/src/Bundle/ChillPersonBundle/config/validation.yaml b/src/Bundle/ChillPersonBundle/config/validation.yaml
index 814db0ee4..b9041ddb9 100644
--- a/src/Bundle/ChillPersonBundle/config/validation.yaml
+++ b/src/Bundle/ChillPersonBundle/config/validation.yaml
@@ -27,9 +27,9 @@ Chill\PersonBundle\Entity\Person:
gender:
- NotNull:
groups: [general, creation]
- accompanyingPeriods:
- - Valid:
- traverse: true
+ #accompanyingPeriods:
+ # - Valid:
+ # traverse: true
email:
- Email:
groups: [general, creation]
@@ -51,8 +51,9 @@ Chill\PersonBundle\Entity\Person:
- Chill\MainBundle\Validation\Constraint\PhonenumberConstraint:
type: mobile
groups: [ general, creation ]
-
-
+ otherPhoneNumbers:
+ - Valid:
+ traverse: true
constraints:
- Callback:
callback: isAccompanyingPeriodValid
@@ -77,3 +78,14 @@ Chill\PersonBundle\Entity\AccompanyingPeriod:
constraints:
- Callback:
callback: isDateConsistent
+
+Chill\PersonBundle\Entity\PersonPhone:
+ properties:
+ phonenumber:
+ - Regex:
+ pattern: '/^([\+{1}])([0-9\s*]{4,20})$/'
+ groups: [ general, creation ]
+ message: 'Invalid phone number: it should begin with the international prefix starting with "+", hold only digits and be smaller than 20 characters. Ex: +33123456789'
+ - Chill\MainBundle\Validation\Constraint\PhonenumberConstraint:
+ type: any
+ groups: [ general, creation ]
diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210318095831.php b/src/Bundle/ChillPersonBundle/migrations/Version20210318095831.php
new file mode 100644
index 000000000..3258bd351
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/migrations/Version20210318095831.php
@@ -0,0 +1,36 @@
+addSql('CREATE SEQUENCE chill_person_phone_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
+ $this->addSql('CREATE TABLE chill_person_phone (id INT NOT NULL, person_id INT DEFAULT NULL, phonenumber TEXT NOT NULL, description TEXT DEFAULT NULL, date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, PRIMARY KEY(id))');
+ $this->addSql('CREATE INDEX IDX_72C1F87217BBB47 ON chill_person_phone (person_id)');
+ $this->addSql('ALTER TABLE chill_person_phone ADD CONSTRAINT FK_72C1F87217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ }
+
+ public function down(Schema $schema) : void
+ {
+ // this down() migration is auto-generated, please modify it to your needs
+ $this->addSql('DROP SEQUENCE chill_person_phone_id_seq CASCADE');
+ $this->addSql('DROP TABLE chill_person_phone');
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210325141540.php b/src/Bundle/ChillPersonBundle/migrations/Version20210325141540.php
new file mode 100644
index 000000000..6e2f105df
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/migrations/Version20210325141540.php
@@ -0,0 +1,31 @@
+addSql('ALTER TABLE chill_person_phone ADD type TEXT DEFAULT NULL');
+ }
+
+ public function down(Schema $schema) : void
+ {
+ // this down() migration is auto-generated, please modify it to your need
+ $this->addSql('ALTER TABLE chill_person_phone DROP type');
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210326113045.php b/src/Bundle/ChillPersonBundle/migrations/Version20210326113045.php
new file mode 100644
index 000000000..8ae60b739
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/migrations/Version20210326113045.php
@@ -0,0 +1,70 @@
+addSql('CREATE TABLE persons_accompanying_periods (person_id INT NOT NULL, accompanyingperiod_id INT NOT NULL, PRIMARY KEY(person_id, accompanyingperiod_id))');
+ $this->addSql('CREATE INDEX IDX_49A3871F217BBB47 ON persons_accompanying_periods (person_id)');
+ $this->addSql('CREATE INDEX IDX_49A3871F550B0C53 ON persons_accompanying_periods (accompanyingperiod_id)');
+ $this->addSql('ALTER TABLE persons_accompanying_periods ADD CONSTRAINT FK_49A3871F217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE persons_accompanying_periods ADD CONSTRAINT FK_49A3871F550B0C53 FOREIGN KEY (accompanyingperiod_id) REFERENCES chill_person_accompanying_period (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
+
+ // insert datas in new join table
+ $this->addSql('INSERT INTO persons_accompanying_periods (person_id, accompanyingperiod_id) '
+ . 'SELECT person_id, id as accompagnying_period_id FROM chill_person_accompanying_period WHERE person_id IS NOT NULL');
+
+ // drop column
+ $this->addSql('DROP INDEX idx_64a4a621217bbb47');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period DROP CONSTRAINT fk_64a4a621217bbb47');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period DROP person_id');
+ }
+
+ /**
+ * The distinct clause makes that for each group of duplicates, it keeps only the first row in the returned result set.
+ * Then we have only few lost datas. Lost datas: when many persons for one AccompanyingPeriod (keep only first person)
+ */
+ public function down(Schema $schema) : void
+ {
+ // add column
+ $this->addSql('ALTER TABLE chill_person_accompanying_period ADD person_id INT DEFAULT NULL');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period ADD CONSTRAINT fk_64a4a621217bbb47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('CREATE INDEX idx_64a4a621217bbb47 ON chill_person_accompanying_period (person_id)');
+
+ // insert datas in existing table
+ $this->addSql('UPDATE chill_person_accompanying_period AS ap '
+ . 'SET person_id = jt.person_id '
+ . 'FROM ( '
+ . 'SELECT DISTINCT ON (accompanyingperiod_id) accompanyingperiod_id AS id, person_id FROM persons_accompanying_periods '
+ . 'ORDER BY id, person_id ASC '
+ . ') AS jt '
+ . 'WHERE ap.id = jt.id');
+
+ // drop join table
+ $this->addSql('DROP TABLE persons_accompanying_periods');
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210329090904.php b/src/Bundle/ChillPersonBundle/migrations/Version20210329090904.php
new file mode 100644
index 000000000..1ccab6a50
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/migrations/Version20210329090904.php
@@ -0,0 +1,45 @@
+addSql('CREATE SEQUENCE chill_person_accompanying_period_origin_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
+ $this->addSql('CREATE TABLE chill_person_accompanying_period_origin (id INT NOT NULL, label VARCHAR(255) NOT NULL, noActiveAfter DATE DEFAULT NULL, PRIMARY KEY(id))');
+ $this->addSql('COMMENT ON COLUMN chill_person_accompanying_period_origin.noActiveAfter IS \'(DC2Type:date_immutable)\'');
+
+ $this->addSql('ALTER TABLE chill_person_accompanying_period ADD origin_id INT DEFAULT NULL');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period ADD CONSTRAINT FK_E260A86856A273CC FOREIGN KEY (origin_id) REFERENCES chill_person_accompanying_period_origin (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('CREATE INDEX IDX_E260A86856A273CC ON chill_person_accompanying_period (origin_id)');
+
+ }
+
+ public function down(Schema $schema) : void
+ {
+ $this->addSql('ALTER TABLE chill_person_accompanying_period DROP CONSTRAINT FK_E260A86856A273CC');
+
+ $this->addSql('DROP SEQUENCE chill_person_accompanying_period_origin_id_seq CASCADE');
+ $this->addSql('DROP TABLE chill_person_accompanying_period_origin');
+
+ $this->addSql('DROP INDEX IDX_E260A86856A273CC');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period DROP origin_id');
+
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210329113152.php b/src/Bundle/ChillPersonBundle/migrations/Version20210329113152.php
new file mode 100644
index 000000000..2cba2dd7e
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/migrations/Version20210329113152.php
@@ -0,0 +1,60 @@
+addSql('CREATE SEQUENCE chill_person_accompanying_period_comment_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
+ $this->addSql('CREATE TABLE chill_person_accompanying_period_comment (id INT NOT NULL, creator_id INT NOT NULL, createdAt TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, updatedAt TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, content TEXT NOT NULL, accompanyingPeriod_id INT NOT NULL, updatedBy_id INT NOT NULL, PRIMARY KEY(id))');
+
+ $this->addSql('CREATE INDEX IDX_CD960EF3D7FA8EF0 ON chill_person_accompanying_period_comment (accompanyingPeriod_id)');
+ $this->addSql('CREATE INDEX IDX_CD960EF361220EA6 ON chill_person_accompanying_period_comment (creator_id)');
+ $this->addSql('CREATE INDEX IDX_CD960EF365FF1AEC ON chill_person_accompanying_period_comment (updatedBy_id)');
+
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_comment ADD CONSTRAINT FK_CD960EF3D7FA8EF0 FOREIGN KEY (accompanyingPeriod_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_comment ADD CONSTRAINT FK_CD960EF361220EA6 FOREIGN KEY (creator_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_comment ADD CONSTRAINT FK_CD960EF365FF1AEC FOREIGN KEY (updatedBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+
+
+ $this->addSql('CREATE SEQUENCE chill_person_accompanying_period_resource_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
+ $this->addSql('CREATE TABLE chill_person_accompanying_period_resource (id INT NOT NULL, person_id INT DEFAULT NULL, comment_id INT DEFAULT NULL, accompanyingPeriod_id INT NOT NULL, thirdParty_id INT DEFAULT NULL, PRIMARY KEY(id))');
+
+ $this->addSql('CREATE INDEX IDX_DC78989FD7FA8EF0 ON chill_person_accompanying_period_resource (accompanyingPeriod_id)');
+ $this->addSql('CREATE INDEX IDX_DC78989F3EA5CAB0 ON chill_person_accompanying_period_resource (thirdParty_id)');
+ $this->addSql('CREATE INDEX IDX_DC78989F217BBB47 ON chill_person_accompanying_period_resource (person_id)');
+ $this->addSql('CREATE INDEX IDX_DC78989FF8697D13 ON chill_person_accompanying_period_resource (comment_id)');
+
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_resource ADD CONSTRAINT FK_DC78989FD7FA8EF0 FOREIGN KEY (accompanyingPeriod_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_resource ADD CONSTRAINT FK_DC78989F3EA5CAB0 FOREIGN KEY (thirdParty_id) REFERENCES chill_3party.third_party (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_resource ADD CONSTRAINT FK_DC78989F217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_resource ADD CONSTRAINT FK_DC78989FF8697D13 FOREIGN KEY (comment_id) REFERENCES chill_person_accompanying_period_comment (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+
+ }
+
+ public function down(Schema $schema) : void
+ {
+ $this->addSql('DROP SEQUENCE chill_person_accompanying_period_resource_id_seq CASCADE');
+ $this->addSql('DROP TABLE chill_person_accompanying_period_resource');
+
+ $this->addSql('DROP SEQUENCE chill_person_accompanying_period_comment_id_seq CASCADE');
+ $this->addSql('DROP TABLE chill_person_accompanying_period_comment');
+
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210329144338.php b/src/Bundle/ChillPersonBundle/migrations/Version20210329144338.php
new file mode 100644
index 000000000..dc75997ab
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/migrations/Version20210329144338.php
@@ -0,0 +1,74 @@
+addSql('CREATE TABLE accompanying_periods_scopes (accompanying_period_id INT NOT NULL, scope_id INT NOT NULL, PRIMARY KEY(accompanying_period_id, scope_id))');
+
+ $this->addSql('CREATE INDEX IDX_87C4EAB032A7A428 ON accompanying_periods_scopes (accompanying_period_id)');
+ $this->addSql('CREATE INDEX IDX_87C4EAB0682B5931 ON accompanying_periods_scopes (scope_id)');
+
+ $this->addSql('ALTER TABLE accompanying_periods_scopes ADD CONSTRAINT FK_87C4EAB032A7A428 FOREIGN KEY (accompanying_period_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE accompanying_periods_scopes ADD CONSTRAINT FK_87C4EAB0682B5931 FOREIGN KEY (scope_id) REFERENCES scopes (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+
+ $this->addSql('ALTER TABLE chill_person_accompanying_period ADD step VARCHAR(32) DEFAULT NULL');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period ADD intensity VARCHAR(255) DEFAULT NULL');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period ADD createdBy_id INT DEFAULT NULL');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period ADD requestorPerson_id INT DEFAULT NULL');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period ADD requestorThirdParty_id INT DEFAULT NULL');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period ADD requestorAnonymous BOOLEAN NOT NULL DEFAULT \'false\'');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period ADD emergency BOOLEAN NOT NULL DEFAULT \'false\'');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period ADD confidential BOOLEAN NOT NULL DEFAULT \'false\'');
+
+ $this->addSql('ALTER TABLE chill_person_accompanying_period ADD CONSTRAINT FK_E260A8683174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period ADD CONSTRAINT FK_E260A86834269C3F FOREIGN KEY (requestorPerson_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period ADD CONSTRAINT FK_E260A868CFE4D554 FOREIGN KEY (requestorThirdParty_id) REFERENCES chill_3party.third_party (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+
+ $this->addSql('CREATE INDEX IDX_E260A8683174800F ON chill_person_accompanying_period (createdBy_id)');
+ $this->addSql('CREATE INDEX IDX_E260A86834269C3F ON chill_person_accompanying_period (requestorPerson_id)');
+ $this->addSql('CREATE INDEX IDX_E260A868CFE4D554 ON chill_person_accompanying_period (requestorThirdParty_id)');
+
+ }
+
+ public function down(Schema $schema) : void
+ {
+
+ $this->addSql('DROP TABLE accompanying_periods_scopes');
+
+ $this->addSql('ALTER TABLE chill_person_accompanying_period DROP CONSTRAINT FK_E260A8683174800F');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period DROP CONSTRAINT FK_E260A86834269C3F');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period DROP CONSTRAINT FK_E260A868CFE4D554');
+
+ $this->addSql('DROP INDEX IDX_E260A8683174800F');
+ $this->addSql('DROP INDEX IDX_E260A86834269C3F');
+ $this->addSql('DROP INDEX IDX_E260A868CFE4D554');
+
+ $this->addSql('ALTER TABLE chill_person_accompanying_period DROP step');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period DROP intensity');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period DROP createdBy_id');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period DROP requestorPerson_id');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period DROP requestorThirdParty_id');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period DROP requestorAnonymous');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period DROP emergency');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period DROP confidential');
+
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210330164922.php b/src/Bundle/ChillPersonBundle/migrations/Version20210330164922.php
new file mode 100644
index 000000000..681132565
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/migrations/Version20210330164922.php
@@ -0,0 +1,35 @@
+addSql('ALTER TABLE chill_person_closingmotive RENAME TO chill_person_accompanying_period_closingmotive');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_closingmotive RENAME CONSTRAINT fk_92351ece727aca70 TO FK_72D110E8727ACA70');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period RENAME CONSTRAINT fk_64a4a621504cb38d TO FK_E260A868504CB38D');
+ }
+
+ public function down(Schema $schema) : void
+ {
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_closingmotive RENAME TO chill_person_closingmotive');
+ $this->addSql('ALTER TABLE chill_person_closingmotive RENAME CONSTRAINT FK_72D110E8727ACA70 TO fk_92351ece727aca70');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period RENAME CONSTRAINT FK_E260A868504CB38D TO fk_64a4a621504cb38d');
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210331084527.php b/src/Bundle/ChillPersonBundle/migrations/Version20210331084527.php
new file mode 100644
index 000000000..9c379c4b0
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/migrations/Version20210331084527.php
@@ -0,0 +1,67 @@
+addSql('ALTER TABLE persons_accompanying_periods DROP CONSTRAINT persons_accompanying_periods_pkey');
+ $this->addSql('ALTER TABLE persons_accompanying_periods RENAME TO chill_person_accompanying_period_participation');
+
+ // 2
+ // SERIAL automatically create sequence with NEXTVAL()
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD COLUMN id SERIAL NOT NULL PRIMARY KEY');
+ // drop NEXTVAL() in column definition
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ALTER id DROP DEFAULT');
+
+ // 3
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD startDate DATE NOT NULL DEFAULT \'1970-01-01\'');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD endDate DATE DEFAULT NULL');
+
+ // 4
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP CONSTRAINT fk_49a3871f217bbb47');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP CONSTRAINT fk_49a3871f550b0c53');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD CONSTRAINT FK_A59DF89F217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD CONSTRAINT FK_A59DF89F550B0C53 FOREIGN KEY (accompanyingperiod_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER INDEX idx_49a3871f217bbb47 RENAME TO IDX_A59DF89F217BBB47');
+ $this->addSql('ALTER INDEX idx_49a3871f550b0c53 RENAME TO IDX_A59DF89F550B0C53');
+ }
+
+ public function down(Schema $schema) : void
+ {
+ // 4
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP CONSTRAINT FK_A59DF89F217BBB47');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP CONSTRAINT FK_A59DF89F550B0C53');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD CONSTRAINT fk_49a3871f217bbb47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD CONSTRAINT fk_49a3871f550b0c53 FOREIGN KEY (accompanyingperiod_id) REFERENCES chill_person_accompanying_period (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER INDEX idx_a59df89f550b0c53 RENAME TO idx_49a3871f550b0c53');
+ $this->addSql('ALTER INDEX idx_a59df89f217bbb47 RENAME TO idx_49a3871f217bbb47');
+
+ // 3
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP startDate');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP endDate');
+
+ // 2
+ $this->addSql('DROP SEQUENCE chill_person_accompanying_period_participation_id_seq CASCADE');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP id');
+
+ // 1
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_participation RENAME TO persons_accompanying_periods');
+ $this->addSql('ALTER TABLE persons_accompanying_periods ADD CONSTRAINT persons_accompanying_periods_pkey PRIMARY KEY (person_id, accompanyingperiod_id)');
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml
index f5d1bb0f5..373fd668c 100644
--- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml
+++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml
@@ -40,6 +40,10 @@ Phonenumber: 'Numéro de téléphone'
phonenumber: numéro de téléphone
Mobilenumber: 'Numéro de téléphone portable'
mobilenumber: numéro de téléphone portable
+Other phonenumber: Autre numéro de téléphone
+Description: description
+Add new phone: Ajouter un numéro de téléphone
+Remove phone: Supprimer
'Notes on contact information': 'Remarques sur les informations de contact'
'Remarks': 'Remarques'
'{0} Born the %date% | {1} Born the %date%': '{0} Né le %date% | {1} Née le %date%'
@@ -281,7 +285,10 @@ person_admin:
marital status explanation: >
Configurer la liste des états civils.
+# specific to accompanying period
accompanying_period:
dates: Période
dates_from_%opening_date%: Ouvert depuis le %opening_date%
dates_from_%opening_date%_to_%closing_date%: Ouvert du %opening_date% au %closing_date%
+occasional: ponctuel
+regular: régulier
diff --git a/src/Bundle/ChillPersonBundle/translations/validators.fr.yml b/src/Bundle/ChillPersonBundle/translations/validators.fr.yml
index 22cb4c719..9f2030f02 100644
--- a/src/Bundle/ChillPersonBundle/translations/validators.fr.yml
+++ b/src/Bundle/ChillPersonBundle/translations/validators.fr.yml
@@ -10,7 +10,7 @@
'Opening date can not be null': 'La date d''ouverure ne peut être nulle'
'Closing date is not valid': 'La date de fermeture n''est pas valide'
'Closing date can not be null': 'La date de fermeture ne peut être nulle'
-The date of closing is before the date of opening: La période de fermeture est après la période d'ouverture
+The date of closing is before the date of opening: La période de fermeture est avant la période d'ouverture
The birthdate must be before %date%: La date de naissance doit être avant le %date%
'Invalid phone number: it should begin with the international prefix starting with "+", hold only digits and be smaller than 20 characters. Ex: +33123456789': 'Numéro de téléphone invalide: il doit commencer par le préfixe international précédé de "+", ne comporter que des chiffres et faire moins de 20 caractères. Ex: +31623456789'
'Invalid phone number: it should begin with the international prefix starting with "+", hold only digits and be smaller than 20 characters. Ex: +33623456789': 'Numéro de téléphone invalide: il doit commencer par le préfixe international précédé de "+", ne comporter que des chiffres et faire moins de 20 caractères. Ex: +33623456789'
diff --git a/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php b/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php
index d215c2b75..16f000aa2 100644
--- a/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php
+++ b/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php
@@ -22,15 +22,12 @@ use Symfony\Component\Form\FormBuilderInterface;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\MainBundle\Entity\Center;
use Symfony\Component\Form\Extension\Core\Type\TextType;
-use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Chill\MainBundle\Form\Type\UserPickerType;
use Chill\MainBundle\Form\Type\ScopePickerType;
-use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
-use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\Role\Role;
-use Chill\TaskBundle\Security\Authorization\TaskVoter;
use Chill\MainBundle\Form\Type\DateIntervalType;
+use Chill\MainBundle\Form\Type\ChillTextareaType;
/**
*
@@ -43,7 +40,7 @@ class SingleTaskType extends AbstractType
{
$builder
->add('title', TextType::class)
- ->add('description', TextareaType::class, [
+ ->add('description', ChillTextareaType::class, [
'required' => false
])
->add('assignee', UserPickerType::class, [
diff --git a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/show.html.twig b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/show.html.twig
index 4f01b6b27..7dc48f058 100644
--- a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/show.html.twig
+++ b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/show.html.twig
@@ -37,7 +37,7 @@
{{"No description"|trans}}
{% else %}
- {{ task.description }}
+ {{ task.description|chill_markdown_to_html }}
{% endif %}
diff --git a/src/Bundle/ChillTaskBundle/Resources/views/Timeline/single_task_transition_person_context.html.twig b/src/Bundle/ChillTaskBundle/Resources/views/Timeline/single_task_transition_person_context.html.twig
index ec0c5195d..234bbc134 100644
--- a/src/Bundle/ChillTaskBundle/Resources/views/Timeline/single_task_transition_person_context.html.twig
+++ b/src/Bundle/ChillTaskBundle/Resources/views/Timeline/single_task_transition_person_context.html.twig
@@ -18,7 +18,7 @@
- {{ 'Description'|trans }}
-
- {{ event.task.description }}
+ {{ event.task.description|chill_markdown_to_html }}
{% endif %}
| |