Completed
Pull Request — master (#31)
by
unknown
02:35
created

ObjectType::parseRange()   C

Complexity

Conditions 15
Paths 130

Size

Total Lines 19
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 19
rs 6.4166
c 0
b 0
f 0
cc 15
eloc 13
nc 130
nop 2

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace SwaggerGen\Swagger\Type;
4
5
/**
6
 * Basic object 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 ObjectType extends AbstractType
14
{
15
16
	const REGEX_OBJECT_CONTENT = '(?:(\{)(.*)\})?';
17
	const REGEX_PROP_START = '/^';
18
	const REGEX_PROP_NAME = '([^?!:]+)';
19
	const REGEX_PROP_REQUIRED = '([\?!])?';
20
	const REGEX_PROP_ASSIGN = ':';
21
	const REGEX_PROP_DEFINITION = '(.+)';
22
	const REGEX_PROP_ADDITIONAL = '\.\.\.(!|.+)?';
23
	const REGEX_PROP_END = '$/';
24
25
	private $minProperties = null;
26
	private $maxProperties = null;
27
	private $discriminator = null;
28
	private $additionalProperties = null;
29
	private $required = array();
30
31
	/**
32
	 * @var Property[]
33
	 */
34
	private $properties = array();
35
36
	/**
37
	 * @var Property
38
	 */
39
	private $mostRecentProperty = null;
40
41
	protected function parseDefinition($definition)
42
	{
43
		$definition = self::trim($definition);
44
45
		$match = array();
46
		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...
47
			// recognized format
48
		} elseif (preg_match(self::REGEX_START . self::REGEX_OBJECT_CONTENT . self::REGEX_RANGE . self::REGEX_END, $definition, $match) === 1) {
49
			$match[1] = 'object';
50
		} else {
51
			throw new \SwaggerGen\Exception("Unparseable object definition: '{$definition}'");
52
		}
53
54
55
		$this->parseFormat($definition, $match);
56
		$this->parseProperties($definition, $match);
57
		$this->parseRange($definition, $match);
58
	}
59
60
	private function parseFormat($definition, $match)
61
	{
62
		if (strtolower($match[1]) !== 'object') {
63
			throw new \SwaggerGen\Exception("Not an object: '{$definition}'");
64
		}
65
	}
66
67
	/**
68
	 * @param AbstractType|bool $type
69
	 * @return void
70
	 */
71
	private function setAdditionalProperties($type)
72
	{
73
		if ($this->additionalProperties !== null) {
74
			throw new \SwaggerGen\Exception('Additional properties may only be set once');
75
		}
76
		$this->additionalProperties = $type;
77
	}
78
79
	private function parseProperties($definition, $match)
1 ignored issue
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...
80
	{
81
		if (empty($match[2])) {
82
			return;
83
		}
84
85
		while (($property = self::parseListItem($match[2])) !== '') {
86
			$prop_match = array();
87
			if (preg_match(self::REGEX_PROP_START . self::REGEX_PROP_ADDITIONAL . self::REGEX_PROP_END, $property, $prop_match) === 1) {
88
				if (empty($prop_match[1])) {
89
					$this->setAdditionalProperties(true);
90
				} else if ($prop_match[1] === '!') {
91
					$this->setAdditionalProperties(false);
92
				} else {
93
					$this->setAdditionalProperties(self::typeFactory($this, $prop_match[1], "Unparseable additional properties definition: '...%s'"));
94
				}
95
				continue;
96
			}
97
			if (preg_match(self::REGEX_PROP_START . self::REGEX_PROP_NAME . self::REGEX_PROP_REQUIRED . self::REGEX_PROP_ASSIGN . self::REGEX_PROP_DEFINITION . self::REGEX_PROP_END, $property, $prop_match) !== 1) {
98
				throw new \SwaggerGen\Exception("Unparseable property definition: '{$property}'");
99
			}
100
			$this->properties[$prop_match[1]] = new Property($this, $prop_match[3]);
101
			if ($prop_match[2] !== '!' && $prop_match[2] !== '?') {
102
				$this->required[$prop_match[1]] = true;
103
			}
104
		}
105
106
	}
107
108
	private function parseRange($definition, $match)
109
	{
110
		if (!empty($match[3])) {
111
			if ($match[4] === '' && $match[5] === '') {
112
				throw new \SwaggerGen\Exception("Empty object range: '{$definition}'");
113
			}
114
115
			$exclusiveMinimum = isset($match[3]) ? ($match[3] == '<') : null;
116
			$this->minProperties = $match[4] === '' ? null : intval($match[4]);
117
			$this->maxProperties = $match[5] === '' ? null : intval($match[5]);
118
			$exclusiveMaximum = isset($match[6]) ? ($match[6] == '>') : null;
119
			if ($this->minProperties && $this->maxProperties && $this->minProperties > $this->maxProperties) {
120
				self::swap($this->minProperties, $this->maxProperties);
121
				self::swap($exclusiveMinimum, $exclusiveMaximum);
122
			}
123
			$this->minProperties = $this->minProperties === null ? null : max(0, $exclusiveMinimum ? $this->minProperties + 1 : $this->minProperties);
124
			$this->maxProperties = $this->maxProperties === null ? null : max(0, $exclusiveMaximum ? $this->maxProperties - 1 : $this->maxProperties);
125
		}
126
	}
