• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

diego-ninja / granite / 16608963009

29 Jul 2025 10:37PM UTC coverage: 50.423%. First build
16608963009

Pull #5

github

web-flow
Merge 43d8840d7 into 6a6caca51
Pull Request #5: code: adds phpstan level max, pint with per and github actions

321 of 632 new or added lines in 77 files covered. (50.79%)

1132 of 2245 relevant lines covered (50.42%)

9.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

59.52
/src/Validation/GraniteValidator.php
1
<?php
2

3
namespace Ninja\Granite\Validation;
4

5
use InvalidArgumentException;
6
use Ninja\Granite\Exceptions\ValidationException;
7

8
final class GraniteValidator
9
{
10
    /**
11
     * Collections of validation rules.
12
     *
13
     * @var RuleCollection[]
14
     */
15
    private array $collections = [];
16

17
    /**
18
     * Constructor.
19
     *
20
     * @param RuleCollection|RuleCollection[] $collections Rule collections (optional)
21
     */
22
    public function __construct(RuleCollection|array $collections = [])
23✔
23
    {
24
        if ($collections instanceof RuleCollection) {
23✔
25
            $this->collections[$collections->getProperty()] = $collections;
1✔
26
        } elseif (is_array($collections)) {
22✔
27
            foreach ($collections as $collection) {
22✔
28
                $this->collections[$collection->getProperty()] = $collection;
1✔
29
            }
30
        }
31
    }
32

33
    /**
34
     * Create a validator from an array of rule definitions.
35
     * Supports both array format and string format rules.
36
     *
37
     * @param array $rulesArray Array of rule definitions
38
     * @return self New validator instance
39
     */
40
    public static function fromArray(array $rulesArray): self
5✔
41
    {
42
        $validator = new self();
5✔
43

44
        foreach ($rulesArray as $property => $propertyRules) {
5✔
45
            $collection = new RuleCollection($property);
4✔
46

47
            // Handle string format rules (e.g. 'required|string|min:3')
48
            if (is_string($propertyRules)) {
4✔
49
                $rules = RuleParser::parse($propertyRules);
4✔
50
                foreach ($rules as $rule) {
4✔
51
                    $collection->add($rule);
4✔
52
                }
53
            }
54
            // Handle array format rules
55
            elseif (is_array($propertyRules)) {
1✔
56
                foreach ($propertyRules as $ruleDefinition) {
1✔
57
                    // Support for string format within arrays (e.g. ['required|string', ...])
58
                    if (is_string($ruleDefinition)) {
1✔
59
                        $rules = RuleParser::parse($ruleDefinition);
1✔
60
                        foreach ($rules as $rule) {
1✔
61
                            $collection->add($rule);
1✔
62
                        }
63
                    }
64
                    // Support for traditional array format
NEW
65
                    elseif (is_array($ruleDefinition)) {
×
NEW
66
                        $rule = self::createRuleFromDefinition($ruleDefinition);
×
NEW
67
                        if (null !== $rule) {
×
NEW
68
                            $collection->add($rule);
×
69
                        }
NEW
70
                    } elseif ($ruleDefinition instanceof ValidationRule) {
×
NEW
71
                        $collection->add($ruleDefinition);
×
72
                    } else {
NEW
73
                        throw new InvalidArgumentException("Invalid rule definition for property '{$property}'");
×
74
                    }
75
                }
76
            }
77

78
            if ( ! empty($collection->getRules())) {
4✔
79
                $validator->addRules($collection);
4✔
80
            }
81
        }
82

83
        return $validator;
5✔
84
    }
85

86
    /**
87
     * Add a rule collection to the validator.
88
     *
89
     * @param RuleCollection $collection The rule collection
90
     * @return $this For method chaining
91
     */
92
    public function addRules(RuleCollection $collection): self
5✔
93
    {
94
        $this->collections[$collection->getProperty()] = $collection;
5✔
95
        return $this;
5✔
96
    }
97

98
    /**
99
     * Add a single rule for a property.
100
     *
101
     * @param string $property The property name
102
     * @param ValidationRule $rule The validation rule
103
     * @return $this For method chaining
104
     */
105
    public function addRule(string $property, ValidationRule $rule): self
12✔
106
    {
107
        if ( ! isset($this->collections[$property])) {
12✔
108
            $this->collections[$property] = new RuleCollection($property);
12✔
109
        }
110

111
        $this->collections[$property]->add($rule);
12✔
112
        return $this;
12✔
113
    }
114

115
    /**
116
     * Create a rule collection for a property.
117
     *
118
     * @param string $property The property name
119
     * @return RuleCollection New rule collection
120
     */
121
    public function forProperty(string $property): RuleCollection
3✔
122
    {
123
        if ( ! isset($this->collections[$property])) {
3✔
124
            $this->collections[$property] = new RuleCollection($property);
3✔
125
        }
126

127
        return $this->collections[$property];
3✔
128
    }
129

130
    /**
131
     * Validate data against all rule collections.
132
     *
133
     * @param array $data Data to validate
134
     * @param string $objectName Object name for error messages
135
     * @throws ValidationException If validation fails
136
     */
137
    public function validate(array $data, string $objectName = 'Object'): void
12✔
138
    {
139
        $errors = [];
12✔
140

141
        foreach ($this->collections as $property => $collection) {
12✔
142
            // Check if property exists in data
143
            if ( ! array_key_exists($property, $data)) {
11✔
144
                // Look for required rule
145
                foreach ($collection->getRules() as $rule) {
2✔
146
                    if ($rule instanceof Rules\Required) {
2✔
147
                        $errors[$property][] = $rule->message($property);
1✔
148
                        break;
1✔
149
                    }
150
                }
151
                continue;
2✔
152
            }
153

154
            $value = $data[$property];
9✔
155
            $propertyErrors = $collection->validate($value, $data);
9✔
156

157
            if ( ! empty($propertyErrors)) {
9✔
158
                $errors[$property] = $propertyErrors;
3✔
159
            }
160
        }
161

162
        // Throw exception with validation errors if any
163
        if ( ! empty($errors)) {
12✔
164
            throw new ValidationException($objectName, $errors);
4✔
165
        }
166
    }
167
    /**
168
     * Create a rule instance from a rule definition array.
169
     *
170
     * @param array $definition Rule definition
171
     * @return ValidationRule|null Rule instance or null if invalid
172
     */
173
    private static function createRuleFromDefinition(array $definition): ?ValidationRule
×
174
    {
175
        $type = $definition['type'] ?? '';
×
176
        $message = $definition['message'] ?? null;
×
177

178
        $rule = match ($type) {
×
179
            'required' => new Rules\Required(),
×
180
            'string' => new Rules\StringType(),
×
181
            'int', 'integer' => new Rules\IntegerType(),
×
182
            'float', 'number' => new Rules\NumberType(),
×
183
            'bool', 'boolean' => new Rules\BooleanType(),
×
184
            'array' => new Rules\ArrayType(),
×
NEW
185
            'min' => isset($definition['value']) && is_numeric($definition['value']) ? new Rules\Min((float) $definition['value']) : null,
×
NEW
186
            'max' => isset($definition['value']) && is_numeric($definition['value']) ? new Rules\Max((float) $definition['value']) : null,
×
NEW
187
            'in' => isset($definition['values']) && is_array($definition['values']) ? new Rules\In($definition['values']) : null,
×
NEW
188
            'regex' => isset($definition['pattern']) && is_string($definition['pattern']) ? new Rules\Regex($definition['pattern']) : null,
×
189
            'email' => new Rules\Email(),
×
190
            'url' => new Rules\Url(),
×
191
            'ip' => new Rules\IpAddress(),
×
NEW
192
            'callback' => isset($definition['callback']) && is_callable($definition['callback']) ? new Rules\Callback($definition['callback']) : null,
×
NEW
193
            'when' => isset($definition['condition']) && isset($definition['rule']) && is_callable($definition['condition']) && $definition['rule'] instanceof ValidationRule
×
194
                ? new Rules\When($definition['condition'], $definition['rule']) : null,
×
NEW
195
            'each' => isset($definition['rules']) && ($definition['rules'] instanceof ValidationRule)
×
196
                ? new Rules\Each($definition['rules']) : null,
×
197
            default => null,
×
198
        };
×
199

NEW
200
        if (null !== $rule && null !== $message && is_string($message)) {
×
201
            $rule->withMessage($message);
×
202
        }
203

204
        return $rule;
×
205
    }
206
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc