ArgumentParser::parseToken()   A
last analyzed

Complexity

Conditions 6
Paths 6

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.1111
c 0
b 0
f 0
cc 6
nc 6
nop 2
1
<?php namespace Wn\Generators\Argument;
2
3
use Wn\Generators\Argument\ArgumentFormat;
4
use Wn\Generators\Exceptions\ArgumentParserException;
5
6
7
class ArgumentParser {
8
9
	protected $format;
10
11
	public function __construct(ArgumentFormat $format)
12
	{
13
	    $this->format = $format;
14
	}
15
16
	public function parse($args)
17
	{
18
		return $this->parseToken($args, $this->format);
19
	}
20
21
	protected function parseToken($token, ArgumentFormat $format){
22
	    switch($format->type) {
23
	        case 'string':
24
	            return $token;
25
	        case 'number':
26
	            return $this->parseNumber($token);
27
	        case 'boolean':
28
	            return $this->parseBoolean($token, $format->name);
29
	        case 'array':
30
	            return $this->parseArray($token, $format->separator, $format->format);
31
	        case 'object':
32
	            return $this->parseObject($token, $format->separator, $format->format);
33
	        default:
34
	            throw new ArgumentParserException("Unknown format type: '{$format->type}'");
35
	    }
36
	}
37
38
	protected function parseNumber($token)
39
	{
40
	    if(! is_numeric($token)) {
41
	        throw new ArgumentParserException("Unable to parse '{$token}' as number");
42
	    }
43
	    return $token + 0;
44
	}
45
46
	protected function parseBoolean($token, $name)
47
	{
48
	    if(in_array($token, ['yes', 'true', '1', $name])) {
49
	        return true;
50
	    } else if(in_array($token, ['no', 'false', '0', "!{$name}"])){
51
	        return false;
52
	    } else {
53
	        return null;
54
	    }
55
	}
56
57
	protected function parseArray($token, $separator, ArgumentFormat $format)
58
	{
59
	    $result = [];
60
	    $tokens = explode($separator, $token);
61
	    foreach($tokens as $value) {
62
	        array_push($result, $this->parseToken($value, $format));
63
	    }
64
	    return $result;
65
	}
66
67
	protected function parseObject($token, $separator, $fields)
68
	{
69
	    $result = [];
70
	    $tokens = explode($separator, $token);
71
	    $tokensNumber = count($tokens);
72
73
	    $requiredFieldsIndexes = [];
74
	    $optionalFieldsIndexes = [];
75
	    foreach($fields as $index => $format) {
76
	        if($format->default === null) {
77
	            array_push($requiredFieldsIndexes, $index);
78
	        } else {
79
	            array_push($optionalFieldsIndexes, $index);
80
	        }
81
	    }
82
	    $requiredFieldsIndexesNumber = count($requiredFieldsIndexes);
83
84
	    if($tokensNumber < $requiredFieldsIndexesNumber) {
85
	        $requiredFields = array_map(function($index) use ($fields) {
86
	                return $fields[$index]->name;
87
	            }, $requiredFieldsIndexes);
88
	        $requiredFields = implode($separator, $requiredFields);
89
	        throw new ArgumentParserException("Required field missing: {$tokensNumber} given "
90
	            . "({$token}) but {$requiredFieldsIndexesNumber} required ({$requiredFields})");
91
	    }
92
93
	    $givenOptionalFieldsIndexes = array_slice(
94
	        $optionalFieldsIndexes, 0, $tokensNumber - $requiredFieldsIndexesNumber);
95
	    $notPresentFieldsIndexes = array_slice(
96
	        $optionalFieldsIndexes, $tokensNumber - $requiredFieldsIndexesNumber);
97
	    $givenFieldsIndexes = array_merge($requiredFieldsIndexes, $givenOptionalFieldsIndexes);
98
	    sort($givenFieldsIndexes);
99
100
	    // Fill the given fields
101
	    for($i = 0; $i < $tokensNumber; $i ++) {
102
	        $fieldFormat = $fields[$givenFieldsIndexes[$i]];
103
	        $result[$fieldFormat->name] = $this->parseToken($tokens[$i], $fieldFormat);
104
	    }
105
106
	    // Fill other fields with default values
107
	    foreach($notPresentFieldsIndexes as $index) {
108
	        $fieldFormat = $fields[$index];
109
	        $result[$fieldFormat->name] = $fieldFormat->default;
110
	    }
111
112
	    return $result;
113
	}
114
115
}
116