diff --git a/docs/source/development/embeddable-comments.rst b/docs/source/development/embeddable-comments.rst new file mode 100644 index 000000000..e14e8e84b --- /dev/null +++ b/docs/source/development/embeddable-comments.rst @@ -0,0 +1,121 @@ + +.. Copyright (C) 2016 Champs Libres Cooperative SCRLFS + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.3 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + A copy of the license is included in the section entitled "GNU + Free Documentation License". + + +Embeddable comments +################### + +Those embeddable comments is a comment with some metadata: + +* the one who updated the comment (the comment itself, and not the whole entity); +* the date and time for the last update (again, the comment itself, and not the whole entity). + +We make usage of `embeddables `_. + +Embed the comment +================= + +The comment may be embedded into the entity: + +.. code-block:: php + + namespace Chill\ActivityBundle\Entity; + + use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable; + use Doctrine\ORM\Mapping as ORM; + + /** + * Class Activity + * + * @ORM\Entity() + */ + class Activity + { + /** + * @var integer + * + * @ORM\Id + * @ORM\Column(name="id", type="integer") + * @ORM\GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * @ORM\Embedded(class="Chill\MainBundle\Entity\Embeddable\CommentEmbeddable", columnPrefix="comment_") + */ + private $comment; + + + /** + * @return \Chill\MainBundle\Entity\Embeddalbe\CommentEmbeddable + */ + public function getComment() + { + return $this->comment; + } + + /** + * @param \Chill\MainBundle\Entity\Embeddalbe\CommentEmbeddable $comment + */ + public function setComment($comment) + { + $this->comment = $comment; + } + } + +Note on relation to :class:`User` +================================= + +The embeddable proposed by Doctrine does not support relationship to other entities. The entity Comment is able to render a user's id, but not an User object. + + +.. code-block:: php + + $activity->getComment()->getUserId(); // return user id of the last author + + $activity->getComment()->getUser(); // does not work ! + + +Usage into form +=============== + +Use the :class:`Chill\MainBundle\Form\Type\CommentType` to load the form widget: + +.. code-block:: php + + namespace Chill\ActivityBundle\Form; + + use Chill\MainBundle\Form\Type\CommentType; + use Symfony\Component\Form\AbstractType; + use Symfony\Component\Form\FormBuilderInterface; + + class ActivityType extends AbstractType + { + /** + * @param FormBuilderInterface $builder + * @param array $options + */ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder + ->add('comment', CommentType::class, [ + 'required' => false, + ]) + ; + } + } + +Render the comment +================== + +.. code-block:: twig + + {{ activity.comment|chill_entity_render_box }} + + diff --git a/docs/source/development/index.rst b/docs/source/development/index.rst index b5d39e166..04f91ede1 100644 --- a/docs/source/development/index.rst +++ b/docs/source/development/index.rst @@ -29,6 +29,7 @@ As Chill rely on the `symfony `_ framework, reading the fram Searching Timelines Exports + Embeddable comments Testing Useful snippets manual/index.rst @@ -40,6 +41,7 @@ Layout and UI .. toctree:: :maxdepth: 2 + Render entities automatically Layout / Template usage Classes and mixins Widgets diff --git a/docs/source/development/render-entity.rst b/docs/source/development/render-entity.rst new file mode 100644 index 000000000..bfc579682 --- /dev/null +++ b/docs/source/development/render-entity.rst @@ -0,0 +1,154 @@ + +Rendering entity automatically +############################## + +Some entity need to be rendered automatically for a couple of times: a person, a user, ... + +One can use some twig filter to render those entities: + +.. code-block:: twig + + {{ person|chill_entity_render_box }} + +Define a renderer +================= + +By default, the object passed through the renderer will be rendered using the :code:`__toString()` method. To customize this behaviour, you have to define a service and tag it using :code:`chill.render_entity`. + +The rendered is implemented using :class:`Chill\MainBundle\Templating\Entity\ChillEntityRenderInterface`. This interface has 3 methods: + +* :code:`public function supports($entity, array $options): bool`: return true if the :code:`$entity` given in parameter, with custom options, is supported by this renderer; +* :code:`public function renderString($entity, array $options): string`: render the entity as a single string, for instance in a select list; +* :code:`public function renderBox($entity, array $options): string`: render the entity in an html box. + +.. warning:: + + The HTML returned by :code:`renderBox` **MUST BE SAFE** of any XSS injection. + +:class:`Chill\MainBundle\Templating\Entity\AbstractChillEntityRender` provides some useful methods to get the opening and closing boxes that should be used. + +Usage about rendering comment: + +.. code-block:: php + + namespace Chill\MainBundle\Templating\Entity; + + use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable; + use Chill\MainBundle\Repository\UserRepository; + use Chill\MainBundle\Templating\Entity\AbstractChillEntityRender; + use Symfony\Component\Templating\EngineInterface; + + class CommentRender extends AbstractChillEntityRender + { + /** + * @var \Chill\MainBundle\Repository\UserRepository + */ + private $userRepository; + + /** + * + * @var EngineInterface + */ + private $engine; + + public function __construct( + UserRepository $userRepository, + EngineInterface $engine + ) { + $this->userRepository = $userRepository; + $this->engine = $engine; + } + + /** + * @param CommentEmbeddable $entity + * @param array $options + * + * @return string + */ + public function renderBox($entity, array $options): string + { + // default options + $options = \array_merge([ + 'user' => [], + 'disable_markdown' => false, + 'limit_lines' => null, + 'metadata' => true + ], $options); + + if ($entity->getUserId()) { + $user = $this->userRepository->find($entity->getUserId()); + } + + 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 + ] + ); + } + + /** + * @param CommentEmbeddable $entity + * @param array $options + * + * @return string + */ + public function renderString($entity, array $options): string + { + return $entity->getComment(); + } + + public function supports($entity, array $options): bool + { + return $entity instanceof CommentEmbeddable; + } + } + +Logic inside the template: + +.. code-block:: twig + + {{ opening_box|raw }} +
+ {# logic for rendering #} +
+ {{ closing_box|raw }} + +Usage in templates +================== + +For rendering entity as a box: + +.. code-block:: twig + + {{ entity|chill_entity_render_box }} + +For rendering entity as a string: + +.. code-block:: twig + + {{ entity|chill_entity_render_string }} + +Available renderer and options +============================== + +:code:`Person` (Person Bundle) +------------------------------ + +* no options + +:code:`CommentEmbeddable` (Main Bundle) +--------------------------------------- + +Options: + +* :code:`user`: options which will be passed to "user" renderer +* :code:`disable_markdown`: disable markdown renderer, default to :code:`FALSE` +* :code:`limit_lines` (integer) limit the number of lines. Default to :code:`NULL`. May be an integer. +* :code:`metadata` (boolean): show the last updating user and last updating date. Default to :code:`TRUE`. + 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/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 1e03bc527..1e8573f2f 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/main.js +++ b/src/Bundle/ChillMainBundle/Resources/public/main.js @@ -36,6 +36,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.scss b/src/Bundle/ChillMainBundle/Resources/public/modules/ckeditor5/index.scss index 3e5259af4..5fceab7bc 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/modules/ckeditor5/index.scss +++ b/src/Bundle/ChillMainBundle/Resources/public/modules/ckeditor5/index.scss @@ -1,4 +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/sass/modules/_forms.scss b/src/Bundle/ChillMainBundle/Resources/public/sass/modules/_forms.scss index b01c802b6..dcffddec9 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/sass/modules/_forms.scss +++ b/src/Bundle/ChillMainBundle/Resources/public/sass/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['limit_lines'] is not null -%} + {% set content = comment.comment|split('\n')|slice(0, options['limit_lines'])|join('\n') %} + {%- else -%} + {% set content = comment.comment %} + {%- endif -%} + +
+ {% if options['disable_markdown'] %} + {{ content|nl2br }} + {% else %} + {{ content|chill_markdown_to_html }} + {% endif %} +
+
+
+{% if options['metadata'] %} + +{% endif %} +{{ closing_box|raw }} \ No newline at end of file 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'). - ''. - nl2br($entity->getComment()). - ''; - - if ($entity->getDate() instanceof \DateTime) { - $str .= ''. - $entity->getDate()->format('d/m/Y H:i'); - ''; - } - - if (strlen($username) > 0) { - $str .= ''. - $username. - ''; - } - - $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/config/services/templating.yaml b/src/Bundle/ChillMainBundle/config/services/templating.yaml index f9bd8d7fb..29dc676d1 100644 --- a/src/Bundle/ChillMainBundle/config/services/templating.yaml +++ b/src/Bundle/ChillMainBundle/config/services/templating.yaml @@ -34,6 +34,7 @@ services: Chill\MainBundle\Templating\Entity\CommentRender: arguments: - '@chill.main.user_repository' + - '@Symfony\Component\Templating\EngineInterface' tags: - { name: 'chill.render_entity' } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20210308111926.php b/src/Bundle/ChillMainBundle/migrations/Version20210308111926.php index 368a3dec8..fa4f001bb 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20210308111926.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20210308111926.php @@ -1,6 +1,6 @@ , * * 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,7 @@ 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; /** @@ -63,48 +65,38 @@ class AccompanyingPeriodController extends AbstractController $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() ]); @@ -114,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(); @@ -124,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!')); @@ -136,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')); @@ -196,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); @@ -247,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') @@ -267,6 +267,7 @@ class AccompanyingPeriodController extends AbstractController ->add('info', $error->getMessage()); } } + } else { //if form is not valid $this->get('session')->getFlashBag() ->add('error', @@ -281,39 +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) + private function _validatePerson(Person $person): ConstraintViolationListInterface { $errors = $this->validator->validate($person, null, - array('Default')); + ['Default']); - $errors_accompanying_period = $this->validator->validate($person, null, - array('accompanying_period_consistent')); - - 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, @@ -324,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); @@ -348,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') @@ -368,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(); @@ -405,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); @@ -415,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) @@ -430,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/PersonController.php b/src/Bundle/ChillPersonBundle/Controller/PersonController.php index f9fb98849..db2b8b9d1 100644 --- a/src/Bundle/ChillPersonBundle/Controller/PersonController.php +++ b/src/Bundle/ChillPersonBundle/Controller/PersonController.php @@ -52,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 @@ -128,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, @@ -301,7 +300,7 @@ class PersonController extends AbstractController $r->setStatusCode(400); return $r; } - + $form = $this->createForm( //CreationPersonType::NAME, CreationPersonType::class, @@ -314,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 be1be8124..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\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 Chill\MainBundle\Form\Type\ChillTextareaType; +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,13 +83,13 @@ 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', ChillTextareaType::class, array('required' => false)) @@ -104,11 +107,25 @@ class PersonType extends AbstractType 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 45c8cd1ed..796a7f82e 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/Person/view.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/Person/view.html.twig @@ -227,6 +227,17 @@ This view should receive those arguments:
    {% 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 }} :
    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 %}