QueryBuilder::getParams()   B
last analyzed

Complexity

Conditions 8
Paths 16

Size

Total Lines 47

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 8.0327

Importance

Changes 0
Metric Value
dl 0
loc 47
ccs 23
cts 25
cp 0.92
rs 7.9119
c 0
b 0
f 0
cc 8
nc 16
nop 1
crap 8.0327
1
<?php
2
3
/**
4
 * This software package is licensed under `AGPL-3.0-only, proprietary` license[s].
5
 *
6
 * @package maslosoft/manganel
7
 * @license AGPL-3.0-only, proprietary
8
 *
9
 * @copyright Copyright (c) Peter Maselkowski <[email protected]>
10
 * @link https://maslosoft.com/manganel/
11
 */
12
13
namespace Maslosoft\Manganel;
14
15
use Elasticsearch\Common\Exceptions\BadRequest400Exception;
16
use Elasticsearch\Common\Exceptions\Missing404Exception;
17
use Elasticsearch\Common\Exceptions\NoNodesAvailableException;
18
use Maslosoft\Addendum\Interfaces\AnnotatedInterface;
19
use Maslosoft\Mangan\Interfaces\CriteriaAwareInterface;
20
use Maslosoft\Mangan\Interfaces\CriteriaInterface;
21
use Maslosoft\Mangan\Traits\CriteriaAwareTrait;
22
use Maslosoft\Manganel\Events\ErrorEvent;
23
use Maslosoft\Manganel\Helpers\ExceptionHandler;
24
use Maslosoft\Manganel\Helpers\QueryBuilderDecorator;
25
use Maslosoft\Manganel\Helpers\RecursiveFilter;
26
use Maslosoft\Manganel\Helpers\TypeNamer;
27
use Maslosoft\Manganel\Traits\UniqueModelsAwareTrait;
28
use UnexpectedValueException;
29
30
/**
31
 * QueryBuilder
32
 * @method SearchCriteria getCriteria()
33
 * @author Piotr Maselkowski <pmaselkowski at gmail.com>
34
 */
35
class QueryBuilder implements CriteriaAwareInterface
36
{
37
38
	use CriteriaAwareTrait,
39
	  UniqueModelsAwareTrait;
40
41
	/**
42
	 * Manganel instance
43
	 * @var Manganel
44
	 */
45
	private $manganel = null;
46
47 33
	public function __construct($model = null)
48
	{
49 33
		if (!empty($model))
50
		{
51 25
			$this->addModel($model);
52
		}
53 33
		if (!empty($model))
54
		{
55 25
			$this->manganel = Manganel::create($model);
56
		}
57
		else
58
		{
59 28
			$this->manganel = Manganel::fly();
60
		}
61 33
	}
62
63
	/**
64
	 * Add model or array of models
65
	 * @param AnnotatedInterface|AnnotatedInterface[] $model
66
	 * @return void
67
	 */
68 28
	public function add($model)
69
	{
70 28
		if (is_array($model))
71
		{
72 26
			foreach ($model as $m)
73
			{
74 26
				$this->addModel($m);
75
			}
76 26
			return;
77
		}
78 2
		$this->addModel($model);
79 2
	}
80
81
	/**
82
	 * Set criteria
83
	 * @param CriteriaInterface|array $criteria
84
	 * @return static
85
	 */
86 24
	public function setCriteria($criteria)
87
	{
88 24
		$this->criteria = $criteria;
89 24
		assert($criteria instanceof SearchCriteria);
90 24
		$this->add($criteria->getModels());
91 24
		return $this;
92
	}
93
94
	/**
95
	 *
96
	 * @param string $q
97
	 * @return int
98
	 */
99 26
	public function count($q = null)
100
	{
101 26
		$params = $this->getParams($q);
102
		try
103
		{
104 26
			$result = $this->manganel->getClient()->count($params);
105
		}
106
		catch (Missing404Exception $e)
107
		{
108
			$params = ['index' => strtolower($this->manganel->index)];
109
			$this->manganel->getClient()->indices()->create($params);
110
		}
111
		catch (BadRequest400Exception $e)
112
		{
113
			if(!ExceptionHandler::handled($e, $this->models[0], ErrorEvent::EventBadRequest))
114
			{
115
				throw ExceptionHandler::getDecorated($this->manganel, $e, $params);
116
			}
117
		}
118
		catch (NoNodesAvailableException $e)
119
		{
120
			if(!ExceptionHandler::handled($e, $this->models[0], ErrorEvent::EventNoNodes))
121
			{
122
				throw ExceptionHandler::getDecorated($this->manganel, $e, $params);
123
			}
124
		}
125 26
		if (empty($result) && empty($result['count']))
126
		{
127
			return 0; // @codeCoverageIgnore
128
		}
129 26
		return $result['count'];
130
	}
131
132
	/**
133
	 * Get search results - hits from elasticsearch response.
134
	 * Optionally raw results might be obtained by reference via second param.
135
	 *
136
	 * @param string $q
137
	 * @param array $result
138
	 * @return array
139
	 */
140 20
	public function search($q = null, &$result = [])
141
	{
142 20
		$params = $this->getParams($q);
143
144
		try
145
		{
146 20
			$result = $this->manganel->getClient()->search($params);
147
		}
148
		catch (Missing404Exception $e)
149
		{
150
			$params = ['index' => strtolower($this->manganel->index)];
151
			$this->manganel->getClient()->indices()->create($params);
152
		}
153
		catch (BadRequest400Exception $e)
154
		{
155
			if(!ExceptionHandler::handled($e, $this->models[0], ErrorEvent::EventBadRequest))
156
			{
157
				throw ExceptionHandler::getDecorated($this->manganel, $e, $params);
158
			}
159
		}
160
		catch(NoNodesAvailableException $e)
161
		{
162
			if(!ExceptionHandler::handled($e, $this->models[0], ErrorEvent::EventNoNodes))
163
			{
164
				throw ExceptionHandler::getDecorated($this->manganel, $e, $params);
165
			}
166
		}
167
168 20
		if (empty($result) && empty($result['hits']) && empty($result['hits']['hits']))
169
		{
170
			return [];
171
		}
172 20
		return $result['hits']['hits'];
173
	}
174
175 32
	public function getParams($q = null)
176
	{
177 32
		$body = [];
178
		// Try to get query from criteria if empty
179 32
		$criteria = $this->getCriteria();
180 32
		if (!$criteria instanceof SearchCriteria && $criteria instanceof CriteriaInterface)
181
		{
182
			$criteria = new SearchCriteria($criteria);
183
		}
184 32
		if (empty($criteria))
185
		{
186 8
			$criteria = new SearchCriteria;
187
		}
188 32
		if (!empty($q))
189
		{
190 25
			$criteria->search($q);
191
		}
192
193 32
		$criteria->setModels($this->getModels());
194
195 32
		$decorator = new QueryBuilderDecorator($this->manganel);
196 32
		$decorator->setModels($this->getModels());
197 32
		$decorator->decorate($body, $criteria);
198 32
		$models = $this->getModels();
199 32
		if (empty($models))
200
		{
201
			$type = '_all';
202
		}
203
		else
204
		{
205 32
			$types = [];
206 32
			foreach ($models as $model)
207
			{
208 32
				assert($model instanceof AnnotatedInterface, new UnexpectedValueException(sprintf('Expected `%s` instance, got `%s`', AnnotatedInterface::class, is_object($model) ? get_class($model) : gettype($model))));
209 32
				$types[] = TypeNamer::nameType($model);
210
			}
211 32
			$type = implode(',', array_unique($types));
212
		}
213
214
		$params = [
215 32
			'index' => strtolower($this->manganel->index),
216 32
			'type' => $type,
217 32
			'body' => $body
218
		];
219
//		return $params;
220 32
		return RecursiveFilter::mongoIdToString($params);
221
	}
222
223
}
224