Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
87.50% covered (warning)
87.50%
91 / 104
76.00% covered (warning)
76.00%
19 / 25
CRAP
0.00% covered (danger)
0.00%
0 / 1
common_report_Report
87.50% covered (warning)
87.50%
91 / 104
76.00% covered (warning)
76.00%
19 / 25
54.88
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 __callStatic
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
3
 __call
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
3
 getMessage
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAllMessages
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 setMessage
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setType
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getData
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setData
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 hasChildren
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getChildren
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 add
50.00% covered (danger)
50.00%
5 / 10
0.00% covered (danger)
0.00%
0 / 1
10.50
 contains
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
4
 filterChildrenByTypes
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 getIterator
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __toString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 jsonUnserialize
88.89% covered (warning)
88.89%
8 / 9
0.00% covered (danger)
0.00%
0 / 1
6.05
 jsonSerialize
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 toArray
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 createFailure
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 handleGetCalls
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 handleContainsCalls
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 getRecursiveIterator
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 isValidType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3/**
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; under version 2
7 * of the License (non-upgradable).
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 *
18 * Copyright (c) 2013 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
19 *
20 */
21
22use oat\oatbox\reporting\RecursiveReportIterator;
23use oat\oatbox\reporting\Report;
24use oat\oatbox\reporting\ReportInterface;
25
26/**
27 * The Report allows to return a more detailed return value
28 * then a simple boolean variable denoting the success
29 *
30 * @author Bertrand Chevrier, <bertrand.chevrier@tudor.lu>
31 * @deprecated Please, use oat\oatbox\reporting\Report::class.
32 */
33class common_report_Report implements ReportInterface
34{
35    /**
36     * Type of the report
37     *
38     * @var string
39     */
40    private $type;
41
42    /**
43     * Message of the report
44     *
45     * @var string
46     */
47    private $message;
48
49    /**
50     * Elements of the report
51     *
52     * @var array
53     */
54    private $children = [];
55
56    /**
57     * Attached to the report data
58     *
59     * @var mixed
60     */
61    private $data;
62
63    /**
64     * Report constructor.
65     *
66     * @param string $type
67     * @param string $message
68     * @param null   $data
69     * @param array  $children
70     *
71     * @throws common_exception_Error
72     */
73    public function __construct(string $type, string $message = '', $data = null, array $children = [])
74    {
75        if (!self::isValidType($type)) {
76            throw new OutOfBoundsException(sprintf('Type of the report `%s` is unsupported for creation', $type));
77        }
78
79        $this->type = $type;
80        $this->message = $message;
81        $this->data = $data;
82
83        foreach ($children as $child) {
84            $this->add($child);
85        }
86    }
87
88    /**
89     * Covers static helpers by the next template: Report::create<Type>
90     *
91     * @param string $name
92     * @param array  $arguments
93     *
94     * @return Report
95     * @throws common_exception_Error
96     */
97    public static function __callStatic(string $name, array $arguments): self
98    {
99        if (strpos($name, 'create') !== 0) {
100            throw new BadMethodCallException(
101                sprintf(
102                    'Requested method `%s` is not found or is not allowed in class %s',
103                    $name,
104                    __CLASS__
105                )
106            );
107        }
108
109        $type = strtolower(str_replace('create', '', $name));
110
111        if (!self::isValidType($type)) {
112            throw new OutOfBoundsException(sprintf('Type of the report `%s` is unsupported for creation', $type));
113        }
114
115        return new static($type, ...$arguments);
116    }
117
118    /**
119     * Covers helpers (methods) by defined templates
120     *
121     * @param string $name
122     * @param array  $arguments
123     *
124     * @return bool|array
125     */
126    public function __call(string $name, array $arguments)
127    {
128        /** Covers methods by template: get<Type>[e]s */
129        if (0 === strpos($name, 'get')) {
130            return $this->handleGetCalls($name, $arguments);
131        }
132
133        /** Covers methods by template: contains<Type> */
134        if (0 === strpos($name, 'contains')) {
135            return $this->handleContainsCalls($name, $arguments);
136        }
137
138        throw new BadMethodCallException(
139            sprintf(
140                'Requested method `%s` is not found or is not allowed in class %s',
141                $name,
142                __CLASS__
143            )
144        );
145    }
146
147    /**
148     * Get message of the report
149     *
150     * @return string
151     */
152    public function getMessage(): string
153    {
154        return $this->message;
155    }
156
157    public function getAllMessages(): string
158    {
159        $messages = [$this->getMessage()];
160
161        foreach ($this->children as $child) {
162            $messages[] = $child->getAllMessages();
163        }
164
165        return implode(', ', $messages);
166    }
167
168    /**
169     * Update message of the report
170     *
171     * @param string $message
172     *
173     * @return Report
174     */
175    public function setMessage(string $message): self
176    {
177        $this->message = $message;
178
179        return $this;
180    }
181
182    /**
183     * Return type of the report
184     *
185     * @return string
186     */
187    public function getType(): string
188    {
189        return $this->type;
190    }
191
192    /**
193     * Update type of the report
194     *
195     * @param string $type
196     *
197     * @return Report
198     */
199    public function setType(string $type): self
200    {
201        $this->type = $type;
202
203        return $this;
204    }
205
206    /**
207     * Return attached data
208     *
209     * @return mixed|null
210     */
211    public function getData()
212    {
213        return $this->data;
214    }
215
216    /**
217     * Attach data to the report
218     *
219     * @param mixed|null $data
220     *
221     * @return $this
222     */
223    public function setData($data): self
224    {
225        $this->data = $data;
226
227        return $this;
228    }
229
230    /**
231     * Whenever or not there are child reports
232     *
233     * @return boolean
234     */
235    public function hasChildren(): bool
236    {
237        return count($this->children) > 0;
238    }
239
240    /**
241     * Return child reports
242     *
243     * @return array
244     */
245    public function getChildren(): array
246    {
247        return $this->children;
248    }
249
250    /**
251     * Add something (children) to the report
252     *
253     * @param mixed $mixed accepts single values and arrays of Reports and UserReadableExceptions
254     *
255     * @return Report
256     *
257     * @throws common_exception_Error
258     */
259    public function add($mixed): self
260    {
261        $mixedArray = is_array($mixed) ? $mixed : [$mixed];
262
263        foreach ($mixedArray as $element) {
264            if ($element instanceof self) {
265                $this->children[] = $element;
266            } elseif ($element instanceof UserReadableException) {
267                $this->children[] = new static(self::TYPE_ERROR, $element->getUserMessage());
268            } else {
269                throw new common_exception_Error(
270                    'Tried to add ' . (is_object($element) ? get_class($element) : gettype($element)) . ' to the report'
271                );
272            }
273        }
274
275        return $this;
276    }
277
278    /**
279     * Whenever or not the type can be found in the report
280     *
281     * @param string $type
282     *
283     * @return boolean
284     */
285    public function contains(string $type): bool
286    {
287        foreach ($this as $child) {
288            if ($child->getType() === $type || $child->contains($type)) {
289                return true;
290            }
291        }
292
293        return false;
294    }
295
296    /**
297     * Returns all children based on type
298     *
299     * @param array $types
300     * @param bool  $asFlat
301     *
302     * @return array
303     */
304    public function filterChildrenByTypes(array $types, $asFlat = false): array
305    {
306        $iterator = true === $asFlat
307            ? $this->getRecursiveIterator()
308            : $this;
309
310        $found = [];
311
312        foreach ($iterator as $element) {
313            if (in_array($element->getType(), $types, true)) {
314                $found[] = $element;
315            }
316        }
317
318        return $found;
319    }
320
321    /**
322     * Returns an iterator over the children
323     */
324    public function getIterator(): ArrayIterator
325    {
326        return new ArrayIterator($this->getChildren());
327    }
328
329    /**
330     * User feedback message
331     */
332    public function __toString(): string
333    {
334        return $this->getMessage();
335    }
336
337    /**
338     * Recursively restores report object from json string or array
339     *
340     * @param string|array $data
341     *
342     * @return self|null
343     *
344     * @throws common_exception_Error
345     */
346    public static function jsonUnserialize($data): ?self
347    {
348        if (!is_array($data)) {
349            $data = (array) json_decode((string) $data, true);
350        }
351
352        if (count(array_intersect(['type', 'message', 'data'], array_keys($data))) !== 3) {
353            return null;
354        }
355
356        $report = new static($data['type'], $data['message'], $data['data']);
357
358        $data['children'] = (!isset($data['children']) || !is_array($data['children'])) ? [] : $data['children'];
359        foreach ($data['children'] as $child) {
360            $report->add(static::jsonUnserialize($child));
361        }
362
363        return $report;
364    }
365
366    /**
367     * Prepares object data for valid converting to json
368     */
369    public function jsonSerialize(): array
370    {
371        return [
372            'type' => $this->getType(),
373            'message' => $this->getMessage(),
374            'data' => $this->getData(),
375            'children' => $this->getChildren()
376        ];
377    }
378
379    /**
380     * Returns array representation of the report, recursively
381     */
382    public function toArray(): array
383    {
384        return array_merge($this->jsonSerialize(), [
385            'children' => array_map(static function (self $report) {
386                return $report->toArray();
387            }, $this->children)
388        ]);
389    }
390
391    /**
392     * Convenience method to create a simple failure report
393     *
394     * @param string $message
395     * @param mixed  $errors
396     * @param null   $data
397     *
398     * @return Report
399     * @throws common_exception_Error
400     * @deprecated Please, use `createError` method instead
401     */
402    public static function createFailure(string $message, array $errors = [], $data = null): self
403    {
404        return new static(self::TYPE_ERROR, $message, $data, $errors);
405    }
406
407    private function handleGetCalls(string $name, array $arguments): array
408    {
409        $type = strtolower(str_replace('get', '', $name));
410        $type = rtrim(substr($type, 0, -1), 'e');
411
412        if (!self::isValidType($type)) {
413            throw new OutOfBoundsException(sprintf('Type of report `%s` is unsupported', $type));
414        }
415
416        return $this->filterChildrenByTypes([$type], ...$arguments);
417    }
418
419    private function handleContainsCalls(string $name, array $arguments): bool
420    {
421        $type = strtolower(str_replace('contains', '', $name));
422
423        if (!self::isValidType($type)) {
424            throw new OutOfBoundsException(sprintf('Type of report `%s` is unsupported', $type));
425        }
426
427        return $this->contains($type);
428    }
429
430    private function getRecursiveIterator(): RecursiveIteratorIterator
431    {
432        return new RecursiveIteratorIterator(
433            new RecursiveReportIterator($this->getIterator()),
434            RecursiveIteratorIterator::SELF_FIRST
435        );
436    }
437
438    private static function isValidType(string $type): bool
439    {
440        return in_array($type, static::ALLOWED_TYPES);
441    }
442}