em = $em; $this->user = $tokenStorage->getToken()->getUser(); $this->helper = $helper; $this->paginatorFactory = $paginatorFactory; $this->personSearch = $personSearch; // throw an error if user is not a valid user if (!$this->user instanceof \Chill\MainBundle\Entity\User) { throw new \LogicException('The user provided must be an instance' . ' of Chill\MainBundle\Entity\User'); } } /* * (non-PHPdoc) * @see \Chill\MainBundle\Search\SearchInterface::getOrder() */ public function getOrder() { return 200; } /* * (non-PHPdoc) * @see \Chill\MainBundle\Search\SearchInterface::isActiveByDefault() */ public function isActiveByDefault() { return true; } public function supports($domain, $format) { return 'person' === $domain; } /** * @param array $terms * @param int $start * @param int $limit * @param array $options * @param string $format * @return array */ public function renderResult(array $terms, $start = 0, $limit = 50, array $options = array(), $format = 'html') { $total = $this->count($terms); $paginator = $this->paginatorFactory->create($total); if ($format === 'html') { if ($total !== 0) { return $this->container->get('templating')->render('ChillPersonBundle:Person:list.html.twig', array( 'persons' => $this->search($terms, $start, $limit, $options), 'pattern' => $this->recomposePattern($terms, array('nationality', 'firstname', 'lastname', 'birthdate', 'gender', 'birthdate-before','birthdate-after'), $terms['_domain']), 'total' => $total, 'start' => $start, 'search_name' => self::NAME, 'preview' => $options[SearchInterface::SEARCH_PREVIEW_OPTION], 'paginator' => $paginator, 'title' => "Similar persons" )); } else { return null; } } elseif ($format === 'json') { return [ 'results' => $this->search($terms, $start, $limit, \array_merge($options, [ 'simplify' => true ])), 'pagination' => [ 'more' => $paginator->hasNextPage() ] ]; } } /** * * @param string $pattern * @param int $start * @param int $limit * @param array $options * @return Person[] */ protected function search(array $terms, $start, $limit, array $options = array()) { $qb = $this->createQuery($terms, 'search'); if ($options['simplify'] ?? false) { $qb->select( 'sp.id', $qb->expr()->concat( 'sp.firstName', $qb->expr()->literal(' '), 'sp.lastName' ).'AS text' ); } else { $qb->select('sp'); } $qb ->setMaxResults($limit) ->setFirstResult($start); //order by firstname, lastname $qb ->orderBy('sp.firstName') ->addOrderBy('sp.lastName'); if ($options['simplify'] ?? false) { return $qb->getQuery()->getResult(Query::HYDRATE_ARRAY); } else { return $qb->getQuery()->getResult(); } } protected function count(array $terms) { $qb = $this->createQuery($terms); $qb->select('COUNT(sp.id)'); return $qb->getQuery()->getSingleScalarResult(); } private $_cacheQuery = array(); /** * * @param array $terms * @return \Doctrine\ORM\QueryBuilder */ protected function createQuery(array $terms) { //get from cache $cacheKey = md5(serialize($terms)); if (array_key_exists($cacheKey, $this->_cacheQuery)) { return clone $this->_cacheQuery[$cacheKey]; } $qb = $this->em->createQueryBuilder(); $qb ->select('sp') ->from('ChillPersonBundle:Person', 'sp'); if ($terms['_default'] !== '') { $grams = explode(' ', $terms['_default']); foreach($grams as $key => $gram) { $qb->andWhere('SIMILARITY(sp.fullnameCanonical, UNACCENT(LOWER(:default_'.$key.')) ) >= 0.15') ->setParameter('default_'.$key, '%'.$gram.'%'); } $qb->andWhere($qb->expr() ->notIn( 'sp.id', $this->personSearch ->createQuery($terms) ->addSelect('p.id') ->getDQL() ) ); } //restraint center for security $reachableCenters = $this->helper->getReachableCenters($this->user, new Role('CHILL_PERSON_SEE')); $qb->andWhere($qb->expr() ->in('sp.center', ':centers')) ->setParameter('centers', $reachableCenters) ; $this->_cacheQuery[$cacheKey] = $qb; return clone $qb; } }