Passed
Push — master ( 8ec95d...ba9743 )
by Sebastian
04:36
created

renderRegex()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 8
nc 2
nop 1
dl 0
loc 14
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Mailcode;
6
7
class Mailcode_Translator_Syntax_ApacheVelocity_Contains_StatementBuilder
8
{
9
    const ERROR_INVALID_LIST_VARIABLE_NAME = 76701;
10
11
    /**
12
     * @var Mailcode_Variables_Variable
13
     */
14
    private $variable;
15
16
    /**
17
     * @var bool
18
     */
19
    private $caseSensitive;
20
21
    /**
22
     * @var array
23
     */
24
    private $searchTerms;
25
26
    /**
27
     * @var string
28
     */
29
    private $containsType;
30
31
    /**
32
     * @var Mailcode_Translator_Syntax_ApacheVelocity
33
     */
34
    private $translator;
35
36
    public function __construct(Mailcode_Translator_Syntax_ApacheVelocity $translator, Mailcode_Variables_Variable $variable, bool $caseSensitive, array $searchTerms, string $containsType)
37
    {
38
        $this->translator = $translator;
39
        $this->variable = $variable;
40
        $this->caseSensitive = $caseSensitive;
41
        $this->searchTerms = $searchTerms;
42
        $this->containsType = $containsType;
43
    }
44
45
    /**
46
     * Is this a not contains command? (list or regular)
47
     * @return bool
48
     */
49
    public function isNotContains() : bool
50
    {
51
        return strstr($this->containsType, 'not-contains') !== false;
52
    }
53
54
    /**
55
     * Is this a contains command to be used on a list variable?
56
     * @return bool
57
     */
58
    public function isList() : bool
59
    {
60
        return strstr($this->containsType, 'list-') !== false;
61
    }
62
63
    /**
64
     * Gets the sign to prepend the command with, i.e.
65
     * whether to add the negation "!" or not, depending
66
     * on the type of command.
67
     *
68
     * @return string
69
     */
70
    public function getSign() : string
71
    {
72
        if($this->isNotContains())
73
        {
74
            return '!';
75
        }
76
77
        return '';
78
    }
79
80
    /**
81
     * Gets the logical connector sign to combine several search
82
     * terms with, i.e. "&&" or "||" depending on whether it is
83
     * a regular contains or not contains.
84
     *
85
     * @return string
86
     */
87
    public function getConnector()
88
    {
89
        if($this->isNotContains())
90
        {
91
            return '&&';
92
        }
93
94
        return '||';
95
    }
96
97
    /**
98
     * @return string
99
     * @throws Mailcode_Exception
100
     */
101
    public function render() : string
102
    {
103
        $parts = array();
104
105
        foreach($this->searchTerms as $token)
106
        {
107
            $parts[] = $this->renderCommand($token);
108
        }
109
110
        return implode(' '.$this->getConnector().' ', $parts);
111
    }
112
113
    /**
114
     * @param Mailcode_Parser_Statement_Tokenizer_Token_StringLiteral $searchTerm
115
     * @return string
116
     * @throws Mailcode_Exception
117
     */
118
    private function renderCommand(Mailcode_Parser_Statement_Tokenizer_Token_StringLiteral $searchTerm) : string
119
    {
120
        if($this->isList())
121
        {
122
            $command = $this->renderListCommand($searchTerm);
123
        }
124
        else
125
        {
126
            $command = $this->renderRegularCommand($searchTerm);
127
        }
128
129
        return $this->getSign().$command;
130
    }
131
132
    private function renderRegularCommand(Mailcode_Parser_Statement_Tokenizer_Token_StringLiteral $searchTerm) : string
133
    {
134
        return sprintf(
135
            '%s.matches(%s)',
136
            $this->variable->getFullName(),
137
            $this->renderRegex($searchTerm)
138
        );
139
    }
140
141
    /**
142
     * @param Mailcode_Parser_Statement_Tokenizer_Token_StringLiteral $searchTerm
143
     * @return string
144
     * @throws Mailcode_Exception
145
     */
146
    private function renderListCommand(Mailcode_Parser_Statement_Tokenizer_Token_StringLiteral $searchTerm) : string
147
    {
148
        $name = $this->parseVarName();
149
150
        return sprintf(
151
            '$map.hasElement(%s.list(), "%s", %s)',
152
            '$'.$name['path'],
153
            $name['name'],
154
            $this->renderRegex($searchTerm)
155
        );
156
    }
157
158
    private function renderRegex(Mailcode_Parser_Statement_Tokenizer_Token_StringLiteral $searchTerm) : string
159
    {
160
        $opts = 's';
161
        if($this->caseSensitive)
162
        {
163
            $opts = 'is';
164
        }
165
166
        $filtered = $this->translator->filterRegexString(trim($searchTerm->getNormalized(), '"'));
167
168
        return sprintf(
169
            '"(?%s)%s"',
170
            $opts,
171
            $filtered
172
        );
173
    }
174
175
    /**
176
     * @return array<string,string>
177
     * @throws Mailcode_Exception
178
     */
179
     private function parseVarName() : array
180
     {
181
         $tokens = explode('.', ltrim($this->variable->getFullName(), '$'));
182
183
         if(count($tokens) === 2)
184
         {
185
             return array(
186
                 'path' => $tokens[0],
187
                 'name' => $tokens[1]
188
             );
189
         }
190
191
         throw new Mailcode_Exception(
192
             'Invalid variable name for a list property.',
193
             sprintf(
194
                 'Exactly 2 parts are required, variable [%s] has [%s].',
195
                 $this->variable->getFullName(),
196
                 count($tokens)
197
             ),
198
             self::ERROR_INVALID_LIST_VARIABLE_NAME
199
         );
200
     }
201
}
202
203