Passed
Push — main ( ce87af...9fb0de )
by Nobufumi
02:38
created

BaseValidator::extractValidationErrors()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 1
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Jidaikobo\Kontiki\Validation;
4
5
use Illuminate\Database\Connection;
6
use Valitron\Validator;
7
8
use Jidaikobo\Kontiki\Core\Database;
9
use Jidaikobo\Kontiki\Models\ModelInterface;
10
11
class BaseValidator implements ValidatorInterface
12
{
13
    protected Connection $db;
14
    protected Validator $validator;
15
    private ?ModelInterface $model = null;
16
17
    /**
18
     * ValidationService constructor.
19
     *
20
     * @param Database $db Instance of Illuminate\Database\Connection
21
     * @param Validator $validator Instance of Valitron\Validator
22
     */
23
    public function __construct(
24
        Database $db,
25
        Validator $validator
26
    )
27
    {
28
        $this->db = $db->getConnection();
29
        $this->validator = $validator;
30
        $this->validator->setPrependLabels(false);
31
        $this->registerCustomRules();
32
    }
33
34
    public function setModel(ModelInterface $model): void
35
    {
36
        $this->model = $model;
37
    }
38
39
    /**
40
     * Validate the given data based on field definitions.
41
     *
42
     * @param array $data The input data to validate.
43
     * @param array $context Additional validation context (e.g., ['id' => 123, 'role' => 'admin']).
44
     * @return array Validation result with 'valid' (bool) and 'errors' (array).
45
     */
46
    public function validate(
47
        array $data,
48
        array $context = []
49
    ): array {
50
        $validator = $this->validator->withData($data);
51
        $fields = $this->model->getFields(
0 ignored issues
show
Bug introduced by
The method getFields() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

51
        /** @scrutinizer ignore-call */ 
52
        $fields = $this->model->getFields(

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
52
            $context['context'] ?? 'create',
0 ignored issues
show
Unused Code introduced by
The call to Jidaikobo\Kontiki\Models...lInterface::getFields() has too many arguments starting with $context['context'] ?? 'create'. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

52
        /** @scrutinizer ignore-call */ 
53
        $fields = $this->model->getFields(

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
53
            $data,
54
            $context['id'] ?? null,
55
        );
56
57
        foreach ($fields as $field => $definition) {
58
            $rules = $definition['rules'] ?? [];
59
            foreach ($rules as $rule) {
60
                if (is_array($rule)) {
61
                    $validator->rule($rule[0], $field, ...array_slice($rule, 1));
62
                } else {
63
                    $validator->rule($rule, $field);
64
                }
65
            }
66
        }
67
68
        $validator = $this->additionalvalidate($validator, $data, $context);
69
70
        $isValid = $validator->validate();
71
72
        return [
73
            'valid' => $isValid,
74
            'errors' => $isValid ? [] : $this->extractValidationErrors($validator)
75
        ];
76
    }
77
78
    /**
79
     * Additional validation logic (to be overridden by subclasses if needed).
80
     *
81
     * @param Validator $validator The validator instance.
82
     * @param array $data The input data to validate.
83
     * @param array $context Context for validation.
84
     * @return Validator Modified validator instance.
85
     */
86
    public function additionalvalidate(
87
        Validator $validator,
88
        array $data,
89
        array $context
90
    ): Validator {
91
        return $validator;
92
    }
93
94
    /**
95
     * Registers custom validation rules for Valitron\Validator.
96
     *
97
     * Currently registers the 'unique' rule for database uniqueness checks.
98
     *
99
     * @return void
100
     */
101
    protected function registerCustomRules(): void
102
    {
103
        Validator::addRule(
104
            'unique',
105
            function ($field, $value, array $params, array $fields) {
0 ignored issues
show
Unused Code introduced by
The parameter $fields is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

105
            function ($field, $value, array $params, /** @scrutinizer ignore-unused */ array $fields) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
106
                return $this->isUnique($params[0], $params[1], $value, $params[2] ?? null);
107
            },
108
            __('is_already_exists', 'is already exists')
109
        );
110
    }
111
112
    /**
113
     * Extract validation errors from the validator instance.
114
     *
115
     * @return array The extracted errors formatted for response.
116
     */
117
    private function extractValidationErrors($validator): array
118
    {
119
        $errors = [];
120
        foreach ($validator->errors() as $field => $messages) {
121
            $errors[$field] = [
122
                'messages' => $messages,
123
                'htmlName' => $field,
124
            ];
125
        }
126
        return $errors;
127
    }
128
129
    /**
130
     * Check if a value is unique.
131
     *
132
     * @param string $table The table name to check in.
133
     * @param string $column The column name to check.
134
     * @param mixed $value The value to check for uniqueness.
135
     * @param int|null $excludeId The ID of the record to exclude from the check.
136
     *
137
     * @return bool True if the value is unique, false otherwise.
138
     */
139
    private function isUnique(
140
        string $table,
141
        string $column,
142
        mixed $value,
143
        ?int $excludeId = null
144
    ): bool {
145
        $query = $this->db->table($table)
146
            ->where($column, '=', $value);
147
148
        // exclude condition
149
        if ($excludeId !== null) {
150
            $query->where('id', '!=', $excludeId);
151
        }
152
153
        // fetch count
154
        $count = $query->count();
155
156
        return $count === 0;
157
    }
158
}
159