127
128
	private function setDiscriminator($discriminator)
129
	{
130
		if (!empty($this->discriminator)) {
131
			throw new \SwaggerGen\Exception("Discriminator may only be set once, "
132
											. "trying to change it "
133
											. "from '{$this->discriminator}' "
134
											. "to '{$discriminator}'");
135
		}
136
		if (isset($this->properties[$discriminator]) && empty($this->required[$discriminator])) {
137
			throw new \SwaggerGen\Exception("Discriminator must be a required property, "
138
											. "property '{$discriminator}' is not required");
139
		}
140
		$this->discriminator = $discriminator;
141
	}
142
143
	/**
144
	 * @param string $command The comment command
145
	 * @param string $data Any data added after the command
146
	 * @return \SwaggerGen\Swagger\Type\AbstractType|boolean
147
	 */
148
	public function handleCommand($command, $data = null)
149
	{
150
		switch (strtolower($command)) {
151
			// type name description...
152
			case 'additionalproperties':
153
				$value = self::wordShift($data);
154
				if ($value === 'false') {
155
					$type = false;
156
				} else if ($value === 'true') {
157
					$type = true;
158
				} else {
159
					$type = self::typeFactory($this, $value, "Unparseable additional properties definition: '%s'");
160
				}
161
				$this->setAdditionalProperties($type);
0 ignored issues
show
Bug introduced by
It seems like $type defined by self::typeFactory($this,...es definition: \'%s\'') on line 159 can also be of type object; however, SwaggerGen\Swagger\Type\...tAdditionalProperties() does only seem to accept object<SwaggerGen\Swagge...e\AbstractType>|boolean, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
162
				return $this;
163
			case 'discriminator':
164
				$discriminator = self::wordShift($data);
165
				$this->setDiscriminator($discriminator);
166
				return $this;
167
			case 'property':
168
			case 'property?':
169
			case 'property!':
170
				$definition = self::wordShift($data);
171
				if (empty($definition)) {
172
					throw new \SwaggerGen\Exception("Missing property definition");
173
				}
174
175
				$name = self::wordShift($data);
176
				if (empty($name)) {
177
					throw new \SwaggerGen\Exception("Missing property name: '{$definition}'");
178
				}
179
180
				$readOnly = null;
181
				$required = false;
182
				$propertySuffix = substr($command, -1);
183
				if ($propertySuffix === '!') {
184
					$readOnly = true;
185
				} else if ($propertySuffix !== '?') {
186
					$required = true;
187
				}
188
189
				if (($name === $this->discriminator) && !$required) {
190
					throw new \SwaggerGen\Exception("Discriminator must be a required property, "
191
													. "property '{$name}' is not required");
192
				}
193
194
				unset($this->required[$name]);
195
				if ($required) {
196
					$this->required[$name] = true;
197
				}
198
199
				$this->mostRecentProperty = new Property($this, $definition, $data, $readOnly);
200
				$this->properties[$name] = $this->mostRecentProperty;
201
				return $this;
202
203
			case 'min':
204
				$this->minProperties = intval($data);
205
				if ($this->minProperties < 0) {
206
					throw new \SwaggerGen\Exception("Minimum less than zero: '{$data}'");
207
				}
208
				if ($this->maxProperties !== null && $this->minProperties > $this->maxProperties) {
209
					throw new \SwaggerGen\Exception("Minimum greater than maximum: '{$data}'");
210
				}
211
				$this->minProperties = intval($data);
212
				return $this;
213
214
			case 'max':
215
				$this->maxProperties = intval($data);
216
				if ($this->minProperties !== null && $this->minProperties > $this->maxProperties) {
217
					throw new \SwaggerGen\Exception("Maximum less than minimum: '{$data}'");
218
				}
219
				if ($this->maxProperties < 0) {
220
					throw new \SwaggerGen\Exception("Maximum less than zero: '{$data}'");
221
				}
222
				return $this;
223
		}
224
225
		// Pass through to most recent Property
226
		if ($this->mostRecentProperty && $this->mostRecentProperty->handleCommand($command, $data)) {
227
			return $this;
228
		}
229
230
		return parent::handleCommand($command, $data);
231
	}
232
233
	public function toArray()
234
	{
235
		return self::arrayFilterNull(array_merge(array(
236
					'type' => 'object',
237
					'required' => array_keys($this->required),
238
					'properties' => self::objectsToArray($this->properties),
239
					'minProperties' => $this->minProperties,
240
					'maxProperties' => $this->maxProperties,
241
					'discriminator' => $this->discriminator,
242
					'additionalProperties' => $this->additionalProperties instanceof AbstractType ? $this->additionalProperties->toArray() : $this->additionalProperties,
243
								), parent::toArray()));
244
	}
245
246
	public function __toString()
247
	{
248
		return __CLASS__;
249
	}
250
251
}
252