ValidationService::validate()   A
last analyzed

Complexity

Conditions 5
Paths 8

Size

Total Lines 31
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 16
c 1
b 0
f 0
nc 8
nop 2
dl 0
loc 31
rs 9.4222
1
<?php
2
3
namespace Jidaikobo\Kontiki\Services;
4
5
use Illuminate\Database\Connection;
6
use Valitron\Validator;
7
use Jidaikobo\Kontiki\Core\Database;
8
use Jidaikobo\Kontiki\Models\ModelInterface;
9
10
class ValidationService
11
{
12
    private Connection $db;
13
    private Validator $validator;
14
    private ?ModelInterface $model = null;
15
16
    /**
17
     * ValidationService constructor.
18
     *
19
     * @param Validator $validator Instance of Valitron\Validator
20
     */
21
    public function __construct(
22
        Database $db,
23
        Validator $validator
24
    ) {
25
        $this->db = $db->getConnection();
26
        $this->validator = $validator;
27
        $this->validator->setPrependLabels(false);
28
        $this->registerCustomRules();
29
    }
30
31
    public function setModel(ModelInterface $model): void
32
    {
33
        $this->model = $model;
34
    }
35
36
    /**
37
     * Validate the given data based on field definitions.
38
     *
39
     * @param array $data The input data to validate.
40
     * @param array $context Additional validation context (e.g., ['id' => 123, 'role' => 'admin']).
41
     * @return array Validation result with 'valid' (bool) and 'errors' (array).
42
     */
43
    public function validate(
44
        array $data,
45
        array $context
46
    ): array {
47
        // set data/field to `valitron\validator`
48
        $validator = $this->validator->withData($data);
49
50
        // get fieldDefinitions from model
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',
53
            $data,
54
            $context['id'] ?? null,
55
        );
56
57
        // Validation
58
        foreach ($fields as $field => $definition) {
59
            $rules = $definition['rules'] ?? [];
60
            foreach ($rules as $rule) {
61
                if (is_array($rule)) {
62
                    $validator->rule($rule[0], $field, ...array_slice($rule, 1));
63
                } else {
64
                    $validator->rule($rule, $field);
65
                }
66
            }
67
        }
68
69
        $isValid = $validator->validate();
70
71
        return [
72
            'valid' => $isValid,
73
            'errors' => $isValid ? [] : $this->extractValidationErrors($validator)
74
        ];
75
    }
76
77
    /**
78
     * Additional validation logic (to be overridden by subclasses if needed).
79
     *
80
     * @param Validator $validator The validator instance.
81
     * @param array $data The input data to validate.
82
     * @param array $context Context for validation.
83
     * @return Validator Modified validator instance.
84
     */
85
    public function additionalvalidate(
86
        Validator $validator,
87
        array $data,
0 ignored issues
show
Unused Code introduced by
The parameter $data 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

87
        /** @scrutinizer ignore-unused */ array $data,

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...
88
        array $context
0 ignored issues
show
Unused Code introduced by
The parameter $context 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

88
        /** @scrutinizer ignore-unused */ array $context

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...
89
    ): Validator {
90
        return $validator;
91
    }
92
93
    /**
94
     * Registers custom validation rules for Valitron\Validator.
95
     *
96
     * Currently registers the 'unique' rule for database uniqueness checks.
97
     *
98
     * @return void
99
     */
100
    protected function registerCustomRules(): void
101
    {
102
        Validator::addRule(
103
            'unique',
104
            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

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