123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- <?php
-
- namespace Muzich\CoreBundle\Util;
-
- use Doctrine\Bundle\DoctrineBundle\Registry;
- use Muzich\CoreBundle\Util\StrictCanonicalizer;
-
- /**
- * Cette classe permet d'aider a la recherche de mot similaires a un mot
- *
- *
- */
- class TagLike
- {
-
- protected $registry;
-
- public function __construct(Registry $registry)
- {
- $this->registry = $registry;
- }
-
- /**
- * Ajoute le tag au début du tableau passé en paramètre si celui-ci
- * n'est pas a l'intérieur.
- *
- * @param array $array
- * @param Tag $tag
- * @return array
- */
- private function sort_addtop_if_isnt_in($array, $tag)
- {
- $in = false;
- for ($x=0;$x<=sizeof($array)-1;$x++)
- {
- if ($array[$x]['id'] == $tag['id'])
- {
- $in = true;
- break;
- }
- }
-
- if (!$in)
- {
- array_unshift($array, $tag);
- return $array;
- }
- return $array;
- }
-
- /**
- * Ajoute le tag a al fin du tableau passé en paramètre si celui-ci
- * n'est pas a l'intérieur.
- *
- * @param array $array
- * @param Tag $tag
- * @return array
- */
- private function sort_addbottom_if_isnt_in($array, $tag)
- {
- $in = false;
- for ($x=0;$x<=sizeof($array)-1;$x++)
- {
- if ($array[$x]['id'] == $tag['id'])
- {
- $in = true;
- break;
- }
- }
-
- if (!$in)
- {
- $array[] = $tag;
- return $array;
- }
- return $array;
- }
-
- /**
- * Construit un tableau de mot a partir du terme de recherche. Ces mots
- * permettrons la recherche de tags en base et le trie des tags trouvé.
- *
- * La déduction de ces mot est basé sur:
- * * Le remplacement des espaces par des tirets et inversement (virgules aussi)
- *
- * Et chaque mot doit dépasser deux caractères
- *
- * @param string $search
- * @return array
- */
- protected function getSearchWordsReplacing($search)
- {
- // En base les tags sont composé de mot a '-' ou a ' '.
- $words = array_unique(array(
- str_replace(' ', '-', $search),
- str_replace('-', ' ', $search),
- str_replace(',', ' ', $search),
- str_replace(', ', ' ', $search),
- str_replace(',', '-', $search),
- str_replace(', ', '-', $search),
- str_replace(' & ', ' AND ', $search)
- ));
-
- return $words;
- }
-
- /**
- * Construit un tableau de mot a partir du terme de recherche. Ces mots
- * permettrons la recherche de tags en base et le trie des tags trouvé.
- *
- * La déduction de ces mot est basé sur:
- * * La découpe du terme par espaces, tirets et virgules
- *
- * Et chaque mot doit dépasser deux caractères
- *
- * @param string $search
- */
- protected function getSearchWordsExploding($search)
- {
- $words = array_unique(array_merge(
- explode(' ', $search),
- explode('-', $search),
- explode('- ', $search),
- explode(' -', $search),
- explode(' - ', $search),
- explode(',', $search),
- explode(', ', $search),
- explode(' ,', $search),
- explode(' , ', $search)
- ));
-
- $words_filetereds = array();
- foreach ($words as $i => $word)
- {
- if (trim(strlen($word)) > 1)
- {
- $words_filetereds[] = trim($word);
- }
- }
-
- return $words_filetereds;
- }
-
- /**
- * Recherche en base les tags ressemblant a la recherche.
- *
- * @param array $words
- * @param int $user_id
- * @return array
- */
- protected function searchTags($words, $user_id)
- {
- $where = '';
- $params = array();
-
- foreach ($words as $i => $word)
- {
- if ($where == '')
- {
- $where .= 'WHERE UPPER(t.slug) LIKE :str'.$i;
- }
- else
- {
- $where .= ' OR UPPER(t.slug) LIKE :str'.$i;
- }
-
- $params['str'.$i] = '%'.$word.'%';
- }
-
- $params['uid'] = '%"'.$user_id.'"%';
- $tags_query = $this->registry->getEntityManager()->createQuery("
- SELECT t.name, t.slug, t.id FROM MuzichCoreBundle:Tag t
- $where
-
- AND (t.tomoderate = '0' OR t.tomoderate IS NULL
- OR t.privateids LIKE :uid)
-
- ORDER BY t.name ASC"
- )
- ->setParameters($params)
- ->getScalarResult()
- ;
-
- $tags = array();
- foreach ($tags_query as $tag)
- {
- $tags[] = array(
- 'name' => $tag['name'],
- 'id' => $tag['id'],
- 'slug' => $tag['slug']
- );
- }
-
- return $tags;
- }
-
- /**
- * Trie les tags de manière a ce que les tags les plus ressemblant a la
- * recherche soient au début du tableau.
- *
- * @param array $tags
- * @param array $search
- * @param array $words
- * @param array $words_replacing
- * @param array $words_exploding
- * @return array
- */
- protected function sortTags($tags, $search, $words, $words_replacing, $words_exploding)
- {
- $same_found = false;
- $tag_sorted = array();
-
- /*
- * Première passe: Pas plus de trois caractères différents de la recherche
- * On se base ici sur le recherche non découpé
- */
- foreach ($tags as $i => $tag)
- {
- foreach ($words_replacing as $word)
- {
- $word = trim($word);
- if (strlen($word) > 1)
- {
- if (
- strlen(str_replace($word, '', strtoupper($tag['slug']))) < 4
- // Si on tombe sur le même nom, il ne faut pas le mettre en haut maintenant
- // ou il se fera décallé vers le bas
- && $word != $search
- )
- {
- $tag_sorted = $this->sort_addtop_if_isnt_in($tag_sorted, $tag);
- }
- }
- }
-
- }
-
- /*
- * Pour une recherche en plusieurs mots, on cherche la similitude avec
- * des tags. De façon a ce que "dark psytrance" soit reconnue comme proche de
- * "psytrance dark".
- */
- if (count($words_exploding) > 1)
- {
-
- $tags_counteds = array();
- /*
- * Pour chaque mot qui compose la recherche on regarde si ce mot
- * est compris dans un des tags
- */
- foreach ($tags as $i => $tag)
- {
- foreach ($words_exploding as $word)
- {
- if (strpos(strtoupper($tag['slug']), $word) !== false)
- {
- $count = 1;
- if (array_key_exists($tag['id'], $tags_counteds))
- {
- $count = ($tags_counteds[$tag['id']]['count'])+1;
- }
- $tags_counteds[$tag['id']] = array(
- 'count' => $count,
- 'tag' => $tag
- );
- }
- }
- }
-
- /*
- * Maintenant que l'on a un tableau contenant les tags comportant au moins
- * un mot identique a recherche
- */
- foreach ($tags_counteds as $id => $counted)
- {
- // Si le tag a eu plus d'une fois le même mot
- if ($counted['count'] > 1)
- {
- // Ci-dessous on va chercher a voir si le tag et la recherche on le
- // même nombre de mots, si c'est le cas on pourra considérer cette
- // recherche comme lié a un tag connu.
-
- if (count($words_exploding) == count($this->getSearchWordsExploding($counted['tag']['slug'])))
- {
- $same_found = true;
- }
-
- // Cette verif permet de ne pas ajouter les tags qui n'ont qu'un mot
- // Si on ajouté ce tag maintenant il ne serais pas ajouté au controle en dessous
- // (nom identique) et donc pas au dessus.
- $tag_sorted = $this->sort_addtop_if_isnt_in($tag_sorted, $counted['tag']);
-
- }
- }
-
- }
-
- /*
- * On recherche maintenant les noms de tags identique a la recherche
- */
- foreach ($tags as $i => $tag)
- {
- foreach ($words_replacing as $word)
- {
- if ($word == strtoupper($tag['slug']))
- {
- // Ci-dessous on déduit si le mot est identique au tag .
- // De façon a ce que si c'est le cas, pouvoir dire:
- // oui le terme recherché est connu.
- if (in_array($word, $words_replacing))
- {
- $same_found = true;
- }
- $tag_sorted = $this->sort_addtop_if_isnt_in($tag_sorted, $tag);
- }
- }
- }
-
- foreach ($tags as $i => $tag)
- {
- $tag_sorted = $this->sort_addbottom_if_isnt_in($tag_sorted, $tag);
- }
-
- return array(
- 'tags' => $tag_sorted,
- 'same_found' => $same_found
- );
- }
-
- public function getSimilarTags($search, $user_id)
- {
- $canonicalizer = new StrictCanonicalizer();
- $search = strtoupper($canonicalizer->canonicalize(trim($search)));
-
- if (strlen($search) < 2)
- {
- // Le terme de recherche doit faire au moins 2 caractéres
- return array('tags' => array(), 'same_found' => false);
- }
-
- $words_e = $this->getSearchWordsExploding($search);
- $words_r = $this->getSearchWordsReplacing($search);
- $words = array_unique(array_merge($words_e, $words_r));
- $tags = $this->searchTags($words, $user_id);
-
- return $this->sortTags($tags, $search, $words, $words_r, $words_e);
- }
-
- }
|