Test Failed
Push — hasmany-subpath-includes ( 1bee8d )
by Alex
02:36
created

RelationshipIterator::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
dl 0
loc 9
rs 9.6666
c 2
b 0
f 0
cc 2
eloc 5
nc 2
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 the relationship 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
        $relation = null;
68
        [$relation, $path] = array_pad(explode('.', $path, 2), 2, null);
69
70
        $resolved = $resolved->{$relation};
71
72
        if ($resolved instanceof Collection) {
73
            return $resolved->map(function ($record) use ($path) {
74
                return $this->iterate($record, $path);
75
            });
76
        }
77
78
        if (!$resolved instanceof Model || in_array($relation, $resolved->getHidden())) {
79
            throw new InvalidRelationPathException($this->path);
80
        }
81
82
        return $this->iterate($resolved, $path);
83
    }
84
}
85