Completed
Push — master ( 6e3b43...934df1 )
by Peter
08:14
created

QueryBuilder::__construct()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 7
cts 7
cp 1
rs 9.7666
c 0
b 0
f 0
cc 3
nc 4
nop 1
crap 3
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 72
	public function __construct($model = null)
48
	{
49 72
		if (!empty($model))
50
		{
51 47
			$this->addModel($model);
52
		}
53 72
		if (!empty($model))
54
		{
55 47
			$this->manganel = Manganel::create($model);
56
		}
57
		else
58
		{
59 67
			$this->manganel = Manganel::fly();
60
		}
61 72
	}
62
63
	/**
64
	 * Add model or array of models
65
	 * @param AnnotatedInterface|AnnotatedInterface[] $model
66
	 * @return void
67
	 */
68 68
	public function add($model)
69
	{
70 68
		if (is_array($model))
71
		{
72 66
			foreach ($model as $m)
73
			{
74 66
				$this->addModel($m);
75
			}
76 66
			return;
77
		}
78 2
		$this->addModel($model);
79 2
	}
80
81
	/**
82
	 * Set criteria
83
	 * @param CriteriaInterface|array $criteria
84
	 * @return static
85
	 */
86 64
	public function setCriteria($criteria)
87
	{
88 64
		$this->criteria = $criteria;
89 64
		assert($criteria instanceof SearchCriteria);
90 64
		$this->add($criteria->getModels());
91 64
		return $this;
92
	}
93
94
	/**
95
	 *
96
	 * @param string $q
97
	 * @return int
98
	 */
99 53
	public function count($q = null)
100
	{
101 53
		$params = $this->getParams($q);
102
		try
103
		{
104 53
			$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 53
		if (empty($result) && empty($result['count']))
126
		{
127
			return 0; // @codeCoverageIgnore
128
		}
129 53
		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 63
	public function search($q = null, &$result = [])
141
	{
142 63
		$params = $this->getParams($q);
143
144
		try
145
		{
146 63
			$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 63
		if (empty($result) && empty($result['hits']) && empty($result['hits']['hits']))
169
		{
170
			return [];
171
		}
172 63
		return $result['hits']['hits'];
173
	}
174
175 72
	public function getParams($q = null)
176
	{
177 72
		$body = [];
178
		// Try to get query from criteria if empty
179 72
		$criteria = $this->getCriteria();
180 72
		if (!$criteria instanceof SearchCriteria && $criteria instanceof CriteriaInterface)
181
		{
182
			$criteria = new SearchCriteria($criteria);
183
		}
184 72
		if (empty($criteria))
185
		{
186 8
			$criteria = new SearchCriteria;
187
		}
188 72
		if (!empty($q))
189
		{
190 39
			$criteria->search($q);
191
		}
192
193 72
		$criteria->setModels($this->getModels());
194
195 72
		$decorator = new QueryBuilderDecorator($this->manganel);
196 72
		$decorator->setModels($this->getModels());
197 72
		$decorator->decorate($body, $criteria);
198 72
		$models = $this->getModels();
199 72
		if (empty($models))
200
		{
201 1
			$type = '_all';
202
		}
203
		else
204
		{
205 72
			$types = [];
206 72
			foreach ($models as $model)
207
			{
208 72
				assert($model instanceof AnnotatedInterface, new UnexpectedValueException(sprintf('Expected `%s` instance, got `%s`', AnnotatedInterface::class, is_object($model) ? get_class($model) : gettype($model))));
209 72
				$types[] = TypeNamer::nameType($model);
210
			}
211 72
			$type = implode(',', array_unique($types));
212
		}
213
214
		$params = [
215 72
			'index' => strtolower($this->manganel->index),
216 72
			'type' => $type,
217 72
			'body' => $body
218
		];
219
//		return $params;
220 72
		return RecursiveFilter::mongoIdToString($params);
221
	}
222
223
}
224