Passed
Pull Request — master (#343)
by Alexander
05:10 queued 02:26
created

Callback   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 87
Duplicated Lines 0 %

Test Coverage

Coverage 80.77%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 13
eloc 34
c 1
b 0
f 0
dl 0
loc 87
ccs 21
cts 26
cp 0.8077
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A getMethod() 0 3 1
A getName() 0 3 1
A afterInitAttribute() 0 21 3
A __construct() 0 23 5
A getCallback() 0 3 1
A getHandlerClassName() 0 3 1
A getOptions() 0 5 1
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 Yiisoft\Validator\AttributeEventInterface;
13
use Yiisoft\Validator\DataSet\ObjectDataSet;
14
use Yiisoft\Validator\DataSetInterface;
15
use Yiisoft\Validator\Rule\Trait\SkipOnEmptyTrait;
16
use Yiisoft\Validator\Rule\Trait\SkipOnErrorTrait;
17
use Yiisoft\Validator\Rule\Trait\WhenTrait;
18
use Yiisoft\Validator\SerializableRuleInterface;
19
use Yiisoft\Validator\SkipOnEmptyInterface;
20
use Yiisoft\Validator\SkipOnErrorInterface;
21
use Yiisoft\Validator\ValidationContext;
22
use Yiisoft\Validator\WhenInterface;
23
24
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
25
final class Callback implements
26
    SerializableRuleInterface,
27
    SkipOnErrorInterface,
28
    WhenInterface,
29
    SkipOnEmptyInterface,
30
    AttributeEventInterface
31
{
32
    use SkipOnEmptyTrait;
33
    use SkipOnErrorTrait;
34
    use WhenTrait;
35
36 9
    public function __construct(
37
        /**
38
         * @var callable|null
39
         */
40
        private $callback = null,
41
        private ?string $method = null,
42
43
        /**
44
         * @var bool|callable|null
45
         */
46
        private $skipOnEmpty = null,
47
        private bool $skipOnError = false,
48
        /**
49
         * @var Closure(mixed, ValidationContext):bool|null
50
         */
51
        private ?Closure $when = null,
52
    ) {
53 9
        if ($this->callback === null && $this->method === null) {
54
            throw new InvalidArgumentException('Either "$callback" or "$method" must be specified.');
55
        }
56
57 9
        if ($this->callback !== null && $this->method !== null) {
58
            throw new InvalidArgumentException('"$callback" and "$method" are mutually exclusive.');
59
        }
60
    }
61
62 1
    public function getName(): string
63
    {
64 1
        return 'callback';
65
    }
66
67 14
    public function getCallback(): ?callable
68
    {
69 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...
70
    }
71
72
    public function getMethod(): ?string
73
    {
74
        return $this->method;
75
    }
76
77 3
    public function afterInitAttribute(DataSetInterface $dataSet): void
78
    {
79 3
        if (!$dataSet instanceof ObjectDataSet) {
80
            return;
81
        }
82
83 3
        $object = $dataSet->getObject();
84 3
        $method = $this->method;
85
86 3
        $reflection = new ReflectionObject($object);
87
        try {
88 3
            $reflection->getMethod($method);
89 1
        } catch (ReflectionException) {
90 1
            throw new InvalidArgumentException(sprintf(
91
                'Method "%s" does not exist in class "%s".',
92
                $method,
93
                $object::class,
94
            ));
95
        }
96
97 2
        $this->callback = Closure::bind(fn (...$args) => $object->{$method}(...$args), $object, $object);
98
    }
99
100 2
    public function getOptions(): array
101
    {
102
        return [
103 2
            'skipOnEmpty' => $this->getSkipOnEmptyOption(),
104 2
            'skipOnError' => $this->skipOnError,
105
        ];
106
    }
107
108 14
    public function getHandlerClassName(): string
109
    {
110 14
        return CallbackHandler::class;
111
    }
112
}
113