Completed
Push — master ( 088bf6...a47832 )
by Martijn
02:41
created

ArrayType   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 195
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
dl 0
loc 195
rs 8.439
c 0
b 0
f 0
wmc 47
lcom 1
cbo 4

8 Methods

Rating   Name   Duplication   Size   Complexity  
A parseDefinition() 0 16 3
B parseFormat() 0 16 5
A parseItems() 0 6 2
C parseRange() 0 19 15
C handleCommand() 0 37 12
A toArray() 0 10 3
B validateItems() 0 25 6
A __toString() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like ArrayType often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ArrayType, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace SwaggerGen\Swagger\Type;
4
5
/**
6
 * Basic array type definition.
7
 *
8
 * @package    SwaggerGen
9
 * @author     Martijn van der Lee <[email protected]>
10
 * @copyright  2014-2015 Martijn van der Lee
11
 * @license    https://opensource.org/licenses/MIT MIT
12
 */
13
class ArrayType extends AbstractType
14
{
15
16
	const REGEX_ARRAY_CONTENT = '(?:(\[)(.*)\])?';
17
18
	private static $classTypes = array(
19
		'integer' => 'Integer',
20
		'int' => 'Integer',
21
		'int32' => 'Integer',
22
		'int64' => 'Integer',
23
		'long' => 'Integer',
24
		'float' => 'Number',
25
		'double' => 'Number',
26
		'string' => 'String',
27
		'uuid' => 'StringUuid',
28
		'byte' => 'String',
29
		'binary' => 'String',
30
		'password' => 'String',
31
		'enum' => 'String',
32
		'boolean' => 'Boolean',
33
		'bool' => 'Boolean',
34
		'array' => 'Array',
35
		'csv' => 'Array',
36
		'ssv' => 'Array',
37
		'tsv' => 'Array',
38
		'pipes' => 'Array',
39
		'date' => 'Date',
40
		'datetime' => 'Date',
41
		'date-time' => 'Date',
42
		'object' => 'Object',
43
	);
44
	private static $collectionFormats = array(
45
		'array' => 'csv',
46
		'csv' => 'csv',
47
		'ssv' => 'ssv',
48
		'tsv' => 'tsv',
49
		'pipes' => 'pipes',
50
		'multi' => 'multi',
51
	);
52
53
	/**
54
	 * @var AbstractType
55
	 */
56
	private $Items = null;
57
	private $minItems = null;
58
	private $maxItems = null;
59
	private $collectionFormat = null;
60
61
	protected function parseDefinition($definition)
62
	{
63
		$definition = self::trim($definition);
64
		$match = array();
65
		if (preg_match(self::REGEX_START . self::REGEX_FORMAT . self::REGEX_CONTENT . self::REGEX_RANGE . self::REGEX_END, $definition, $match) === 1) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
66
			// recognized format
67
		} elseif (preg_match(self::REGEX_START . self::REGEX_ARRAY_CONTENT . self::REGEX_RANGE . self::REGEX_END, $definition, $match) === 1) {
68
			$match[1] = 'array';
69
		} else {
70
			throw new \SwaggerGen\Exception("Unparseable array definition: '{$definition}'");
71
		}
72
73
		$this->parseFormat($definition, $match);
74
		$this->parseItems($definition, $match);
75
		$this->parseRange($definition, $match);
76
	}
77
78
	private function parseFormat($definition, $match)
79
	{
80
		$type = strtolower($match[1]);
81
		if (!isset(self::$collectionFormats[$type])) {
82
			throw new \SwaggerGen\Exception("Not an array: '{$definition}'");
83
		}
84
85
		if ($type === 'multi') {
86
			$parent = $this->getParent();
87
			if (!($parent instanceof \SwaggerGen\Swagger\Parameter) || !$parent->isMulti()) {
88
				throw new \SwaggerGen\Exception("Multi array only allowed on query or form parameter: '{$definition}'");
89
			}
90
		}
91
92
		$this->collectionFormat = self::$collectionFormats[$type];
93
	}
94
95
	private function parseItems($definition, $match)
0 ignored issues
show
Unused Code introduced by
The parameter $definition is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
96
	{
97
		if (!empty($match[2])) {
98
			$this->Items = $this->validateItems($match[2]);
99
		}
100
	}
