This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Fousky\Component\iDoklad\Functions; |
||
4 | |||
5 | use Fousky\Component\iDoklad\Exception\InvalidModelException; |
||
6 | use Fousky\Component\iDoklad\Model\iDokladAbstractModel; |
||
7 | use Fousky\Component\iDoklad\Model\iDokladModelInterface; |
||
8 | use Fousky\Component\iDoklad\UrlExtension\iDokladFilter; |
||
9 | use Fousky\Component\iDoklad\UrlExtension\iDokladPaginator; |
||
10 | use Fousky\Component\iDoklad\UrlExtension\iDokladSortable; |
||
11 | use Psr\Http\Message\ResponseInterface; |
||
12 | use Symfony\Component\OptionsResolver\Exception\ExceptionInterface; |
||
13 | use Symfony\Component\OptionsResolver\OptionsResolver; |
||
14 | |||
15 | /** |
||
16 | * @author Lukáš Brzák <[email protected]> |
||
17 | */ |
||
18 | abstract class iDokladAbstractFunction implements iDokladFunctionInterface |
||
19 | { |
||
20 | /** @var ResponseInterface|null $response */ |
||
21 | protected $response; |
||
22 | |||
23 | /** @var array $config */ |
||
24 | protected $config; |
||
25 | |||
26 | /** @var null|iDokladFilter $filter */ |
||
27 | protected $filter; |
||
28 | |||
29 | /** @var null|iDokladPaginator $paginator */ |
||
30 | protected $paginator; |
||
31 | |||
32 | /** @var null|iDokladSortable $sortable */ |
||
33 | protected $sortable; |
||
34 | |||
35 | /** |
||
36 | * @param iDokladPaginator $paginator |
||
37 | * |
||
38 | * @return iDokladAbstractFunction |
||
39 | */ |
||
40 | public function paginator(iDokladPaginator $paginator): self |
||
41 | { |
||
42 | $this->setPaginator($paginator); |
||
43 | |||
44 | return $this; |
||
45 | } |
||
46 | |||
47 | /** |
||
48 | * @param iDokladSortable $sortable |
||
49 | * |
||
50 | * @return iDokladAbstractFunction |
||
51 | */ |
||
52 | public function sortable(iDokladSortable $sortable): self |
||
53 | { |
||
54 | $this->setSortable($sortable); |
||
55 | |||
56 | return $this; |
||
57 | } |
||
58 | |||
59 | /** |
||
60 | * @param iDokladFilter $filter |
||
61 | * |
||
62 | * @return $this |
||
63 | */ |
||
64 | public function filter(iDokladFilter $filter) |
||
65 | { |
||
66 | $this->setFilter($filter); |
||
67 | |||
68 | return $this; |
||
69 | } |
||
70 | |||
71 | /** |
||
72 | * @return bool |
||
73 | */ |
||
74 | public function injectAccessTokenToHeaders(): bool |
||
75 | { |
||
76 | return true; |
||
77 | } |
||
78 | |||
79 | /** |
||
80 | * Handle response from iDoklad and create model instance. |
||
81 | * |
||
82 | * @param ResponseInterface $response |
||
83 | * |
||
84 | * @throws \InvalidArgumentException |
||
85 | * @throws \Fousky\Component\iDoklad\Exception\InvalidResponseException |
||
86 | * @throws \ReflectionException |
||
87 | * |
||
88 | * @return iDokladModelInterface |
||
89 | */ |
||
90 | public function handleResponse(ResponseInterface $response): iDokladModelInterface |
||
91 | { |
||
92 | return $this->createModel($this->getModelClass(), $response); |
||
93 | } |
||
94 | |||
95 | /** |
||
96 | * @param string|iDokladModelInterface $modelClass |
||
97 | * @param ResponseInterface $response |
||
98 | * |
||
99 | * @throws \ReflectionException |
||
100 | * @throws \InvalidArgumentException |
||
101 | * @throws \Fousky\Component\iDoklad\Exception\InvalidResponseException |
||
102 | * |
||
103 | * @return iDokladModelInterface |
||
104 | */ |
||
105 | protected function createModel($modelClass, ResponseInterface $response): iDokladModelInterface |
||
106 | { |
||
107 | if (!class_exists($modelClass) || |
||
108 | !(new \ReflectionClass($modelClass))->implementsInterface(iDokladModelInterface::class) |
||
109 | ) { |
||
110 | throw new \InvalidArgumentException(sprintf( |
||
111 | 'Class %s not exists or does not implements interface %s', |
||
112 | $modelClass, |
||
113 | iDokladModelInterface::class |
||
114 | )); |
||
115 | } |
||
116 | |||
117 | return $modelClass::createFromResponse($response); |
||
118 | } |
||
119 | |||
120 | /** |
||
121 | * @param iDokladAbstractModel $model |
||
122 | * |
||
123 | * @throws InvalidModelException |
||
124 | */ |
||
125 | protected function validate(iDokladAbstractModel $model) |
||
126 | { |
||
127 | try { |
||
128 | $errorList = $model->validate(); |
||
129 | } catch (\Throwable $e) { |
||
130 | throw new InvalidModelException([$e->getMessage()]); |
||
131 | } |
||
132 | |||
133 | if (0 === $errorList->count()) { |
||
134 | return; |
||
135 | } |
||
136 | |||
137 | $errors = [ |
||
138 | sprintf('Model class %s has following errors:', \get_class($model)), |
||
139 | ]; |
||
140 | |||
141 | foreach ($errorList as $error) { |
||
142 | $errors[] = sprintf('- %s: %s', $error->getPropertyPath(), $error->getMessage()); |
||
143 | } |
||
144 | |||
145 | throw new InvalidModelException($errors); |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * @param array $config |
||
150 | * |
||
151 | * @throws ExceptionInterface |
||
152 | * |
||
153 | * @return array |
||
154 | */ |
||
155 | public static function assertConfiguration(array $config): array |
||
156 | { |
||
157 | return (new OptionsResolver()) |
||
158 | ->setDefaults([ |
||
159 | 'debug' => false, |
||
160 | 'url' => 'https://app.idoklad.cz/developer/api/v2/', |
||
161 | 'token_endpoint' => 'https://app.idoklad.cz/identity/server/connect/token', |
||
162 | 'scope' => 'idoklad_api', |
||
163 | // iDoklad sends DateTime in UTC, so we tranform to another PHP \DateTimeZone |
||
164 | 'timezone' => 'Europe/Prague', |
||
165 | // iDoklad generates invoices in available locales: ['cs-CZ', 'sk-SK', 'de-DE', 'en-US'] |
||
166 | 'language' => 'cs-CZ', |
||
167 | ]) |
||
168 | ->setRequired([ |
||
169 | 'client_id', |
||
170 | 'client_secret', |
||
171 | ]) |
||
172 | ->setAllowedTypes('debug', ['boolean']) |
||
173 | ->setAllowedTypes('url', ['string']) |
||
174 | ->setAllowedTypes('client_id', ['string']) |
||
175 | ->setAllowedTypes('client_secret', ['string']) |
||
176 | ->setAllowedTypes('token_endpoint', ['string']) |
||
177 | ->setAllowedTypes('scope', ['string']) |
||
178 | ->setAllowedTypes('language', ['string']) |
||
179 | ->setAllowedValues('language', ['cs-CZ', 'sk-SK', 'de-DE', 'en-US']) |
||
180 | ->resolve($config); |
||
181 | } |
||
182 | |||
183 | /** |
||
184 | * @param array $config |
||
185 | * |
||
186 | * @return iDokladFunctionInterface |
||
187 | */ |
||
188 | public function setConfig(array $config): iDokladFunctionInterface |
||
189 | { |
||
190 | $this->config = $config; |
||
191 | |||
192 | return $this; |
||
0 ignored issues
–
show
|
|||
193 | } |
||
194 | |||
195 | /** |
||
196 | * @return bool |
||
197 | */ |
||
198 | public function hasSortable(): bool |
||
199 | { |
||
200 | return null !== $this->sortable; |
||
201 | } |
||
202 | |||
203 | /** |
||
204 | * @throws \RuntimeException |
||
205 | * |
||
206 | * @return iDokladSortable |
||
207 | */ |
||
208 | public function getSortable(): iDokladSortable |
||
209 | { |
||
210 | if (null === $this->sortable) { |
||
211 | throw new \RuntimeException(sprintf( |
||
212 | 'Function %s does not have iDokladSortable instance.', |
||
213 | __CLASS__ |
||
214 | )); |
||
215 | } |
||
216 | |||
217 | return $this->sortable; |
||
218 | } |
||
219 | |||
220 | /** |
||
221 | * @param null|iDokladSortable $sortable |
||
222 | */ |
||
223 | public function setSortable(iDokladSortable $sortable = null) |
||
224 | { |
||
225 | $this->sortable = $sortable; |
||
226 | } |
||
227 | |||
228 | /** |
||
229 | * @return bool |
||
230 | */ |
||
231 | public function hasPaginator(): bool |
||
232 | { |
||
233 | return null !== $this->paginator; |
||
234 | } |
||
235 | |||
236 | /** |
||
237 | * @throws \RuntimeException |
||
238 | * |
||
239 | * @return iDokladPaginator |
||
240 | */ |
||
241 | public function getPaginator(): iDokladPaginator |
||
242 | { |
||
243 | if (null === $this->paginator) { |
||
244 | throw new \RuntimeException(sprintf( |
||
245 | 'Function %s does not have iDokladPaginator instance.', |
||
246 | __CLASS__ |
||
247 | )); |
||
248 | } |
||
249 | |||
250 | return $this->paginator; |
||
251 | } |
||
252 | |||
253 | /** |
||
254 | * @param null|iDokladPaginator $paginator |
||
255 | */ |
||
256 | public function setPaginator(iDokladPaginator $paginator = null) |
||
257 | { |
||
258 | $this->paginator = $paginator; |
||
259 | } |
||
260 | |||
261 | /** |
||
262 | * @return bool |
||
263 | */ |
||
264 | public function hasFilter(): bool |
||
265 | { |
||
266 | return null !== $this->filter; |
||
267 | } |
||
268 | |||
269 | /** |
||
270 | * @throws \RuntimeException |
||
271 | * |
||
272 | * @return iDokladFilter |
||
273 | */ |
||
274 | public function getFilter(): iDokladFilter |
||
275 | { |
||
276 | if (null === $this->filter) { |
||
277 | throw new \RuntimeException(sprintf( |
||
278 | 'Function %s does not have iDokladFilter instance.', |
||
279 | __CLASS__ |
||
280 | )); |
||
281 | } |
||
282 | |||
283 | return $this->filter; |
||
284 | } |
||
285 | |||
286 | /** |
||
287 | * @param null|iDokladFilter $filter |
||
288 | */ |
||
289 | public function setFilter(iDokladFilter $filter = null) |
||
290 | { |
||
291 | $this->filter = $filter; |
||
292 | } |
||
293 | } |
||
294 |
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:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.