/src/Sherlock/requests/SearchRequest.php

https://bitbucket.org/openplacement/sherlock · PHP · 348 lines · 170 code · 65 blank · 113 comment · 26 complexity · bf8e891e4aed7f41364620e84a58e356 MD5 · raw file

  1. <?php
  2. /**
  3. * User: Zachary Tong
  4. * Date: 2/10/13
  5. * Time: 12:10 PM
  6. * @package Sherlock\requests
  7. */
  8. namespace Sherlock\requests;
  9. use Sherlock\common\exceptions;
  10. use Sherlock\components;
  11. use Sherlock\components\queries;
  12. use Symfony\Component\EventDispatcher\EventDispatcher;
  13. use sherlock\components\FacetInterface;
  14. use Sherlock\responses\QueryResponse;
  15. /**
  16. * SearchRequest facilitates searching an ES index using the ES query DSL
  17. *
  18. * @method \Sherlock\requests\SearchRequest timeout() timeout(\int $value)
  19. * @method \Sherlock\requests\SearchRequest from() from(\int $value)
  20. * @method \Sherlock\requests\SearchRequest size() size(\int $value)
  21. * @method \Sherlock\requests\SearchRequest search_type() search_type(\int $value)
  22. * @method \Sherlock\requests\SearchRequest routing() routing(mixed $value)
  23. */
  24. class SearchRequest extends Request
  25. {
  26. /**
  27. * @var array
  28. */
  29. protected $params;
  30. /**
  31. * @var \Symfony\Component\EventDispatcher\EventDispatcher
  32. */
  33. protected $dispatcher;
  34. /**
  35. * @param \Symfony\Component\EventDispatcher\EventDispatcher $dispatcher
  36. *
  37. * @throws \Sherlock\common\exceptions\BadMethodCallException
  38. */
  39. public function __construct($dispatcher)
  40. {
  41. if (!isset($dispatcher)) {
  42. throw new \Sherlock\common\exceptions\BadMethodCallException("Dispatcher argument required for IndexRequest");
  43. }
  44. $this->params['filter'] = array();
  45. $this->dispatcher = $dispatcher;
  46. parent::__construct($dispatcher);
  47. }
  48. /**
  49. * @param $name
  50. * @param $args
  51. *
  52. * @return SearchRequest
  53. */
  54. public function __call($name, $args)
  55. {
  56. $this->params[$name] = $args[0];
  57. return $this;
  58. }
  59. /**
  60. * Sets the index to operate on
  61. *
  62. * @param string $index indices to query
  63. * @param string $index,... indices to query
  64. *
  65. * @return SearchRequest
  66. */
  67. public function index($index)
  68. {
  69. $this->params['index'] = array();
  70. $args = func_get_args();
  71. foreach ($args as $arg) {
  72. $this->params['index'][] = $arg;
  73. }
  74. return $this;
  75. }
  76. /**
  77. * Sets the type to operate on
  78. *
  79. * @param string $type types to query
  80. * @param string $type,... types to query
  81. *
  82. * @return SearchRequest
  83. */
  84. public function type($type)
  85. {
  86. $this->params['type'] = array();
  87. $args = func_get_args();
  88. foreach ($args as $arg) {
  89. $this->params['type'][] = $arg;
  90. }
  91. return $this;
  92. }
  93. /**
  94. * Sets the query that will be executed
  95. *
  96. * @param $query
  97. *
  98. * @return SearchRequest
  99. */
  100. public function query($query)
  101. {
  102. $this->params['query'] = $query;
  103. return $this;
  104. }
  105. /**
  106. * Sets the query or queries that will be executed
  107. *
  108. * @param \Sherlock\components\SortInterface|array,... $value
  109. *
  110. * @return SearchRequest
  111. */
  112. public function sort($value)
  113. {
  114. $args = func_get_args();
  115. //single param, array of sorts
  116. if (count($args) == 1 && is_array($args[0])) {
  117. $args = $args[0];
  118. }
  119. foreach ($args as $arg) {
  120. if ($arg instanceof \Sherlock\components\SortInterface) {
  121. $this->params['sort'][] = $arg->toArray();
  122. }
  123. }
  124. return $this;
  125. }
  126. /**
  127. * Sets the fields that will be returned
  128. *
  129. * @param $fields
  130. *
  131. * @return SearchRequest
  132. */
  133. public function fields($fields)
  134. {
  135. $this->params['fields'] = $fields;
  136. return $this;
  137. }
  138. /**
  139. * Sets the filter that will be executed
  140. *
  141. * @param $filter
  142. *
  143. * @return SearchRequest
  144. */
  145. public function filter($filter)
  146. {
  147. $this->params['filter'] = $filter;
  148. return $this;
  149. }
  150. /**
  151. * Sets the facets to operate on
  152. *
  153. * @param FacetInterface $facets types to query
  154. * @param FacetInterface $facets,... types to query
  155. *
  156. * @return SearchRequest
  157. */
  158. public function facets($facets)
  159. {
  160. $this->params['facets'] = array();
  161. if (is_array($facets)){
  162. $args = $facets;
  163. }else{
  164. $args = func_get_args();
  165. }
  166. foreach ($args as $arg) {
  167. if ($arg instanceof FacetInterface) {
  168. $this->params['facets'][] = $arg;
  169. }
  170. }
  171. return $this;
  172. }
  173. /**
  174. * @param HighlightInterface $highlight
  175. *
  176. * @return SearchRequest
  177. */
  178. public function highlight($highlight)
  179. {
  180. $this->params['highlight'] = $highlight;
  181. return $this;
  182. }
  183. /**
  184. * Execute the search request on the ES cluster
  185. *
  186. * @throws \Sherlock\common\exceptions\RuntimeException
  187. * @return \Sherlock\responses\QueryResponse
  188. */
  189. public function execute()
  190. {
  191. $finalQuery = $this->composeFinalQuery();
  192. if (isset($this->params['index'])) {
  193. $index = implode(',', $this->params['index']);
  194. } else {
  195. $index = '';
  196. }
  197. if (isset($this->params['type'])) {
  198. $type = implode(',', $this->params['type']);
  199. } else {
  200. $type = '';
  201. }
  202. if (isset($this->params['search_type'])) {
  203. $queryParams[] = $this->params['search_type'];
  204. }
  205. if (isset($this->params['routing'])) {
  206. $queryParams[] = $this->params['routing'];
  207. }
  208. if (isset($queryParams)) {
  209. $queryParams = '?' . implode("&", $queryParams);
  210. } else {
  211. $queryParams = '';
  212. }
  213. $command = new Command();
  214. $command->index($index)
  215. ->type($type)
  216. ->id('_search' . $queryParams)
  217. ->action('post')
  218. ->data($finalQuery);
  219. $this->batch->clearCommands();
  220. $this->batch->addCommand($command);
  221. $ret = parent::execute();
  222. return $ret[0];
  223. }
  224. /**
  225. * Return a JSON representation of the final search request
  226. *
  227. * @return string
  228. */
  229. public function toJSON()
  230. {
  231. $finalQuery = $this->composeFinalQuery();
  232. return $finalQuery;
  233. }
  234. /**
  235. * Composes the final query, aggregating together the queries, filters, facets and associated parameters
  236. *
  237. * @return string
  238. * @throws \Sherlock\common\exceptions\RuntimeException
  239. */
  240. private function composeFinalQuery()
  241. {
  242. $finalQuery = array();
  243. if (isset($this->params['fields'])) {
  244. $finalQuery['fields'] = $this->params['fields'];
  245. }
  246. if (isset($this->params['query']) && $this->params['query'] instanceof components\QueryInterface) {
  247. $finalQuery['query'] = $this->params['query']->toArray();
  248. }
  249. if (isset($this->params['filter']) && $this->params['filter'] instanceof components\FilterInterface) {
  250. $finalQuery['filter'] = $this->params['filter']->toArray();
  251. }
  252. if (isset($this->params['facets'])) {
  253. $tFacets = array();
  254. foreach ($this->params['facets'] as $facet) {
  255. //@todo Investigate a better way of doing this
  256. //array_merge is supposedly slow when merging arrays of arrays
  257. if ($facet instanceof FacetInterface) {
  258. $tFacets = array_merge($tFacets, $facet->toArray());
  259. }
  260. }
  261. $finalQuery['facets'] = $tFacets;
  262. unset($tFacets);
  263. }
  264. if (isset($this->params['highlight']) && $this->params['highlight'] instanceof components\HighlightInterface) {
  265. $finalQuery['highlight'] = $this->params['highlight']->toArray();
  266. }
  267. foreach (array('from', 'size', 'timeout', 'sort') as $key) {
  268. if (isset($this->params[$key])) {
  269. $finalQuery[$key] = $this->params[$key];
  270. }
  271. }
  272. $finalQuery = json_encode($finalQuery, true);
  273. return $finalQuery;
  274. }
  275. /**
  276. * @param $response
  277. * @return \Sherlock\responses\QueryResponse|\Sherlock\responses\Response
  278. */
  279. protected function getReturnResponse($response)
  280. {
  281. return new QueryResponse($response);
  282. }
  283. }