1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace VGirol\JsonApiStructure\Constraint; |
6
|
|
|
|
7
|
|
|
use VGirol\JsonApiStructure\Messages; |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* Constraint that checks if a name is a valid member name. |
11
|
|
|
*/ |
12
|
|
|
class MemberName extends Constraint |
13
|
|
|
{ |
14
|
|
|
/** |
15
|
|
|
* Undocumented variable |
16
|
|
|
* |
17
|
|
|
* @var bool |
18
|
|
|
*/ |
19
|
|
|
private $strict; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* Class constructor. |
23
|
|
|
* |
24
|
|
|
* @param boolean $strict If true, unsafe characters are not allowed when checking members name. |
25
|
|
|
*/ |
26
|
225 |
|
public function __construct(bool $strict) |
27
|
|
|
{ |
28
|
225 |
|
$this->strict = $strict; |
29
|
225 |
|
} |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* Returns a string representation of the constraint. |
33
|
|
|
*/ |
34
|
81 |
|
public function default(): string |
35
|
|
|
{ |
36
|
81 |
|
return Messages::MEMBER_NAME_NOT_VALID; |
37
|
|
|
} |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* Evaluates the constraint for parameter $json. Returns true if the constraint is met, false otherwise. |
41
|
|
|
* |
42
|
|
|
* Asserts that a member name is valid. |
43
|
|
|
* |
44
|
|
|
* It will do the following checks : |
45
|
|
|
* 1) asserts that the name is a string with at least one character. |
46
|
|
|
* 2) asserts that the name has only allowed characters. |
47
|
|
|
* 3) asserts that it starts and ends with a globally allowed character. |
48
|
|
|
* |
49
|
|
|
* @link https://jsonapi.org/format/#document-member-names-allowed-characters |
50
|
|
|
* |
51
|
|
|
* @param mixed $name Value or object to evaluate |
52
|
|
|
* |
53
|
|
|
* @return bool |
54
|
|
|
* @throws \VGirol\JsonApiStructure\Exception\ValidationException |
55
|
|
|
*/ |
56
|
225 |
|
public function handle($name): bool |
57
|
|
|
{ |
58
|
225 |
|
if (!\is_string($name)) { |
59
|
3 |
|
$this->setFailureMessage(Messages::MEMBER_NAME_MUST_BE_STRING); |
60
|
|
|
|
61
|
3 |
|
return false; |
62
|
|
|
} |
63
|
|
|
|
64
|
222 |
|
if (\strlen($name) < 1) { |
65
|
3 |
|
$this->setFailureMessage(Messages::MEMBER_NAME_IS_TOO_SHORT); |
66
|
|
|
|
67
|
3 |
|
return false; |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
// Globally allowed characters |
71
|
219 |
|
$globally = '\x{0030}-\x{0039}\x{0041}-\x{005A}\x{0061}-\x{007A}'; |
72
|
219 |
|
$globallyNotSafe = '\x{0080}-\x{FFFF}'; |
73
|
|
|
|
74
|
|
|
// Allowed characters |
75
|
219 |
|
$allowed = '\x{002D}\x{005F}'; |
76
|
219 |
|
$allowedNotSafe = '\x{0020}'; |
77
|
|
|
|
78
|
219 |
|
$regex = "/[^{$globally}{$globallyNotSafe}{$allowed}{$allowedNotSafe}]+/u"; |
79
|
219 |
|
$safeRegex = "/[^{$globally}{$allowed}]+/u"; |
80
|
|
|
|
81
|
219 |
|
if (\preg_match($this->strict ? $safeRegex : $regex, $name) > 0) { |
82
|
69 |
|
$this->setFailureMessage(Messages::MEMBER_NAME_MUST_NOT_HAVE_RESERVED_CHARACTERS); |
83
|
|
|
|
84
|
69 |
|
return false; |
85
|
|
|
} |
86
|
|
|
|
87
|
168 |
|
$regex = "/^[{$globally}{$globallyNotSafe}]{1}(?:.*[{$globally}{$globallyNotSafe}]{1})?$/u"; |
88
|
168 |
|
$safeRegex = "/^[{$globally}]{1}(?:.*[{$globally}]{1})?$/u"; |
89
|
168 |
|
if (\preg_match($this->strict ? $safeRegex : $regex, $name) == 0) { |
90
|
6 |
|
$this->setFailureMessage(Messages::MEMBER_NAME_MUST_START_AND_END_WITH_ALLOWED_CHARACTERS); |
91
|
|
|
|
92
|
6 |
|
return false; |
93
|
|
|
} |
94
|
|
|
|
95
|
162 |
|
return true; |
96
|
|
|
} |
97
|
|
|
} |
98
|
|
|
|