Completed
Push — master ( 475e3b...eae72f )
by Peter
07:52
created

QueryBuilder   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 170
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 10

Test Coverage

Coverage 81.54%

Importance

Changes 6
Bugs 1 Features 0
Metric Value
wmc 26
lcom 2
cbo 10
dl 0
loc 170
ccs 53
cts 65
cp 0.8154
rs 10
c 6
b 1
f 0

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