Passed
Pull Request — master (#343)
by Dmitriy
02:42
created

Callback::getName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Rule;
6
7
use Attribute;
8
use Closure;
9
use InvalidArgumentException;
10
use ReflectionException;
11
use ReflectionObject;
12
use TypeError;
13
use Yiisoft\Validator\AttributeEventInterface;
14
use Yiisoft\Validator\DataSet\ObjectDataSet;
15
use Yiisoft\Validator\DataSetInterface;
16
use Yiisoft\Validator\Rule\Trait\SkipOnEmptyTrait;
17
use Yiisoft\Validator\Rule\Trait\SkipOnErrorTrait;
18
use Yiisoft\Validator\Rule\Trait\WhenTrait;
19
use Yiisoft\Validator\SerializableRuleInterface;
20
use Yiisoft\Validator\SkipOnEmptyInterface;
21
use Yiisoft\Validator\SkipOnErrorInterface;
22
use Yiisoft\Validator\ValidationContext;
23
use Yiisoft\Validator\WhenInterface;
24
25
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
26
final class Callback implements
27
    SerializableRuleInterface,
28
    SkipOnErrorInterface,
29
    WhenInterface,
30
    SkipOnEmptyInterface,
31
    AttributeEventInterface
32
{
33
    use SkipOnEmptyTrait;
34
    use SkipOnErrorTrait;
35
    use WhenTrait;
36
37 9
    public function __construct(
38
        /**
39
         * @var callable|null
40
         */
41
        private $callback = null,
42
        private ?string $method = null,
43
44
        /**
45
         * @var bool|callable|null
46
         */
47
        private $skipOnEmpty = null,
48
        private bool $skipOnError = false,
49
        /**
50
         * @var Closure(mixed, ValidationContext):bool|null
51
         */
52
        private ?Closure $when = null,
53
    ) {
54 9
        if ($this->callback === null && $this->method === null) {
55
            throw new InvalidArgumentException('Either "$callback" or "$method" must be specified.');
56
        }
57
58 9
        if ($this->callback !== null && $this->method !== null) {
59
            throw new InvalidArgumentException('"$callback" and "$method" are mutually exclusive.');
60
        }
61
    }
62
63 1
    public function getName(): string
64
    {
65 1
        return 'callback';
66
    }
67
68 14
    public function getCallback(): ?callable
69
    {
70 14
        return $this->callback;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->callback returns the type mixed which is incompatible with the type-hinted return callable|null.
Loading history...
71
    }
72
73
    public function getMethod(): ?string
74
    {
75
        return $this->method;
76
    }
77
78 3
    public function afterInitAttribute(DataSetInterface $dataSet): void
79
    {
80 3
        if (!$dataSet instanceof ObjectDataSet) {
81
            return;
82
        }
83
84 3
        $object = $dataSet->getObject();
85 3
        $method = $this->method;
86
87 3
        $reflection = new ReflectionObject($object);
88
        try {
89 3
            $reflection->getMethod($method);
90 1
        } catch (ReflectionException) {
91 1
            throw new InvalidArgumentException(sprintf(
92
                'Method "%s" does not exist in class "%s".',
93
                $method,
94
                $object::class,
95
            ));
96
        }
97
98 2
        $this->callback = Closure::bind(fn(...$args) => $object->{$method}(...$args), $object, $object);
99
    }
100
101 2
    public function getOptions(): array
102
    {
103
        return [
104 2
            'skipOnEmpty' => $this->getSkipOnEmptyOption(),
105 2
            'skipOnError' => $this->skipOnError,
106
        ];
107
    }
108
109 14
    public function getHandlerClassName(): string
110
    {
111 14
        return CallbackHandler::class;
112
    }
113
}
114