Merge branch 'notification/improve' into 'master'

Improve notifications

See merge request Chill-Projet/chill-bundles!294
This commit is contained in:
Julien Fastré 2022-01-24 10:09:57 +00:00
commit 2b47868d88
26 changed files with 385 additions and 97 deletions

View File

@ -12,6 +12,12 @@ and this project adheres to
<!-- write down unreleased development here -->
* [person] name suggestions within create person form when person is created departing from a search input (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/377)
* [notification: formulaire création] descend la box avec la description dans le bas du formulaire
* [notification for activity]: fix link to activity
* [notification] add "URGENT" before accompanying course with emergency = true
* [notification] add a "read more" button on system notification
* [notification] add `[Chill]` in the subject of each notification, automatically
* [notification] add a counter for notification in activity list and accompanying period list, and search results
* [parcours] bugfix if deathdate is not defined (eg. for a thirdparty) parcours is still displayed. Gave error before.
## Test releases

View File

@ -31,6 +31,7 @@ use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use InvalidArgumentException;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
@ -38,8 +39,8 @@ use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Serializer\SerializerInterface;
use function array_key_exists;
final class ActivityController extends AbstractController
@ -471,20 +472,21 @@ final class ActivityController extends AbstractController
public function showAction(Request $request, int $id): Response
{
$view = null;
$entity = $this->activityRepository->find($id);
[$person, $accompanyingPeriod] = $this->getEntity($request);
if (null === $entity) {
throw $this->createNotFoundException('Unable to find Activity entity.');
}
$accompanyingPeriod = $entity->getAccompanyingPeriod();
$person = $entity->getPerson();
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$view = 'ChillActivityBundle:Activity:showAccompanyingCourse.html.twig';
} elseif ($person instanceof Person) {
$view = 'ChillActivityBundle:Activity:showPerson.html.twig';
}
$entity = $this->activityRepository->find($id);
if (null === $entity) {
throw $this->createNotFoundException('Unable to find Activity entity.');
} else {
throw new RuntimeException('the activity should be linked with a period or person');
}
if (null !== $accompanyingPeriod) {
@ -493,8 +495,7 @@ final class ActivityController extends AbstractController
$entity->personsNotAssociated = $entity->getPersonsNotAssociated();
}
// TODO revoir le Voter de Activity pour tenir compte qu'une activité peut appartenir a une période
// $this->denyAccessUnlessGranted('CHILL_ACTIVITY_SEE', $entity);
$this->denyAccessUnlessGranted(ActivityVoter::SEE, $entity);
$deleteForm = $this->createDeleteForm($entity->getId(), $person, $accompanyingPeriod);

View File

