Test Failed
Pull Request — main (#64)
by Lode
08:15
created

ErrorsDocument::determineHttpStatusCode()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 33

Duplication

Lines 18
Ratio 54.55 %

Importance

Changes 0
Metric Value
dl 18
loc 33
rs 8.4586
c 0
b 0
f 0
cc 7
nc 6
nop 1
1
<?php
2
3
namespace alsvanzelf\jsonapi;
4
5
use alsvanzelf\jsonapi\Document;
6
use alsvanzelf\jsonapi\exceptions\InputException;
7
use alsvanzelf\jsonapi\objects\ErrorObject;
8
9
/**
10
 * this document is used to send one or multiple errors
11
 */
0 ignored issues
show
Coding Style introduced by
Missing @link tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @category tag in class comment
Loading history...
12
class ErrorsDocument extends Document {
13
	/** @var ErrorObject[] */
14
	protected $errors = [];
15
	/** @var array */
16
	protected $httpStatusCodes;
17
	/** @var array */
18
	protected static $defaults = [
19
		/**
20
		 * add the trace of exceptions when adding exceptions
21
		 * in some cases it might be handy to disable if traces are too big
22
		 */
23
		'includeExceptionTrace' => true,
24
		
25
		/**
26
		 * add previous exceptions as separate errors when adding exceptions
27
		 */
28
		'includeExceptionPrevious' => true,
29
	];
30
	
31
	/**
32
	 * @param ErrorObject $errorObject optional
33
	 */
34
	public function __construct(ErrorObject $errorObject=null) {
35
		parent::__construct();
36
		
37
		if ($errorObject !== null) {
38
			$this->addErrorObject($errorObject);
39
		}
40
	}
41
	
42
	/**
43
	 * human api
44
	 */
45
	
46
	/**
47
	 * @param  \Exception|\Throwable $exception
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
48
	 * @param  array                 $options   optional {@see ErrorsDocument::$defaults}
49
	 * @return ErrorsDocument
50
	 * 
51
	 * @throws InputException if $exception is not \Exception or \Throwable
52
	 */
53
	public static function fromException($exception, array $options=[]) {
54 View Code Duplication
		if ($exception instanceof \Exception === false && $exception instanceof \Throwable === false) {
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...
55
			throw new InputException('input is not a real exception in php5 or php7');
56
		}
57
		
58
		$options = array_merge(self::$defaults, $options);
59
		
60
		$errorsDocument = new self();
61
		$errorsDocument->addException($exception, $options);
62
		
63
		return $errorsDocument;
64
	}
65
	
66
	/**
67
	 * add an ErrorObject for the given $exception
68
	 * 
69
	 * recursively adds multiple ErrorObjects if $exception carries a ->getPrevious()
70
	 * 
71
	 * @param \Exception|\Throwable $exception
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
72
	 * @param array                 $options   optional {@see ErrorsDocument::$defaults}
73
	 * 
74
	 * @throws InputException if $exception is not \Exception or \Throwable
75
	 */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
76
	public function addException($exception, array $options=[]) {
77 View Code Duplication
		if ($exception instanceof \Exception === false && $exception instanceof \Throwable === false) {
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...
78
			throw new InputException('input is not a real exception in php5 or php7');
79
		}
80
		
81
		$options = array_merge(self::$defaults, $options);
82
		
83
		$this->addErrorObject(ErrorObject::fromException($exception, $options));
84
		
85
		if ($options['includeExceptionPrevious']) {
86
			$exception = $exception->getPrevious();
87
			while ($exception !== null) {
88
				$this->addException($exception, $options);
89
				$exception = $exception->getPrevious();
90
			}
91
		}
92
	}
93
	
94
	/**
95
	 * @param string|int $genericCode       developer-friendly code of the generic type of error
96
	 * @param string     $genericTitle      human-friendly title of the generic type of error
97
	 * @param string     $specificDetails   optional, human-friendly explanation of the specific error
98
	 * @param string     $specificAboutLink optional, human-friendly explanation of the specific error
99
	 * @param string     $genericTypeLink   optional, human-friendly explanation of the generic type of error
100
	 */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
101
	public function add($genericCode, $genericTitle, $specificDetails=null, $specificAboutLink=null, $genericTypeLink=null) {
102
		$errorObject = new ErrorObject($genericCode, $genericTitle, $specificDetails, $specificAboutLink, $genericTypeLink);
103
		
104
		$this->addErrorObject($errorObject);
105
	}
106
	
107
	/**
108
	 * spec api
109
	 */
110
	
111
	/**
112
	 * @note also defines the http status code of the document if the ErrorObject has it defined
113
	 * 
114
	 * @param ErrorObject $errorObject
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
115
	 */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
116
	public function addErrorObject(ErrorObject $errorObject) {
117
		$this->errors[] = $errorObject;
118
		
119
		if ($errorObject->hasHttpStatusCode()) {
120
			$this->setHttpStatusCode($this->determineHttpStatusCode($errorObject->getHttpStatusCode()));
121
		}
122
	}
123
	
124
	/**
125
	 * DocumentInterface
126
	 */
127
	
128
	/**
129
	 * @inheritDoc
130
	 */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
131
	public function toArray() {
132
		$array = parent::toArray();
133
		
134
		$array['errors'] = [];
135
		foreach ($this->errors as $error) {
136
			if ($error->isEmpty()) {
137
				continue;
138
			}
139
			
140
			$array['errors'][] = $error->toArray();
141
		}
142
		
143
		return $array;
144
	}
145
	
146
	/**
147
	 * internal api
148
	 */
149
	
150
	/**
151
	 * @internal
152
	 * 
153
	 * @param  string|int $httpStatusCode
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
154
	 * @return int
155
	 */
156
	protected function determineHttpStatusCode($httpStatusCode) {
157
		// add the new code
158
		$category = substr($httpStatusCode, 0, 1);
159
		$this->httpStatusCodes[$category][$httpStatusCode] = true;
160
		
161
		$advisedStatusCode = $httpStatusCode;
162
		
163
		// when there's multiple, give preference to 5xx errors
164
		if (isset($this->httpStatusCodes['5']) && isset($this->httpStatusCodes['4'])) {
165
			// use a generic one
166
			$advisedStatusCode = 500;
167
		}
168 View Code Duplication
		elseif (isset($this->httpStatusCodes['5'])) {
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...
169
			if (count($this->httpStatusCodes['5']) === 1) {
170
				$advisedStatusCode = key($this->httpStatusCodes['5']);
171
			}
172
			else {
173
				// use a generic one
174
				$advisedStatusCode = 500;
175
			}
176
		}
177 View Code Duplication
		elseif (isset($this->httpStatusCodes['4'])) {
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...
178
			if (count($this->httpStatusCodes['4']) === 1) {
179
				$advisedStatusCode = key($this->httpStatusCodes['4']);
180
			}
181
			else {
182
				// use a generic one
183
				$advisedStatusCode = 400;
184
			}
185
		}
186
		
187
		return (int) $advisedStatusCode;
188
	}
189
}
190