101
102
	private function parseRange($definition, $match)
103
	{
104
		if (!empty($match[3])) {
105
			if ($match[4] === '' && $match[5] === '') {
106
				throw new \SwaggerGen\Exception("Empty array range: '{$definition}'");
107
			}
108
109
			$exclusiveMinimum = isset($match[3]) ? ($match[3] == '<') : null;
110
			$this->minItems = $match[4] === '' ? null : intval($match[4]);
111
			$this->maxItems = $match[5] === '' ? null : intval($match[5]);
112
			$exclusiveMaximum = isset($match[6]) ? ($match[6] == '>') : null;
113
			if ($this->minItems && $this->maxItems && $this->minItems > $this->maxItems) {
114
				self::swap($this->minItems, $this->maxItems);
115
				self::swap($exclusiveMinimum, $exclusiveMaximum);
116
			}
117
			$this->minItems = $this->minItems === null ? null : max(0, $exclusiveMinimum ? $this->minItems + 1 : $this->minItems);
118
			$this->maxItems = $this->maxItems === null ? null : max(0, $exclusiveMaximum ? $this->maxItems - 1 : $this->maxItems);
119
		}
120
	}
121
122
	/**
123
	 * @param string $command The comment command
124
	 * @param string $data Any data added after the command
125
	 * @return \SwaggerGen\Swagger\Type\AbstractType|boolean
126
	 */
127
	public function handleCommand($command, $data = null)
128
	{
129
		if ($this->Items) {
130
			$return = $this->Items->handleCommand($command, $data);
131
			if ($return) {
132
				return $return;
133
			}
134
		}
135
136
		switch (strtolower($command)) {
137
			case 'min':
138
				$this->minItems = intval($data);
139
				if ($this->minItems < 0) {
140
					throw new \SwaggerGen\Exception("Minimum less than zero: '{$data}'");
141
				}
142
				if ($this->maxItems !== null && $this->minItems > $this->maxItems) {
143
					throw new \SwaggerGen\Exception("Minimum greater than maximum: '{$data}'");
144
				}
145
				return $this;
146
147
			case 'max':
148
				$this->maxItems = intval($data);
149
				if ($this->minItems !== null && $this->minItems > $this->maxItems) {
150
					throw new \SwaggerGen\Exception("Maximum less than minimum: '{$data}'");
151
				}
152
				if ($this->maxItems < 0) {
153
					throw new \SwaggerGen\Exception("Maximum less than zero: '{$data}'");
154
				}
155
				return $this;
156
157
			case 'items':
158
				$this->Items = $this->validateItems($data);
159
				return $this->Items;
160
		}
161
162
		return parent::handleCommand($command, $data);
163
	}
164
165
	public function toArray()
166
	{
167
		return self::arrayFilterNull(array(
168
					'type' => 'array',
169
					'items' => empty($this->Items) ? null : $this->Items->toArray(),
170
					'collectionFormat' => $this->collectionFormat == 'csv' ? null : $this->collectionFormat,
171
					'minItems' => $this->minItems,
172
					'maxItems' => $this->maxItems,
173
		));
174
	}
175
176
	private function validateItems($items)
177
	{
178
		if (empty($items)) {
179
			throw new \SwaggerGen\Exception("Empty items definition: '{$items}'");
180
		}
181
182
		$match = array();
183
		if (preg_match('/^([a-z]+)/i', $items, $match) === 1) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
184
			// recognized format
185
		} elseif (preg_match('/^(\[)(?:.*?)\]$/i', $items, $match) === 1) {
186
			$match[1] = 'array';
187
		} elseif (preg_match('/^(\{)(?:.*?)\}$/i', $items, $match) === 1) {
188
			$match[1] = 'object';
189
		} else {
190
			throw new \SwaggerGen\Exception("Unparseable items definition: '{$items}'");
191
		}
192
		$format = strtolower($match[1]);
193
		if (isset(self::$classTypes[$format])) {
194
			$type = self::$classTypes[$format];
195
			$typeClass = "SwaggerGen\\Swagger\\Type\\{$type}Type";
196
			return new $typeClass($this, $items);
197
		}
198
199
		return new ReferenceObjectType($this, $items);
200
	}
201
202
	public function __toString()
203
	{
204
		return __CLASS__;
205
	}
206
207
}
208