@ -1,58 +1,64 @@
{% macro recordAction(activity, context = null, person_id = null, accompanying_course_id = null) %}
{% if no_action is not defined or no_action == false %}
<li>
<a class="btn btn-notify" href="{{ chill_path_add_return_path('chill_main_notification_create', {
'entityClass': 'Chill\\ActivityBundle\\Entity\\Activity',
'entityId': activity.id
}) }}">{{ 'notification.Notify'|trans }}</a>
</li>
{% endif %}
{% if context == 'person' and activity.accompanyingPeriod is not empty %}
{#
Disable person_id in following links, for redirect to accompanyingCourse context
#}
{% set person_id = null %}
{% set accompanying_course_id = activity.accompanyingPeriod.id %}
<li>
<a href="{{ chill_path_add_return_path('chill_activity_activity_list',{
'accompanying_period_id': accompanying_course_id
}) }}"
class="btn btn-primary"
title="{{ 'See activity in accompanying course context'|trans }}">
<i class="fa fa-random fa-fw"></i>
{{ 'Period number %number%'|trans({'%number%': accompanying_course_id}) }}
</a>
</li>
{% endif %}
<li>
<a href="{{ path('chill_activity_activity_show', {'id': activity.id,
'person_id': person_id,
'accompanying_period_id': accompanying_course_id
}) }}"
class="btn btn-show"
title="{{ 'Show'|trans }}"></a>
</li>
{% if no_action is not defined or no_action == false %}
{% if is_granted('CHILL_ACTIVITY_UPDATE', activity) %}
{% if is_granted('CHILL_ACTIVITY_SEE_DETAILS', activity) %}
{% if no_action is not defined or no_action == false %}
{% set notif_counter = chill_count_notifications('Chill\\ActivityBundle\\Entity\\Activity', activity.id) %}
{% if notif_counter.total > 0 %}
<li>{{ chill_counter_notifications('Chill\\ActivityBundle\\Entity\\Activity', activity.id) }}</li>
{% endif %}
<li>
<a href="{{ path('chill_activity_activity_edit', {'id': activity.id,
'person_id': person_id,
'accompanying_period_id': accompanying_course_id
}) }}"
class="btn btn-update"
title="{{ 'Edit'|trans }}"></a>
<a class="btn btn-notify" href="{{ chill_path_add_return_path('chill_main_notification_create', {
'entityClass': 'Chill\\ActivityBundle\\Entity\\Activity',
'entityId': activity.id
}) }}">{{ 'notification.Notify'|trans }}</a>
</li>
{% endif %}
{% if is_granted('CHILL_ACTIVITY_DELETE', activity) %}
{% if context == 'person' and activity.accompanyingPeriod is not empty %}
{#
Disable person_id in following links, for redirect to accompanyingCourse context
#}
{% set person_id = null %}
{% set accompanying_course_id = activity.accompanyingPeriod.id %}
<li>
<a href="{{ path('chill_activity_activity_delete', {'id': activity.id,
'person_id': person_id,
<a href="{{ chill_path_add_return_path('chill_activity_activity_list',{
'accompanying_period_id': accompanying_course_id
}) }}"
class="btn btn-delete"
title="{{ 'Delete'|trans }}"></a>
class="btn btn-primary"
title="{{ 'See activity in accompanying course context'|trans }}">
<i class="fa fa-random fa-fw"></i>
{{ 'Period number %number%'|trans({'%number%': accompanying_course_id}) }}
</a>
</li>
{% endif %}
<li>
<a href="{{ path('chill_activity_activity_show', {'id': activity.id,
'person_id': person_id,
'accompanying_period_id': accompanying_course_id
}) }}"
class="btn btn-show"
title="{{ 'Show'|trans }}"></a>
</li>
{% if no_action is not defined or no_action == false %}
{% if is_granted('CHILL_ACTIVITY_UPDATE', activity) %}
<li>
<a href="{{ path('chill_activity_activity_edit', {'id': activity.id,
'person_id': person_id,
'accompanying_period_id': accompanying_course_id
}) }}"
class="btn btn-update"
title="{{ 'Edit'|trans }}"></a>
</li>
{% endif %}
{% if is_granted('CHILL_ACTIVITY_DELETE', activity) %}
<li>
<a href="{{ path('chill_activity_activity_delete', {'id': activity.id,
'person_id': person_id,
'accompanying_period_id': accompanying_course_id
}) }}"
class="btn btn-delete"
title="{{ 'Delete'|trans }}"></a>
</li>
{% endif %}
{% endif %}
{% endif %}
{% endmacro %}

View File

@ -168,6 +168,7 @@ class ChillMainExtension extends Extension implements
$loader->load('services/timeline.yaml');
$loader->load('services/search.yaml');
$loader->load('services/serializer.yaml');
$loader->load('services/mailer.yaml');
$this->configureCruds($container, $config['cruds'], $config['apis'], $loader);
}

View File

@ -23,6 +23,9 @@ use Symfony\Component\Validator\Constraints as Assert;
* @ORM\Entity
* @ORM\Table(
* name="chill_main_notification",
* indexes={
* @ORM\Index(name="chill_main_notification_related_entity_idx", columns={"relatedentityclass", "relatedentityid"})
* }
* )
* @ORM\HasLifecycleCallbacks
*/

View File

