diff --git a/Controller/TaskController.php b/Controller/TaskController.php index 0648225f0..bd3ab33a2 100644 --- a/Controller/TaskController.php +++ b/Controller/TaskController.php @@ -46,8 +46,8 @@ class TaskController extends Controller ->find($taskId) ; $defaultReturnPath = $this->generateUrl( - 'chill_task_task_list_by_person', - [ 'personId' => $task->getPerson() ] + 'chill_task_singletask_list', + [ 'person_id' => $task->getPerson() ] ); break; default: diff --git a/DependencyInjection/ChillTaskExtension.php b/DependencyInjection/ChillTaskExtension.php index 31dcd3d4a..acc4257a1 100644 --- a/DependencyInjection/ChillTaskExtension.php +++ b/DependencyInjection/ChillTaskExtension.php @@ -31,6 +31,7 @@ class ChillTaskExtension extends Extension implements PrependExtensionInterface $loader->load('services/repositories.yml'); $loader->load('services/workflow.yml'); $loader->load('services/templating.yml'); + $loader->load('services/menu.yml'); } public function prepend(ContainerBuilder $container) diff --git a/DependencyInjection/Compiler/TaskWorkflowDefinitionCompilerPass.php b/DependencyInjection/Compiler/TaskWorkflowDefinitionCompilerPass.php index fb1a9e2aa..81d387922 100644 --- a/DependencyInjection/Compiler/TaskWorkflowDefinitionCompilerPass.php +++ b/DependencyInjection/Compiler/TaskWorkflowDefinitionCompilerPass.php @@ -21,6 +21,7 @@ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Chill\TaskBundle\Workflow\TaskWorkflowManager; use Symfony\Component\DependencyInjection\Reference; +use Chill\TaskBundle\Templating\UI\CountNotificationTask; /** * @@ -37,6 +38,7 @@ class TaskWorkflowDefinitionCompilerPass implements CompilerPassInterface } $workflowManagerDefinition = $container->getDefinition(TaskWorkflowManager::class); + $counterDefinition = $container->getDefinition(CountNotificationTask::class); foreach ($container->findTaggedServiceIds('chill_task.workflow_definition') as $id => $tags) { // registering the definition to manager @@ -50,6 +52,12 @@ class TaskWorkflowDefinitionCompilerPass implements CompilerPassInterface 'method' => 'onTaskStateEntered', 'priority' => -255 ]); + $counterDefinition + ->addTag('kernel.event_listener', [ + 'event' => sprintf('workflow.%s.entered', $definition->getClass()::getAssociatedWorkflowName()), + 'method' => 'resetCacheOnNewStates', + 'priority' => 0 + ]); } } } diff --git a/Menu/UserMenuBuilder.php b/Menu/UserMenuBuilder.php new file mode 100644 index 000000000..6e0319b61 --- /dev/null +++ b/Menu/UserMenuBuilder.php @@ -0,0 +1,77 @@ + + * + * 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\TaskBundle\Menu; + +use Chill\MainBundle\Routing\LocalMenuBuilderInterface; +use Knp\Menu\MenuItem; +use Chill\TaskBundle\Templating\UI\CountNotificationTask; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Chill\TaskBundle\Repository\SingleTaskRepository; + +/** + * + * + * @author Julien Fastré + */ +class UserMenuBuilder implements LocalMenuBuilderInterface +{ + + /** + * + * @var CountNotificationTask + */ + public $counter; + + /* + * @var TokenStorageInterface + */ + public $tokenStorage; + + public function __construct( + CountNotificationTask $counter, + TokenStorageInterface $tokenStorage + ) { + $this->counter = $counter; + $this->tokenStorage = $tokenStorage; + } + + public static function getMenuIds(): array + { + return [ 'user' ]; + } + + public function buildMenu($menuId, MenuItem $menu, array $parameters) + { + if ($this->counter->countNotification($this->tokenStorage->getToken() + ->getUser()) > 0) { + $menu->addChild('Task near deadlines', [ + 'route' => 'chill_task_singletask_list', + 'routeParameters' => [ + 'user_id' => $this->tokenStorage + ->getToken() + ->getUser() + ->getId(), + 'status' => [ + SingleTaskRepository::DATE_STATUS_WARNING, + SingleTaskRepository::DATE_STATUS_ENDED + ] + ] + ]); + } + } +} diff --git a/Repository/SingleTaskRepository.php b/Repository/SingleTaskRepository.php index 9f7d0f0c5..4c802d3d5 100644 --- a/Repository/SingleTaskRepository.php +++ b/Repository/SingleTaskRepository.php @@ -48,7 +48,7 @@ class SingleTaskRepository extends \Doctrine\ORM\EntityRepository * @param User $currentUser * @return int */ - public function countByParameters($params, User $currentUser) + public function countByParameters($params, User $currentUser = null) { $qb = $this->createQueryBuilder('st') ->select('COUNT(st)'); @@ -97,9 +97,11 @@ class SingleTaskRepository extends \Doctrine\ORM\EntityRepository ; } - protected function buildQuery(QueryBuilder $qb, $params, User $currentUser) + protected function buildQuery(QueryBuilder $qb, $params, User $currentUser = null) { - $this->buildACLQuery($qb, $currentUser); + if (NULL !== $currentUser) { + $this->buildACLQuery($qb, $currentUser); + } if (\array_key_exists('person', $params) and !empty($params['person'])) { $qb->andWhere($qb->expr()->eq('st.person', ':person')); diff --git a/Resources/config/services/menu.yml b/Resources/config/services/menu.yml new file mode 100644 index 000000000..7c15d2aae --- /dev/null +++ b/Resources/config/services/menu.yml @@ -0,0 +1,7 @@ +services: + Chill\TaskBundle\Menu\UserMenuBuilder: + arguments: + $tokenStorage: '@Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface' + $counter: '@Chill\TaskBundle\Templating\UI\CountNotificationTask' + tags: + - { name: 'chill.menu_builder' } diff --git a/Resources/config/services/templating.yml b/Resources/config/services/templating.yml index dca4e36f6..401bef6d5 100644 --- a/Resources/config/services/templating.yml +++ b/Resources/config/services/templating.yml @@ -4,3 +4,10 @@ services: $taskWorkflowManager: '@Chill\TaskBundle\Workflow\TaskWorkflowManager' tags: - { name: 'twig.extension' } + + Chill\TaskBundle\Templating\UI\CountNotificationTask: + arguments: + $singleTaskRepository: '@Chill\TaskBundle\Repository\SingleTaskRepository' + $cachePool: '@cache.user_data' + tags: + - { name: chill.count_notification.user } diff --git a/Templating/UI/CountNotificationTask.php b/Templating/UI/CountNotificationTask.php new file mode 100644 index 000000000..76a350ae2 --- /dev/null +++ b/Templating/UI/CountNotificationTask.php @@ -0,0 +1,108 @@ + + * + * 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\TaskBundle\Templating\UI; + +use Chill\MainBundle\Templating\UI\NotificationCounterInterface; +use Chill\MainBundle\Entity\User; +use Chill\TaskBundle\Repository\SingleTaskRepository; +use Psr\Cache\CacheItemPoolInterface; +use Symfony\Component\Workflow\Event\Event; + +/** + * + * + * @author Julien Fastré + */ +class CountNotificationTask implements NotificationCounterInterface +{ + /** + * + * @var SingleTaskRepository + */ + protected $singleTaskRepository; + + /** + * + * @var CacheItempPoolInterface + */ + protected $cachePool; + + const CACHE_KEY = 'chill_task.count_notifications.user.%d'; + + public function __construct( + SingleTaskRepository $singleTaskRepository, + CacheItemPoolInterface $cachePool + ) { + $this->singleTaskRepository = $singleTaskRepository; + $this->cachePool = $cachePool; + } + + public function countNotification(User $u): int + { + $sumCache = $this->cachePool->getItem($this->getCacheKey($u)); + + if ($sumCache->isHit()) { + return $sumCache->get(); + } + + $params = [ + 'user' => $u, + 'is_closed' => false + ]; + + $sum = 0; + + foreach ([ + SingleTaskRepository::DATE_STATUS_ENDED, + SingleTaskRepository::DATE_STATUS_WARNING] as $status) { + + $sum += $this->singleTaskRepository->countByParameters( + \array_merge($params, [ 'date_status' => $status ]) + ); + } + + $sumCache->set($sum); + $this->cachePool->save($sumCache); + + return $sum; + } + + public function addNotification(User $u): int + { + return $this->countNotification($u); + } + + public function resetCacheOnNewStates(Event $e) + { + /* @var $task \Chill\TaskBundle\Entity\SingleTask */ + $task = $e->getSubject(); + + if (NULL !== $task->getAssignee()) { + $sumCache = $this->cachePool->getItem($this->getCacheKey($task->getAssignee())); + + if ($sumCache->isHit()) { + $this->cachePool->deleteItem($this->getCacheKey($task->getAssignee())); + } + } + } + + private function getCacheKey(User $u) + { + return sprintf(self::CACHE_KEY, $u->getId()); + } +} diff --git a/Workflow/TaskWorkflowManager.php b/Workflow/TaskWorkflowManager.php index ceeffc29a..1b74da21c 100644 --- a/Workflow/TaskWorkflowManager.php +++ b/Workflow/TaskWorkflowManager.php @@ -89,7 +89,5 @@ class TaskWorkflowManager implements SupportStrategyInterface $definition = $this->getTaskWorkflowDefinition($task); $task->setClosed($definition->isClosed($task)); - - dump($task); } }