|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace KI\CoreBundle\Service; |
|
4
|
|
|
|
|
5
|
|
|
use Doctrine\ORM\EntityManager; |
|
6
|
|
|
use Doctrine\ORM\EntityRepository; |
|
7
|
|
|
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; |
|
8
|
|
|
|
|
9
|
|
|
class SearchService |
|
10
|
|
|
{ |
|
11
|
|
|
protected $manager; |
|
12
|
|
|
protected $userRepository; |
|
13
|
|
|
|
|
14
|
|
|
public function __construct(EntityManager $manager, EntityRepository $userRepository) |
|
|
|
|
|
|
15
|
|
|
{ |
|
16
|
|
|
$this->manager = $manager; |
|
17
|
|
|
$this->userRepository = $userRepository; |
|
18
|
|
|
} |
|
19
|
|
|
|
|
20
|
|
|
/** |
|
21
|
|
|
* @param string $search La recherche complète venant de la requête |
|
22
|
|
|
* @return array $category, $criteria |
|
23
|
|
|
* @throws BadRequestHttpException Si le format n'est pas bon |
|
24
|
|
|
*/ |
|
25
|
|
|
public function analyzeRequest($search) |
|
26
|
|
|
{ |
|
27
|
|
|
$match = []; |
|
28
|
|
|
|
|
29
|
|
|
if (!preg_match('/(.*)\/(.*)/', $search, $match)) { |
|
30
|
|
|
throw new BadRequestHttpException('Syntaxe de la recherche erronée'); |
|
31
|
|
|
} |
|
32
|
|
|
|
|
33
|
|
|
return [$match[1], $match[2]]; |
|
34
|
|
|
} |
|
35
|
|
|
|
|
36
|
|
|
/** |
|
37
|
|
|
* Recherche au travers des repos suivant la catégorie voulue |
|
38
|
|
|
* @param string $category La catégorie d'objets recherchés |
|
39
|
|
|
* @param string $criteria Le critère de recherche |
|
40
|
|
|
* @return array Un tableau de résultats formaté |
|
41
|
|
|
* @see $this->format() |
|
42
|
|
|
* @throws BadRequestHttpException Si la catégorie d'objets recherchés n'existe pas |
|
43
|
|
|
*/ |
|
44
|
|
|
public function search($category, $criteria) |
|
45
|
|
|
{ |
|
46
|
|
|
switch ($category) { |
|
47
|
|
|
case 'User': |
|
48
|
|
|
return ['users' => $this->searchUser($criteria)]; |
|
49
|
|
|
case '': |
|
50
|
|
|
return [ |
|
51
|
|
|
'clubs' => $this->searchRepository('KIUserBundle:Club', $criteria, 'fullName'), |
|
52
|
|
|
'courses' => $this->searchRepository('KIPublicationBundle:Course', $criteria), |
|
53
|
|
|
'files' => $this->searchRepository('KIPonthubBundle:PonthubFile', $criteria), |
|
54
|
|
|
'posts' => $this->searchRepository('KIPublicationBundle:Post', $criteria), |
|
55
|
|
|
'users' => $this->searchUser($criteria), |
|
56
|
|
|
]; |
|
57
|
|
|
default: |
|
58
|
|
|
throw new BadRequestHttpException('Syntaxe de la recherche erronée'); |
|
59
|
|
|
} |
|
60
|
|
|
} |
|
61
|
|
|
|
|
62
|
|
|
// On fouille un repo à la recherche d'entités correspondantes au nom |
|
63
|
|
|
protected function searchRepository($repositoryName, $criteria, $additionnalField = null) { |
|
64
|
|
|
$repository = $this->manager->getRepository($repositoryName); |
|
65
|
|
|
$qb = $repository->createQueryBuilder('e'); |
|
66
|
|
|
|
|
67
|
|
|
// Si on a affaire au repo club on peut chercher sur le nom complet |
|
68
|
|
|
if ($additionnalField !== null) { |
|
69
|
|
|
$qb |
|
70
|
|
|
->orWhere('SOUNDEX(e.'.$additionnalField.') = SOUNDEX(:search)') |
|
71
|
|
|
->orwhere('e.'.$additionnalField.' LIKE :searchlike') |
|
72
|
|
|
; |
|
73
|
|
|
} |
|
74
|
|
|
|
|
75
|
|
|
$results = $qb |
|
76
|
|
|
->orwhere('SOUNDEX(e.name) = SOUNDEX(:search)') |
|
77
|
|
|
->orwhere('e.name LIKE :searchlike') |
|
78
|
|
|
->andwhere('e.name <> \'message\'') |
|
79
|
|
|
->setParameter('search', $criteria) |
|
80
|
|
|
->setParameter('searchlike', '%'.$criteria.'%') |
|
81
|
|
|
->setMaxResults(10) |
|
82
|
|
|
->getQuery() |
|
83
|
|
|
->getResult() |
|
84
|
|
|
; |
|
85
|
|
|
|
|
86
|
|
|
return $this->format($results, $criteria); |
|
87
|
|
|
} |
|
88
|
|
|
|
|
89
|
|
|
// La recherche d'user demande une fonction particulière (champs différents, acronyme...) |
|
90
|
|
|
protected function searchUser($criteria) { |
|
91
|
|
|
$qb = $this->userRepository->createQueryBuilder('e'); |
|
92
|
|
|
|
|
93
|
|
|
$results = $qb |
|
94
|
|
|
->orwhere('SOUNDEX(CONCAT(e.firstName, CONCAT(\' \', CONCAT(e.lastName, CONCAT(\' \', COALESCE(e.nickname, \'\')))))) = SOUNDEX(:search)') |
|
95
|
|
|
->orwhere('CONCAT(e.firstName, CONCAT(\' \', CONCAT(e.lastName, CONCAT(\' \', COALESCE(e.nickname, \'\'))))) LIKE :searchlike') |
|
96
|
|
|
->setParameter('search', $criteria) |
|
97
|
|
|
->setParameter('searchlike', '%'.$criteria.'%') |
|
98
|
|
|
->setMaxResults(10) |
|
99
|
|
|
->getQuery() |
|
100
|
|
|
->getResult() |
|
101
|
|
|
; |
|
102
|
|
|
|
|
103
|
|
|
return $this->format($results, $criteria); |
|
104
|
|
|
} |
|
105
|
|
|
|
|
106
|
|
|
// On formate et ordonne les données pour le retour |
|
107
|
|
|
protected function format($results, $criteria) { |
|
108
|
|
|
$return = $score = []; |
|
109
|
|
|
$percent = 0; |
|
110
|
|
|
|
|
111
|
|
|
foreach ($results as $result) { |
|
112
|
|
|
$name = $result->getName(); |
|
113
|
|
|
$class = preg_replace('/.*\\\/', '', get_class($result)); |
|
114
|
|
|
$item = [ |
|
115
|
|
|
'name' => $name, |
|
116
|
|
|
'slug' => $result->getSlug(), |
|
117
|
|
|
'type' => $class |
|
118
|
|
|
]; |
|
119
|
|
|
|
|
120
|
|
|
// On sort les objets non actifs |
|
121
|
|
|
if ($class == 'Course' && ($result->getActive() === null || !$result->getActive())) { |
|
122
|
|
|
continue; |
|
123
|
|
|
} |
|
124
|
|
|
// On précise des choses en plus pour les utilisateurs |
|
125
|
|
|
if ($class == 'User') { |
|
126
|
|
|
$item['balance'] = $result->getBalance(); |
|
127
|
|
|
$item['promo'] = $result->getPromo(); |
|
128
|
|
|
} |
|
129
|
|
|
|
|
130
|
|
|
// Pour les épisodes, on ajoute une référence à l'entité parent |
|
131
|
|
|
if ($class == 'Episode') { |
|
132
|
|
|
$item['parent'] = $result->getSerie()->getSlug(); |
|
133
|
|
|
} |
|
134
|
|
|
|
|
135
|
|
|
// Si une image existe on la rajoute |
|
136
|
|
|
if (method_exists($result, 'imageUrl') && $result->imageUrl() !== null) { |
|
137
|
|
|
$item['image_url'] = $result->imageUrl(); |
|
138
|
|
|
} |
|
139
|
|
|
|
|
140
|
|
|
$return[] = $item; |
|
141
|
|
|
|
|
142
|
|
|
// On trie par pertinence |
|
143
|
|
|
similar_text(strtolower($name), strtolower($criteria), $percent); |
|
144
|
|
|
$score[] = $percent; |
|
145
|
|
|
} |
|
146
|
|
|
array_multisort($score, SORT_DESC, $return); |
|
147
|
|
|
|
|
148
|
|
|
return $return; |
|
149
|
|
|
} |
|
150
|
|
|
} |
|
151
|
|
|
|
The
EntityManagermight become unusable for example if a transaction is rolled back and it gets closed. Let’s assume that somewhere in your application, or in a third-party library, there is code such as the following:If that code throws an exception and the
EntityManageris closed. Any other code which depends on the same instance of theEntityManagerduring this request will fail.On the other hand, if you instead inject the
ManagerRegistry, thegetManager()method guarantees that you will always get a usable manager instance.