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