Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
SearchQuery
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
2 / 2
4
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 withLimit
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5/** @license For full copyright and license information, please see the LICENSE.md file. */
6
7namespace App\Core\Search\Domain\Model;
8
9defined('AMMONLY_APP') || exit('Direct script access is forbidden.');
10
11use App\Core\Search\Domain\Exception\SearchException;
12
13/**
14 * Search Query Value Object.
15 *
16 * Encapsulates search term, execution mode, module scoping, and pagination limits.
17 *
18 * @package App\Core\Search\Domain\Model
19 */
20final readonly class SearchQuery
21{
22    public const int DEFAULT_LIMIT_PER_MODULE = 5;
23    public const int MAX_LIMIT_PER_MODULE = 50;
24    public const int MAX_TERM_LENGTH = 255;
25
26    public string $term;
27
28    /**
29     * SearchQuery constructor.
30     *
31     * @param string       $term            Raw search expression.
32     * @param SearchMode   $mode            Search execution mode.
33     * @param list<string> $modules         Target module names (empty for all accessible).
34     * @param int          $limitPerModule  Maximum records returned per module.
35     * @throws SearchException When the search term is empty or too short.
36     */
37    public function __construct(
38        string $term,
39        public SearchMode $mode = SearchMode::SMART,
40        public array $modules = [],
41        public int $limitPerModule = self::DEFAULT_LIMIT_PER_MODULE
42    ) {
43        $trimmed = trim($term);
44        if ($trimmed === '') {
45            throw new SearchException('Search query term cannot be empty.');
46        }
47
48        if (mb_strlen($trimmed) > self::MAX_TERM_LENGTH) {
49            $trimmed = mb_substr($trimmed, 0, self::MAX_TERM_LENGTH);
50        }
51
52        $this->term = $trimmed;
53    }
54
55    /**
56     * Creates a new instance with a clamped limit.
57     *
58     * @param int $limit Target limit.
59     * @return self New instance.
60     */
61    public function withLimit(int $limit): self
62    {
63        $clamped = max(1, min(self::MAX_LIMIT_PER_MODULE, $limit));
64
65        return new self($this->term, $this->mode, $this->modules, $clamped);
66    }
67}