mirror of
				https://gitlab.com/Chill-Projet/chill-bundles.git
				synced 2025-11-03 18:58:24 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			266 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			266 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
namespace Chill\PersonBundle\Search;
 | 
						|
 | 
						|
 | 
						|
use Chill\MainBundle\Pagination\PaginatorFactory;
 | 
						|
use Chill\MainBundle\Search\AbstractSearch;
 | 
						|
use Chill\MainBundle\Search\SearchInterface;
 | 
						|
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
 | 
						|
use Doctrine\ORM\EntityManagerInterface;
 | 
						|
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
 | 
						|
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
 | 
						|
use Symfony\Component\Form\FormBuilderInterface;
 | 
						|
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
 | 
						|
use Symfony\Component\Security\Core\Role\Role;
 | 
						|
 | 
						|
/**
 | 
						|
 * Class SimilarityPersonSearch
 | 
						|
 *
 | 
						|
 * @package Chill\PersonBundle\Search
 | 
						|
 */
 | 
						|
class SimilarityPersonSearch extends AbstractSearch
 | 
						|
{
 | 
						|
    
 | 
						|
    use ContainerAwareTrait;
 | 
						|
    
 | 
						|
    /**
 | 
						|
     *
 | 
						|
     * @var EntityManagerInterface
 | 
						|
     */
 | 
						|
    private $em;
 | 
						|
    
 | 
						|
    /**
 | 
						|
     *
 | 
						|
     * @var \Chill\MainBundle\Entity\User
 | 
						|
     */
 | 
						|
    private $user;
 | 
						|
    
 | 
						|
    /**
 | 
						|
     *
 | 
						|
     * @var AuthorizationHelper
 | 
						|
     */
 | 
						|
    private $helper;
 | 
						|
    
 | 
						|
    /**
 | 
						|
     *
 | 
						|
     * @var PaginatorFactory
 | 
						|
     */
 | 
						|
    protected $paginatorFactory;
 | 
						|
    
 | 
						|
    const NAME = "person_similarity";
 | 
						|
    
 | 
						|
    /**
 | 
						|
     *
 | 
						|
     * @var PersonSearch
 | 
						|
     */
 | 
						|
    private $personSearch;
 | 
						|
    
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * SimilarityPersonSearch constructor.
 | 
						|
     *
 | 
						|
     * @param EntityManagerInterface $em
 | 
						|
     * @param TokenStorage $tokenStorage
 | 
						|
     * @param AuthorizationHelper $helper
 | 
						|
     * @param PaginatorFactory $paginatorFactory
 | 
						|
     * @param PersonSearch $personSearch
 | 
						|
     */
 | 
						|
    public function __construct(
 | 
						|
        EntityManagerInterface $em,
 | 
						|
        TokenStorage $tokenStorage,
 | 
						|
        AuthorizationHelper $helper,
 | 
						|
        PaginatorFactory $paginatorFactory,
 | 
						|
        PersonSearch $personSearch)
 | 
						|
    {
 | 
						|
        $this->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;
 | 
						|
    }
 | 
						|
    
 | 
						|
} |