Passed
Push — master ( 8e43c9...4981d1 )
by Tarmo
116:46 queued 51:34
created

SearchTerm::getTerm()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 12
nc 4
nop 2
dl 0
loc 16
rs 9.8666
c 0
b 0
f 0
ccs 11
cts 11
cp 1
crap 4
1
<?php
2
declare(strict_types = 1);
3
/**
4
 * /src/Rest/SearchTerm.php
5
 *
6
 * @author TLe, Tarmo Leppänen <[email protected]>
7
 */
8
9
namespace App\Rest;
10
11
use App\Rest\Interfaces\SearchTermInterface;
12
use Closure;
13
use function array_filter;
14
use function array_map;
15
use function array_merge;
16
use function array_unique;
17
use function array_values;
18
use function count;
19
use function explode;
20
use function is_array;
21
use function str_contains;
22
use function trim;
23
24
/**
25
 * Class SearchTerm
26
 *
27
 * @package App\Rest
28
 * @author TLe, Tarmo Leppänen <[email protected]>
29
 */
30
final class SearchTerm implements SearchTermInterface
31
{
32
    public static function getCriteria(
33
        array | string | null $column,
34
        array | string | null $search,
35 43
        ?string $operand = null,
36
        ?int $mode = null,
37 43
    ): ?array {
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected ')', expecting T_VARIABLE on line 37 at column 4
Loading history...
38 43
        $operand ??= self::OPERAND_OR;
39
        $mode ??= self::MODE_FULL;
40 43
41 43
        $columns = self::getColumns($column);
42
        $searchTerms = self::getSearchTerms($search);
43
44 43
        // Fallback to OR operand if not supported one given
45 1
        if ($operand !== self::OPERAND_AND && $operand !== self::OPERAND_OR) {
46
            $operand = self::OPERAND_OR;
47
        }
48 43
49
        return self::createCriteria($columns, $searchTerms, $operand, $mode);
50
    }
51
52
    /**
53
     * Helper method to create used criteria array with given columns and search terms.
54
     *
55
     * @param array<int, string> $columns
56
     * @param array<int, string> $searchTerms
57
     *
58
     * @return array<string, array<string, array>>|null
59 43
     */
60
    private static function createCriteria(array $columns, array $searchTerms, string $operand, int $mode): ?array
61 43
    {
62
        $iteratorTerm = self::getTermIterator($columns, $mode);
63
64
        /**
65
         * Get criteria
66
         *
67
         * @var array<string, array<string, array>>
68 43
         */
69
        $criteria = array_filter(array_map($iteratorTerm, $searchTerms));
70
71 43
        // Initialize output
72
        $output = null;
73
74 43
        // We have some generated criteria
75
        if (count($criteria) > 0) {
76
            // Create used criteria array
77
            $output = [
78 20
                'and' => [
79
                    $operand => array_merge(...array_values($criteria)),
80
                ],
81
            ];
82
        }
83 43
84
        return $output;
85
    }
86
87
    /**
88
     * Method to get term iterator closure.
89
     *
90
     * @param array<int, string> $columns
91 43
     */
92
    private static function getTermIterator(array $columns, int $mode): Closure
93 43
    {
94 20
        return static fn (string $term): ?array => count($columns) > 0
95 43
            ? array_map(self::getColumnIterator($term, $mode), $columns)
96
            : null;
97
    }
98
99
    /**
100
     * Method to get column iterator closure.
101 20
     */
102
    private static function getColumnIterator(string $term, int $mode): Closure
103
    {
104
        /*
105
         * Lambda function to create actual criteria for specified column + term + mode combo.
106
         *
107
         * @param string $column
108
         *
109
         * @return array<int, string>
110 20
         */
111 20
        return static fn (string $column): array => [
112 20
            !str_contains($column, '.') ? 'entity.' . $column : $column, 'like', self::getTerm($mode, $term),
113
        ];
114
    }
115
116
    /**
117
     * Method to get search term clause for 'LIKE' query for specified mode.
118 20
     */
119
    private static function getTerm(int $mode, string $term): string
120
    {
121 20
        return match ($mode) {
122 1
            self::MODE_STARTS_WITH => $term . '%',
123 1
            self::MODE_ENDS_WITH => '%' . $term,
124 19
            default => '%' . $term . '%', // self::MODE_FULL
125 1
        };
126 1
    }
127 18
128
    /**
129 18
     * @param string|array<int, string>|null $column search column(s), could be a
130 18
     *                                               string or an array of strings
131
     *
132
     * @return array<int, string>
133 20
     */
134
    private static function getColumns(array | string | null $column): array
135
    {
136
        // Normalize column and search parameters
137
        return array_filter(
138
            array_map('trim', (is_array($column) ? $column : (array)(string)$column)),
139
            static fn (string $value): bool => trim($value) !== ''
140
        );
141
    }
142 43
143
    /**
144
     * Method to get search terms.
145 43
     *
146 43
     * @param string|array<int, string>|null $search search term(s), could be a string or an array of strings
147 43
     *
148 43
     * @return array<int, string>
149
     */
150
    private static function getSearchTerms(array | string | null $search): array
151
    {
152
        return array_unique(
153
            array_filter(
154
                array_map('trim', (is_array($search) ? $search : explode(' ', (string)$search))),
155
                static fn (string $value): bool => trim($value) !== ''
156
            )
157
        );
158
    }
159
}
160