Completed
Push — master ( 0ef921...49b538 )
by Martijn
03:08
created

Swagger::__toString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace SwaggerGen\Swagger;
4
5
/**
6
 * Object representing the root level of a Swagger 2.0 document.
7
 *
8
 * @package    SwaggerGen
9
 * @author     Martijn van der Lee <[email protected]>
10
 * @copyright  2014-2016 Martijn van der Lee
11
 * @license    https://opensource.org/licenses/MIT MIT
12
 */
13
class Swagger extends AbstractDocumentableObject
14
{
15
16
	private $swagger = '2.0';
17
	private $host;
18
	private $basePath;
19
20
	/**
21
	 * @var Info $Info
22
	 */
23
	private $info;
24
	private $schemes = array();
25
	private $consumes = array();
26
	private $produces = array();
27
28
	/**
29
	 * @var \SwaggerGen\Swagger\Path[] $Paths
30
	 */
31
	private $paths = array();
32
33
	/**
34
	 * @var \SwaggerGen\Swagger\Schema[] $definitions
35
	 */
36
	private $definitions = array();
37
38
	/**
39
	 * @var \SwaggerGen\Swagger\IParameter[] $parameters
40
	 */
41
	private $parameters = array();
42
43
	/**
44
	 * @var \SwaggerGen\Swagger\Response[] $responses
45
	 */
46
	private $responses = array();
47
48
	/**
49
	 * @var Tag[] $Tags
50
	 */
51
	private $tags = array();
52
53
	/**
54
	 * Default tag for new endpoints/operations. Set by the api command.
55
	 * @var Tag
56
	 */
57
	private $defaultTag = null;
58
	private $securityDefinitions = array();
59
	private $security = array();
60
61
	/**
62
	 * @inheritDoc
63
	 * @param string $host
64
	 * @param string $basePath
65
	 */
66
	public function __construct($host = null, $basePath = null)
67
	{
68
		parent::__construct(null);
69
70
		$this->host = $host;
71
		$this->basePath = $basePath;
72
73
		$this->info = new Info($this);
74
	}
75
76
	/**
77
	 * @inheritDoc
78
	 */
79
	protected function getSwagger()
80
	{
81
		return $this;
82
	}
83
84
	/**
85
	 * Return all consumes
86
	 * @todo Deprecate in favour of a getConsume($name);
87
	 * @return string
88
	 */
89
	public function getConsumes()
90
	{
91
		return $this->consumes;
92
	}
93
94
	/**
95
	 * Return the named security if it exists. Otherwise return FALSE
96
	 * @param string $name
97
	 * @return boolean|SecurityScheme
98
	 */
99
	public function getSecurity($name)
100
	{
101
		if (isset($this->securityDefinitions[$name])) {
102
			return $this->securityDefinitions[$name];
103
		}
104
105
		return false;
106
	}
107
108
	/**
109
	 * @param string $command
110
	 * @param string $data
111
	 * @return \SwaggerGen\Swagger\AbstractObject|boolean
112
	 */
113
	public function handleCommand($command, $data = null)
114
	{
115
		switch (strtolower($command)) {
116
			// pass to Info
117
			case 'title':
118
			case 'description':
119
			case 'version':
120
			case 'terms': // alias
121
			case 'tos': // alias
122
			case 'termsofservice':
123
			case 'contact':
124
			case 'license':
125
				return $this->info->handleCommand($command, $data);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->info->hand...mmand($command, $data); (SwaggerGen\Swagger\Info|...n\Swagger\License|false) is incompatible with the return type of the parent method SwaggerGen\Swagger\Abstr...leObject::handleCommand of type SwaggerGen\Swagger\Exter...ocumentableObject|false.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
126
127
			// string[]
128
			case 'scheme':
129
			case 'schemes':
130
				$this->schemes = array_unique(array_merge($this->schemes, self::wordSplit($data)));
131
				return $this;
132
133
			// MIME[]
134
			case 'consume':
135
			case 'consumes':
136
				$this->consumes = array_merge($this->consumes, self::translateMimeTypes(self::wordSplit($data)));
137
				return $this;
138
139
			case 'produce':
140 View Code Duplication
			case 'produces':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
141
				$this->produces = array_merge($this->produces, self::translateMimeTypes(self::wordSplit($data)));
142
				return $this;
143
144
			case 'model':
145
			case 'definition':
146
				$definition = new Schema($this);
147
				$name = self::wordShift($data);
148
				if (empty($name)) {
149
					throw new \SwaggerGen\Exception('Missing definition name');
150
				}
151
				$this->definitions[$name] = $definition;
152
				return $definition;			
153
154
			case 'path':
155
			case 'query':
156
			case 'query?':
157
			case 'header':
158
			case 'header?':
159
			case 'form':
160 View Code Duplication
			case 'form?':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
161
				$in = rtrim($command, '?');
162
				$Parameter = new Parameter($this, $in, $data, substr($command, -1) !== '?');
163
				$this->parameters[$Parameter->getName()] = $Parameter;
164
				return $Parameter;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $Parameter; (SwaggerGen\Swagger\Parameter) is incompatible with the return type of the parent method SwaggerGen\Swagger\Abstr...leObject::handleCommand of type SwaggerGen\Swagger\Exter...ocumentableObject|false.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
165
166
			case 'body':
167 View Code Duplication
			case 'body?':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
168
				$Parameter = new BodyParameter($this, $data, substr($command, -1) !== '?');
169
				$this->parameters[$Parameter->getName()] = $Parameter;
170
				return $Parameter;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $Parameter; (SwaggerGen\Swagger\BodyParameter) is incompatible with the return type of the parent method SwaggerGen\Swagger\Abstr...leObject::handleCommand of type SwaggerGen\Swagger\Exter...ocumentableObject|false.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
171
				
172 View Code Duplication
			case 'response':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
173
				$name = self::wordShift($data);
174
				$definition = self::wordShift($data);
175
				$description = $data;
176
				if (empty($description)) {
177
					throw new \SwaggerGen\Exception('Response definition missing description');
178
				}
179
				$Response = new Response($this, $name, $definition === 'null' ? null : $definition, $description);
180
				$this->responses[$name] = $Response;
181
				return $Response;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $Response; (SwaggerGen\Swagger\Response) is incompatible with the return type of the parent method SwaggerGen\Swagger\Abstr...leObject::handleCommand of type SwaggerGen\Swagger\Exter...ocumentableObject|false.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
182
183
			case 'api': // alias
184
			case 'tag':
185
				$tagname = self::wordShift($data);
186
				if (empty($tagname)) {
187
					throw new \SwaggerGen\Exception('Missing tag name');
188
				}
189
190
				$Tag = null;
191
				foreach ($this->tags as $T) {
192
					if ($T->getName() === $tagname) {
193
						$Tag = $T;
194
						break;
195
					}
196
				}
197
				if (!$Tag) {
198
					$Tag = new Tag($this, $tagname, $data);
199
					$this->tags[] = $Tag;
200
				}
201
202
				if ($command === 'api') { // backwards compatibility
203
					$this->defaultTag = $Tag;
204
				}
205
				return $Tag;
206
207
			case 'endpoint':
208
				$path = self::wordShift($data);
209
				if ($path{0} !== '/') {
210
					$path = '/' . $path;
211
				}
212
213
				$Tag = null;
214
				if (($tagname = self::wordShift($data)) !== false) {
215
					foreach ($this->tags as $T) {
216
						if (strtolower($T->getName()) === strtolower($tagname)) {
217
							$Tag = $T;
218
							break;
219
						}
220
					}
221
					if (!$Tag) {
222
						$Tag = new Tag($this, $tagname, $data);
223
						$this->tags[] = $Tag;
224
					}
225
				}
226
227
				if (!isset($this->paths[$path])) {
228
					$this->paths[$path] = new Path($this, $Tag ?: $this->defaultTag);
229
				}
230
				return $this->paths[$path];
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->paths[$path]; (SwaggerGen\Swagger\Path) is incompatible with the return type of the parent method SwaggerGen\Swagger\Abstr...leObject::handleCommand of type SwaggerGen\Swagger\Exter...ocumentableObject|false.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
231
232 View Code Duplication
			case 'security':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
233
				$name = self::wordShift($data);
234
				if (empty($name)) {
235
					throw new \SwaggerGen\Exception('Missing security name');
236
				}
237
				$type = self::wordShift($data);
238
				if (empty($type)) {
239
					throw new \SwaggerGen\Exception('Missing security type');
240
				}
241
				$SecurityScheme = new SecurityScheme($this, $type, $data);
242
				$this->securityDefinitions[$name] = $SecurityScheme;
243
				return $SecurityScheme;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $SecurityScheme; (SwaggerGen\Swagger\SecurityScheme) is incompatible with the return type of the parent method SwaggerGen\Swagger\Abstr...leObject::handleCommand of type SwaggerGen\Swagger\Exter...ocumentableObject|false.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
244
245 View Code Duplication
			case 'require':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
246
				$name = self::wordShift($data);
247
				if (empty($name)) {
248
					throw new \SwaggerGen\Exception('Missing require name');
249
				}
250
				$scopes = self::wordSplit($data);
251
				sort($scopes);
252
				$this->security[] = array(
253
					$name => empty($scopes) ? array() : $scopes,
254
				);
255
				return $this;
256
		}
257
258
		return parent::handleCommand($command, $data);
259
	}
260
261
	/**
262
	 * @inheritDoc
263
	 */
264
	public function toArray()
265
	{
266
		if (empty($this->paths)) {
267
			throw new \SwaggerGen\Exception('No path defined');
268
		}
269
270
		$schemes = array_unique($this->schemes);
271
		sort($schemes);
272
273
		$consumes = array_unique($this->consumes);
274
		sort($consumes);
275
276
		$produces = array_unique($this->produces);
277
		sort($produces);
278
279
		foreach ($this->security as $security) {
280
			foreach ($security as $name => $scopes) {
281
				if (!isset($this->securityDefinitions[$name])) {
282
					throw new \SwaggerGen\Exception("Required security scheme not defined: '{$name}'");
283
				}
284
			}
285
		}
286
287
		return self::arrayFilterNull(array_merge(array(
288
					'swagger' => $this->swagger,
289
					'info' => $this->info->toArray(),
290
					'host' => empty($this->host) ? null : $this->host,
291
					'basePath' => empty($this->basePath) ? null : $this->basePath,
292
					'consumes' => $consumes,
293
					'produces' => $produces,
294
					'schemes' => $schemes,
295
					'paths' => self::objectsToArray($this->paths),
296
					'definitions' => self::objectsToArray($this->definitions),
297
					'parameters' => self::objectsToArray($this->parameters),
298
					'responses' => self::objectsToArray($this->responses),
299
					'securityDefinitions' => self::objectsToArray($this->securityDefinitions),
300
					'security' => $this->security,
301
					'tags' => self::objectsToArray($this->tags),
302
								), parent::toArray()));
303
	}
304
305
	public function __toString()
306
	{
307
		return __CLASS__;
308
	}
309
310
	/**
311
	 * Check if an operation with the given id exists.
312
	 * 
313
	 * @param string $operationId
314
	 * @return boolean
315
	 */
316
	public function hasOperationId($operationId)
317
	{
318
		foreach ($this->paths as $path) {
319
			if ($path->hasOperationId($operationId)) {
320
				return true;
321
			}
322
		}
323
324
		return false;
325
	}
326
327
}
328