Passed
Push — master ( 62880d...2f714f )
by Sebastian
07:50
created

Mailcode_Collection_NestingValidator::validate()   A

Complexity

Conditions 5
Paths 7

Size

Total Lines 37
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 18
c 1
b 0
f 0
nc 7
nop 0
dl 0
loc 37
rs 9.3554
1
<?php
2
/**
3
 * File containing the {@see Mailcode_Collection} class.
4
 *
5
 * @package Mailcode
6
 * @subpackage Collection
7
 * @see Mailcode_Collection
8
 */
9
10
declare(strict_types=1);
11
12
namespace Mailcode;
13
14
use AppUtils\OperationResult;
15
16
/**
17
 * Commands collection: container for commands.
18
 *
19
 * @package Mailcode
20
 * @subpackage Collection
21
 * @author Sebastian Mordziol <[email protected]>
22
 */
23
class Mailcode_Collection_NestingValidator
24
{
25
    const ERROR_MISSING_COMMAND_TYPE_METHOD = 49001;
26
    
27
    const VALIDATION_SIBLING_WITHOUT_PARENT = 49101;
28
    const VALIDATION_SIBLING_WRONG_PARENT = 49102; 
29
    const VALIDATION_COMMANDS_ALREADY_CLOSED = 49103;
30
    const VALIDATION_UNCLOSED_COMMAND = 49104;
31
    
32
   /**
33
    * @var Mailcode_Collection
34
    */
35
    protected $collection;
36
    
37
   /**
38
    * @var OperationResult
39
    */
40
    protected $validationResult;
41
    
42
   /**
43
    * @var Mailcode_Commands_Command[]
44
    */
45
    protected $stack = array();
46
    
47
    public function __construct(Mailcode_Collection $collection)
48
    {
49
        $this->collection = $collection;
50
    }
51
    
52
    public function getCollection() : Mailcode_Collection
53
    {
54
        return $this->collection;
55
    }
56
    
57
    public function validate() : OperationResult
58
    {
59
        $this->validationResult = new OperationResult($this);
60
        
61
        $commands = $this->collection->getCommands();
62
        
63
        foreach($commands as $command)
64
        {
65
            $method = 'validate_'.$command->getCommandType();
66
            
67
            if(!method_exists($this, $method))
68
            {
69
                throw new Mailcode_Exception(
70
                    'Unknown command type validation method.',
71
                    sprintf(
72
                        'The method [%s] does not exist in class [%s].',
73
                        $method,
74
                        get_class($this)
75
                    ),
76
                    self::ERROR_MISSING_COMMAND_TYPE_METHOD
77
                );
78
            }
79
            
80
            $this->$method($command);
81
            
82
            if(!$this->validationResult->isValid())
83
            {
84
                break;
85
            }
86
        }
87
        
88
        if($this->validationResult->isValid())
89
        {
90
            $this->validate_Unclosed();
91
        }
92
        
93
        return $this->validationResult;
94
    }
95
96
    protected function validate_Unclosed()
97
    {
98
        $leftover = $this->getOpenCommand();
99
        
100
        if($leftover === null)
101
        {
102
            return;
103
        }
104
        
105
        $this->validationResult->makeError(
106
            t(
107
                'The command %1$s was never ended.',
108
                $leftover->getName()
109
            ).' ('.$leftover->getMatchedText().')',
110
            self::VALIDATION_UNCLOSED_COMMAND
111
        );
112
    }
113
    
114
    protected function getOpenCommand() : ?Mailcode_Commands_Command_Type_Opening
115
    {
116
        if(empty($this->stack))
117
        {
118
            return null;
119
        }
120
        
121
        end($this->stack);
122
        $idx = key($this->stack);
123
        reset($this->stack);
124
        
125
        $cmd = $this->stack[$idx];
126
        
127
        if($cmd instanceof Mailcode_Commands_Command_Type_Opening)
128
        {
129
            return $cmd;
130
        }
131
        
132
        return null;
133
    }
134
    
135
    protected function validate_Standalone(Mailcode_Commands_Command_Type_Standalone $command)
136
    {
137
        // standalone commands have no nesting issues
138
    }
139
    
140
    protected function validate_Opening(Mailcode_Commands_Command_Type_Opening $command)
141
    {
142
        $this->log(sprintf('Opening %s', $command->getName()));
143
        
144
        $this->stack[] = $command;
145
    }
146
    
147
    protected function validate_Sibling(Mailcode_Commands_Command_Type_Sibling $command)
148
    {
149
        $parent = $this->getOpenCommand();
150
        
151
        if($parent === null)
152
        {
153
            $this->validationResult->makeError(
154
                t(
155
                    '%1$s command has no parent %2$s command.',
156
                    $command->getName(),
157
                    $command->getParentName()
158
                ),
159
                self::VALIDATION_SIBLING_WITHOUT_PARENT
160
            );
161
            
162
            return;
163
        }
164
        
165
        if($parent->getName() !== $command->getParentName())
166
        {
167
            $this->validationResult->makeError(
168
                t(
169
                    '%1$s command cannot be used as child of a %2$s command.',
170
                    $command->getName(),
171
                    $parent->getName()
172
                ),
173
                self::VALIDATION_SIBLING_WRONG_PARENT
174
            );
175
            
176
            return;
177
        }
178
        
179
        $this->log(sprintf('Sibling command %s in %s', $command->getName(), $parent->getName()));
180
    }
181
    
182
    protected function validate_Closing(Mailcode_Commands_Command_Type_Closing $command)
183
    {
184
        if(empty($this->stack))
185
        {
186
            $this->validationResult->makeError(
187
                t('All open commands have already been ended.'),
188
                self::VALIDATION_COMMANDS_ALREADY_CLOSED
189
            );
190
            
191
            return;
192
        }
193
        
194
        $close = array_pop($this->stack);
195
        
196
        $this->log(sprintf('Closing command %s', $close->getName()));
197
    }
198
    
199
    protected function log(string $message) : void
200
    {
201
        //echo $message.PHP_EOL;
202
    }
203
}
204