Completed
Push — master ( 69e30f...0602c8 )
by Freek
14:10
created

CatchableCollectionProxy::catch()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 21
rs 9.2728
c 0
b 0
f 0
cc 5
nc 5
nop 1
1
<?php
2
3
namespace Spatie\CollectionMacros\Helpers;
4
5
use Exception;
6
use Illuminate\Support\Enumerable;
7
use ReflectionFunction;
8
9
/**
10
 * @mixin \Illuminate\Collections\Enumerable
11
 */
12
class CatchableCollectionProxy
13
{
14
    /**
15
     * The collection being operated on.
16
     *
17
     * @var \Illuminate\Collections\Enumerable
18
     */
19
    protected $collection;
20
21
    /**
22
     * The collection methods to handle exceptions for.
23
     *
24
     * @var array
25
     */
26
    protected $calledMethods = [];
27
28
    /**
29
     * Create a new proxy instance.
30
     *
31
     * @param  \Illuminate\Collections\Enumerable  $collection
32
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
33
     */
34
    public function __construct(Enumerable $collection)
35
    {
36
        $this->collection = $collection;
37
    }
38
39
    /**
40
     * Proxy a method call onto the collection items.
41
     *
42
     * @param  string  $method
43
     * @param  array  $parameters
44
     * @return $this
45
     */
46
    public function __call($method, $parameters)
47
    {
48
        $this->calledMethods[] = ['name' => $method, 'parameters' => $parameters];
49
50
        return $this;
51
    }
52
53
    /**
54
     * @param \Closure[] $handlers
55
     *
56
     * @return \Illuminate\Collections\Enumerable
57
     */
58
    public function catch(...$handlers)
59
    {
60
        $originalCollection = $this->collection;
61
62
        try {
63
            foreach ($this->calledMethods as $calledMethod) {
64
                $this->collection = $this->collection->{$calledMethod['name']}(...$calledMethod['parameters']);
65
            }
66
        } catch (Exception $exception) {
67
            foreach ($handlers as $callable) {
68
                $type = $this->exceptionType($callable);
69
                if ($exception instanceof $type) {
70
                    return $callable($exception, $originalCollection) ?? $originalCollection;
71
                }
72
            }
73
74
            throw $exception;
75
        }
76
77
        return $this->collection;
78
    }
79
80
    private function exceptionType($callable)
81
    {
82
        $reflection = new ReflectionFunction($callable);
83
84
        if (empty($reflection->getParameters())) {
85
            return Exception::class;
86
        }
87
88
        return optional($reflection->getParameters()[0]->getType())->getName() ?? Exception::class;
89
    }
90
}
91