Completed
Push — master ( 37902c...ffb897 )
by Martijn
02:31
created

Operation   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 200
Duplicated Lines 12 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 0
Metric Value
wmc 45
lcom 1
cbo 8
dl 24
loc 200
rs 8.3673
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A getConsumes() 0 4 1
A __construct() 0 8 2
D handleCommand() 24 100 29
C toArray() 0 43 11
A getId() 0 4 1
A __toString() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Operation 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 Operation, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace SwaggerGen\Swagger;
4
5
/**
6
 * Describes a Swagger Operation object, which describes a method call of a
7
 * specific endpoint.
8
 *
9
 * @package    SwaggerGen
10
 * @author     Martijn van der Lee <[email protected]>
11
 * @copyright  2014-2015 Martijn van der Lee
12
 * @license    https://opensource.org/licenses/MIT MIT
13
 */
14
class Operation extends AbstractDocumentableObject
15
{
16
17
	private $tags = array();
18
	private $summary;
19
	private $description;
20
	private $operationid;
0 ignored issues
show
Unused Code introduced by
The property $operationid is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
21
	private $consumes = array();
22
	private $produces = array();
23
24
	/**
25
	 * @var IParameter[]
26
	 */
27
	private $parameters = array();
28
	private $responses = array();
29
	private $schemes = array();
30
	private $deprecated = false;
31
	private $security = array();
32
	private $operationId = null;
33
34
	public function getConsumes()
35
	{
36
		return $this->consumes;
37
	}
38
39
	public function __construct(AbstractObject $parent, $summary = null, Tag $tag = null)
40
	{
41
		parent::__construct($parent);
42
		$this->summary = $summary;
43
		if ($tag) {
44
			$this->tags[] = $tag->getName();
45
		}
46
	}
47
48
	/**
49
	 * @param string $command
50
	 * @param string $data
51
	 * @return \SwaggerGen\Swagger\AbstractObject|boolean
52
	 */
53
	public function handleCommand($command, $data = null)
54
	{
55
		switch (strtolower($command)) {
56
			// string
57
			case 'summary':
58
			case 'description':
59
				$this->$command = $data;
60
				return $this;
61
62
			// string[]
63
			case 'tags':
64
			case 'schemes':
65
				$this->$command = array_merge($this->$command, self::wordSplit($data));
66
				return $this;
67
68
			// MIME[]
69
			case 'consumes':
70 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...
71
				$this->$command = array_merge($this->$command, self::translateMimeTypes(self::wordSplit($data)));
72
				return $this;
73
74
			// boolean
75
			case 'deprecated':
76
				$this->deprecated = true;
77
				return $this;
78
79 View Code Duplication
			case 'error':
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...
80
				$code = self::wordShift($data);
81
				$reasoncode = Response::getCode($code);
82
				if ($reasoncode === null) {
83
					throw new \SwaggerGen\Exception("Invalid error code: '$code'");
84
				}
85
				$description = $data;
86
				$Error = new Error($this, $reasoncode, $description);
87
				$this->responses[$reasoncode] = $Error;
88
				return $Error;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $Error; (SwaggerGen\Swagger\Error) 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...
89
90
			case 'errors':
91
				foreach (self::wordSplit($data) as $code) {
92
					$reasoncode = Response::getCode($code);
93
					if ($reasoncode === null) {
94
						throw new \SwaggerGen\Exception("Invalid error code: '$code'");
95
					}
96
					$this->responses[$reasoncode] = new Error($this, $reasoncode);
97
				}
98
				return $this;
99
100
			case 'path':
101
			case 'query':
102
			case 'query?':
103
			case 'header':
104
			case 'header?':
105
			case 'form':
106
			case 'form?':
107
				$in = rtrim($command, '?');
108
				$Parameter = new Parameter($this, $in, $data, substr($command, -1) !== '?');
109
				$this->parameters[$Parameter->getName()] = $Parameter;
110
				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...
111
112
			case 'body':
113
			case 'body?':
114
				$Parameter = new BodyParameter($this, $data, substr($command, -1) !== '?');
115
				$this->parameters[$Parameter->getName()] = $Parameter;
116
				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...
117
118
			case 'response':
119
				$code = self::wordShift($data);
120
				$reasoncode = Response::getCode($code);
121
				if ($reasoncode === null) {
122
					throw new \SwaggerGen\Exception("Invalid response code: '$code'");
123
				}
124
				$definition = self::wordShift($data);
125
				$description = $data;
126
				$Response = new Response($this, $reasoncode, $definition, $description);
127
				$this->responses[$reasoncode] = $Response;
128
				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...
129
130 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...
131
				$name = self::wordShift($data);
132
				if (empty($name)) {
133
					throw new \SwaggerGen\Exception('Empty security requirement name');
134
				}
135
				$scopes = self::wordSplit($data);
136
				sort($scopes);
137
				$this->security[] = array(
138
					$name => empty($scopes) ? array() : $scopes,
139
				);
140
				return $this;
141
142
			case 'id':
143
				$operationId = self::trim($data);
144
				if ($this->getSwagger()->hasOperationId($operationId)) {
145
					throw new \SwaggerGen\Exception("Duplicate operation id '{$operationId}'");
146
				}
147
				$this->operationId = $operationId;
148
				return $this;
149
		}
150
151
		return parent::handleCommand($command, $data);
152
	}
153
154
	public function toArray()
155
	{
156
		if (empty($this->responses)) {
157
			throw new \SwaggerGen\Exception('No response defined for operation');
158
		}
159
		ksort($this->responses);
160
161
		$tags = array_unique($this->tags);
162
		sort($tags);
163
164
		$schemes = array_unique($this->schemes);
165
		sort($schemes);
166
167
		$consumes = array_unique($this->consumes);
168
		sort($consumes);
169
170
		$produces = array_unique($this->produces);
171
		sort($produces);
172
173
		foreach ($this->security as $security) {
174
			foreach ($security as $name => $scope) {
175
				if ($this->getSwagger()->getSecurity($name) === false) {
176
					throw new \SwaggerGen\Exception("Required security scheme not defined: '{$name}'");
177
				}
178
			}
179
		}
180
181
		$parameters = $this->parameters ? array_values($this->parameters) : null;
182
183
		return self::arrayFilterNull(array_merge(array(
184
					'deprecated' => $this->deprecated ? true : null,
185
					'tags' => $tags,
186
					'summary' => empty($this->summary) ? null : $this->summary,
187
					'description' => empty($this->description) ? null : $this->description,
188
					'operationId' => $this->operationId,
189
					'consumes' => $consumes,
190
					'produces' => $produces,
191
					'parameters' => $parameters ? self::objectsToArray($parameters) : null,
192
					'schemes' => $schemes,
193
					'responses' => $this->responses ? self::objectsToArray($this->responses) : null,
194
					'security' => $this->security,
195
								), parent::toArray()));
196
	}
197
198
	/**
199
	 * Return the operation ID
200
	 * 
201
	 * @return string
202
	 */
203
	public function getId()
204
	{
205
		return $this->operationId;
206
	}
207
208
	public function __toString()
209
	{
210
		return __CLASS__ . ' ' . $this->summary;
211
	}
212
213
}
214