Completed
Push — master ( 00144e...167f4c )
by Maxence
01:32
created

SearchRequest::addSearch()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
declare(strict_types=1);
3
4
5
/**
6
 * FullTextSearch - Full text search framework for Nextcloud
7
 *
8
 * This file is licensed under the Affero General Public License version 3 or
9
 * later. See the COPYING file.
10
 *
11
 * @author Maxence Lange <[email protected]>
12
 * @copyright 2018
13
 * @license GNU AGPL version 3 or any later version
14
 *
15
 * This program is free software: you can redistribute it and/or modify
16
 * it under the terms of the GNU Affero General Public License as
17
 * published by the Free Software Foundation, either version 3 of the
18
 * License, or (at your option) any later version.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 * GNU Affero General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU Affero General Public License
26
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
27
 *
28
 */
29
30
31
namespace OCA\FullTextSearch\Model;
32
33
34
use daita\MySmallPhpTools\Traits\TArrayTools;
35
use JsonSerializable;
36
use OCP\FullTextSearch\Model\ISearchRequest;
37
use OCP\FullTextSearch\Model\ISearchRequestSimpleQuery;
38
39
40
/**
41
 * Class SearchRequest
42
 *
43
 * @package OCA\FullTextSearch\Model
44
 */
45
class SearchRequest implements ISearchRequest, JsonSerializable {
46
47
48
	use TArrayTools;
49
50
51
	/** @var array */
52
	private $providers;
53
54
	/** @var string */
55
	private $search;
56
57
	/** @var int */
58
	private $page = 1;
59
60
	/** @var int */
61
	private $size = 10;
62
63
	/** @var string */
64
	private $author;
65
66
	/** @var array */
67
	private $tags = [];
68
69
	/** @var array */
70
	public $metaTags = [];
71
72
	/** @var array */
73
	public $subTags = [];
74
75
	/** @var array */
76
	private $options;
77
78
	/** @var array */
79
	private $parts = [];
80
81
	/** @var array */
82
	private $fields = [];
83
84
	/** @var array */
85
	private $limitFields = [];
86
87
	/** @var array */
88
	private $wildcardFields = [];
89
90
//	/** @var array */
91
//	private $wildcardQueries = [];
92
93
	/** @var array */
94
	private $wildcardFilters = [];
95
96
	/** @var array */
97
	private $regexFilters = [];
98
99
	/** @var array */
100
	private $simpleQueries = [];
101
102
103
	/**
104
	 * SearchRequest constructor.
105
	 */
106
	public function __construct() {
107
	}
108
109
110
	/**
111
	 * @return array
112
	 */
113
	public function getProviders(): array {
114
		return $this->providers;
115
	}
116
117
	/**
118
	 * @param array $providers
119
	 *
120
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
121
	 */
122
	public function setProviders(array $providers): ISearchRequest {
123
		$this->providers = $providers;
124
125
		return $this;
126
	}
127
128
129
	/**
130
	 * @return string
131
	 */
132
	public function getAuthor(): string {
133
		return $this->author;
134
	}
135
136
	/**
137
	 * @param string $author
138
	 *
139
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
140
	 */
141
	public function setAuthor(string $author): ISearchRequest {
142
		$this->author = $author;
143
144
		return $this;
145
	}
146
147
148
	/**
149
	 * @return string
150
	 */
151
	public function getSearch(): string {
152
		return $this->search;
153
	}
154
155
	/**
156
	 * @param string $search
157
	 *
158
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
159
	 */
160
	public function setSearch(string $search): ISearchRequest {
161
		$this->search = $search;
162
163
		return $this;
164
	}
165
166
	/**
167
	 * @param string $search
168
	 *
169
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
170
	 */
171
	public function addSearch(string $search): ISearchRequest {
172
		$this->search .= ' ' . $search;
173
174
		return $this;
175
	}
176
177
178
	/**
179
	 *
180
	 */
181
	public function cleanSearch(): ISearchRequest {
182
		$search = trim(str_replace('  ', ' ', $this->getSearch()));
183
184
		preg_match_all('/[^?]"(?:\\\\.|[^\\\\"])*"|\S+/', " $search ", $words);
185
		$searchItems = [];
186
		foreach ($words[0] as $word) {
187
			if ($this->searchQueryOptions($word)) {
188
				continue;
189
			}
190
191
			$searchItems[] = $word;
192
		}
193
194
		$this->setSearch(implode(" ", $searchItems));
195
196
		return $this;
197
	}
198
199
200
	/**
201
	 * @param string $word
202
	 *
203
	 * @return bool
204
	 */
205
	private function searchQueryOptions(string $word): bool {
206
		if (($pos = strpos($word, ':')) === false || $pos === 0) {
207
			return false;
208
		}
209
210
		list($kw, $value) = explode(':', $word, 2);
211
212
		$options = ['is', 'show'];
213
		if (in_array($kw, $options)) {
214
			$this->addOption($kw . '_' . $value, '1');
215
216
			return true;
217
		}
218
219
		$valuedOptions = ['in', 'meta'];
220
		if (in_array($kw, $valuedOptions)) {
221
			$this->addMultipleOption($kw, $value);
222
223
			return true;
224
		}
225
226
		$valuedSubOptions = ['and'];
227
		if (in_array($kw, $valuedSubOptions)) {
228
			list($key, $value) = explode(':', $value, 2);
229
			$this->addMultipleOption($kw . ':' . $key, $value);
230
231
			return true;
232
		}
233
234
		return false;
235
	}
236
237
238
	/**
239
	 * @return int
240
	 */
241
	public function getPage(): int {
242
		return $this->page;
243
	}
244
245
	/**
246
	 * @param int $page
247
	 *
248
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
249
	 */
250
	public function setPage(int $page): ISearchRequest {
251
		if ($page < 1) {
252
			$page = 1;
253
		}
254
255
		$this->page = $page;
256
257
		return $this;
258
	}
259
260
261
	/**
262
	 * @return int
263
	 */
264
	public function getSize(): int {
265
		return $this->size;
266
	}
267
268
	/**
269
	 * @param int $size
270
	 *
271
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
272
	 */
273
	public function setSize(int $size): ISearchRequest {
274
		$this->size = $size;
275
276
		return $this;
277
	}
278
279
280
	/**
281
	 * @return array
282
	 */
283
	public function getOptions(): array {
284
		return $this->options;
285
	}
286
287
	/**
288
	 * @param array $options
289
	 *
290
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
291
	 */
292
	public function setOptions(array $options): ISearchRequest {
293
		$this->options = $options;
294
295
		return $this;
296
	}
297
298
	/**
299
	 * @param $option
300
	 * @param $value
301
	 *
302
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
303
	 */
304
	public function addOption(string $option, string $value): ISearchRequest {
305
		$this->options[$option] = $value;
306
307
		return $this;
308
	}
309
310
	/**
311
	 * @param string $option
312
	 * @param array $value
313
	 *
314
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
315
	 */
316
	public function addOptionArray(string $option, array $value): ISearchRequest {
317
		$this->options[$option] = $value;
318
319
		return $this;
320
	}
321
322
	/**
323
	 * @param string $option
324
	 * @param bool $value
325
	 *
326
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
327
	 */
328
	public function addOptionBool(string $option, bool $value): ISearchRequest {
329
		$this->options[$option] = $value;
330
331
		return $this;
332
	}
333
334
	/**
335
	 * @param string $option
336
	 * @param string $value
337
	 *
338
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
339
	 */
340
	public function addMultipleOption(string $option, string $value): ISearchRequest {
341
		if (!array_key_exists($option, $this->options)) {
342
			$this->options[$option] = [];
343
		}
344
345
		$this->options[$option][] = $value;
346
347
		return $this;
348
	}
349
350
	/**
351
	 * @param string $option
352
	 * @param string $default
353
	 *
354
	 * @return string
355
	 */
356
	public function getOption(string $option, string $default = ''): string {
357
		return $this->get($option, $this->options, $default);
358
	}
359
360
361
	/**
362
	 * @param string $option
363
	 * @param array $default
364
	 *
365
	 * @return array
366
	 */
367
	public function getOptionArray(string $option, array $default = []): array {
368
		return $this->getArray($option, $this->options, $default);
369
	}
370
371
372
	/**
373
	 * @param string $part
374
	 *
375
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
376
	 */
377
	public function addPart(string $part): ISearchRequest {
378
		$this->parts[] = $part;
379
380
		return $this;
381
	}
382
383
	/**
384
	 * @return array
385
	 */
386
	public function getParts(): array {
387
		return $this->parts;
388
	}
389
390
391
	/**
392
	 * @param array $parts
393
	 *
394
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
395
	 * @since 15.0.0
396
	 *
397
	 */
398
	public function setParts(array $parts): ISearchRequest {
399
		$this->parts = $parts;
400
401
		return $this;
402
	}
403
404
405
	/**
406
	 * @return array
407
	 */
408
	public function getFields(): array {
409
		return $this->fields;
410
	}
411
412
	/**
413
	 * @param array $fields
414
	 *
415
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
416
	 */
417
	public function setFields(array $fields): ISearchRequest {
418
		$this->fields = $fields;
419
420
		return $this;
421
	}
422
423
424
	/**
425
	 * @param string $field
426
	 *
427
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
428
	 */
429
	public function addLimitField(string $field): ISearchRequest {
430
		array_push($this->limitFields, $field);
431
432
		return $this;
433
	}
434
435
	/**
436
	 * @return array
437
	 */
438
	public function getLimitFields(): array {
439
		return $this->limitFields;
440
	}
441
442
443
	/**
444
	 * @param string $field
445
	 *
446
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
447
	 */
448
	public function addField(string $field): ISearchRequest {
449
		$this->fields[] = $field;
450
451
		return $this;
452
	}
453
454
455
	/**
456
	 * @param string $tag
457
	 *
458
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
459
	 */
460
	public function addTag(string $tag): ISearchRequest {
461
		$this->tags[] = $tag;
462
463
		return $this;
464
	}
465
466
	/**
467
	 * @return array
468
	 */
469
	public function getTags(): array {
470
		return $this->tags;
471
	}
472
473
	/**
474
	 * @param array $tags
475
	 *
476
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
477
	 */
478
	public function setTags(array $tags): ISearchRequest {
479
		$this->tags = $tags;
480
481
		return $this;
482
	}
483
484
485
	/**
486
	 * @param array $tags
487
	 *
488
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
489
	 */
490
	public function setMetaTags(array $tags): ISearchRequest {
491
		$this->metaTags = $tags;
492
493
		return $this;
494
	}
495
496
	/**
497
	 * @return array
498
	 */
499
	public function getMetaTags(): array {
500
		return $this->metaTags;
501
	}
502
503
	/**
504
	 * @param string $tag
505
	 *
506
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
507
	 */
508
	public function addMetaTag(string $tag): ISearchRequest {
509
		$this->metaTags[] = $tag;
510
511
		return $this;
512
	}
513
514
515
	/**
516
	 * @param array $tags
517
	 *
518
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
519
	 */
520
	public function setSubTags(array $tags): ISearchRequest {
521
		$this->subTags = $tags;
522
523
		return $this;
524
	}
525
526
	/**
527
	 * @param bool $formatted
528
	 *
529
	 * @return array
530
	 */
531
	public function getSubTags(bool $formatted = false): array {
532
		if ($formatted === false) {
533
			return $this->subTags;
534
		}
535
536
		$subTags = [];
537
		$ak = array_keys($this->subTags);
538
		foreach ($ak as $source) {
539
			$tags = $this->subTags[$source];
540
			foreach ($tags as $tag) {
541
				$subTags[] = $source . '_' . $tag;
542
			}
543
		}
544
545
		return $subTags;
546
	}
547
548
	/**
549
	 * @param string $source
550
	 * @param string $tag
551
	 *
552
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
553
	 */
554
	public function addSubTag(string $source, string $tag): ISearchRequest {
555
		if (!array_key_exists($source, $this->subTags)) {
556
			$this->subTags[$source] = [];
557
		}
558
559
		$this->subTags[$source][] = $tag;
560
561
		return $this;
562
	}
563
564
565
	/**
566
	 * @param string $field
567
	 *
568
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
569
	 */
570
	public function addWildcardField(string $field): ISearchRequest {
571
		$this->wildcardFields[] = $field;
572
573
		return $this;
574
	}
575
576
577
	/**
578
	 * @return array
579
	 */
580
	public function getWildcardFields(): array {
581
		return $this->wildcardFields;
582
	}
583
584
//
585
//	/**
586
//	 * @param array $query
587
//	 *
588
//	 * @return ISearchRequest
589
//	 */
590
//	public function addWildcardQuery($query) {
591
//		$this->addWildcardQueries([$query]);
592
//
593
//		return $this;
594
//	}
595
//
596
//	/**
597
//	 * @param array $query
598
//	 *
599
//	 * @return ISearchRequest
600
//	 */
601
//	public function addWildcardQueries($query) {
602
//		array_push($this->wildcardQueries, $query);
603
//
604
//		return $this;
605
//	}
606
//
607
//	/**
608
//	 * @return array
609
//	 */
610
//	public function getWildcardQueries() {
611
//		return $this->wildcardQueries;
612
//	}
613
614
615
	/**
616
	 * @param array $filter
617
	 *
618
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
619
	 */
620
	public function addWildcardFilter(array $filter): ISearchRequest {
621
		$this->addWildcardFilters([$filter]);
622
623
		return $this;
624
	}
625
626
	/**
627
	 * @param array $filters
628
	 *
629
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
630
	 */
631
	public function addWildcardFilters(array $filters): ISearchRequest {
632
		array_push($this->wildcardFilters, $filters);
633
634
		return $this;
635
	}
636
637
	/**
638
	 * @return array
639
	 */
640
	public function getWildcardFilters(): array {
641
		return $this->wildcardFilters;
642
	}
643
644
645
	/**
646
	 * @param string $filter
647
	 *
648
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
649
	 */
650
	public function addRegexFilter(string $filter): ISearchRequest {
651
		$this->addRegexFilters([$filter]);
652
653
		return $this;
654
	}
655
656
	/**
657
	 * @param array $filters
658
	 *
659
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
660
	 */
661
	public function addRegexFilters(array $filters): ISearchRequest {
662
		array_push($this->regexFilters, $filters);
663
664
		return $this;
665
	}
666
667
	/**
668
	 * @return array
669
	 */
670
	public function getRegexFilters(): array {
671
		return $this->regexFilters;
672
	}
673
674
675
	/**
676
	 * @param ISearchRequestSimpleQuery $query
677
	 *
678
	 * @return ISearchRequest
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use SearchRequest.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
679
	 */
680
	public function addSimpleQuery(ISearchRequestSimpleQuery $query): ISearchRequest {
681
		$this->simpleQueries[] = $query;
682
683
		return $this;
684
	}
685
686
687
	/**
688
	 * @return ISearchRequestSimpleQuery[]
689
	 */
690
	public function getSimpleQueries(): array {
691
		return $this->simpleQueries;
692
	}
693
694
695
	/**
696
	 * @return array
697
	 */
698
	public function jsonSerialize(): array {
699
		return [
700
			'providers' => $this->getProviders(),
701
			'author'    => $this->getAuthor(),
702
			'search'    => $this->getSearch(),
703
			'page'      => $this->getPage(),
704
			'size'      => $this->getSize(),
705
			'parts'     => $this->getParts(),
706
			'queries'   => $this->getSimpleQueries(),
707
			'options'   => $this->getOptions(),
708
			'metatags'  => $this->getMetaTags(),
709
			'subtags'   => $this->getSubTags(),
710
			'tags'      => $this->getTags()
711
		];
712
	}
713
714
715
	/**
716
	 * @param array $arr
717
	 *
718
	 * @return SearchRequest
719
	 */
720
	public function importFromArray($arr): SearchRequest {
721
		$providers = $arr['providers'];
722
		if (!is_array($providers)) {
723
			$providers = [$providers];
724
		}
725
726
		$this->setProviders($providers);
727
		$this->setAuthor($this->get('author', $arr, ''));
728
		$this->setSearch($this->get('search', $arr, ''));
729
		$this->setPage($this->getInt('page', $arr, 0));
730
		$this->setParts($this->getArray('parts', $arr, []));
731
		$this->setSize($this->getInt('size', $arr, 10));
732
		$this->setOptions($this->getArray('options', $arr, []));
733
		$this->setMetaTags($this->getArray('metatags', $arr, []));
734
		$this->setSubTags($this->getArray('subtags', $arr, []));
735
		$this->setTags($this->getArray('tags', $arr, []));
736
737
		return $this;
738
	}
739
740
741
	/**
742
	 * @param string $json
743
	 *
744
	 * @return SearchRequest
745
	 */
746
	public static function fromJSON(string $json): SearchRequest {
747
		$searchRequest = new SearchRequest();
748
		$searchRequest->importFromArray(json_decode($json, true));
749
750
		return $searchRequest;
751
	}
752
753
}
754