1 | <?php |
||||
2 | /** |
||||
3 | * Created by PhpStorm. |
||||
4 | * User: fomvasss |
||||
5 | * Date: 26.10.18 |
||||
6 | * Time: 03:21 |
||||
7 | */ |
||||
8 | |||||
9 | namespace Fomvasss\LaravelStrTokens; |
||||
10 | |||||
11 | use Carbon\Carbon; |
||||
12 | use Illuminate\Database\Eloquent\Collection; |
||||
0 ignored issues
–
show
|
|||||
13 | use Illuminate\Database\Eloquent\Model; |
||||
0 ignored issues
–
show
The type
Illuminate\Database\Eloquent\Model was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||||
14 | use Illuminate\Support\Str; |
||||
15 | |||||
16 | class StrTokenGenerator |
||||
17 | { |
||||
18 | /** @var \Illuminate\Foundation\Application The Laravel application instance. */ |
||||
0 ignored issues
–
show
The type
Illuminate\Foundation\Application was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||||
19 | protected $app; |
||||
20 | |||||
21 | /** @var mixed The Laravel application configs. */ |
||||
22 | protected $config; |
||||
23 | |||||
24 | /** @var string */ |
||||
25 | protected $text = ''; |
||||
26 | |||||
27 | /** @var null */ |
||||
28 | protected $date = null; |
||||
29 | |||||
30 | /** @var null */ |
||||
31 | protected $entity = null; |
||||
32 | |||||
33 | /** @var array */ |
||||
34 | protected $entities = []; |
||||
35 | |||||
36 | /** @var array */ |
||||
37 | protected $vars = []; |
||||
38 | |||||
39 | /** @var bool */ |
||||
40 | protected $clearEmptyTokens = true; |
||||
41 | |||||
42 | /** |
||||
43 | * StrTokenGenerator constructor. |
||||
44 | */ |
||||
45 | public function __construct($app = null) |
||||
46 | { |
||||
47 | if (!$app) { |
||||
48 | $app = app(); //Fallback when $app is not given |
||||
0 ignored issues
–
show
The function
app was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
49 | } |
||||
50 | $this->app = $app; |
||||
51 | |||||
52 | $this->config = $this->app['config']; |
||||
53 | } |
||||
54 | |||||
55 | /** |
||||
56 | * @param string $text |
||||
57 | * @return StrTokenGenerator |
||||
58 | */ |
||||
59 | public function setText(string $text = ''): self |
||||
60 | { |
||||
61 | $this->text = $text; |
||||
62 | |||||
63 | return $this; |
||||
64 | } |
||||
65 | |||||
66 | /** |
||||
67 | * @param Carbon $date |
||||
68 | * @return StrTokenGenerator |
||||
69 | */ |
||||
70 | public function setDate(Carbon $date): self |
||||
71 | { |
||||
72 | $this->date = $date; |
||||
0 ignored issues
–
show
It seems like
$date of type Carbon\Carbon is incompatible with the declared type null of property $date .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||||
73 | |||||
74 | return $this; |
||||
75 | } |
||||
76 | |||||
77 | /** |
||||
78 | * @param Model $entity |
||||
79 | * @return StrTokenGenerator |
||||
80 | */ |
||||
81 | public function setEntity(Model $entity): self |
||||
82 | { |
||||
83 | $this->entity = $entity; |
||||
0 ignored issues
–
show
It seems like
$entity of type Illuminate\Database\Eloquent\Model is incompatible with the declared type null of property $entity .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||||
84 | |||||
85 | return $this; |
||||
86 | } |
||||
87 | |||||
88 | /** |
||||
89 | * @param array $entities|Illuminate\Database\Eloquent\Model |
||||
90 | * @return \Fomvasss\LaravelStrTokens\StrTokenGenerator |
||||
91 | * @throws \Exception |
||||
92 | */ |
||||
93 | public function setEntities(array $entities): self |
||||
94 | { |
||||
95 | foreach ($entities as $key => $entity) { |
||||
96 | $this->ensureValidEntity($entity); |
||||
97 | } |
||||
98 | |||||
99 | $this->entities = $entities; |
||||
100 | |||||
101 | return $this; |
||||
102 | } |
||||
103 | |||||
104 | /** |
||||
105 | * @param array $vars |
||||
106 | * @return $this |
||||
107 | */ |
||||
108 | public function setVars(array $vars): self |
||||
109 | { |
||||
110 | $this->vars = $vars; |
||||
111 | |||||
112 | return $this; |
||||
113 | } |
||||
114 | |||||
115 | /** |
||||
116 | * @param string $key |
||||
117 | * @param $value |
||||
118 | * @return $this |
||||
119 | */ |
||||
120 | public function setVar(string $key, $value): self |
||||
121 | { |
||||
122 | $this->vars[$key] = $value; |
||||
123 | |||||
124 | return $this; |
||||
125 | } |
||||
126 | |||||
127 | /** |
||||
128 | * @return StrTokenGenerator |
||||
129 | */ |
||||
130 | public function doNotClearEmptyTokens(): self |
||||
131 | { |
||||
132 | $this->clearEmptyTokens = false; |
||||
133 | |||||
134 | return $this; |
||||
135 | } |
||||
136 | |||||
137 | /** |
||||
138 | * @return StrTokenGenerator |
||||
139 | */ |
||||
140 | public function clearEmptyTokens(): self |
||||
141 | { |
||||
142 | $this->clearEmptyTokens = true; |
||||
143 | |||||
144 | return $this; |
||||
145 | } |
||||
146 | |||||
147 | /** |
||||
148 | * @return string |
||||
149 | */ |
||||
150 | public function replace(): string |
||||
151 | { |
||||
152 | $groupTokens = $this->tokenScan($this->text); |
||||
153 | $replacements = []; |
||||
154 | |||||
155 | foreach ($groupTokens as $key => $attributes) { |
||||
156 | |||||
157 | if ($key === 'date') { |
||||
158 | $replacements += $this->dateTokens($attributes); |
||||
159 | |||||
160 | } elseif ($key === 'config') { |
||||
161 | $replacements += $this->configTokens($attributes); |
||||
162 | |||||
163 | } elseif ($key === 'var') { |
||||
164 | $replacements += $this->varTokens($attributes); |
||||
165 | |||||
166 | } elseif ($this->entity && strtolower($key) === Str::snake(class_basename($this->entity))) { |
||||
167 | $replacements += $this->eloquentModelTokens($this->entity, $attributes, $key); |
||||
168 | |||||
169 | // For related taxonomy: https://github.com/fomvasss/laravel-taxonomy |
||||
170 | // and you set preffix in your relation methods - "tx" |
||||
171 | } elseif ($this->entity && substr($key, 0, 2) === 'tx') { |
||||
172 | $replacements += $this->eloquentModelTokens($this->entity, $attributes, $key); |
||||
173 | |||||
174 | } elseif (in_array($key, array_keys($this->entities))) { |
||||
175 | $eloquentModel = $this->entities[$key]; |
||||
176 | $replacements += $this->eloquentModelTokens($eloquentModel, $attributes, $key); |
||||
177 | } |
||||
178 | |||||
179 | if ($this->clearEmptyTokens) { |
||||
180 | $replacements += array_fill_keys($attributes, ''); |
||||
181 | } |
||||
182 | } |
||||
183 | |||||
184 | $attributes = array_keys($replacements); |
||||
185 | $values = array_values($replacements); |
||||
186 | |||||
187 | return str_replace($attributes, $values, $this->text); |
||||
188 | } |
||||
189 | |||||
190 | /** |
||||
191 | * Token scan with CMS Drupal :) |
||||
192 | * https://api.drupal.org/api/drupal/includes%21token.inc/function/token_scan/7.x |
||||
193 | * preg_match_all('/\[([^\]:]*):([^\]]*)\]/', $tokenStr, $matches); |
||||
194 | * |
||||
195 | * @param $text |
||||
196 | * @return array |
||||
197 | */ |
||||
198 | private function tokenScan(string $text): array |
||||
199 | { |
||||
200 | |||||
201 | // Matches tokens with the following pattern: [$type:$name] |
||||
202 | // $type and $name may not contain [ ] characters. |
||||
203 | // $type may not contain : or whitespace characters, but $name may. |
||||
204 | preg_match_all('/ |
||||
205 | \\[ # [ - pattern start |
||||
206 | ([^\\s\\[\\]:]*) # match $type not containing whitespace : [ or ] |
||||
207 | : # : - separator |
||||
208 | ([^\\[\\]]*) # match $name not containing [ or ] |
||||
209 | \\] # ] - pattern end |
||||
210 | /x', $text, $matches); |
||||
211 | $types = $matches[1]; |
||||
212 | $tokens = $matches[2]; |
||||
213 | |||||
214 | // Iterate through the matches, building an associative array containing |
||||
215 | // $tokens grouped by $types, pointing to the version of the token found in |
||||
216 | // the source text. For example, $results['node']['title'] = '[node:title]'; |
||||
217 | $results = []; |
||||
218 | for ($i = 0; $i < count($tokens); $i++) { |
||||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||||
219 | $results[$types[$i]][$tokens[$i]] = $matches[0][$i]; |
||||
220 | } |
||||
221 | |||||
222 | return $results; |
||||
223 | } |
||||
224 | |||||
225 | /** |
||||
226 | * @param array $tokens |
||||
227 | * @param string $type |
||||
228 | * @return array |
||||
229 | */ |
||||
230 | protected function eloquentModelTokens(Model $eloquentModel, array $tokens, string $type): array |
||||
231 | { |
||||
232 | $replacements = []; |
||||
233 | |||||
234 | foreach ($tokens as $key => $original) { |
||||
235 | $function = explode(':', $key)[0]; |
||||
236 | $strTokenMethod = Str::camel('str_token_'.$function); |
||||
237 | |||||
238 | // Exists token generate method (defined user) |
||||
239 | if (method_exists($eloquentModel, $strTokenMethod)) { |
||||
240 | |||||
241 | $replacements[$original] = $eloquentModel->{$strTokenMethod}($eloquentModel, ...explode(':', $key)); |
||||
242 | |||||
243 | // Exists relation function (defined user) |
||||
244 | } elseif (method_exists($eloquentModel, $function)) { |
||||
245 | |||||
246 | $newOriginal = str_replace("$type:", '', $original); |
||||
247 | |||||
248 | if ($eloquentModel->{$function} instanceof Model) { |
||||
249 | $tm = new static(); |
||||
250 | |||||
251 | $replacements[$original] = $tm->setText($newOriginal)->setEntity($eloquentModel->{$function})->replace(); |
||||
252 | } elseif ($eloquentModel->{$function} instanceof Collection && ($firstRelatedEntity = $eloquentModel->{$function}->first())) { |
||||
253 | $tm = new static(); |
||||
254 | |||||
255 | $replacements[$original] = $tm->setText($newOriginal)->setEntity($firstRelatedEntity)->replace(); |
||||
256 | } |
||||
257 | // Is field model |
||||
258 | } else { |
||||
259 | // TODO: make and check available model fields |
||||
260 | $replacements[$original] = $eloquentModel->{$key}; |
||||
261 | } |
||||
262 | } |
||||
263 | |||||
264 | return $replacements; |
||||
265 | } |
||||
266 | |||||
267 | /** |
||||
268 | * @param array $tokens |
||||
269 | * @return array |
||||
270 | */ |
||||
271 | protected function configTokens(array $tokens): array |
||||
272 | { |
||||
273 | $replacements = []; |
||||
274 | |||||
275 | $disable = $this->config->get('str-tokens.disable_configs', []); |
||||
276 | |||||
277 | foreach ($tokens as $name => $original) { |
||||
278 | if (! Str::is($disable, $name)) { |
||||
279 | $res = $this->config->get($name, ''); |
||||
280 | $replacements[$original] = is_string($res) ? $res : ''; |
||||
281 | } |
||||
282 | } |
||||
283 | |||||
284 | return $replacements; |
||||
285 | } |
||||
286 | |||||
287 | /** |
||||
288 | * @param array $tokens |
||||
289 | * @return array |
||||
290 | */ |
||||
291 | protected function varTokens(array $tokens): array |
||||
292 | { |
||||
293 | $replacements = []; |
||||
294 | |||||
295 | foreach ($tokens as $name => $original) { |
||||
296 | $res = $this->vars[$name] ?? ''; |
||||
297 | $replacements[$original] = is_string($res) ? $res : ''; |
||||
298 | } |
||||
299 | |||||
300 | return $replacements; |
||||
301 | } |
||||
302 | |||||
303 | /** |
||||
304 | * @param $tokens |
||||
305 | * @return array |
||||
306 | */ |
||||
307 | protected function dateTokens(array $tokens):array |
||||
308 | { |
||||
309 | $this->date = $this->date ?: Carbon::now(); |
||||
0 ignored issues
–
show
It seems like
$this->date ?: Carbon\Carbon::now() can also be of type Carbon\Carbon . However, the property $date is declared as type null . Maybe add an additional type check?
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 Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||||
310 | $replacements = []; |
||||
311 | |||||
312 | foreach ($tokens as $name => $original) { |
||||
313 | if ($name === 'raw') { |
||||
314 | $replacements[$original] = $this->date; |
||||
315 | } else { |
||||
316 | $format = $this->config->get('str-tokens.date.formats.'.$name, 'D, m/d/Y - H:i'); |
||||
317 | $replacements[$original] = $this->date->format($format); |
||||
318 | } |
||||
319 | } |
||||
320 | |||||
321 | return $replacements; |
||||
322 | } |
||||
323 | |||||
324 | /** |
||||
325 | * @param $entity |
||||
326 | * @throws \Exception |
||||
327 | */ |
||||
328 | protected function ensureValidEntity($entity) |
||||
329 | { |
||||
330 | if (! $entity instanceof Model) { |
||||
331 | throw new \Exception("StrToken Entity must by instance of '" . Model::class . "'. Current instance of '" . gettype($entity) . "'"); |
||||
332 | } |
||||
333 | } |
||||
334 | } |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths