[ 'onBuildForm', -200 ], RegistrationEvents::HANDLE_FORM => [ 'onHandleForm', -20 // After persisting user ], KernelEvents::REQUEST => 'onKernelRequest' ]; if (class_exists(AdminEvents::class) && defined(AdminEvents::class . '::FILTER_LIST')) { $handlers[AdminEvents::FILTER_LIST] = [ [ 'onFilterListCreateForm', 10 ], [ 'onFilterListFilter', -10 ] ]; } return $handlers; } public function __construct($terms, $tosVersion, CacheItemPoolInterface $cache, EntityManagerInterface $em, TokenStorageInterface $tokenStorage, UrlGeneratorInterface $urlGenerator) { $this->terms = $terms; $this->tosVersion = $tosVersion; $this->cache = $cache; $this->em = $em; $this->tokenStorage = $tokenStorage; $this->urlGenerator = $urlGenerator; } public function onBuildForm(RegistrationFormEvent $event) { $event->getFormBuilder()->add('vl_tos', AcceptTosType::class, [ 'terms' => $this->terms, 'mapped' => false ]); } public function onHandleForm(RegistrationHandleEvent $event) { if ($event->getForm() ->get('vl_tos') ->getData()['accept']) { $user = $event->getForm()->getData(); /* @var $user \App\Entity\User */ $tosUser = new UserTos($user); $tosUser->setAcceptedVersion($this->tosVersion); $this->em->persist($tosUser); $this->cache->deleteItem('version_u_'.$user->getId()); } } private function getAcceptedTosVersion(User $user, $force = false) { $cacheItem = $this->cache->getItem('version_u_'.$user->getId()); if(!$cacheItem->isHit() || $force) { $userTos = $this->em->find(UserTos::class, $user); if($userTos) { $cacheItem->set($userTos->getAcceptedVersion()); } else { $cacheItem->set(null); } $cacheItem->expiresAfter(24*60*60); // One day $this->cache->saveDeferred($cacheItem); } return $cacheItem->get(); } public function onKernelRequest(GetResponseEvent $event) { if (!$event->isMasterRequest()) return; if (!($token = $this->tokenStorage->getToken())) return; if (!($user = $token->getUser())) return; if (!($user instanceof User)) return; if ($token->hasAttribute('vl_tos_accept_ok')) return; if ($this->getAcceptedTosVersion($user) >= $this->tosVersion) { $token->setAttribute('vl_tos_accept_ok', true); return; } if ($event->getRequest()->getRequestFormat() !== 'html') { throw new AccessDeniedHttpException('You need to accept the latest version of the terms of service.'); } switch ($event->getRequest()->attributes->get('_route')) { case 'vl_tos_accept': break; default: $response = RedirectResponse::create($this->urlGenerator->generate('vl_tos_accept')); $event->setResponse($response); } } public function onFilterListCreateForm(FilterListEvent $event) { $event->getSearchFormBuilder()->add('tos_accepted', ChoiceType::class, [ 'choices' => [ 'Yes' => '1', 'No' => '0' ], 'expanded' => true, 'required' => false ]); } public function onFilterListFilter(FilterListEvent $event) { $field = $event->getSearchForm()->get('tos_accepted'); if ($field->isEmpty() || $field->getData() === null) return; $toses = $this->em->createQueryBuilder() ->select('t') ->from(UserTos::class, 't') ->where('t.acceptedVersion >= :currentVersion') ->setParameter('currentVersion', $this->tosVersion) ->groupBy('t.user') ->getQuery() ->getArrayResult(); $userIds = array_map(function ($tos) { return $tos['user_id']; }, $toses); $expr = $field->getData() === "1" ? Criteria::expr()->in('id', $userIds) : Criteria::expr()->notIn('id', $userIds); $event->addFilter('tos_accepted', $expr); } }