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

piko-framework / core / 23945056048

03 Apr 2026 11:43AM UTC coverage: 95.506% (-4.5%) from 100.0%
23945056048

push

github

ilhooq
Update .gitignore

85 of 89 relevant lines covered (95.51%)

1.8 hits per line

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

90.0
/src/ModelTrait.php
1
<?php
2

3
/**
4
 * This file is part of Piko - Web micro framework
5
 *
6
 * @copyright 2019-2022 Sylvain PHILIP
7
 * @license LGPL-3.0; see LICENSE.txt
8
 * @link https://github.com/piko-framework/core
9
 */
10

11
declare(strict_types=1);
12

13
namespace Piko;
14

15
use ReflectionClass;
16
use ReflectionProperty;
17

18
/**
19
 * Base model trait.
20
 *
21
 * @author Sylvain PHILIP <contact@sphilip.com>
22
 */
23
trait ModelTrait
24
{
25
    /**
26
     * Errors hash container
27
     *
28
     * @var array<string>
29
     */
30
    protected $errors = [];
31

32
    /**
33
     * Get the public properties reprenting the data model
34
     *
35
     * @return array<mixed>
36
     */
37
    protected function getAttributes(): array
38
    {
39
        $class = get_called_class();
2✔
40
        $reflection = new ReflectionClass($class);
2✔
41
        $properties = $reflection->getProperties(\ReflectionProperty::IS_PUBLIC);
2✔
42
        $attributes = [];
2✔
43

44
        foreach ($properties as $property) {
2✔
45
            /* @var $property \ReflectionProperty */
46
            if ($property->class === $class) {
2✔
47
                $attributes[$property->name] = $this->{$property->name} ?? null;
2✔
48
            }
49
        }
50

51
        return $attributes;
2✔
52
    }
53

54
    /**
55
     * Bind the data to the model attributes.
56
     *
57
     * @param array<mixed> $data An array of data (name-value pairs).
58
     * @return void
59
     */
60
    public function bind(array $data): void
61
    {
62
        $reflection = new ReflectionClass($this);
2✔
63

64
        foreach ($data as $key => $value) {
2✔
65

66
            if ($reflection->hasProperty($key)) {
2✔
67
                $property = $reflection->getProperty($key);
2✔
68

69
                if ($property->isPublic() && $property->class === $reflection->getName()) {
2✔
70
                    $this->{$key} = $this->castValueForProperty($property, $value);
2✔
71
                }
72
            }
73
        }
74
    }
75

76
    /**
77
     * Cast a bound value according to the declared property type.
78
     *
79
     * @param ReflectionProperty $property
80
     * @param mixed $value
81
     *
82
     * @return mixed
83
     */
84
    private function castValueForProperty(ReflectionProperty $property, $value)
85
    {
86
        if ($value === null) {
2✔
87
            return null;
1✔
88
        }
89

90
        $type = $property->getType();
2✔
91

92
        if ($type === null) {
2✔
93
            return $value;
1✔
94
        }
95

96
        $typeName = $type->getName();
1✔
97

98
        if ($type->allowsNull() && $value === '' && $typeName !== 'string') {
1✔
99
            return null;
×
100
        }
101

102
        return match ($typeName) {
1✔
103
            'int' => (int) $value,
1✔
104
            'float' => (float) $value,
1✔
105
            'bool' => $this->castBooleanValue($value),
1✔
106
            'string' =>  (string) $value,
×
107
            default => $value
1✔
108
        };
1✔
109
    }
110

111
    /**
112
     * Cast a value to a boolean using common form representations.
113
     *
114
     * @param mixed $value
115
     *
116
     * @return bool
117
     */
118
    private function castBooleanValue($value): bool
119
    {
120
        if (is_bool($value)) {
1✔
121
            return $value;
×
122
        }
123

124
        $filtered = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
1✔
125

126
        if ($filtered !== null) {
1✔
127
            return $filtered;
1✔
128
        }
129

130
        return (bool) $value;
×
131
    }
132

133
    /**
134
     * Get the model data as an associative array.
135
     *
136
     * @return array<mixed>
137
     */
138
    public function toArray(): array
139
    {
140
        return $this->getAttributes();
2✔
141
    }
142

143
    /**
144
     * Return the errors hash container
145
     *
146
     * @return array<string>
147
     */
148
    public function getErrors(): array
149
    {
150
        return $this->errors;
1✔
151
    }
152

153
    /**
154
     * Set an error that will be appended to the errors container
155
     *
156
     * @param string $errorName
157
     * @param string $errorMsg
158
     *
159
     * @see ModelTrait::$errors
160
     */
161
    protected function setError(string $errorName, string $errorMsg): void
162
    {
163
        $this->errors[$errorName] = $errorMsg;
1✔
164
    }
165

166
    /**
167
     * Validate this model (Should be extended).
168
     * Inherited method should fill the errors array using the setError method if the model is not valid.
169
     *
170
     * @see ModelTrait::setError()
171
     * @see ModelTrait::isValid()
172
     *
173
     * @codeCoverageIgnore
174
     *
175
     * @return void
176
     */
177
    protected function validate(): void
178
    {
179
    }
180

181
    /**
182
     * Check if the model is valid
183
     *
184
     * @return boolean
185
     */
186
    public function isValid(): bool
187
    {
188
        $this->validate();
1✔
189

190
        return empty($this->errors);
1✔
191
    }
192
}
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