123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486 |
- <?php
-
- namespace Muzich\CoreBundle\Searcher;
-
- use Doctrine\ORM\EntityManager;
- use Doctrine\ORM\QueryBuilder;
- use Doctrine\ORM\Query\Expr\Join;
-
- class ElementSearcherQueryBuilder
- {
-
- /**
- *
- * @var \Doctrine\ORM\EntityManager
- */
- protected $em;
-
- protected $user_id;
-
- /**
- *
- * @var array
- */
- protected $parameters_ids = array();
-
- /**
- *
- * @var array
- */
- protected $parameters_elements = array();
-
- /**
- *
- * @var ElementSearcher
- */
- protected $es;
-
- /**
- *
- * @var QueryBuilder
- */
- protected $query_ids;
-
- /**
- *
- * @var QueryBuilder
- */
- protected $query_elements;
-
- /**
- *
- * @var array
- */
- protected $builder_params = array();
-
- /**
- *
- * @param EntityManager $em
- * @param ElementSearcher $es
- */
- public function __construct(EntityManager $em, ElementSearcher $es, $user_id, $builder_params = array())
- {
- $this->em = $em;
- $this->es = $es;
- $this->user_id = $user_id;
- $this->builder_params = $builder_params;
- }
-
- private function buildTags()
- {
- if (count($tags = $this->es->getTags()))
- {
- // Un truc pas propre fait que des fois (quand ajax on dirais)
- // on a du string a la place du tableau
- if (!is_array($tags))
- {
-
- $tags_decoded = json_decode($tags);
- $tags = array();
- foreach ($tags_decoded as $tag_id)
- {
- $tags[$tag_id] = $tag_id;
- }
- }
-
-
- if (count($tags))
- {
- $str_or = $this->query_ids->expr()->orx();
- $this->query_ids->leftJoin('e.tags', 't');
- foreach ($tags as $tag_id => $tag_name)
- {
- $str_or->add($this->query_ids->expr()->eq('t.id', ":itag".$tag_id));
- $this->parameters_ids["itag".$tag_id] = $tag_id;
- }
-
- $this->query_ids->andWhere($str_or);
- }
-
- }
- }
-
- private function buildString()
- {
- if (($string = $this->es->getString()))
- {
- // On prépare notre liste de mots
- $words = array_unique(array_merge(
- explode(' ', $string),
- explode('-', $string),
- explode('- ', $string),
- explode(' -', $string),
- explode(' - ', $string),
- explode(',', $string),
- explode(', ', $string),
- explode(' ,', $string),
- explode(' , ', $string)
- ));
-
- // On récupère les ids des elements correspondants
- $word_min_length = 0;
- if (isset($this->builder_params['word_min_length']))
- {
- $word_min_length = $this->builder_params['word_min_length'];
- }
-
- // On prépare un sous-where avec des or
- $str_or = $this->query_ids->expr()->orx();
-
- foreach ($words as $i => $word)
- {
- if (strlen($word) >= $word_min_length)
- {
- // On ajoute un or pour chaque mots
- $str_or->add($this->query_ids->expr()->like('UPPER(e.name)', ":str".$i));
- $this->parameters_ids['str'.$i] = '%'.strtoupper($word).'%';
- }
- }
-
- $this->query_ids->andWhere($str_or);
- }
- }
-
- private function buildNetwork()
- {
- if ($this->es->getNetwork() == ElementSearcher::NETWORK_PERSONAL && $this->user_id)
- {
- $this->query_ids
- ->join('e.owner', 'o')
- ->leftJoin('e.group', 'g')
- ->leftJoin('o.followers_users', 'f')
- ->leftJoin('g.followers', 'gf')
- ;
-
- $this->query_ids->andWhere('f.follower = :userid OR gf.follower = :useridg');
- $this->parameters_ids['userid'] = $this->user_id;
- $this->parameters_ids['useridg'] = $this->user_id;
- }
- }
-
- private function buildFavorite()
- {
- if ($this->es->isFavorite())
- {
- if (($favorite_user_id = $this->es->getUserId()) && !$this->es->getGroupId())
- {
- $this->query_ids->leftJoin('e.elements_favorites', 'fav2');
- $this->query_ids->andWhere('fav2.user = :fuid');
- $this->parameters_ids['fuid'] = $favorite_user_id;
- }
- else if (($favorite_group_id = $this->es->getGroupId()) && !$this->es->getUserId())
- {
- // TODO: Faire en sorte que ça affiche les favoris des gens suivant
- // le groupe
- }
- else
- {
- throw new Exception('For use favorite search element, you must specify an user_id or group_id');
- }
- }
- }
-
- private function buildUserAndGroup()
- {
- // (flou) Si on recherche les élements d'un user
- if (($search_user_id = $this->es->getUserId()) && !$this->es->isFavorite())
- {
- $this->query_ids->andWhere('e.owner = :suid');
- $this->parameters_ids['suid'] = $search_user_id;
- }
-
- // (flou) Si on recherche les éléments d'un groupe
- if (($search_group_id = $this->es->getGroupId()) && !$this->es->isFavorite())
- {
- $this->query_ids->andWhere('e.group = :sgid');
- $this->parameters_ids['sgid'] = $search_group_id;
- }
- }
-
- private function buildLimits()
- {
- // Si id_limit est précisé c'est que l'on demande "la suite" ou "les nouveaux"
- if (($id_limit = $this->es->getIdLimit()) && !$this->es->isSearchingNew())
- {
- $this->query_ids->andWhere("e.id < :id_limit");
- $this->parameters_ids['id_limit'] = $id_limit;
- }
- elseif ($id_limit && $this->es->isSearchingNew())
- {
- $this->query_ids->andWhere("e.id > :id_limit");
- $this->parameters_ids['id_limit'] = $id_limit;
- $this->query_ids->orderBy("e.created", 'ASC')
- ->addOrderBy("e.id", 'ASC');
- }
- }
-
- private function buildStrict()
- {
- // Recherche strict ou non ?
- if ($this->es->getTagStrict() && count(($tags = $this->es->getTags())) && $this->es->getTags() != '[]')
- {
- if (is_null($tags) && !count($tags))
- {
- return;
- }
-
- if (is_string($tags))
- {
- if (is_null(trim($tags)))
- {
- return;
- }
- }
- // On a besoin de récupérer la liste des element_id qui ont les tags
- // demandés.
- $tag_ids = '';
- if (count($tags))
- {
- foreach ($tags as $tag_id => $tag_name)
- {
- if ($tag_ids === '')
- {
- $tag_ids .= (int)$tag_id;
- }
- else
- {
- $tag_ids .= ','.(int)$tag_id;
- }
- }
-
- if (!is_null(trim($tag_ids)))
- {
- $sql = "SELECT et.element_id FROM elements_tag et "
- ."WHERE et.tag_id IN ($tag_ids) group by et.element_id "
- ."having count(distinct et.tag_id) = ".count($tags);
- $rsm = new \Doctrine\ORM\Query\ResultSetMapping;
- $rsm->addScalarResult('element_id', 'element_id');
-
- $strict_element_ids_result = $this->em
- ->createNativeQuery($sql, $rsm)
- //->setParameter('ids', $tag_ids)
- ->getScalarResult()
- ;
-
- $strict_element_ids = array();
- if (count($strict_element_ids_result))
- {
- foreach ($strict_element_ids_result as $strict_id)
- {
- $strict_element_ids[] = $strict_id['element_id'];
- }
- }
-
- if (count($strict_element_ids))
- {
- $this->query_ids->andWhere('e.id IN (:tag_strict_ids)');
- $this->parameters_ids['tag_strict_ids'] = $strict_element_ids;
- }
- // Ce else palie au bug du au cas ou $strict_element_ids est egal a array();
- else
- {
- return false;
- }
- }
- }
- }
- }
-
- private function buildNeedTags()
- {
- // Si id_limit est précisé c'est que l'on demande "la suite" ou "les nouveaux"
- if ($this->es->isNeedTags())
- {
- $this->query_ids->andWhere("e.need_tags = '1'");
- }
- }
-
- private function buildIdsLimits()
- {
- if ($this->es->hasIds())
- {
- $this->query_ids->andWhere('e.id IN (:limiteds_ids)');
- $this->parameters_ids['limiteds_ids'] = $this->es->getIds();
- }
- }
-
- /**
- *
- * @param boolean $disable_limit
- */
- protected function proceedIdsQuery($disable_limit = false)
- {
-
- $this->query_ids = $this->em->createQueryBuilder()
- ->select('e.id')
- ->from('MuzichCoreBundle:Element', 'e')
- ->groupBy('e.id')
- ->orderBy('e.created', 'DESC')
- ->addOrderBy('e.id', 'DESC')
- ;
-
- if (!$disable_limit)
- {
- $this->query_ids->setMaxResults($this->es->getCount());
- }
-
- // Prise en compte des tags
- $this->buildTags();
- // Si on effectue une recherche avec un string
- $this->buildString();
- // Paramètrage en fonction du réseau
- $this->buildNetwork();
- // Si on recherche des elements d'user ou de groupe
- $this->buildUserAndGroup();
- // Si on recherche des elements mis en favoris
- $this->buildFavorite();
- // Pour les demandes de "more" ou "nouveaux" elements.
- $this->buildLimits();
- // Si on recherche les tags de manière stricte
- if ($this->buildStrict() === false)
- {
- return false;
- }
- // Si on recherche des partages en demande de tags
- $this->buildNeedTags();
- // Si on a fournis des ids dés le départ
- $this->buildIdsLimits();
-
- $this->query_ids->setParameters($this->parameters_ids);
- }
-
- /**
- *
- * @param boolean $disable_limit
- * @return \Doctrine\ORM\Query
- * @throws \Exception
- */
- public function getIdsQuery($disable_limit = false)
- {
- //// Contrôle de la demande
- //if ($this->es->hasIds())
- //{
- // throw new \Exception("Vous demandez un Query_ids avec un ElementSearcher "
- // ."possédant déjà une liste d'ids");
- //}
-
- if ($this->proceedIdsQuery($disable_limit) === false)
- {
- return false;
- }
-
- return $this->query_ids->getQuery();
- }
-
- protected function proceedElementsQuery()
- {
-
- // On récupère les ids d'éléments
- if (($ids_query = $this->getIdsQuery()) === false)
- {
- return false;
- }
-
- // On va récupérer les ids en base en fonction des paramètres
- $q_ids = $ids_query->getArrayResult();
-
- $element_ids = array();
- if (count($q_ids))
- {
- // On prépare les ids pour la requete des éléments
- foreach ($q_ids as $r_id)
- {
- $element_ids[] = $r_id['id'];
- }
- }
-
- if (!count($element_ids))
- {
- // Si on a pas d'ids on retourne une requete qui ne donnera rien
- return false;
- }
-
- // On prépare des paramètres de la requete d'éléments
- $this->parameters_elements['ids'] = $element_ids;
-
- // On prépare la requete des elements
- $this->query_elements = $this->em->createQueryBuilder();
-
- if ($this->user_id)
- {
- $this->query_elements->select('e', 'p', 'po', 't', 'o', 'g', 'fav');
- }
- else{
- $this->query_elements->select('e', 'p', 'po', 't', 'o', 'g');
- }
-
- $this->query_elements
- ->from('MuzichCoreBundle:Element', 'e')
- ->leftJoin('e.group', 'g')
- ->leftJoin('e.parent', 'p')
- ->leftJoin('p.owner', 'po')
- ;
-
- if ($this->user_id)
- {
- $this->parameters_elements['uidt'] = '%"'. $this->user_id.'"%';
- $this->parameters_elements['uid'] = $this->user_id;
- $this->query_elements
- ->leftJoin('e.tags', 't', Join::WITH,
- "(t.tomoderate = 'FALSE' OR t.tomoderate IS NULL OR t.privateids LIKE :uidt)")
- ->leftJoin('e.elements_favorites', 'fav', Join::WITH,
- 'fav.user = :uid')
- ;
- }
- else
- {
- $this->query_elements
- ->leftJoin('e.tags', 't', Join::WITH,
- "(t.tomoderate = 'FALSE' OR t.tomoderate IS NULL)")
- ;
- }
-
- $this->query_elements
- ->join('e.owner', 'o')
- ->where('e.id IN (:ids)')
- ->orderBy("e.created", 'DESC')
- ->addOrderBy("e.id", 'DESC')
- ;
-
- // Ce code est désactivé: Les ids ont déjà été filtré par la id_query.
- // // Ce cas de figure se présente lorsque l'on fait un ajax de "plus d'éléments"
- // if (($id_limit = $this->es->getIdLimit()))
- // {
- // $this->query_elements->andWhere("e.id < :id_limit");
- // $this->query_elements->setMaxResults($this->es->getCount());
- // $this->parameters_elements['id_limit'] = $id_limit;
- // }
-
- // Lorsque l'on impose les ids (typiquement affichage des éléments avec un commentaire etc)
- // On charge les tags proposés dés la requete pour économiser les échanges avec la bdd
- if (($ids_display = $this->es->getIdsDisplay()))
- {
- $this->query_elements
- ->addSelect('tp', 'tpu', 'tpt')
- ->leftJoin('e.tags_propositions', 'tp')
- ->leftJoin('tp.user', 'tpu')
- ->leftJoin('tp.tags', 'tpt')
- ;
- }
-
- $this->query_elements->setParameters($this->parameters_elements);
- }
-
- public function getElementsQuery()
- {
- if ($this->proceedElementsQuery() === false)
- {
- return $this->em
- ->createQuery("SELECT e FROM MuzichCoreBundle:Element e WHERE 1 = 2")
- ;
- }
-
- return $this->query_elements->getQuery();
- }
-
- }
|