Completed
Push — master ( 1350a6...d3076a )
by Peter
08:18
created

QueryBuilder   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 178
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 10

Test Coverage

Coverage 72.86%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 26
c 3
b 0
f 0
lcom 2
cbo 10
dl 0
loc 178
ccs 51
cts 70
cp 0.7286
rs 10

6 Methods

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