@ -50,7 +50,7 @@ class NotificationMailer
$email = new TemplatedEmail();
$email
->to($dest->getEmail())
->subject('Re: [Chill] ' . $comment->getNotification()->getTitle())
->subject('Re: ' . $comment->getNotification()->getTitle())
->textTemplate('@ChillMain/Notification/email_notification_comment_persist.fr.md.twig')
->context([
'comment' => $comment,
@ -79,11 +79,13 @@ class NotificationMailer
continue;
}
$email = new Email();
$email
->subject($notification->getTitle());
if ($notification->isSystem()) {
$email = new Email();
$email
->text($notification->getMessage())
->subject('[Chill] ' . $notification->getTitle());
->text($notification->getMessage());
} else {
$email = new TemplatedEmail();
$email

View File

@ -15,12 +15,15 @@ use Chill\MainBundle\Entity\Notification;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Repository\NotificationRepository;
use Symfony\Component\Security\Core\Security;
use function array_key_exists;
/**
* Helps to find if a notification exist for a given entity.
*/
class NotificationPresence
{
private array $cache = [];
private NotificationRepository $notificationRepository;
private Security $security;
@ -31,6 +34,29 @@ class NotificationPresence
$this->notificationRepository = $notificationRepository;
}
public function countNotificationsForClassAndEntity(string $relatedEntityClass, int $relatedEntityId): array
{
if (array_key_exists($relatedEntityClass, $this->cache) && array_key_exists($relatedEntityId, $this->cache[$relatedEntityClass])) {
return $this->cache[$relatedEntityClass][$relatedEntityId];
}
$user = $this->security->getUser();
if ($user instanceof User) {
$counter = $this->notificationRepository->countNotificationByRelatedEntityAndUserAssociated(
$relatedEntityClass,
$relatedEntityId,
$user
);
$this->cache[$relatedEntityClass][$relatedEntityId] = $counter;
return $counter;
}
return ['unread' => 0, 'read' => 0];
}
/**
* @return array|Notification[]
*/

View File

@ -23,6 +23,13 @@ class NotificationTwigExtension extends AbstractExtension
'needs_environment' => true,
'is_safe' => ['html'],
]),
new TwigFunction('chill_count_notifications', [NotificationTwigExtensionRuntime::class, 'countNotificationsFor'], [
'is_safe' => [],
]),
new TwigFunction('chill_counter_notifications', [NotificationTwigExtensionRuntime::class, 'counterNotificationFor'], [
'needs_environment' => true,
'is_safe' => ['html'],
]),
];
}
}

View File

