EdlpSearchController.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. <?php
  2. namespace Drupal\edlp_search\Controller;
  3. use Drupal\Core\Controller\ControllerBase;
  4. use Symfony\Component\DependencyInjection\ContainerInterface;
  5. use Drupal\Core\Form\FormBuilder;
  6. use Drupal\search_api\Entity\Index;
  7. use Drupal\Core\Url;
  8. use Drupal\Core\Language\LanguageInterface;
  9. use Symfony\Component\HttpFoundation\Request;
  10. use Symfony\Component\HttpFoundation\JsonResponse;
  11. // use Drupal\Core\Cache\CacheableJsonResponse;
  12. // use Drupal\Core\Cache\CacheableMetadata;
  13. use Drupal\core\render\RenderContext;
  14. /**
  15. * Class EdlpSearchController.
  16. */
  17. class EdlpSearchController extends ControllerBase {
  18. /**
  19. * The form builder.
  20. *
  21. * @var \Drupal\Core\Form\FormBuilder
  22. */
  23. protected $formBuilder;
  24. protected $sapi_index_id;
  25. /**
  26. * Construct.
  27. */
  28. public function __construct(FormBuilder $formBuilder) {
  29. $this->formBuilder = $formBuilder;
  30. $this->sapi_index_id = "collection";
  31. }
  32. /**
  33. * {@inheritdoc}
  34. */
  35. public static function create(ContainerInterface $container) {
  36. return new static(
  37. $container->get('form_builder')
  38. );
  39. }
  40. private function getSearchForm(){
  41. $this->form = $this->formBuilder->getForm('Drupal\edlp_search\Form\EdlpSearchForm');
  42. }
  43. private function buildRenderable(){
  44. $this->getSearchForm();
  45. $this->renderable = array(
  46. "#theme" => "edlp_search_search_form",
  47. '#form' => $this->form
  48. );
  49. }
  50. /**
  51. * Searchform.
  52. *
  53. * @return string
  54. * Return Hello string.
  55. */
  56. public function searchForm() {
  57. $this->buildRenderable();
  58. return $this->renderable;
  59. }
  60. /**
  61. * searchFormJson
  62. */
  63. public function searchFormJson(){
  64. $this->buildRenderable();
  65. $rendered = \Drupal::service('renderer')->render($this->renderable);
  66. $data = [
  67. 'rendered' => $rendered,
  68. 'title' => 'Search',
  69. ];
  70. // translations links
  71. $route_name = 'edlp_search.edlp_search_controller_searchForm';
  72. $links = \Drupal::languageManager()->getLanguageSwitchLinks(LanguageInterface::TYPE_URL, Url::fromRoute($route_name));
  73. if (isset($links->links)) {
  74. $translations_build = [
  75. '#theme' => 'links__language_block',
  76. '#links' => $links->links,
  77. '#attributes' => ['class' => ["language-switcher-{$links->method_id}",],],
  78. '#set_active_class' => TRUE,
  79. ];
  80. $translations_rendered = \Drupal::service('renderer')->executeInRenderContext(new RenderContext(), function () use ($translations_build) {return \Drupal::service('renderer')->render($translations_build);});
  81. $data['translations_links'] = $translations_rendered;
  82. }
  83. // TODO: make respponse cachable
  84. $response = new JsonResponse();
  85. $response->setData($data);
  86. return $response;
  87. }
  88. public function autocomplete(Request $request){
  89. // TODO: get field_name parameter
  90. $this->request = $request;
  91. $this->getRequestAutocompleteArgs();
  92. // run a search on selected field and get the fields unique values
  93. $this->autocompleteQuery();
  94. $response = new JsonResponse($this->matches);
  95. return $response;
  96. // return array(
  97. // "#markup" => "autocomplete"
  98. // );
  99. }
  100. /**
  101. * autocompleteQuery
  102. */
  103. private function autocompleteQuery(){
  104. // TODO: get the sapi index id with settings
  105. /* @var $sapi_index \Drupal\search_api\IndexInterface */
  106. $sapi_index = Index::load($this->sapi_index_id);
  107. // dpm($sapi_index);
  108. // Create the query.
  109. $query = $sapi_index->query();
  110. $query->setSearchID('edlp_search:autocomplete');
  111. $parse_mode = \Drupal::getContainer()
  112. ->get('plugin.manager.search_api.parse_mode')
  113. ->createInstance('direct');
  114. $query->setParseMode($parse_mode);
  115. $current_langcode = \Drupal::languageManager()->getCurrentLanguage()->getId();
  116. $query->setLanguages(array($current_langcode));
  117. // $query->range(0, 20);
  118. // workflow
  119. $wf_condition_group = $query->createConditionGroup('OR');
  120. $wf_condition_group->addCondition('field_workflow', 'corpus_documents_publie', "=");
  121. // TODO: add condition with the other workflow field
  122. $query->addConditionGroup($wf_condition_group);
  123. // Search for keys.
  124. if (!empty($this->keys)) { // && strlen($this->keys) > 2
  125. // dpm($this->keys);
  126. $query->keys($this->keys);
  127. }
  128. // else{
  129. // $this->matches = [];
  130. // return;
  131. // }
  132. if(null !== $this->field_synonyms){
  133. // select the taxo field AND the synonym field in which search will be performed
  134. $query->setFulltextFields(array($this->field_name, $this->field_synonyms));
  135. }else{
  136. // OR select the unique taxo field in which search will be performed
  137. $query->setFulltextFields(array($this->field_name));
  138. }
  139. $result = $query->execute();
  140. $items = $result->getResultItems();
  141. // dpm($items);
  142. $this->matches = [];
  143. foreach ($items as $item) {
  144. // get the field from item
  145. try {
  146. /** @var \Drupal\Core\Entity\EntityInterface $entity */
  147. $fields = $item->getField($this->field_name)->getValues();
  148. }catch (SearchApiException $e) {
  149. // if error on getinfg the field, skip item
  150. continue;
  151. }
  152. // if no fields returned, skip item
  153. if (!$fields) {
  154. continue;
  155. }
  156. // dpm($fields);
  157. // get field content
  158. $field_text = $fields[0]->getText();
  159. // $entity_id = $fields[0]->get('tid');
  160. // if content already in matches, skip item
  161. if( in_array($field_text, $this->matches) ){
  162. continue;
  163. }
  164. // add the item to the return list
  165. // $matches_names = $field_text . '('.$entity_id.')';
  166. $this->matches[] = $field_text;
  167. // do not return more than 14 items
  168. if(count($this->matches) > 14){
  169. break;
  170. }
  171. }
  172. // dpm($this->matches);
  173. }
  174. /**
  175. * getRequestArgs
  176. */
  177. private function getRequestAutocompleteArgs(){
  178. // args are provided by form definition with autocomplete_route_parameters
  179. // dpm($this->request);
  180. $this->field_name = $this->request->query->get('field_name');
  181. // if($this->request->query->get('field_synonyms')){
  182. $this->field_synonyms = $this->request->query->get('field_synonyms');
  183. // }
  184. // if($this->request->query->get('node_type')){
  185. // $this->node_type = $this->request->query->get('node_type');
  186. // }
  187. $this->keys = $this->request->query->get('q');
  188. }
  189. /**
  190. * searchResults
  191. */
  192. public function searchResults(Request $request) {
  193. $this->request = $request;
  194. $this->getRequestSearchArgs();
  195. return $this->getrenderable();
  196. }
  197. /**
  198. * searchResultsJson
  199. */
  200. public function searchResultsJson(Request $request){
  201. $this->request = $request;
  202. $this->getRequestSearchArgs();
  203. $renderable = $this->getrenderable();
  204. $rendered = \Drupal::service('renderer')->render($renderable);
  205. // build an array of results's nids
  206. $results_nids = [];
  207. foreach ($this->items as $item) {
  208. $results_nids[] = $item->id();
  209. }
  210. $response = new JsonResponse();
  211. $response->setData([
  212. 'keys'=>$this->keys,
  213. 'entries' => $this->entries,
  214. 'entry_names' => $this->entry_names,
  215. 'langues' => $this->langues,
  216. 'genres' => $this->genres,
  217. 'rendered'=> $rendered,
  218. 'results_nids'=>$results_nids,
  219. ]);
  220. return $response;
  221. }
  222. /**
  223. * getRenderable
  224. */
  225. private function getRenderable(){
  226. $this->query();
  227. $build = array(
  228. '#theme' => 'edlp_search_results',
  229. '#items' => $this->items
  230. );
  231. if(!count($this->items)){
  232. $build['#no_results_found'] = array(
  233. '#markup' => t('Your search yielded no results.')
  234. );
  235. // $build['#search_help'] = array(
  236. // '#markup' => $this->t('<ul>
  237. // <li>Check if your spelling is correct.</li>
  238. // <li>Remove quotes around phrases to search for each word individually. <em>bike shed</em> will often show more results than <em>&quot;bike shed&quot;</em>.</li>
  239. // <li>Consider loosening your query with <em>OR</em>. <em>bike OR shed</em> will often show more results than <em>bike shed</em>.</li>
  240. // </ul>')
  241. // );
  242. }
  243. return $build;
  244. }
  245. /**
  246. * query
  247. */
  248. private function query(){
  249. // TODO: get the sapi index id with settings
  250. /* @var $sapi_index \Drupal\search_api\IndexInterface */
  251. $sapi_index = Index::load($this->sapi_index_id);
  252. // dpm($sapi_index);
  253. // Create the query.
  254. $query = $sapi_index->query();
  255. // dpm($query);
  256. $query->setSearchID('edlp_search:ajaxsearch');
  257. $parse_mode = \Drupal::getContainer()
  258. ->get('plugin.manager.search_api.parse_mode')
  259. ->createInstance('direct');
  260. // $parse_mode->setConjunction('AND');
  261. $query->setParseMode($parse_mode);
  262. // search in both languages (if not conditions will not work)
  263. $query->setLanguages(array('fr','en'));
  264. // workflow
  265. $wf_condition_group = $query->createConditionGroup('OR');
  266. $wf_condition_group->addCondition('field_workflow', 'corpus_documents_publie', "=");
  267. // TODO: add condition with the other workflow field
  268. $query->addConditionGroup($wf_condition_group);
  269. // Search for keys.
  270. if (!empty($this->keys)) {
  271. // $query->keys($this->keys);
  272. $keys_condition_group = $query->createConditionGroup('OR');
  273. $keys_condition_group->addCondition('title', $this->keys, 'IN');
  274. $keys_condition_group->addCondition('field_description', $this->keys, 'IN');
  275. $query->addConditionGroup($keys_condition_group);
  276. }
  277. // langues
  278. if (!empty($this->langues)) {
  279. $query->addCondition('field_langues', $this->langues, "=");
  280. }
  281. // genres
  282. if (!empty($this->genres)) {
  283. $query->addCondition('field_genres', $this->genres, "=");
  284. }
  285. // TODO: locuteurs
  286. // entries
  287. $this->entry_names = [];
  288. if (!empty($this->entries)){
  289. $terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadMultiple($this->entries);
  290. $entries_condition_group = $query->createConditionGroup();
  291. foreach ($terms as $tid => $term) {
  292. $entries_condition_group->addCondition('field_entrees', (int)$tid, "=");
  293. $this->entry_names[] = $term->getName();
  294. }
  295. // dpm($entries_condition_group);
  296. $query->addConditionGroup($entries_condition_group);
  297. }
  298. $result = $query->execute();
  299. $items = $result->getResultItems();
  300. // dpm($items);
  301. $this->items = [];
  302. $ids = [];
  303. foreach ($items as $item) {
  304. try {
  305. /** @var \Drupal\Core\Entity\EntityInterface $entity */
  306. $entity = $item->getOriginalObject()->getValue();
  307. }
  308. catch (SearchApiException $e) {
  309. continue;
  310. }
  311. if (!$entity) {
  312. continue;
  313. }
  314. // get distinct results
  315. if(in_array($entity->id(), $ids)){
  316. continue;
  317. }
  318. $ids[] = $entity->id();
  319. // record results
  320. $this->items[] = $entity;
  321. }
  322. // dpm($this->items);
  323. }
  324. /**
  325. * getRequestArgs
  326. */
  327. private function getRequestSearchArgs(){
  328. // dpm($this->request);
  329. $this->keys = $this->request->query->get('keys');
  330. $this->langues = $this->request->query->get('langues');
  331. $this->genres = $this->request->query->get('genres');
  332. $this->entries = $this->request->query->get('entries');
  333. }
  334. }