Base.php 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. <?php
  2. // https://www.drupal.org/docs/8/modules/search-api/developer-documentation/executing-a-search-in-code
  3. namespace Drupal\materio_sapi\Controller;
  4. use Drupal\Core\Controller\ControllerBase;
  5. use Symfony\Component\HttpFoundation\JsonResponse;
  6. use Symfony\Component\HttpFoundation\Request;
  7. use Drupal\Component\Utility\Tags;
  8. use Drupal\Component\Utility\Unicode;
  9. use Drupal\search_api\Entity\Index;
  10. // https://drupal.stackexchange.com/questions/225008/programatically-use-search-api
  11. /**
  12. * Defines a route controller for materio sapi search (regular and ajax).
  13. */
  14. class Base extends ControllerBase {
  15. private $limit = 15;
  16. private $offset = 0;
  17. private function sapiQuery(){
  18. // https://www.drupal.org/docs/8/modules/search-api/developer-documentation/executing-a-search-in-code
  19. // https://www.hashbangcode.com/article/drupal-8-date-search-boosting-search-api-and-solr-search
  20. // https://kgaut.net/blog/2018/drupal-8-search-api-effectuer-une-requete-dans-le-code.html
  21. $this->index = Index::load('database');
  22. // // get solarium fileds name
  23. // $solrFields = $this->index->getServerInstance()
  24. // ->getBackend()
  25. // ->getSolrFieldNames($this->index);
  26. //
  27. // // tag_tid"itm_tag_tid"
  28. // // thesaurus_tid"itm_thesaurus_tid"
  29. // $taxoSolrFieldsName = [];
  30. // foreach (['tag_tid', 'thesaurus_tid'] as $f) {
  31. // $taxoSolrFieldsName[] = $solrFields[$f];
  32. // }
  33. $this->query = $this->index->query();
  34. // Change the parse mode for the search.
  35. // Les différentes possibilités sont
  36. // - « direct » => Requête directe
  37. // - « terms » => Multiple words
  38. // - « phrase » => Single phrase
  39. // - " edismax " => ???
  40. $parse_mode = \Drupal::service('plugin.manager.search_api.parse_mode')
  41. ->createInstance('direct');
  42. $parse_mode->setConjunction('OR');
  43. $this->query->setParseMode($parse_mode);
  44. // Set fulltext search keywords and fields.
  45. $this->query->keys($this->keys);
  46. // $this->query->setFulltextFields(['field_reference']);
  47. // Set additional conditions.
  48. // in case we search for material references like W0117
  49. if (preg_match_all('/[WTRPCMFGSO]\d{4}/i', $this->keys, $matches)) {
  50. $ref_conditions = $this->query->createConditionGroup('OR');
  51. foreach ($matches[0] as $key => $value) {
  52. $ref_conditions->addCondition('field_reference', $value);
  53. }
  54. $this->query->addConditionGroup($ref_conditions);
  55. }
  56. // in case of term id provided restrict the keys to taxo fields
  57. if ($this->term) {
  58. // $term_conditions = $this->query->createConditionGroup('OR');
  59. // $term = (int) $this->term;
  60. // foreach (['tag_tid', 'thesaurus_tid'] as $field) {
  61. // $term_conditions->addCondition($field, $term);
  62. // }
  63. // $this->query->addConditionGroup($term_conditions);
  64. // INSTEAD TRY TO BOOST TTHE TAG AND THESAURUS FIELDS
  65. // foreach ($taxoSolrFieldsName as $fname) {
  66. // // $solarium_query->addParam('bf', "recip(abs(ms(NOW,{$solrField})),3.16e-11,10,0.1)");
  67. // $bfparam = "if(gt(termfreq({$fname},{$this->term}),0),^21,0)";
  68. // $this->query->addParam('bf', $bfparam);
  69. // }
  70. $this->query->setOption('termid', $this->term);
  71. }
  72. // filter the search
  73. if ($this->filters) {
  74. $filters_conditions = $this->query->createConditionGroup('OR');
  75. foreach ($this->filters as $filter) {
  76. $filter = (int) $filter;
  77. foreach (['tag_tid', 'thesaurus_tid'] as $field) {
  78. $filters_conditions->addCondition($field, $filter);
  79. }
  80. }
  81. $this->query->addConditionGroup($filters_conditions);
  82. }
  83. // Restrict the search to specific languages.
  84. $lang = \Drupal::languageManager()->getCurrentLanguage()->getId();
  85. $this->query->setLanguages([$lang]);
  86. // Do paging.
  87. $this->query->range($this->offset, $this->limit);
  88. // Add sorting.
  89. $this->query->sort('search_api_relevance', 'DESC');
  90. // Set one or more tags for the query.
  91. // @see hook_search_api_query_TAG_alter()
  92. // @see hook_search_api_results_TAG_alter()
  93. $this->query->addTag('materio_sapi_search');
  94. $this->results = $this->query->execute();
  95. }
  96. private function defaultQuery(){
  97. $lang = \Drupal::languageManager()->getCurrentLanguage()->getId();
  98. $entity_storage = \Drupal::entityTypeManager()->getStorage('node');
  99. $this->query = $entity_storage->getQuery()
  100. ->condition('type', ['materiau', 'thematique'], 'IN')
  101. ->condition('status', '1')
  102. ->condition('langcode', $lang)
  103. ->range($this->offset, $this->limit)
  104. ->accessCheck(TRUE)
  105. ->sort('changed', 'DESC');
  106. // ->condition('field_example', 'test_value')
  107. $this->results = $this->query->execute();
  108. $this->count_query = $entity_storage->getQuery()
  109. ->condition('type', ['materiau', 'thematique'], 'IN')
  110. ->condition('langcode', $lang)
  111. ->accessCheck(TRUE)
  112. ->condition('status', '1')
  113. ->count();
  114. $this->count = $this->count_query->execute();
  115. }
  116. /**
  117. * get params from request
  118. */
  119. private function parseRequest(Request $request){
  120. // Get the typed string from the URL, if it exists.
  121. $this->keys = $request->query->get('keys');
  122. if($this->keys){
  123. $this->keys = Unicode::strtolower($this->keys);
  124. // $this->keys = Tags::explode($this->keys);
  125. \Drupal::logger('materio_sapi')->notice($this->keys);
  126. }
  127. // get the exacte term id in case of autocomplete
  128. $this->term = $request->query->get('term');
  129. // get the filters of advanced search
  130. $f = $request->query->get('filters');
  131. $this->filters = strlen($f) ? explode(',', $f) : null;
  132. // $this->allparams = $request->query->all();
  133. // $request->attributes->get('_raw_variables')->get('filters')
  134. //
  135. $this->offset = $request->query->get('offset') ?? $this->offset;
  136. $this->limit = $request->query->get('limit') ?? $this->limit;
  137. }
  138. /**
  139. * Handler for ajax search.
  140. */
  141. public function getResults(Request $request) {
  142. $this->parseRequest($request);
  143. $resp = [
  144. 'range' => array(
  145. 'offset' => $this->offset,
  146. 'limit' => $this->limit
  147. ),
  148. ];
  149. if ($this->keys) {
  150. $this->sapiQuery();
  151. $resp['keys'] = $this->keys;
  152. $resp['term'] = $this->term;
  153. $resp['count'] = $this->results->getResultCount();
  154. $resp['infos'] = t('The search found @count result(s) with keywords @keys.', array(
  155. "@count" => $resp['count'],
  156. "@keys" => $this->keys
  157. ));
  158. $resp['options'] = $this->query->getOptions();
  159. // $items = [];
  160. $uuids = [];
  161. $nids = [];
  162. foreach ($this->results as $result) {
  163. // $nid = $result->getField('nid')->getValues()[0];
  164. // $uuid = $result->getField('uuid')->getValues()[0];
  165. // $title = $result->getField('title')->getValues()[0]->getText();
  166. // $items[] = [
  167. // 'nid' => $nid,
  168. // 'uuid' => $uuid,
  169. // 'title' => $title,
  170. // ];
  171. $uuids[] = $result->getField('uuid')->getValues()[0];
  172. $nids[] = $result->getField('nid')->getValues()[0];
  173. }
  174. // $resp['items'] = $items;
  175. $resp['uuids'] = $uuids;
  176. $resp['nids'] = $nids;
  177. } else {
  178. // no keys or terms to search for
  179. // display the default base page
  180. $this->defaultQuery();
  181. // $uuids = [];
  182. $nids = [];
  183. // Using entityTypeManager
  184. // Get a node storage object.
  185. // $node_storage = \Drupal::entityTypeManager()->getStorage('node');
  186. foreach ($this->results as $result) {
  187. // $lang = \Drupal::languageManager()->getCurrentLanguage()->getId();
  188. // Load a single node.
  189. // $node = $node_storage->load($result);
  190. // check if has translation
  191. // i used to filter like bellow because of a graphql probleme
  192. // if ($node->hasTranslation($lang)) {
  193. $nids[] = $result;
  194. // }
  195. }
  196. // $resp['uuids'] = $uuids;
  197. $resp['nids'] = $nids;
  198. $resp['count'] = $this->count;
  199. $resp['infos'] = t('Please use the search form to search from our @count materials.', array(
  200. "@count" => $resp['count']
  201. ));
  202. }
  203. return new JsonResponse($resp);
  204. }
  205. /**
  206. * Handler for regular page search.
  207. */
  208. function pageHandler(Request $request){
  209. // \Drupal::logger('materio_sapi')->notice(print_r($request, true));
  210. $this->parseRequest($request);
  211. $resp = [
  212. "#title" => 'Base'
  213. ];
  214. if ($this->keys) {
  215. $resp['#title'] = $this->keys;
  216. $this->sapiQuery();
  217. $node_view_builder = \Drupal::entityTypeManager()->getViewBuilder('node');
  218. $items = $this->results->getResultItems();
  219. $this->items = [];
  220. foreach ($items as $item) {
  221. // \Drupal::logger('materio_sapi')->notice(print_r($item, true));
  222. try {
  223. /** @var \Drupal\Core\Entity\EntityInterface $entity */
  224. $entity = $item->getOriginalObject()->getValue();
  225. }
  226. catch (SearchApiException $e) {
  227. continue;
  228. }
  229. if (!$entity) {
  230. continue;
  231. }
  232. // TODO: define dynamicly viewmode
  233. $this->items[] = $node_view_builder->view($entity, 'teaser');
  234. }
  235. $resp['items'] = $this->items;
  236. }else{
  237. $resp['#markup'] = t("no keys to search for");
  238. }
  239. return $resp;
  240. }
  241. }