Passed
Pull Request — 1.0.0-alpha (#26)
by Alex
02:41
created

RelationshipIterator::iterate()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 22
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 22
rs 8.6737
cc 5
eloc 11
nc 4
nop 2
1
<?php
2
3
namespace Huntie\JsonApi\Support;
4
5
use InvalidArgumentException;
6
use Huntie\JsonApi\Exceptions\InvalidRelationPathException;
7
use Illuminate\Database\Eloquent\Model;
8
use Illuminate\Support\Collection;
9
10
class RelationshipIterator
11
{
12
    /**
13
     * The primary record.
14
     */
15
    private $record;
16
17
    /**
18
     * The path to the relation.
19
     *
20
     * @var string
21
     */
22
    private $path;
23
24
    /**
25
     * Create a new RelationshipIterator instance.
26
     *
27
     * @param Model  $record The primary record
28
     * @param string $path   The path to the relation
29
     *
30
     * @throws InvalidArgumentException
31
     */
32
    public function __construct($record, string $path)
33
    {
34
        if (!preg_match('/^([A-Za-z]+.?)+[A-Za-z]+$/', $path)) {
35
            throw new InvalidArgumentException('The relationship path must be a valid string');
36
        }
37
38
        $this->record = $record;
39
        $this->path = $path;
40
    }
41
42
    /**
43
     * Resolve the relationship from the primary record.
44
     *
45
     * @return Collection|Model|null
46
     */
47
    public function resolve()
48
    {
49
        return $this->iterate($this->record, $this->path);
50
    }
51
52
    /**
53
     * Recursively iterate through a given relation path to return the resolved
54
     * relationship value.
55
     *
56
     * @param Collection|Model|null $resolved
57
     * @param string|null           $path
58
     *
59
     * @return Collection|Model|null
60
     */
61
    private function iterate($resolved, $path)
62
    {
63
        if (empty($path)) {
64
            return $resolved;
65
        }
66
67
        list($relation, $path) = array_pad(explode('.', $path, 2), 2, null);
68
69
        $resolved = $resolved->{$relation};
70
71
        if ($resolved instanceof Collection) {
72
            return $resolved->map(function ($record) use ($path) {
73
                return $this->iterate($record, $path);
74
            });
75
        }
76
77
        if (!$resolved instanceof Model || in_array($relation, $resolved->getHidden())) {
78
            throw new InvalidRelationPathException($this->path);
79
        }
80
81
        return $this->iterate($resolved, $path);
82
    }
83
}
84