1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Db data validation. |
4
|
|
|
* |
5
|
|
|
* @copyright Copyright (c) 2017 Starweb AB |
6
|
|
|
* @license BSD 3-Clause |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
namespace Starlit\DbDataValidation; |
10
|
|
|
|
11
|
|
|
use Starlit\Db\AbstractDbEntity; |
12
|
|
|
use Starlit\Validation\Validator; |
13
|
|
|
use Starlit\Validation\ValidatorTranslatorInterface; |
14
|
|
|
use Symfony\Component\Translation\TranslatorInterface as SymfonyTranslatorInterface; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* Data validator for database entities. |
18
|
|
|
*/ |
19
|
|
|
class DbEntityDataValidator |
20
|
|
|
{ |
21
|
|
|
/** |
22
|
|
|
* @var ValidatorTranslatorInterface|SymfonyTranslatorInterface|null |
23
|
|
|
*/ |
24
|
|
|
protected $translator; |
25
|
|
|
|
26
|
3 |
|
public function __construct($translator = null) |
27
|
|
|
{ |
28
|
3 |
|
$this->translator = $translator; |
29
|
3 |
|
} |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* Create a data validator for database entity. |
33
|
|
|
* |
34
|
|
|
* @param AbstractDbEntity $dbEntity |
35
|
|
|
* @return Validator |
36
|
|
|
*/ |
37
|
3 |
|
public function createValidator(AbstractDbEntity $dbEntity, ...$params): Validator |
38
|
|
|
{ |
39
|
3 |
|
$fieldsRuleProperties = $this->getDbEntityFieldsRuleProperties($dbEntity); |
40
|
3 |
|
$validator = new Validator($fieldsRuleProperties, $this->translator); |
41
|
|
|
|
42
|
3 |
|
if (($additionalFieldsRuleProperties = $this->getAdditionalFieldsRuleProperties($dbEntity, ...$params))) { |
|
|
|
|
43
|
|
|
$validator->addFieldsRuleProperties($additionalFieldsRuleProperties); |
44
|
|
|
} |
45
|
|
|
|
46
|
3 |
|
return $validator; |
47
|
|
|
} |
48
|
|
|
|
49
|
3 |
|
protected function getDbEntityFieldsRuleProperties(AbstractDbEntity $dbEntity): array |
50
|
|
|
{ |
51
|
3 |
|
$validRuleProperties = Validator::getValidRuleProperties(); |
52
|
3 |
|
$fieldsRuleProperties = []; |
53
|
3 |
|
foreach ($dbEntity->getDbProperties() as $propertyName => $attributes) { |
54
|
|
|
// Always validate if validate is not explicitly set to false |
55
|
3 |
|
if (!isset($attributes['validate']) || $attributes['validate'] === true) { |
56
|
3 |
|
$fieldsRuleProperties[$propertyName] = []; |
57
|
3 |
|
foreach ($validRuleProperties as $ruleName) { |
58
|
3 |
|
if (isset($attributes[$ruleName])) { |
59
|
3 |
|
$fieldsRuleProperties[$propertyName][$ruleName] = $attributes[$ruleName]; |
60
|
|
|
} |
61
|
|
|
} |
62
|
|
|
} |
63
|
|
|
} |
64
|
|
|
|
65
|
3 |
|
return $fieldsRuleProperties; |
66
|
|
|
} |
67
|
|
|
|
68
|
3 |
|
protected function getAdditionalFieldsRuleProperties(AbstractDbEntity $dbEntity): array |
|
|
|
|
69
|
|
|
{ |
70
|
3 |
|
return []; |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* Validate and (if no error messages) set database data. |
75
|
|
|
* |
76
|
|
|
* @param array $data The data (e.g. from a form post) to be validated and set |
77
|
|
|
* @return array An array with all (if any) of error messages |
78
|
|
|
*/ |
79
|
2 |
|
public function validateAndSet(AbstractDbEntity $dbEntity, array $data): array |
80
|
|
|
{ |
81
|
|
|
// Get extra arguments this method was called with and forward |
82
|
2 |
|
$extraArguments = array_slice(func_get_args(), 2); |
83
|
2 |
|
$validator = $this->createValidator($dbEntity, ...$extraArguments); |
84
|
|
|
|
85
|
2 |
|
$preProcessedData = $this->preProcessValidationDbData($dbEntity, $data, ...$extraArguments); |
|
|
|
|
86
|
2 |
|
$errorMessages = $validator->validate($preProcessedData); |
87
|
|
|
|
88
|
2 |
|
if (empty($errorMessages)) { |
89
|
1 |
|
$this->setValidatedDbData($dbEntity, $validator->getValidatedData()); |
90
|
|
|
} |
91
|
|
|
|
92
|
2 |
|
return $errorMessages; |
93
|
|
|
} |
94
|
|
|
|
95
|
2 |
|
protected function preProcessValidationDbData(AbstractDbEntity $dbEntity, array $data): array |
|
|
|
|
96
|
|
|
{ |
97
|
2 |
|
return $data; |
98
|
|
|
} |
99
|
|
|
|
100
|
1 |
|
protected function setValidatedDbData(AbstractDbEntity $dbEntity, array $validatedData) |
101
|
|
|
{ |
102
|
1 |
|
$propertyNames = $dbEntity->getDbProperties(); |
103
|
1 |
|
foreach ($validatedData as $propertyName => $value) { |
104
|
1 |
|
if (isset($propertyNames[$propertyName])) { |
105
|
|
|
// Call individual setters to enable easy data set overriding |
106
|
1 |
|
$methodName = 'set' . ucfirst($propertyName); |
107
|
1 |
|
$dbEntity->$methodName($validatedData[$propertyName]); |
108
|
|
|
} |
109
|
|
|
} |
110
|
1 |
|
} |
111
|
|
|
} |
112
|
|
|
|
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.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.