1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Fenos\Notifynder\Parsers; |
4
|
|
|
|
5
|
|
|
use Fenos\Notifynder\Exceptions\ExtraParamsException; |
6
|
|
|
use Fenos\Notifynder\Notifications\ExtraParams; |
7
|
|
|
|
8
|
|
|
/** |
9
|
|
|
* Class NotifynderParser. |
10
|
|
|
*/ |
11
|
|
|
class NotifynderParser |
12
|
|
|
{ |
13
|
|
|
/** |
14
|
|
|
* Regex to get values between curly bracket {$value}. |
15
|
|
|
*/ |
16
|
|
|
const RULE = '/\{(.+?)(?:\{(.+)\})?\}/'; |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* By default it's false. |
20
|
|
|
* |
21
|
|
|
* @var bool |
22
|
|
|
*/ |
23
|
|
|
protected static $strictMode = false; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* Parse the body of a notification |
27
|
|
|
* with your extras values or relation |
28
|
|
|
* values. |
29
|
|
|
* |
30
|
|
|
* @param $item |
31
|
|
|
* @return string |
32
|
|
|
* @throws \Fenos\Notifynder\Exceptions\ExtraParamsException |
33
|
|
|
*/ |
34
|
|
|
public function parse($item) |
35
|
|
|
{ |
36
|
|
|
$body = $item['body']['text']; |
37
|
|
|
|
38
|
|
|
$item['extra'] = $this->extraToArray($item['extra']); |
39
|
|
|
$specialValues = $this->getValues($body); |
40
|
|
|
|
41
|
|
|
if (count($specialValues) > 0) { |
42
|
|
|
$specialValues = array_filter($specialValues, function ($value) { |
43
|
|
|
return starts_with($value, 'extra.') || starts_with($value, 'to.') || starts_with($value, 'from.'); |
44
|
|
|
}); |
45
|
|
|
|
46
|
|
|
foreach ($specialValues as $replacer) { |
47
|
|
|
$replace = $this->mixedGet($item, $replacer); |
48
|
|
|
if (empty($replace) && static::$strictMode) { |
49
|
|
|
$error = "the following [$replacer] param required from your category it's missing. Did you forget to store it?"; |
50
|
|
|
throw new ExtraParamsException($error); |
51
|
|
|
} |
52
|
|
|
$body = $this->replaceBody($body, $replace, $replacer); |
53
|
|
|
} |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
return $body; |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* Set strict mode. |
61
|
|
|
* if it's enabled then will throws exceptions |
62
|
|
|
* when extra params will not be parsed correctly |
63
|
|
|
* will be handy in development. |
64
|
|
|
* |
65
|
|
|
* @param bool|true $set |
66
|
|
|
*/ |
67
|
|
|
public static function setStrictExtra($set = true) |
68
|
|
|
{ |
69
|
|
|
static::$strictMode = $set; |
|
|
|
|
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* Get the values between {} |
74
|
|
|
* and return an array of it. |
75
|
|
|
* |
76
|
|
|
* @param $body |
77
|
|
|
* @return mixed |
78
|
|
|
*/ |
79
|
|
|
protected function getValues($body) |
80
|
|
|
{ |
81
|
|
|
$values = []; |
82
|
|
|
preg_match_all(self::RULE, $body, $values); |
83
|
|
|
|
84
|
|
|
return $values[1]; |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* Trying to transform extra in from few data types |
89
|
|
|
* to array type. |
90
|
|
|
* |
91
|
|
|
* @param $extra |
92
|
|
|
* @return array|mixed |
93
|
|
|
*/ |
94
|
|
|
protected function extraToArray($extra) |
95
|
|
|
{ |
96
|
|
|
if ($this->isJson($extra)) { |
97
|
|
|
$extra = json_decode($extra, true); |
98
|
|
|
|
99
|
|
|
return $extra; |
100
|
|
|
} elseif ($extra instanceof ExtraParams) { |
101
|
|
|
$extra = $extra->toArray(); |
102
|
|
|
|
103
|
|
|
return $extra; |
104
|
|
|
} |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* Replace body of the category. |
109
|
|
|
* |
110
|
|
|
* @param $body |
111
|
|
|
* @param $replacer |
112
|
|
|
* @param $valueMatch |
113
|
|
|
* @return mixed |
114
|
|
|
*/ |
115
|
|
|
protected function replaceBody($body, $valueMatch, $replacer) |
116
|
|
|
{ |
117
|
|
|
$body = str_replace('{'.$replacer.'}', $valueMatch, $body); |
118
|
|
|
|
119
|
|
|
return $body; |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* Check if is a json string. |
124
|
|
|
* |
125
|
|
|
* @param $value |
126
|
|
|
* @return bool |
127
|
|
|
*/ |
128
|
|
View Code Duplication |
protected function isJson($value) |
|
|
|
|
129
|
|
|
{ |
130
|
|
|
if (! is_string($value)) { |
131
|
|
|
return false; |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
json_decode($value); |
135
|
|
|
|
136
|
|
|
return json_last_error() == JSON_ERROR_NONE; |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* Get a value by dot-key of an array, object or mix of both. |
141
|
|
|
* |
142
|
|
|
* @param array|object $object |
143
|
|
|
* @param string $key |
144
|
|
|
* @param null $default |
145
|
|
|
* @return mixed |
146
|
|
|
*/ |
147
|
|
|
protected function mixedGet($object, $key, $default = null) |
148
|
|
|
{ |
149
|
|
|
if (is_null($key) || trim($key) == '') { |
150
|
|
|
return ''; |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
foreach (explode('.', $key) as $segment) { |
154
|
|
|
if (is_object($object) && isset($object->{$segment})) { |
155
|
|
|
$object = $object->{$segment}; |
156
|
|
|
} elseif (is_object($object) && method_exists($object, '__get') && ! is_null($object->__get($segment))) { |
157
|
|
|
$object = $object->__get($segment); |
158
|
|
|
} elseif (is_object($object) && method_exists($object, 'getAttribute') && ! is_null($object->getAttribute($segment))) { |
159
|
|
|
$object = $object->getAttribute($segment); |
160
|
|
|
} elseif (is_array($object) && array_key_exists($segment, $object)) { |
161
|
|
|
$object = array_get($object, $segment, $default); |
162
|
|
|
} else { |
163
|
|
|
return value($default); |
164
|
|
|
} |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
return $object; |
168
|
|
|
} |
169
|
|
|
} |
170
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.