• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

miaoxing / plugin / 10014906925

30 Jun 2024 02:37PM UTC coverage: 42.997% (-0.04%) from 43.032%
10014906925

push

github

semantic-release-bot
chore(release): publish

See CHANGELOG.md for more details.

1231 of 2863 relevant lines covered (43.0%)

7.61 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.01
/src/Service/Config.php
1
<?php
2

3
namespace Miaoxing\Plugin\Service;
4

5
use Miaoxing\Plugin\Model\ModelTrait;
6
use Wei\Base;
7

8
/**
9
 * @mixin \EnvMixin
10
 * @mixin \CacheMixin
11
 * @mixin \AppMixin
12
 * @mixin \PhpFileCacheMixin
13
 */
14
class Config extends \Wei\Config
15
{
16
    /**
17
     * @internal
18
     */
19
    protected const TYPE_STRING = 's';
20

21
    /**
22
     * @internal
23
     */
24
    protected const TYPE_BOOL = 'b';
25

26
    /**
27
     * @internal
28
     */
29
    protected const TYPE_INT = 'i';
30

31
    /**
32
     * @internal
33
     */
34
    protected const TYPE_FLOAT = 'f';
35

36
    /**
37
     * @internal
38
     */
39
    protected const TYPE_NULL = 'n';
40

41
    /**
42
     * @internal
43
     */
44
    protected const TYPE_ARRAY = 'a';
45

46
    /**
47
     * @internal
48
     */
49
    protected const TYPE_OBJECT = 'o';
50

51
    /**
52
     * @internal
53
     */
54
    protected const TYPE_JSON = 'j';
55

56
    /**
57
     * @internal
58
     */
59
    protected const TYPE_EXPRESS = 'e';
60

61
    /**
62
     * The local config file path
63
     *
64
     * @var string
65
     */
66
    protected $localFile = 'storage/configs/%env%.php';
67

68
    /**
69
     * Whether to check update on preload
70
     *
71
     * @var bool
72
     * @option
73
     */
74
    protected $checkPreload = false;
75

76
    /**
77
     * @var array
78
     */
79
    protected $services = [];
80

81
    /**
82
     * The missing config names of the last get action
83
     *
84
     * @var array<string>
85
     */
86
    protected $missing = [];
87

88
    /**
89
     * Native scalar type to config type
90
     *
91
     * @var string[]
92
     * @internal
93
     */
94
    protected $scalarTypes = [
95
        'boolean' => self::TYPE_BOOL,
96
        'integer' => self::TYPE_INT,
97
        'double' => self::TYPE_FLOAT,
98
        'string' => self::TYPE_STRING,
99
        'NULL' => self::TYPE_NULL,
100
        // ignore non-scalar types
101
    ];
102

103
    /**
104
     * @svc
105
     * @param mixed $default
106
     */
107
    protected function get(string $name, $default = null)
108
    {
109
        return $this->getMultiple([$name], [$name => $default])[$name];
14✔
110
    }
111

112
    /**
113
     * @svc
114
     * @param mixed $value
115
     */
116
    protected function set(string $name, $value, array $options = []): self
117
    {
118
        return $this->setApp($name, $value, $options);
4✔
119
    }
120

121
    /**
122
     * Get multiple configs
123
     *
124
     * @param array $names The names of config
125
     * @param array $defaults The values to return when config not found or is null
126
     * @return array
127
     * @svc
128
     */
129
    protected function getMultiple(array $names, array $defaults = []): array
130
    {
131
        $values = $this->getAppMultiple($names);
24✔
132
        $nulls = $this->getNullKeys($values);
24✔
133

134
        if ($nulls) {
24✔
135
            $globalValues = $this->getGlobalMultiple($nulls);
14✔
136
            $values = array_merge($values, $globalValues);
14✔
137
            $nulls = $this->getNullKeys($globalValues);
14✔
138
        }
139

140
        foreach ($nulls as $name) {
24✔
141
            // 注意: 配置名称不含 . 时,文件配置会返回所有下级数据
142
            // 行为和数据库存储配置不一致,但一般不影响使用
143
            $values[$name] = $this->wei->getConfig($name);
10✔
144
        }
145

146
        foreach ($names as $name) {
24✔
147
            $values[$name] = $values[$name] ?? $defaults[$name] ?? null;
22✔
148
        }
149

150
        return $values;
24✔
151
    }
152

153
    /**
154
     * @svc
155
     */
156
    protected function setMultiple(array $values, array $options = []): self
157
    {
158
        return $this->setAppMultiple($values, $options);
4✔
159
    }
160

161
    /**
162
     * @svc
163
     */
164
    protected function getSection(string $name): array
165
    {
166
        return array_merge(
10✔
167
            (array) $this->wei->getConfig($name),
10✔
168
            $this->getGlobalSection($name),
10✔
169
            $this->getAppSection($name)
10✔
170
        );
10✔
171
    }
172

173
    /**
174
     * @svc
175
     * @param mixed $default
176
     */
177
    protected function getGlobal(string $name, $default = null)
178
    {
179
        return $this->getMultipleBy(GlobalConfigModel::class, [$name], [$name => $default])[$name];
32✔
180
    }
181

182
    /**
183
     * @svc
184
     * @param mixed $value
185
     */
186
    protected function setGlobal(string $name, $value, array $options = []): self
187
    {
188
        return $this->setMultipleBy(GlobalConfigModel::class, [$name => $value], $options);
40✔
189
    }
190

191
    /**
192
     * @svc
193
     */
194
    protected function deleteGlobal(string $name): self
195
    {
196
        return $this->deleteBy(GlobalConfigModel::class, $name);
12✔
197
    }
198

199
    /**
200
     * @svc
201
     */
202
    protected function getGlobalMultiple(array $names, array $defaults = []): array
203
    {
204
        return $this->getMultipleBy(GlobalConfigModel::class, $names, $defaults);
18✔
205
    }
206

207
    /**
208
     * @svc
209
     */
210
    protected function setGlobalMultiple(array $values, array $options = []): self
211
    {
212
        return $this->setMultipleBy(GlobalConfigModel::class, $values, $options);
6✔
213
    }
214

215
    /**
216
     * @svc
217
     */
218
    protected function getGlobalSection(string $name): array
219
    {
220
        return $this->getSectionBy(GlobalConfigModel::class, $name);
12✔
221
    }
222

223
    /**
224
     * @svc
225
     * @param mixed $default
226
     */
227
    protected function getApp(string $name, $default = null)
228
    {
229
        return $this->getMultipleBy(ConfigModel::class, [$name], [$name => $default])[$name];
16✔
230
    }
231

232
    /**
233
     * @svc
234
     * @param mixed $value
235
     */
236
    protected function setApp(string $name, $value, array $options = []): self
237
    {
238
        return $this->setMultipleBy(ConfigModel::class, [$name => $value], $options);
20✔
239
    }
240

241
    /**
242
     * @svc
243
     */
244
    protected function deleteApp(string $name): self
245
    {
246
        return $this->deleteBy(ConfigModel::class, $name);
14✔
247
    }
248

249
    /**
250
     * @svc
251
     */
252
    protected function getAppMultiple(array $names, array $defaults = []): array
253
    {
254
        return $this->getMultipleBy(ConfigModel::class, $names, $defaults);
28✔
255
    }
256

257
    /**
258
     * @svc
259
     */
260
    protected function setAppMultiple(array $values, array $options = []): self
261
    {
262
        return $this->setMultipleBy(ConfigModel::class, $values, $options);
16✔
263
    }
264

265
    /**
266
     * @svc
267
     */
268
    protected function getAppSection(string $name): array
269
    {
270
        return $this->getSectionBy(ConfigModel::class, $name);
12✔
271
    }
272

273
    /**
274
     * @template T of Base
275
     * @phpstan-ignore-next-line [bleedingEdge]Template type T xxx is not referenced in a parameter. phpstan#5175
276
     * @param string|class-string<T> $name
277
     * @return Base|T
278
     * @svc
279
     */
280
    protected function createService(string $name): Base
281
    {
282
        $name = $this->wei->getServiceName($name);
4✔
283
        $options = $this->getSection($name);
4✔
284
        return $this->wei->newInstance($name, $options);
4✔
285
    }
286

287
    /**
288
     * @template T of Base
289
     * @phpstan-ignore-next-line [bleedingEdge]Template type T xxx is not referenced in a parameter. phpstan#5175
290
     * @param string|class-string<T> $name
291
     * @return Base|T
292
     * @svc
293
     */
294
    protected function getService(string $name): Base
295
    {
296
        $appId = $this->app->getId();
4✔
297
        $name = $this->wei->getServiceName($name);
4✔
298
        if (!isset($this->services[$appId][$name])) {
4✔
299
            $this->services[$appId][$name] = $this->createService($name);
2✔
300
        }
301
        return $this->services[$appId][$name];
4✔
302
    }
303

304
    /**
305
     * 预加载全局配置
306
     *
307
     * @experimental
308
     * @svc
309
     */
310
    protected function preloadGlobal()
311
    {
312
        // 1. 先获取本地配置
313
        $configs = $this->getPhpFileCache('global-config', []);
2✔
314

315
        // 2. 检查更新配置
316
        if ($this->checkPreload && $this->needsUpdatePreload($configs)) {
2✔
317
            $configs = $this->setPreloadCache();
×
318
        }
319

320
        // 3. 加载配置
321
        $this->wei->setConfig($configs);
2✔
322
    }
323

324
    /**
325
     * 如果本地全局配置过时,则更新配置
326
     *
327
     * @return bool
328
     * @experimental
329
     * @svc
330
     */
331
    protected function updatePreloadIfExpired(): bool
332
    {
333
        $realVersion = $this->getGlobal($this->getPreloadVersionKey());
×
334
        $localVersion = $this->wei->getConfig($this->getPreloadVersionKey());
×
335
        if (!$localVersion || $realVersion > $localVersion) {
×
336
            $this->setPreloadCache();
×
337
            return true;
×
338
        }
339
        return false;
×
340
    }
341

342
    /**
343
     * @return $this
344
     * @svc
345
     */
346
    protected function publishPreload(): self
347
    {
348
        $this->updatePreloadVersion();
2✔
349
        $configs = $this->setPreloadCache();
2✔
350
        $this->wei->setConfig($configs);
2✔
351
        return $this;
2✔
352
    }
353

354
    /**
355
     * Update config model value to cache
356
     *
357
     * @param ConfigModel|GlobalConfigModel $model
358
     * @return $this
359
     * @experimental
360
     * @svc
361
     */
362
    protected function updateCache($model): self
363
    {
364
        $prefix = $this->getPrefix(get_class($model));
×
365
        $this->cache->set($prefix . $model->name, $this->decode($model->value, $model->type));
×
366
        return $this;
×
367
    }
368

369
    /**
370
     * Remove config model value cache
371
     *
372
     * @param ConfigModel|GlobalConfigModel $model
373
     * @return $this
374
     * @experimental
375
     * @svc
376
     */
377
    protected function deleteCache($model): self
378
    {
379
        $this->cache->delete($this->getPrefix(get_class($model)) . $model->name);
×
380
        return $this;
×
381
    }
382

383
    /**
384
     * @return string
385
     * @internal
386
     */
387
    protected function updatePreloadVersion(): string
388
    {
389
        $version = date('Y-m-d H:i:s');
4✔
390
        $this->setGlobal($this->getPreloadVersionKey(), $version, ['preload' => true]);
4✔
391
        return $version;
4✔
392
    }
393

394
    /**
395
     * @param string|class-string<ModelTrait> $model
396
     * @param array $names
397
     * @param array $defaults
398
     * @return array
399
     */
400
    protected function getMultipleBy(string $model, array $names, array $defaults): array
401
    {
402
        $this->missing = [];
76✔
403
        $prefix = $this->getPrefix($model);
76✔
404

405
        // From cache
406
        [$values, $missing] = $this->getMultipleFromCache($prefix, $names);
76✔
407

408
        // From database
409
        if ($missing) {
76✔
410
            [$dbValues, $missing] = $this->getMultipleFromDb($model, $names);
68✔
411
            $values = array_merge($values, $dbValues);
68✔
412

413
            // Next time will fetch from cache
414
            $cacheValues = $dbValues;
68✔
415
            foreach ($missing as $name) {
68✔
416
                $cacheValues[$name] = null;
36✔
417
            }
418
            $this->cacheWithPrefix($prefix, function () use ($cacheValues) {
68✔
419
                $this->cache->setMultiple($cacheValues);
68✔
420
            });
68✔
421
        }
422
        $this->missing = $missing;
76✔
423

424
        // Add default value
425
        foreach ($values as $name => $value) {
76✔
426
            $values[$name] = $value ?? $defaults[$name] ?? null;
74✔
427
        }
428

429
        return $values;
76✔
430
    }
431

432
    /**
433
     * @param string $prefix
434
     * @param array $names
435
     * @return array
436
     * @internal
437
     */
438
    protected function getMultipleFromCache(string $prefix, array $names): array
439
    {
440
        // From cache
441
        if (1 === count($names)) {
76✔
442
            $key = current($names);
60✔
443
            $values = [$key => $this->cache->get($prefix . $key)];
60✔
444
        } else {
445
            $values = $this->cacheWithPrefix($prefix, function () use ($names) {
18✔
446
                return $this->cache->getMultiple($names);
18✔
447
            });
18✔
448
        }
449

450
        $missing = [];
76✔
451
        foreach ($values as $name => $value) {
76✔
452
            if (!$this->cache->isHit($prefix . $name)) {
74✔
453
                $missing[] = $name;
68✔
454
            }
455
        }
456

457
        return [$values, $missing];
76✔
458
    }
459

460
    /**
461
     * @param string|class-string<ModelTrait> $model
462
     * @param array $names
463
     * @return array
464
     * @internal
465
     */
466
    protected function getMultipleFromDb(string $model, array $names): array
467
    {
468
        $configs = $model::select(['name', 'type', 'value'])
66✔
469
            ->where('name', $names)
66✔
470
            ->fetchAll();
66✔
471

472
        $values = [];
66✔
473
        foreach ($configs as $config) {
66✔
474
            $values[$config['name']] = $this->decode($config['value'], $config['type']);
45✔
475
        }
476

477
        $missing = [];
66✔
478
        foreach ($names as $name) {
66✔
479
            if (!array_key_exists($name, $values)) {
66✔
480
                $missing[] = $name;
34✔
481
            }
482
        }
483

484
        return [$values, $missing];
66✔
485
    }
486

487
    /**
488
     * @param string|class-string<ModelTrait> $model
489
     * @param array $values
490
     * @param array $options
491
     * @return $this
492
     */
493
    protected function setMultipleBy(string $model, array $values, array $options = []): self
494
    {
495
        if (!$values) {
72✔
496
            return $this;
2✔
497
        }
498

499
        $configs = $model::where('name', array_keys($values))
70✔
500
            ->indexBy('name')
70✔
501
            ->all();
70✔
502

503
        foreach ($values as $name => $value) {
70✔
504
            if (!isset($configs[$name])) {
70✔
505
                $configs[$name] = $model::fromArray(['name' => $name]);
32✔
506
            }
507

508
            [$value, $type] = $this->encode($value);
70✔
509
            $configs[$name]->fromArray([
70✔
510
                'type' => $type,
70✔
511
                'value' => $value,
70✔
512
            ]);
70✔
513

514
            // For global config
515
            if (isset($options['preload'])) {
70✔
516
                $configs[$name]->preload = $options['preload'];
6✔
517
            }
518
        }
519

520
        $configs->save();
70✔
521

522
        $data = [];
70✔
523
        $prefix = $this->getPrefix($model);
70✔
524
        foreach ($values as $key => $value) {
70✔
525
            $data[$prefix . $key] = $value;
70✔
526
        }
527
        $this->cache->setMultiple($data);
70✔
528

529
        return $this;
70✔
530
    }
531

532
    /**
533
     * @param string|class-string<ModelTrait> $model
534
     * @param string $name
535
     * @return $this
536
     * @internal
537
     */
538
    protected function deleteBy(string $model, string $name): self
539
    {
540
        $this->cache->delete($this->getPrefix($model) . $name);
22✔
541

542
        $config = $model::findBy('name', $name);
22✔
543
        $config && $config->destroy();
22✔
544

545
        return $this;
22✔
546
    }
547

548
    /**
549
     * @param string|class-string<ModelTrait> $model
550
     * @param string $name
551
     * @return array
552
     */
553
    protected function getSectionBy(string $model, string $name): array
554
    {
555
        // From database
556
        $configs = $model::select(['name', 'type', 'value'])
14✔
557
            ->where('name', 'like', $name . '.%')
14✔
558
            ->fetchAll();
14✔
559

560
        $length = strlen($name) + 1;
14✔
561
        $values = [];
14✔
562
        foreach ($configs as $config) {
14✔
563
            $values[substr($config['name'], $length)] = $this->decode($config['value'], $config['type']);
14✔
564
        }
565

566
        return $values;
14✔
567
    }
568

569
    /**
570
     * @param string $model
571
     * @return string
572
     */
573
    protected function getPrefix(string $model): string
574
    {
575
        if (ConfigModel::class === $model) {
92✔
576
            return 'config:' . $this->app->getId() . ':';
54✔
577
        }
578
        return 'globalConfig:';
60✔
579
    }
580

581
    /**
582
     * @param string $prefix
583
     * @param callable $fn
584
     * @return mixed
585
     * @internal
586
     */
587
    protected function cacheWithPrefix(string $prefix, callable $fn)
588
    {
589
        $namespace = $this->cache->getNamespace();
70✔
590
        $this->cache->setNamespace($namespace . $prefix);
70✔
591
        $result = $fn();
70✔
592
        $this->cache->setNamespace($namespace);
70✔
593
        return $result;
70✔
594
    }
595

596
    /**
597
     * Convert PHP value to config value
598
     *
599
     * @param mixed $value
600
     * @return array
601
     * @internal
602
     */
603
    protected function encode($value): array
604
    {
605
        $type = gettype($value);
70✔
606
        if (isset($this->scalarTypes[$type])) {
70✔
607
            return [$value, $this->scalarTypes[$type]];
62✔
608
        }
609

610
        if ('array' === $type) {
8✔
611
            return [json_encode($value, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE), static::TYPE_ARRAY];
4✔
612
        }
613

614
        if ($value instanceof \stdClass) {
4✔
615
            return [json_encode($value, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE), static::TYPE_JSON];
2✔
616
        }
617

618
        return [serialize($value), static::TYPE_OBJECT];
2✔
619
    }
620

621
    /**
622
     * Convert config value to PHP value
623
     *
624
     * @param mixed $value
625
     * @param string $type
626
     * @return mixed
627
     * @internal
628
     */
629
    protected function decode($value, string $type)
630
    {
631
        switch ($type) {
632
            case static::TYPE_STRING:
61✔
633
                return (string) $value;
33✔
634

635
            case static::TYPE_INT:
33✔
636
                return (int) $value;
17✔
637

638
            case static::TYPE_FLOAT:
16✔
639
                return (float) $value;
2✔
640

641
            case static::TYPE_BOOL:
14✔
642
                return filter_var($value, \FILTER_VALIDATE_BOOLEAN);
4✔
643

644
            case static::TYPE_ARRAY:
10✔
645
                return (array) json_decode($value, true);
4✔
646

647
            case static::TYPE_JSON:
6✔
648
                return json_decode($value);
2✔
649

650
            case static::TYPE_OBJECT:
4✔
651
                return unserialize($value);
2✔
652

653
            case static::TYPE_NULL:
2✔
654
                return null;
2✔
655

656
            default:
657
                return $value;
×
658
        }
659
    }
660

661
    /**
662
     * 获取配置文件
663
     *
664
     * @return string
665
     */
666
    protected function getLocalFile(): string
667
    {
668
        return str_replace('%env%', $this->env->getName(), $this->localFile);
4✔
669
    }
670

671
    /**
672
     * 更新配置到本地文件中
673
     *
674
     * @param array $configs
675
     * @svc
676
     */
677
    protected function updateLocal(array $configs)
678
    {
679
        $file = $this->getLocalFile();
2✔
680
        if (is_file($file)) {
2✔
681
            $localConfigs = require $file;
2✔
682
        } else {
683
            $localConfigs = [];
2✔
684
        }
685

686
        foreach ($configs as $name => $value) {
2✔
687
            if (isset($localConfigs[$name])) {
2✔
688
                $localConfigs[$name] = array_merge($localConfigs[$name], $value);
2✔
689
            } else {
690
                $localConfigs[$name] = $value;
2✔
691
            }
692
        }
693

694
        $this->writeConfig($file, $localConfigs);
2✔
695
        $this->wei->setConfig($configs);
2✔
696
    }
697

698
    /**
699
     * @param string $file
700
     * @param mixed $configs
701
     */
702
    protected function writeConfig(string $file, $configs): void
703
    {
704
        $content = $this->generateContent($configs);
4✔
705
        file_put_contents($file, $content);
4✔
706
        function_exists('opcache_invalidate') && opcache_invalidate($file);
4✔
707
    }
708

709
    /**
710
     * 将数据库读出的对象生成文件内容
711
     *
712
     * @param array $configs
713
     * @return string
714
     */
715
    protected function generateContent($configs)
716
    {
717
        return "<?php\n\nreturn " . $this->varExport($configs) . ";\n";
4✔
718
    }
719

720
    /**
721
     * @param mixed $var
722
     * @param string $indent
723
     * @return string
724
     * @link https://stackoverflow.com/questions/24316347/how-to-format-var-export-to-php5-4-array-syntax
725
     */
726
    protected function varExport($var, $indent = '')
727
    {
728
        switch (gettype($var)) {
4✔
729
            case 'string':
4✔
730
                return '\'' . addcslashes($var, "\\\$\\'\r\n\t\v\f") . '\'';
4✔
731
            case 'array':
4✔
732
                $indexed = array_keys($var) === range(0, count($var) - 1);
4✔
733
                $result = [];
4✔
734
                foreach ($var as $key => $value) {
4✔
735
                    $result[] = $indent . '    '
4✔
736
                        . ($indexed ? '' : $this->varExport($key) . ' => ')
4✔
737
                        . $this->varExport($value, "$indent    ");
4✔
738
                }
739

740
                return "[\n" . implode(",\n", $result) . ($result ? ',' : '') . "\n" . $indent . ']';
4✔
741
            case 'boolean':
4✔
742
                return $var ? 'true' : 'false';
2✔
743

744
            case 'NULL':
4✔
745
                return 'null';
2✔
746

747
            case 'object':
4✔
748
                if (isset($var->express)) {
×
749
                    return $var->express;
×
750
                }
751
            // no break
752

753
            default:
754
                return var_export($var, true);
4✔
755
        }
756
    }
757

758
    /**
759
     * 判断本地的配置是否需要更改
760
     *
761
     * @param array $configs
762
     * @return bool
763
     * @internal
764
     */
765
    protected function needsUpdatePreload(array $configs): bool
766
    {
767
        $key = $this->getPreloadVersionKey();
2✔
768

769
        $version = $this->getGlobal($key);
2✔
770
        if (!$version) {
2✔
771
            $version = $this->updatePreloadVersion();
2✔
772
        }
773

774
        [$service, $option] = explode('.', $key);
2✔
775
        return !isset($configs[$service][$option]) || $configs[$service][$option] < $version;
2✔
776
    }
777

778
    /**
779
     * @return string
780
     * @svc
781
     */
782
    protected function getPreloadVersionKey(): string
783
    {
784
        return 'config.preloadVersion';
4✔
785
    }
786

787
    /**
788
     * @return array
789
     * @internal
790
     */
791
    protected function setPreloadCache(): array
792
    {
793
        $configs = GlobalConfigModel::select('name', 'type', 'value')
2✔
794
            ->where('preload', true)
2✔
795
            ->fetchAll();
2✔
796

797
        $data = [];
2✔
798
        foreach ($configs as $config) {
2✔
799
            // 从右边的点(.)拆分为两部分,兼容a.b.c的等情况
800
            $pos = strrpos($config['name'], '.');
2✔
801
            $service = substr($config['name'], 0, $pos);
2✔
802
            $option = substr($config['name'], $pos + 1);
2✔
803
            $data[$service][$option] = $this->decode($config['value'], $config['type']);
2✔
804
        }
805

806
        $this->setPhpFileCache('global-config', $data);
2✔
807

808
        return $data;
2✔
809
    }
810

811
    /**
812
     * @param string $key
813
     * @param mixed $value
814
     * @internal
815
     */
816
    protected function setPhpFileCache(string $key, $value)
817
    {
818
        $file = $this->phpFileCache->getDir() . '/' . $key . '.php';
2✔
819
        $this->writeConfig($file, $value);
2✔
820
    }
821

822
    /**
823
     * @param string $key
824
     * @param mixed $default
825
     * @return mixed
826
     * @internal
827
     */
828
    protected function getPhpFileCache(string $key, $default = null)
829
    {
830
        $file = $this->phpFileCache->getDir() . '/' . $key . '.php';
2✔
831
        if (is_file($file)) {
2✔
832
            return require $file;
2✔
833
        }
834
        return $default;
×
835
    }
836

837
    /**
838
     * @param array $values
839
     * @return array
840
     * @internal
841
     */
842
    protected function getNullKeys(array $values): array
843
    {
844
        $nulls = [];
24✔
845
        foreach ($values as $name => $value) {
24✔
846
            if (null === $value) {
22✔
847
                $nulls[] = $name;
14✔
848
            }
849
        }
850
        return $nulls;
24✔
851
    }
852
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc