Manganel   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 241
Duplicated Lines 0 %

Coupling/Cohesion

Components 5
Dependencies 7

Test Coverage

Coverage 52.63%

Importance

Changes 0
Metric Value
wmc 21
lcom 5
cbo 7
dl 0
loc 241
ccs 10
cts 19
cp 0.5263
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 19 3
A create() 0 14 2
A fly() 0 12 3
A init() 0 4 1
A getVersion() 0 8 2
A drop() 0 12 4
A getClient() 0 16 2
A getProfiler() 0 12 3
A setProfiler() 0 5 1
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 Closure;
16
use Elasticsearch\Client;
17
use Elasticsearch\ClientBuilder;
18
use Maslosoft\Addendum\Interfaces\AnnotatedInterface;
19
use Maslosoft\EmbeDi\EmbeDi;
20
use Maslosoft\Mangan\Interfaces\ProfilerInterface;
21
use Maslosoft\Mangan\Profillers\NullProfiler;
22
use Maslosoft\Manganel\Decorators\QueryBuilder\ConditionDecorator;
23
use Maslosoft\Manganel\Decorators\QueryBuilder\ConditionsDecorator;
24
use Maslosoft\Manganel\Decorators\QueryBuilder\MoreLikeThisDecorator;
25
use Maslosoft\Manganel\Decorators\QueryBuilder\Operators\InDecorator;
26
use Maslosoft\Manganel\Decorators\QueryBuilder\Operators\NotDecorator;
27
use Maslosoft\Manganel\Decorators\QueryBuilder\Operators\OrDecorator;
28
use Maslosoft\Manganel\Decorators\QueryBuilder\Operators\RangeDecorator;
29
use Maslosoft\Manganel\Decorators\QueryBuilder\Operators\SimpleTermDecorator;
30
use Maslosoft\Manganel\Decorators\QueryBuilder\QueryString\BoostDecorator;
31
use Maslosoft\Manganel\Decorators\QueryBuilder\QueryString\PrefixQueryDecorator;
32
use Maslosoft\Manganel\Decorators\QueryBuilder\ScrollDecorator;
33
use Maslosoft\Manganel\Decorators\QueryBuilder\SearchDecorator;
34
use Maslosoft\Manganel\Decorators\QueryBuilder\SelectDecorator;
35
use Maslosoft\Manganel\Decorators\QueryBuilder\TagDecorator;
36
use Maslosoft\Manganel\Interfaces\ManganelAwareInterface;
37
use Maslosoft\Manganel\Meta\ManganelMeta;
38
39
/**
40
 * Manganel
41
 *
42
 * @author Piotr Maselkowski <pmaselkowski at gmail.com>
43
 */
44
class Manganel
45
{
46
47
	const DefaultIndexId = 'manganel';
48
49
	public $decorators = [
50
		SearchCriteria::class => [
51
			SelectDecorator::class,
52
			ConditionDecorator::class,
53
			ConditionsDecorator::class,
54
			ScrollDecorator::class,
55
			SearchDecorator::class,
56
			InDecorator::class,
57
			OrDecorator::class,
58
			NotDecorator::class,
59
			RangeDecorator::class,
60
			SimpleTermDecorator::class,
61
			BoostDecorator::class,
62
			PrefixQueryDecorator::class,
63
			MoreLikeThisDecorator::class
64
		]
65
	];
66
	public $hosts = [
67
		'localhost:9200'
68
	];
69
	public $auth = null;
70
	public $username = '';
71
	public $password = '';
72
	public $params = [];
73
74
	/**
75
	 * TODO Enforce lowercase
76
	 */
77
	public $index = 'my_index';
78
	public $indexId = self::DefaultIndexId;
79
80
	/**
81
	 * Whether to use refresh option when indexing document.
82
	 * NOTE: Due to performance reasons, this should be set to `true` only when
83
	 * really necessary - so it can be also callback.
84
	 *
85
	 * Callback function signature:
86
	 * ```
87
	 * function(AnnotatedInterface $model)
88
	 * ```
89
	 * @var string|Closure
90
	 */
91
	public $refresh = false;
92
93
	/**
94
	 *
95
	 * @var Client
96
	 */
97
	private $client = null;
98
99
	/**
100
	 * Dependency injection container
101
	 * @var EmbeDi
102
	 */
103
	private $di = null;
104
105
	/**
106
	 * Version number holder
107
	 * @var string
108
	 */
109
	private static $_version = null;
110
111
	/**
112
	 * Instances of manganel
113
	 * @var Manganel[]
114
	 */
115
	private static $mnl = [];
116
117
	/**
118
	 * Hash map of class name to id. This is to reduce overhead of Mangan::fromModel()
119
	 * @var string[]
120
	 */
121
	private static $classToId = [];
122
123
	/**
124
	 * Profiler instance
125
	 * @var ProfilerInterface
126
	 */
127
	private $profiler = null;
128
129
	/**
130
	 * Class constructor
131
	 * @codeCoverageIgnore This is implicitly tested
132
	 * @param string $indexId
133
	 */
134
	public function __construct($indexId = self::DefaultIndexId)
135
	{
136
		if (empty($indexId))
137
		{
138
			$indexId = self::DefaultIndexId;
139
		}
140
		$decorators = $this->decorators;
141
142
		$this->indexId = $indexId;
143
		$this->di = new EmbeDi($this->indexId);
144
		$this->di->configure($this);
145
146
		$this->decorators = array_merge_recursive($this->decorators, $decorators);
147
148
		if (empty(self::$mnl[$indexId]))
149
		{
150
			self::$mnl[$indexId] = $this;
151
		}
152
	}
153
154
	/**
155
	 * @codeCoverageIgnore This is implicitly tested
156
	 * @param AnnotatedInterface $model
157
	 * @return static
158
	 */
159
	public static function create(AnnotatedInterface $model)
160
	{
161
		$key = get_class($model);
162
		if (isset(self::$classToId[$key]))
163
		{
164
			$indexId = self::$classToId[$key];
165
		}
166
		else
167
		{
168
			$indexId = ManganelMeta::create($model)->type()->indexId;
169
			self::$classToId[$key] = $indexId;
170
		}
171
		return static::fly($indexId);
172
	}
173
174
	/**
175
	 * Get flyweight instance of Manganel component.
176
	 * Only one instance will be created for each `$indexId`.
177
	 *
178
	 * @codeCoverageIgnore This is implicitly tested
179
	 * @new
180
	 * @param string $indexId
181
	 * @return Manganel
182
	 */
183
	public static function fly($indexId = self::DefaultIndexId)
184
	{
185
		if (empty($indexId))
186
		{
187
			$indexId = self::DefaultIndexId;
188
		}
189
		if (empty(self::$mnl[$indexId]))
190
		{
191
			self::$mnl[$indexId] = new static($indexId);
192
		}
193
		return self::$mnl[$indexId];
194
	}
195
196
	/**
197
	 * @codeCoverageIgnore This is implicitly tested
198
	 */
199
	public function init()
200
	{
201
		$this->di->store($this);
202
	}
203
204
	/**
205
	 * Get mangan version
206
	 * @return string
207
	 */
208
	public function getVersion()
209
	{
210
		if (null === self::$_version)
211
		{
212
			self::$_version = require __DIR__ . '/version.php';
213
		}
214
		return self::$_version;
215
	}
216
217
	/**
218
	 * Drop current index
219
	 * @return bool
220
	 */
221 1
	public function drop()
222
	{
223
		$params = [
224 1
			'index' => strtolower($this->index)
225
		];
226 1
		$result = $this->getClient()->indices()->delete($params);
227 1
		if (is_array($result) && array_key_exists('acknowledged', $result) && $result['acknowledged'])
228
		{
229 1
			return true;
230
		}
231
		return false;
232
	}
233
234
	/**
235
	 * @codeCoverageIgnore This is implicitly tested
236
	 * @return Client
237
	 */
238
	public function getClient()
239
	{
240
		if (null === $this->client)
241
		{
242
			$this->params['hosts'] = $this->hosts;
243
			$this->params['connectionParams']['auth'] = [
244
				$this->username,
245
				$this->password,
246
				$this->auth
247
			];
248
			$cb = ClientBuilder::create();
249
			$cb->setHosts($this->hosts);
250
			$this->client = $cb->build();
251
		}
252
		return $this->client;
253
	}
254
255
	/**
256
	 * Get profiler instance. This is guaranted, if not configured will return NullProfiller.
257
	 * @see NullProfiler
258
	 * @return ProfilerInterface
259
	 */
260 24
	public function getProfiler()
261
	{
262 24
		if (null === $this->profiler)
263
		{
264 1
			$this->profiler = new NullProfiler;
265
		}
266 24
		if ($this->profiler instanceof ManganelAwareInterface)
267
		{
268
			$this->profiler->setManganel($this);
269
		}
270 24
		return $this->profiler;
271
	}
272
273
	/**
274
	 * Set profiler instance
275
	 * @param ProfilerInterface $profiller
276
	 * @return static
277
	 */
278
	public function setProfiler(ProfilerInterface $profiller)
279
	{
280
		$this->profiler = $profiller;
281
		return $this;
282
	}
283
284
}
285