@ -24,6 +24,21 @@ class NotificationTwigExtensionRuntime implements RuntimeExtensionInterface
$this->notificationPresence = $notificationPresence;
}
public function counterNotificationFor(Environment $environment, string $relatedEntityClass, int $relatedEntityId, array $options = []): string
{
return $environment->render(
'@ChillMain/Notification/extension_counter_notifications_for.html.twig',
[
'counter' => $this->notificationPresence->countNotificationsForClassAndEntity($relatedEntityClass, $relatedEntityId),
]
);
}
public function countNotificationsFor(string $relatedEntityClass, int $relatedEntityId, array $options = []): array
{
return $this->notificationPresence->countNotificationsForClassAndEntity($relatedEntityClass, $relatedEntityId);
}
public function listNotificationsFor(Environment $environment, string $relatedEntityClass, int $relatedEntityId, array $options = []): string
{
$notifications = $this->notificationPresence->getNotificationsForClassAndEntity($relatedEntityClass, $relatedEntityId);

View File

@ -13,6 +13,7 @@ namespace Chill\MainBundle\Repository;
use Chill\MainBundle\Entity\Notification;
use Chill\MainBundle\Entity\User;
use Doctrine\DBAL\Statement;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
@ -24,6 +25,8 @@ final class NotificationRepository implements ObjectRepository
{
private EntityManagerInterface $em;
private ?Statement $notificationByRelatedEntityAndUserAssociatedStatement = null;
private EntityRepository $repository;
public function __construct(EntityManagerInterface $entityManager)
@ -48,6 +51,30 @@ final class NotificationRepository implements ObjectRepository
->getSingleScalarResult();
}
public function countNotificationByRelatedEntityAndUserAssociated(string $relatedEntityClass, int $relatedEntityId, User $user): array
{
if (null === $this->notificationByRelatedEntityAndUserAssociatedStatement) {
$sql =
'SELECT
SUM((EXISTS (SELECT 1 AS c FROM chill_main_notification_addresses_unread cmnau WHERE user_id = 1812 and cmnau.notification_id = cmn.id))::int) AS unread,
SUM((cmn.sender_id = 1812)::int) AS sent,
COUNT(cmn.*) AS total
FROM chill_main_notification cmn
WHERE relatedentityclass = :relatedEntityClass AND relatedentityid = :relatedEntityId AND sender_id IS NOT NULL';
$this->notificationByRelatedEntityAndUserAssociatedStatement =
$this->em->getConnection()->prepare($sql);
}
$results = $this->notificationByRelatedEntityAndUserAssociatedStatement
->executeQuery(['relatedEntityClass' => $relatedEntityClass, 'relatedEntityId' => $relatedEntityId]);
$result = $results->fetchAssociative();
$results->free();
return $result;
}
public function countUnreadByUser(User $user): int
{
$sql = 'SELECT count(*) AS c FROM chill_main_notification_addresses_unread WHERE user_id = :userId';
@ -153,11 +180,29 @@ final class NotificationRepository implements ObjectRepository
* @return array|Notification[]
*/
public function findNotificationByRelatedEntityAndUserAssociated(string $relatedEntityClass, int $relatedEntityId, User $user): array
{
return
$this->buildQueryNotificationByRelatedEntityAndUserAssociated($relatedEntityClass, $relatedEntityId, $user)
->select('n')
->getQuery()
->getResult();
}
public function findOneBy(array $criteria, ?array $orderBy = null): ?Notification
{
return $this->repository->findOneBy($criteria, $orderBy);
}
public function getClassName()
{
return Notification::class;
}
private function buildQueryNotificationByRelatedEntityAndUserAssociated(string $relatedEntityClass, int $relatedEntityId, User $user): QueryBuilder
{
$qb = $this->repository->createQueryBuilder('n');
$qb
->select('n')
->where($qb->expr()->eq('n.relatedEntityClass', ':relatedEntityClass'))
->andWhere($qb->expr()->eq('n.relatedEntityId', ':relatedEntityId'))
->andWhere($qb->expr()->isNotNull('n.sender'))
@ -171,17 +216,7 @@ final class NotificationRepository implements ObjectRepository
->setParameter('relatedEntityId', $relatedEntityId)
->setParameter('user', $user);
return $qb->getQuery()->getResult();
}
public function findOneBy(array $criteria, ?array $orderBy = null): ?Notification
{
return $this->repository->findOneBy($criteria, $orderBy);
}
public function getClassName()
{
return Notification::class;
return $qb;
}
private function queryByAddressee(User $addressee, bool $countQuery = false): QueryBuilder

View File

@ -62,6 +62,7 @@
{{ c.notification.message|chill_markdown_to_html }}
{% else %}
{{ c.notification.message|u.truncate(250, '…', false)|chill_markdown_to_html }}
<p class="read-more"><a href="{{ chill_path_add_return_path('chill_main_notification_show', {'id': c.notification.id}) }}">{{ 'Read more'|trans }}</a></p>
{% endif %}
</div>
</div>
@ -85,7 +86,13 @@
{% if is_granted('CHILL_MAIN_NOTIFICATION_SEE', c.notification) %}
<li>
<a href="{{ chill_path_add_return_path('chill_main_notification_show', {'id': c.notification.id}) }}"
class="btn btn-show change-icon" title="{{ 'notification.see_comments_thread'|trans }}"><i class="fa fa-comment"></i></a>
class="btn {% if not c.notification.isSystem %}btn-show change-icon{% else %}btn-misc{% endif %}" title="{{ 'notification.see_comments_thread'|trans }}">
{% if not c.notification.isSystem() %}
<i class="fa fa-comment"></i>
{% else %}
{{ 'Read more'|trans }}
{% endif %}
</a>
</li>
{% endif %}
</ul>

View File

@ -21,8 +21,6 @@
{{ form_row(form.title, { 'label': 'notification.subject'|trans }) }}
{{ form_row(form.addressees, { 'label': 'notification.sent_to'|trans }) }}
{% include handler.template(notification) with handler.templateData(notification) %}
<div class="mb-3 row">
<label class="col-form-label col-sm-4" for="notification_message">{{ form_label(form.message) }}</label>
<div class="col-12">
@ -30,6 +28,8 @@
</div>
</div>
{% include handler.template(notification) with handler.templateData(notification) %}
{{ form_end(form) }}
<ul class="record_actions sticky-form-buttons">

View File

@ -0,0 +1,2 @@
{% if counter.total > 0 %}<span class="badge rounded-pill bg-primary">{{ 'notification.counter total notifications'|trans({'total': counter.total }) }}</span>{% endif %}
{% if counter.unread > 0 %}<span class="badge rounded-pill bg-danger">{{ 'notification.counter unread notifications'|trans({'unread': counter.unread })}}</span>{% endif %}

View File

@ -18,7 +18,7 @@
data-notification-id="{{ notification.id }}"
data-notification-current-is-read="{{ notification.isReadBy(app.user) }}"
data-container="notification-status"
data-show-button-url="{{ chill_path_add_return_path('chill_main_notification_show', {'id': notification.id}) }}"
data-show-button-url="{{ chill_path_add_return_path('chill_main_notification_show', {'id': notification.id}, false) }}"
data-button-class="btn-outline-primary"
data-button-text="false"
></span>

View File

@ -0,0 +1,50 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\MainBundle\Service\Mailer;
use Psr\Log\LoggerInterface;
use Symfony\Component\Mailer\Envelope;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\RawMessage;
class ChillMailer implements MailerInterface
{
private LoggerInterface $chillLogger;
private MailerInterface $initial;
private string $prefix = '[Chill] ';
public function __construct(MailerInterface $initial, LoggerInterface $chillLogger)
{
$this->initial = $initial;
$this->chillLogger = $chillLogger;
}
public function send(RawMessage $message, ?Envelope $envelope = null): void
{
if ($message instanceof Email) {
$message->subject($this->prefix . $message->getSubject());
}
$this->chillLogger->info('chill email sent', [
'to' => array_map(static function (Address $address) {
return $address->getAddress();
}, $message->getTo()),
'subject' => $message->getSubject(),
]);
$this->initial->send($message, $envelope);
}
}

View File

@ -0,0 +1,10 @@
services:
_defaults:
autowire: true
autoconfigure: true
Chill\MainBundle\Service\Mailer\:
resource: '../../Service/Mailer'
Chill\MainBundle\Service\Mailer\ChillMailer:
decorates: Symfony\Component\Mailer\MailerInterface

View File

@ -0,0 +1,33 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\Migrations\Main;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20220120155303 extends AbstractMigration
{
public function down(Schema $schema): void
{
$this->addSql('DROP INDEX chill_main_notification_related_entity_idx');
}
public function getDescription(): string
{
return 'Create index for counting notifications';
}
public function up(Schema $schema): void
{
$this->addSql('CREATE INDEX chill_main_notification_related_entity_idx ON chill_main_notification (relatedentityclass, relatedentityid DESC)');
}
}

View File

@ -13,3 +13,19 @@ notification:
few {# notifications}
other {# notifications}
}
counter total notifications: >-
{total, plural,
=0 {Aucune notification}
one {# notification}
few {# notifications}
other {# notifications}
}
counter unread notifications: >-
{unread, plural,
=0 {Aucune non-lue}
one {# non-lue}
few {# non-lues}
other {# non-lues}
}

View File

@ -58,6 +58,7 @@ comment: commentaire
Comment: Commentaire
Pinned comment: Commentaire épinglé
Any comment: Aucun commentaire
Read more: Lire la suite
# comment embeddable
No comment associated: Aucun commentaire

View File

@ -9,19 +9,20 @@
declare(strict_types=1);
namespace Chill\PersonBundle\AccompanyingPeriod\Workflow;
namespace Chill\PersonBundle\AccompanyingPeriod\Events;
use Chill\MainBundle\Entity\Notification;
use Chill\MainBundle\Entity\User;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\Event\LifecycleEventArgs;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Templating\EngineInterface;
use Symfony\Component\Workflow\Event\EnteredEvent;
use Symfony\Contracts\Translation\TranslatorInterface;
class WorkflowEventSubscriber implements EventSubscriberInterface
class UserRefEventSubscriber implements EventSubscriberInterface
{
private EntityManagerInterface $em;
@ -55,23 +56,46 @@ class WorkflowEventSubscriber implements EventSubscriberInterface
}
}
public function postUpdate(AccompanyingPeriod $period, LifecycleEventArgs $args): void
{
if ($period->hasPreviousUser()
&& $period->getUser() !== $this->security->getUser()
&& $period->getStep() !== AccompanyingPeriod::STEP_DRAFT
) {
$this->generateNotificationToUser($period);
}
// we are just out of a flush operation. Launch a new one
$this->em->flush();
}
private function generateNotificationToUser(AccompanyingPeriod $period)
{
$notification = new Notification();
$urgentStatement =
$period->isEmergency() ? strtoupper($this->translator->trans('accompanying_period.emergency')) . ' ' : '';
$notification
->setRelatedEntityId($period->getId())
->setRelatedEntityClass(AccompanyingPeriod::class)
->setTitle($urgentStatement . $this->translator->trans('period_notification.period_designated_subject'))
->setMessage($this->engine->render(
'@ChillPerson/Notification/accompanying_course_designation.md.twig',
[
'accompanyingCourse' => $period,
]
))
->addAddressee($period->getUser());
$this->em->persist($notification);
}
private function onPeriodConfirmed(AccompanyingPeriod $period)
{
if ($period->getUser() instanceof User
&& $period->getUser() !== $this->security->getUser()) {
$notification = new Notification();
$notification
->setRelatedEntityId($period->getId())
->setRelatedEntityClass(AccompanyingPeriod::class)
->setTitle($this->translator->trans('period_notification.period_designated_subject'))
->setMessage($this->engine->render(
'@ChillPerson/Notification/accompanying_course_designation.md.twig',
[
'accompanyingCourse' => $period,
]
))
->addAddressee($period->getUser());
$this->em->persist($notification);
$this->generateNotificationToUser($period);
}
}
}

View File

@ -327,6 +327,13 @@ class AccompanyingPeriod implements
*/
private ?User $user = null;
/**
* Temporary field, which is filled when the user is changed.
*
* Used internally for listener when user change
*/
private ?User $userPrevious = null;
/**
* @ORM\OneToMany(
* targetEntity=AccompanyingPeriodWork::class,
@ -755,6 +762,11 @@ class AccompanyingPeriod implements
return $this->pinnedComment;
}
public function getPreviousUser(): ?User
{
return $this->userPrevious;
}
/**
* @return Collection|SocialAction[] All the descendant social actions of all
* the descendants of the entity
@ -868,6 +880,11 @@ class AccompanyingPeriod implements
return $this->works;
}
public function hasPreviousUser(): bool
{
return null !== $this->userPrevious;
}
/**
* Returns true if the closing date is after the opening date.
*/
@ -1172,6 +1189,10 @@ class AccompanyingPeriod implements
public function setUser(User $user): self
{
if ($this->user !== $user) {
$this->userPrevious = $this->user;
}
$this->user = $user;
return $this;

View File

@ -61,13 +61,13 @@ final class CreationPersonType extends AbstractType
'required' => false,
])
->add('phonenumber', TelType::class, [
'required' => false
'required' => false,
])
->add('mobilenumber', TelType::class, [
'required' => false
'required' => false,
])
->add('email', EmailType::class, [
'required' => false
'required' => false,
]);
if ($this->askCenters) {

View File

@ -131,6 +131,10 @@
{{ 'le ' ~ w.updatedAt|format_datetime('long', 'short') }}
</div>
<ul class="record_actions">
{% set notif_counter = chill_count_notifications('Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWork', w.id) %}
{% if notif_counter.total > 0 %}
<li>{{ chill_counter_notifications('Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWork', w.id) }}</li>
{% endif %}
<li>
<a class="btn btn-edit" title="{{ 'Edit'|trans }}"
href="{{ chill_path_add_return_path('chill_person_accompanying_period_work_edit', { 'id': w.id }) }}"

View File

@ -5,6 +5,10 @@
{% macro recordAction(period, contextEntity) %}
{# TODO if enable_accompanying_course_with_multiple_persons is true ... #}
{% set notif_counter = chill_count_notifications('Chill\\PersonBundle\\Entity\\AccompanyingPeriod', period.id) %}
{% if notif_counter.total > 0 %}
<li>{{ chill_counter_notifications('Chill\\PersonBundle\\Entity\\AccompanyingPeriod', period.id) }}</li>
{% endif %}
<li>
<a href="{{ path('chill_person_accompanying_course_index', { 'accompanying_period_id': period.id }) }}"
class="btn btn-show" title="{{ 'See accompanying period'|trans }}">{# {{ 'See this period'|trans }} #}</a>

View File

@ -118,6 +118,10 @@
{{ 'File number'|trans }} {{ acp.id }}
</div>
{% set notif_counter = chill_count_notifications('Chill\\PersonBundle\\Entity\\AccompanyingPeriod', acp.id) %}
{% if notif_counter.total > 0 %}
<div class="counter">{{ chill_counter_notifications('Chill\\PersonBundle\\Entity\\AccompanyingPeriod', acp.id) }}</div>
{% endif %}
</div>
<div class="wl-col list">

View File

@ -20,9 +20,19 @@ services:
Chill\PersonBundle\AccompanyingPeriod\Suggestion\ReferralsSuggestionInterface: '@Chill\PersonBundle\AccompanyingPeriod\Suggestion\ReferralsSuggestion'
Chill\PersonBundle\AccompanyingPeriod\Workflow\:
resource: './../../AccompanyingPeriod/Workflow'
Chill\PersonBundle\AccompanyingPeriod\Events\:
resource: './../../AccompanyingPeriod/Events'
autowire: true
autoconfigure: true
Chill\PersonBundle\AccompanyingPeriod\Events\UserRefEventSubscriber:
autowire: true
autoconfigure: true
tags:
- # these are the options required to define the entity listener
name: 'doctrine.orm.entity_listener'
event: 'postUpdate'
entity: 'Chill\PersonBundle\Entity\AccompanyingPeriod'
# set the 'lazy' option to TRUE to only instantiate listeners when they are used
lazy: true