Passed
Pull Request — master (#317)
by Sergei
07:52 queued 05:11
created

MagicRelationsTrait   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 60
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 8
eloc 21
c 1
b 0
f 0
dl 0
loc 60
rs 10

1 Method

Rating   Name   Duplication   Size   Complexity  
B getRelation() 0 41 8
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\ActiveRecord\Trait;
6
7
use Error;
8
use ReflectionException;
9
use ReflectionMethod;
10
use Yiisoft\ActiveRecord\ActiveQueryInterface;
11
use Yiisoft\Db\Exception\InvalidArgumentException;
12
13
use function lcfirst;
14
use function method_exists;
15
use function substr;
16
use function ucfirst;
17
18
trait MagicRelationsTrait
19
{
20
    /**
21
     * Returns the relation object with the specified name.
22
     *
23
     * A relation is defined by a getter method which returns an {@see ActiveQueryInterface} object.
24
     *
25
     * It can be declared in either the Active Record class itself or one of its behaviors.
26
     *
27
     * @param string $name the relation name, e.g. `orders` for a relation defined via `getOrders()` method
28
     * (case-sensitive).
29
     * @param bool $throwException whether to throw exception if the relation does not exist.
30
     *
31
     * @throws InvalidArgumentException if the named relation does not exist.
32
     * @throws ReflectionException
33
     *
34
     * @return ActiveQueryInterface|null the relational query object. If the relation does not exist and
35
     * `$throwException` is `false`, `null` will be returned.
36
     */
37
    public function getRelation(string $name, bool $throwException = true): ActiveQueryInterface|null
38
    {
39
        $getter = 'get' . ucfirst($name);
40
41
        try {
42
            /** the relation could be defined in a behavior */
43
            $relation = $this->$getter();
44
        } catch (Error) {
45
            if ($throwException) {
46
                throw new InvalidArgumentException(static::class . ' has no relation named "' . $name . '".');
47
            }
48
49
            return null;
50
        }
51
52
        if (!$relation instanceof ActiveQueryInterface) {
53
            if ($throwException) {
54
                throw new InvalidArgumentException(static::class . ' has no relation named "' . $name . '".');
55
            }
56
57
            return null;
58
        }
59
60
        if (method_exists($this, $getter)) {
61
            /** relation name is case sensitive, trying to validate it when the relation is defined within this class */
62
            $method = new ReflectionMethod($this, $getter);
63
            $realName = lcfirst(substr($method->getName(), 3));
64
65
            if ($realName !== $name) {
66
                if ($throwException) {
67
                    throw new InvalidArgumentException(
68
                        'Relation names are case sensitive. ' . static::class
69
                        . " has a relation named \"$realName\" instead of \"$name\"."
70
                    );
71
                }
72
73
                return null;
74
            }
75
        }
76
77
        return $relation;
78
    }
79
}
80