Passed
Push — master ( d9af9b...707ba4 )
by Sebastian
03:07
created

Mailcode_Variables_Variable::getUniqueName()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 8
rs 10
1
<?php
2
/**
3
 * File containing the {@see Mailcode_Variables_Variable} class.
4
 *
5
 * @package Mailcode
6
 * @subpackage Variables
7
 * @see Mailcode_Variables_Variable
8
 */
9
10
declare(strict_types=1);
11
12
namespace Mailcode;
13
14
use AppUtils\OperationResult;
15
16
/**
17
 * Simple container for a single variable name occurrence: used
18
 * to store information on variable names used in commands, with
19
 * the possibility to retrieve the actual matched text among other
20
 * things.
21
 *
22
 * @package Mailcode
23
 * @subpackage Variables
24
 * @author Sebastian Mordziol <[email protected]>
25
 */
26
class Mailcode_Variables_Variable
27
{
28
    const ERROR_MISSING_VALIDATION_METHOD = 48601;
29
    
30
    const VALIDATION_ERROR_PATH_NUMERIC = 48201;
31
    const VALIDATION_ERROR_NAME_NUMERIC = 48202;
32
    const VALIDATION_ERROR_PATH_UNDERSCORE = 48203;
33
    const VALIDATION_ERROR_NAME_UNDERSCORE = 48204;
34
    
35
   /**
36
    * @var string
37
    */
38
    protected $path;
39
    
40
   /**
41
    * @var string
42
    */
43
    protected $name;
44
    
45
   /**
46
    * @var string
47
    */
48
    protected $matchedText;
49
    
50
   /**
51
    * @var string
52
    */
53
    protected $hash = '';
54
    
55
   /**
56
    * @var OperationResult
57
    */
58
    protected $validationResult = null;
59
    
60
   /**
61
    * @var array<string>
62
    */
63
    protected $validations = array(
64
        'number_path',
65
        'number_name',
66
        'underscore_path',
67
        'underscore_name'
68
    );
69
70
    /**
71
     * @var Mailcode_Commands_Command|null
72
     */
73
    private $command;
74
75
    public function __construct(string $path, string $name, string $matchedText, ?Mailcode_Commands_Command $sourceCommand=null)
76
    {
77
        $this->path = $path;
78
        $this->name = $name;
79
        $this->matchedText = $matchedText;
80
        $this->command = $sourceCommand;
81
    }
82
83
    /**
84
     * Retrieves the source command of the variable, if any.
85
     * The string parser automatically sets the variable's
86
     * command, but if it was created via other means it will
87
     * not have one.
88
     *
89
     * @return Mailcode_Commands_Command|null
90
     */
91
    public function getSourceCommand() : ?Mailcode_Commands_Command
92
    {
93
        return $this->command;
94
    }
95
    
96
    public function getFullName() : string
97
    {
98
        if(empty($this->path))
99
        {
100
            return '$'.$this->name;
101
        }
102
        
103
        return '$'.$this->path.'.'.$this->name;
104
    }
105
106
    /**
107
     * Retrieves the name of the variable with a suffix that
108
     * uniquely identifies it together with the command it
109
     * came from. Used for grouping identical variables.
110
     *
111
     * @return string
112
     * @throws Mailcode_Exception
113
     */
114
    public function getUniqueName() : string
115
    {
116
        if(isset($this->command))
117
        {
118
            return $this->getFullName().'/'.$this->command->getHash();
0 ignored issues
show
Bug introduced by
The method getHash() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

118
            return $this->getFullName().'/'.$this->command->/** @scrutinizer ignore-call */ getHash();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
119
        }
120
121
        return $this->getFullName();
122
    }
123
    
124
    public function getName() : string
125
    {
126
        return $this->name;
127
    }
128
    
129
    public function getPath() : string
130
    {
131
        return $this->path;
132
    }
133
    
134
    public function getMatchedText() : string
135
    {
136
        return $this->matchedText;
137
    }
138
    
139
    public function getHash() : string
140
    {
141
        if(empty($this->hash))
142
        {
143
            $this->hash = md5($this->matchedText);
144
        }
145
        
146
        return $this->hash;
147
    }
148
    
149
    public function isValid() : bool
150
    {
151
        return $this->getValidationResult()->isValid();
152
    }
153
    
154
    public function getValidationResult() : OperationResult
155
    {
156
        if(isset($this->validationResult))
157
        {
158
            return $this->validationResult;
159
        }
160
        
161
        $this->validationResult = new OperationResult($this);
162
        
163
        $this->validate();
164
        
165
        return $this->validationResult;
166
    }
167
168
    protected function validate() : void
169
    {
170
        foreach($this->validations as $validation)
171
        {
172
            $method = 'validate_'.$validation;
173
            
174
            if(!method_exists($this, $method))
175
            {
176
                throw new Mailcode_Exception(
177
                    'Unknown validation method',
178
                    sprintf(
179
                        'The method [%s] is missing in class [%s].',
180
                        $method,
181
                        get_class($this)
182
                    ),
183
                    self::ERROR_MISSING_VALIDATION_METHOD
184
                );
185
            }
186
            
187
            $this->$method();
188
            
189
            if(!$this->validationResult->isValid())
190
            {
191
                return;
192
            }
193
        }
194
    }
195
    
196
    protected function validate_number_path() : void
197
    {
198
        $this->validateNumber($this->path, self::VALIDATION_ERROR_PATH_NUMERIC);
199
    }
200
    
201
    protected function validate_number_name() : void
202
    {
203
        $this->validateNumber($this->name, self::VALIDATION_ERROR_NAME_NUMERIC);
204
    }
205
    
206
    protected function validate_underscore_path() : void
207
    {
208
        $this->validateUnderscore($this->path, self::VALIDATION_ERROR_PATH_UNDERSCORE);
209
    }
210
    
211
    protected function validate_underscore_name() : void
212
    {
213
        $this->validateUnderscore($this->name, self::VALIDATION_ERROR_NAME_UNDERSCORE);
214
    }
215
    
216
    protected function validateNumber(string $value, int $errorCode) : void
217
    {
218
        if(!is_numeric(substr($value, 0, 1)))
219
        {
220
            return;
221
        }
222
        
223
        $this->validationResult->makeError(
224
            t(
225
                'The %1$s in variable %2$s must begin with a letter.',
226
                $value,
227
                $this->getFullName()
228
            ),
229
            $errorCode
230
        );
231
    }
232
    
233
    protected function validateUnderscore(string $value, int $errorCode) : void
234
    {
235
        // allow empty paths
236
        if(empty($value))
237
        {
238
            return;
239
        }
240
        
241
        $length = strlen($value);
242
        
243
        // trimming underscores does not change the length: no underscores at start or end of string.
244
        if(strlen(trim($value, '_')) == $length)
245
        {
246
            return;
247
        }
248
        
249
        $this->validationResult->makeError(
250
            t(
251
                'The %1$s in variable %2$s may not start or end with an underscore.',
252
                $value,
253
                $this->getFullName()
254
            ),
255
            $errorCode
256
        );
257
    }
258
}
259