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

plank / laravel-metable / 8731338116

18 Apr 2024 02:05AM UTC coverage: 97.685% (-1.1%) from 98.76%
8731338116

Pull #102

github

frasmage
test improvements
Pull Request #102: V6

238 of 248 new or added lines in 18 files covered. (95.97%)

5 existing lines in 1 file now uncovered.

422 of 432 relevant lines covered (97.69%)

65.51 hits per line

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

96.19
/src/Metable.php
1
<?php
2

3
namespace Plank\Metable;
4

5
use Illuminate\Database\Eloquent\Builder;
6
use Illuminate\Database\Eloquent\Collection;
7
use Illuminate\Database\Eloquent\Model;
8
use Illuminate\Database\Eloquent\Relations\MorphMany;
9
use Illuminate\Database\Query\JoinClause;
10
use Illuminate\Support\Facades\DB;
11
use Plank\Metable\DataType\HandlerInterface;
12
use Plank\Metable\DataType\Registry;
13

14
/**
15
 * Trait for giving Eloquent models the ability to handle Meta.
16
 *
17
 * @property Collection<Meta> $meta
18
 * @method static Builder whereHasMeta(string|string[] $key): void
19
 * @method static Builder whereDoesntHaveMeta(string|string[] $key)
20
 * @method static Builder whereHasMetaKeys(array $keys)
21
 * @method static Builder whereMeta(string $key, mixed $operator, mixed $value = null)
22
 * @method static Builder whereMetaNumeric(string $key, mixed $operator, mixed $value = null)
23
 * @method static Builder whereMetaIn(string $key, array $values)
24
 * @method static Builder whereMetaInNumeric(string $key, array $values)
25
 * @method static Builder whereMetaNotIn(string $key, array $values)
26
 * @method static Builder whereMetaNotInNumeric(string $key, array $values)
27
 * @method static Builder whereMetaBetween(string $key, mixed $min, mixed $max, bool $not = false)
28
 * @method static Builder whereMetaBetweenNumeric(string $key, mixed $min, mixed $max, bool $not = false)
29
 * @method static Builder whereMetaNotBetween(string $key, mixed $min, mixed $max)
30
 * @method static Builder whereMetaNotBetweenNumeric(string $key, mixed $min, mixed $max)
31
 * @method static Builder whereMetaIsNull(string $key)
32
 * @method static Builder whereMetaIsModel(string $key, Model|string $classOrInstance, null|int|string $id = null)
33
 * @method static Builder orderByMeta(string $key, string $direction = 'asc', bool $strict = false)
34
 * @method static Builder orderByMetaNumeric(string $key, string $direction = 'asc', bool $strict = false)
35
 */
36
trait Metable
37
{
38
    /**
39
     * @var Collection<Meta>
40
     */
41
    private $indexedMetaCollection;
42

43
    /**
44
     * Initialize the trait.
45
     *
46
     * @return void
47
     */
48
    public static function bootMetable(): void
49
    {
50
        // delete all attached meta on deletion
51
        static::deleted(function (self $model) {
294✔
52
            if (method_exists($model, 'isForceDeleting') && !$model->isForceDeleting()) {
18✔
53
                return;
6✔
54
            }
55
            $model->purgeMeta();
12✔
56
        });
294✔
57
    }
58

59
    /**
60
     * Relationship to the `Meta` model.
61
     *
62
     * @return MorphMany
63
     */
64
    public function meta(): MorphMany
65
    {
66
        return $this->morphMany($this->getMetaClassName(), 'metable');
252✔
67
    }
68

69
    /**
70
     * Add or update the value of the `Meta` at a given key.
71
     *
72
     * @param string $key
73
     * @param mixed $value
74
     */
75
    public function setMeta(string $key, mixed $value): void
76
    {
77
        if ($this->hasMeta($key)) {
228✔
78
            $meta = $this->getMetaRecord($key);
12✔
79
            $meta->setAttribute('value', $value);
12✔
80
            $meta->save();
12✔
81
        } else {
82
            $meta = $this->makeMeta($key, $value);
228✔
83
            $this->meta()->save($meta);
228✔
84
            $this->meta[] = $meta;
228✔
85
            $this->indexedMetaCollection[$key] = $meta;
228✔
86
        }
87
    }
88

89
    /**
90
     * Add or update many `Meta` values.
91
     *
92
     * @param array<string,mixed> $metaDictionary key-value pairs
93
     *
94
     * @return void
95
     */
96
    public function setManyMeta(array $metaDictionary): void
97
    {
98
        if (empty($metaDictionary)) {
12✔
99
            return;
6✔
100
        }
101

102
        $builder = $this->meta()->getBaseQuery();
6✔
103
        $needReload = $this->relationLoaded('meta');
6✔
104

105
        $metaModels = new Collection();
6✔
106
        foreach ($metaDictionary as $key => $value) {
6✔
107
            $metaModels[$key] = $this->makeMeta($key, $value);
6✔
108
        }
109

110
        $builder->upsert(
6✔
111
            $metaModels->map(function (Meta $model) {
6✔
112
                return $model->getAttributesForInsert();
6✔
113
            })->all(),
6✔
114
            ['metable_type', 'metable_id', 'key'],
6✔
115
            ['type', 'value']
6✔
116
        );
6✔
117

118
        if ($needReload) {
6✔
119
            // reload media relation and indexed cache
120
            $this->load('meta');
6✔
121
        }
122
    }
123

124
    /**
125
     * Replace all associated `Meta` with the keys and values provided.
126
     *
127
     * @param iterable $array
128
     *
129
     * @return void
130
     */
131
    public function syncMeta(iterable $array): void
132
    {
133
        $meta = [];
6✔
134

135
        foreach ($array as $key => $value) {
6✔
136
            $meta[$key] = $this->makeMeta($key, $value);
6✔
137
        }
138

139
        $this->meta()->delete();
6✔
140
        $this->meta()->saveMany($meta);
6✔
141

142
        // Update cached relationship.
143
        $collection = $this->makeMeta()->newCollection($meta);
6✔
144
        $this->setRelation('meta', $collection);
6✔
145
    }
146

147
    /**
148
     * Retrieve the value of the `Meta` at a given key.
149
     *
150
     * @param string $key
151
     * @param mixed $default Fallback value if no Meta is found.
152
     *
153
     * @return mixed
154
     */
155
    public function getMeta(string $key, mixed $default = null): mixed
156
    {
157
        if ($this->hasMeta($key)) {
66✔
158
            return $this->getMetaRecord($key)->getAttribute('value');
48✔
159
        }
160

161
        // If we have only one argument provided (i.e. default is not set)
162
        // then we check the model for the defaultMetaValues
163
        if (func_num_args() == 1 && $this->hasDefaultMetaValue($key)) {
18✔
164
            return $this->getDefaultMetaValue($key);
6✔
165
        }
166

167
        return $default;
12✔
168
    }
169

170
    /**
171
     * Check if the default meta array exists and the key is set
172
     *
173
     * @param string $key
174
     * @return boolean
175
     */
176
    protected function hasDefaultMetaValue(string $key): bool
177
    {
178
        return array_key_exists($key, $this->getAllDefaultMeta());
6✔
179
    }
180

181
    /**
182
     * Get the default meta value by key
183
     *
184
     * @param string $key
185
     * @return mixed
186
     */
187
    protected function getDefaultMetaValue(string $key): mixed
188
    {
189
        return $this->getAllDefaultMeta()[$key];
6✔
190
    }
191

192
    /**
193
     * Retrieve all meta attached to the model as a key/value map.
194
     *
195
     * @return \Illuminate\Support\Collection<int, mixed>
196
     */
197
    public function getAllMeta(): \Illuminate\Support\Collection
198
    {
199
        return collect($this->getAllDefaultMeta())->merge(
18✔
200
            $this->getMetaCollection()->toBase()->map(function (Meta $meta) {
18✔
201
                return $meta->getAttribute('value');
12✔
202
            })
18✔
203
        );
18✔
204
    }
205

206
    /**
207
     * Check if a `Meta` has been set at a given key.
208
     *
209
     * @param string $key
210
     *
211
     * @return bool
212
     */
213
    public function hasMeta(string $key): bool
214
    {
215
        return $this->getMetaCollection()->has($key);
258✔
216
    }
217

218
    /**
219
     * Delete the `Meta` at a given key.
220
     *
221
     * @param string $key
222
     *
223
     * @return void
224
     */
225
    public function removeMeta(string $key): void
226
    {
227
        if ($this->hasMeta($key)) {
12✔
228
            $this->getMetaCollection()->pull($key)->delete();
6✔
229
        }
230
    }
231

232
    /**
233
     * Delete many `Meta` keys.
234
     *
235
     * @param string[] $keys
236
     *
237
     * @return void
238
     */
239
    public function removeManyMeta(array $keys): void
240
    {
241
        $relation = $this->meta();
6✔
242
        $relation->newQuery()
6✔
243
            ->where($relation->getMorphType(), $this->getMorphClass())
6✔
244
            ->where($relation->getForeignKeyName(), $this->getKey())
6✔
245
            ->whereIn('key', $keys)
6✔
246
            ->delete();
6✔
247

248
        if ($this->relationLoaded('meta')) {
6✔
249
            $this->load('meta');
6✔
250
        }
251
    }
252

253
    /**
254
     * Delete all meta attached to the model.
255
     *
256
     * @return void
257
     */
258
    public function purgeMeta(): void
259
    {
260
        $this->meta()->delete();
18✔
261
        $this->setRelation('meta', $this->makeMeta()->newCollection());
18✔
262
    }
263

264
    /**
265
     * Retrieve the `Meta` model instance attached to a given key.
266
     *
267
     * @param string $key
268
     *
269
     * @return Meta|null
270
     */
271
    public function getMetaRecord(string $key): ?Meta
272
    {
273
        return $this->getMetaCollection()->get($key);
66✔
274
    }
275

276
    /**
277
     * Query scope to restrict the query to records which have `Meta` attached to a given key.
278
     *
279
     * If an array of keys is passed instead, will restrict the query to records having one or more Meta with any of the keys.
280
     *
281
     * @param Builder $q
282
     * @param string|string[] $key
283
     *
284
     * @return void
285
     */
286
    public function scopeWhereHasMeta(Builder $q, string|array $key): void
287
    {
288
        $q->whereHas('meta', function (Builder $q) use ($key) {
12✔
289
            $q->whereIn('key', (array)$key);
12✔
290
        });
12✔
291
    }
292

293
    /**
294
     * Query scope to restrict the query to records which doesnt have `Meta` attached to a given key.
295
     *
296
     * If an array of keys is passed instead, will restrict the query to records having one or more Meta with any of the keys.
297
     *
298
     * @param Builder $q
299
     * @param string|string[] $key
300
     *
301
     * @return void
302
     */
303
    public function scopeWhereDoesntHaveMeta(Builder $q, string|array $key): void
304
    {
305
        $q->whereDoesntHave('meta', function (Builder $q) use ($key) {
12✔
306
            $q->whereIn('key', (array)$key);
12✔
307
        });
12✔
308
    }
309

310
    /**
311
     * Query scope to restrict the query to records which have `Meta` for all of the provided keys.
312
     *
313
     * @param Builder $q
314
     * @param array $keys
315
     *
316
     * @return void
317
     */
318
    public function scopeWhereHasMetaKeys(Builder $q, array $keys): void
319
    {
320
        $q->whereHas(
6✔
321
            'meta',
6✔
322
            function (Builder $q) use ($keys) {
6✔
323
                $q->whereIn('key', $keys);
6✔
324
            },
6✔
325
            '=',
6✔
326
            count($keys)
6✔
327
        );
6✔
328
    }
329

330
    /**
331
     * Query scope to restrict the query to records which have `Meta` with a specific key and value.
332
     *
333
     * If the `$value` parameter is omitted, the $operator parameter will be considered the value.
334
     *
335
     * Values will be serialized to a string before comparison. If using the `>`, `>=`, `<`, or `<=` comparison operators, note that the value will be compared as a string. If comparing numeric values, use `Metable::scopeWhereMetaNumeric()` instead.
336
     *
337
     * @param Builder $q
338
     * @param string $key
339
     * @param mixed $operator
340
     * @param mixed $value
341
     *
342
     * @return void
343
     */
344
    public function scopeWhereMeta(
345
        Builder $q,
346
        string $key,
347
        mixed $operator,
348
        mixed $value = null
349
    ): void {
350
        // Shift arguments if no operator is present.
351
        if (!isset($value)) {
12✔
352
            $value = $operator;
6✔
353
            $operator = '=';
6✔
354
        }
355

356
        $stringValue = $this->valueToString($value);
12✔
357
        $q->whereHas(
12✔
358
            'meta',
12✔
359
            function (Builder $q) use ($key, $operator, $stringValue, $value) {
12✔
360
                $q->where('key', $key);
12✔
361
                $q->where('string_value', $operator, $stringValue);
12✔
362

363
                // If the value is a string and the string value is at the maximum length,
364
                // we can optimize the query by looking up using the index first
365
                // then compare the serialized value (not indexed) afterward to ensure correctness.
366
                if (strlen($stringValue) >= config(
12✔
367
                    'metable.stringValueIndexLength',
12✔
368
                    255
12✔
369
                )) {
12✔
NEW
UNCOV
370
                    $handler = $this->getHandlerForValue($value);
×
NEW
UNCOV
371
                    if ($handler->isIdempotent()) {
×
NEW
UNCOV
372
                        $q->where('value', $operator, $handler->serializeValue($value));
×
373
                    }
374
                }
375
            }
12✔
376
        );
12✔
377
    }
378

379
    /**
380
     * Query scope to restrict the query to records which have `Meta` with a specific key and numeric value.
381
     *
382
     * Performs numeric comparison instead of string comparison.
383
     *
384
     * @param Builder $q
385
     * @param string $key
386
     * @param mixed|string $operator
387
     * @param mixed $value
388
     *
389
     * @return void
390
     */
391
    public function scopeWhereMetaNumeric(
392
        Builder $q,
393
        string $key,
394
        mixed $operator,
395
        mixed $value = null
396
    ): void {
397
        // Shift arguments if no operator is present.
398
        if (!isset($value)) {
6✔
NEW
399
            $value = $operator;
×
NEW
400
            $operator = '=';
×
401
        }
402

403
        $numericValue = $this->valueToNumeric($value);
6✔
404
        $q->whereHas('meta', function (Builder $q) use ($key, $operator, $numericValue) {
6✔
405
            $q->where('key', $key);
6✔
406
            $q->where('numeric_value', $operator, $numericValue);
6✔
407
        });
6✔
408
    }
409

410
    public function scopeWhereMetaBetween(
411
        Builder $q,
412
        string $key,
413
        mixed $min,
414
        mixed $max,
415
        bool $not = false
416
    ): void {
417
        $min = $this->valueToString($min);
6✔
418
        $max = $this->valueToString($max);
6✔
419

420
        $q->whereHas(
6✔
421
            'meta',
6✔
422
            function (Builder $q) use ($key, $min, $max, $not) {
6✔
423
                $q->where('key', $key);
6✔
424
                $q->whereBetween('string_value', [$min, $max], 'and', $not);
6✔
425
            }
6✔
426
        );
6✔
427
    }
428

429
    public function scopeWhereMetaNotBetween(
430
        Builder $q,
431
        string $key,
432
        mixed $min,
433
        mixed $max,
434
    ): void {
NEW
435
        $this->scopeWhereMetaBetween($q, $key, $min, $max, true);
×
436
    }
437

438
    public function scopeWhereMetaBetweenNumeric(
439
        Builder $q,
440
        string $key,
441
        mixed $min,
442
        mixed $max,
443
        bool $not = false
444
    ): void {
445
        $min = $this->valueToNumeric($min);
12✔
446
        $max = $this->valueToNumeric($max);
12✔
447

448
        $q->whereHas('meta', function (Builder $q) use ($key, $min, $max, $not) {
12✔
449
            $q->where('key', $key);
12✔
450
            $q->whereBetween('numeric_value', [$min, $max], 'and', $not);
12✔
451
        });
12✔
452
    }
453

454
    public function scopeWhereMetaNotBetweenNumeric(
455
        Builder $q,
456
        string $key,
457
        mixed $min,
458
        mixed $max
459
    ): void {
460
        $this->scopeWhereMetaBetweenNumeric($q, $key, $min, $max, true);
6✔
461
    }
462

463
    /**
464
     * Query scope to restrict the query to records which have `Meta` with a specific key and a `null` value.
465
     * @param Builder $q
466
     * @param string $key
467
     * @return void
468
     */
469
    public function scopeWhereMetaIsNull(Builder $q, string $key): void
470
    {
471
        $q->whereHas('meta', function (Builder $q) use ($key) {
6✔
472
            $q->where('key', $key);
6✔
473
            $q->whereNull('string_value');
6✔
474
            $q->where('type', 'null');
6✔
475
        });
6✔
476
    }
477

478
    public function scopeWhereMetaIsModel(
479
        Builder $q,
480
        string $key,
481
        Model|string $classOrInstance,
482
        null|int|string $id = null
483
    ): void {
484
        if ($classOrInstance instanceof Model) {
6✔
485
            $id = $classOrInstance->getKey();
6✔
486
            $classOrInstance = get_class($classOrInstance);
6✔
487
        }
488
        $value = $classOrInstance;
6✔
489
        if ($id) {
6✔
490
            $value .= '#' . $id;
6✔
491
        } else {
492
            $value .= '%';
6✔
493
        }
494

495
        $this->scopeWhereMeta($q, $key, 'like', $value);
6✔
496
    }
497

498
    /**
499
     * Query scope to restrict the query to records which have `Meta` with a specific key and a value within a specified set of options.
500
     *
501
     * @param Builder $q
502
     * @param string $key
503
     * @param array $values
504
     * @param bool $not
505
     *
506
     * @return void
507
     */
508
    public function scopeWhereMetaIn(
509
        Builder $q,
510
        string $key,
511
        array $values,
512
        bool $not = false
513
    ): void {
514
        $values = array_map(function ($val) use ($key) {
12✔
515
            return $this->valueToString($val);
12✔
516
        }, $values);
12✔
517

518
        $q->whereHas('meta', function (Builder $q) use ($key, $values, $not) {
12✔
519
            $q->where('key', $key);
12✔
520
            $q->whereIn('string_value', $values, 'and', $not);
12✔
521
        });
12✔
522
    }
523

524
    public function scopeWhereMetaNotIn(
525
        Builder $q,
526
        string $key,
527
        array $values
528
    ): void {
529
        $this->scopeWhereMetaIn($q, $key, $values, true);
6✔
530
    }
531

532
    public function scopeWhereMetaInNumeric(
533
        Builder $q,
534
        string $key,
535
        array $values,
536
        bool $not = false
537
    ): void {
538
        $values = array_map(function ($val) use ($key) {
12✔
539
            return $this->valueToNumeric($val);
12✔
540
        }, $values);
12✔
541

542
        $q->whereHas('meta', function (Builder $q) use ($key, $values, $not) {
12✔
543
            $q->where('key', $key);
12✔
544
            $q->whereIn('numeric_value', $values, 'and', $not);
12✔
545
        });
12✔
546
    }
547

548
    public function scopeWhereMetaNotInNumeric(
549
        Builder $q,
550
        string $key,
551
        array $values
552
    ): void {
553
        $this->scopeWhereMetaInNumeric($q, $key, $values, true);
6✔
554
    }
555

556
    /**
557
     * Query scope to order the query results by the string value of an attached meta.
558
     *
559
     * @param Builder $q
560
     * @param string $key
561
     * @param string $direction
562
     * @param bool $strict if true, will exclude records that do not have meta for the provided `$key`.
563
     *
564
     * @return void
565
     */
566
    public function scopeOrderByMeta(
567
        Builder $q,
568
        string $key,
569
        string $direction = 'asc',
570
        bool $strict = false
571
    ): void {
572
        $table = $this->joinMetaTable($q, $key, $strict ? 'inner' : 'left');
18✔
573
        $q->orderBy("{$table}.string_value", $direction);
18✔
574
    }
575

576
    /**
577
     * Query scope to order the query results by the numeric value of an attached meta.
578
     *
579
     * @param Builder $q
580
     * @param string $key
581
     * @param string $direction
582
     * @param bool $strict if true, will exclude records that do not have meta for the provided `$key`.
583
     *
584
     * @return void
585
     */
586
    public function scopeOrderByMetaNumeric(
587
        Builder $q,
588
        string $key,
589
        string $direction = 'asc',
590
        bool $strict = false
591
    ): void {
592
        $table = $this->joinMetaTable($q, $key, $strict ? 'inner' : 'left');
12✔
593
        $q->orderBy("{$table}.numeric_value", $direction);
12✔
594
    }
595

596
    /**
597
     * Join the meta table to the query.
598
     *
599
     * @param Builder $q
600
     * @param string $key
601
     * @param string $type Join type.
602
     *
603
     * @return string
604
     */
605
    private function joinMetaTable(Builder $q, string $key, string $type = 'left'): string
606
    {
607
        $relation = $this->meta();
30✔
608
        $metaTable = $relation->getRelated()->getTable();
30✔
609

610
        // Create an alias for the join, to allow the same
611
        // table to be joined multiple times for different keys.
612
        $alias = $metaTable . '__' . $key;
30✔
613

614
        // If no explicit select columns are specified,
615
        // avoid column collision by excluding meta table from select.
616
        if (!$q->getQuery()->columns) {
30✔
617
            $q->select($this->getTable() . '.*');
30✔
618
        }
619

620
        // Join the meta table to the query
621
        $q->join(
30✔
622
            "{$metaTable} as {$alias}",
30✔
623
            function (JoinClause $q) use ($relation, $key, $alias) {
30✔
624
                $q->on(
30✔
625
                    $relation->getQualifiedParentKeyName(),
30✔
626
                    '=',
30✔
627
                    $alias . '.' . $relation->getForeignKeyName()
30✔
628
                )
30✔
629
                    ->where($alias . '.key', '=', $key)
30✔
630
                    ->where(
30✔
631
                        $alias . '.' . $relation->getMorphType(),
30✔
632
                        '=',
30✔
633
                        $this->getMorphClass()
30✔
634
                    );
30✔
635
            },
30✔
636
            null,
30✔
637
            null,
30✔
638
            $type
30✔
639
        );
30✔
640

641
        // Return the alias so that the calling context can
642
        // reference the table.
643
        return $alias;
30✔
644
    }
645

646
    /**
647
     * fetch all meta for the model, if necessary.
648
     *
649
     * In Laravel versions prior to 5.3, relations that are lazy loaded by the
650
     * `getRelationFromMethod()` method ( invoked by the `__get()` magic method)
651
     * are not passed through the `setRelation()` method, so we load the relation
652
     * manually.
653
     *
654
     * @return mixed
655
     */
656
    private function getMetaCollection(): mixed
657
    {
658
        // load meta relation if not loaded.
659
        if (!$this->relationLoaded('meta')) {
270✔
660
            $this->setRelation('meta', $this->meta()->get());
240✔
661
        }
662

663
        // reindex by key for quicker lookups if necessary.
664
        if ($this->indexedMetaCollection === null) {
270✔
665
            $this->indexedMetaCollection = $this->meta->keyBy('key');
270✔
666
        }
667

668
        return $this->indexedMetaCollection;
270✔
669
    }
670

671
    /**
672
     * {@inheritdoc}
673
     */
674
    public function setRelation($relation, $value)
675
    {
676
        $this->indexedMetaCollection = null;
270✔
677
        return parent::setRelation($relation, $value);
270✔
678
    }
679

680
    /**
681
     * Set the entire relations array on the model.
682
     *
683
     * @param array $relations
684
     * @return $this
685
     */
686
    public function setRelations(array $relations)
687
    {
688
        if (isset($relations['meta'])) {
6✔
689
            // clear the indexed cache
690
            $this->indexedMetaCollection = null;
6✔
691
        }
692

693
        return parent::setRelations($relations);
6✔
694
    }
695

696
    /**
697
     * Retrieve the FQCN of the class to use for Meta models.
698
     *
699
     * @return class-string<Meta>
700
     */
701
    protected function getMetaClassName(): string
702
    {
703
        return config('metable.model', Meta::class);
252✔
704
    }
705

706
    /**
707
     * Create a new `Meta` record.
708
     *
709
     * @param string $key
710
     * @param mixed $value
711
     *
712
     * @return Meta
713
     */
714
    protected function makeMeta(string $key = '', mixed $value = ''): Meta
715
    {
716
        $className = $this->getMetaClassName();
228✔
717

718
        $meta = new $className([
228✔
719
            'key' => $key,
228✔
720
            'value' => $value,
228✔
721
        ]);
228✔
722
        $meta->metable_type = $this->getMorphClass();
228✔
723
        $meta->metable_id = $this->getKey();
228✔
724

725
        return $meta;
228✔
726
    }
727

728
    protected function getAllDefaultMeta(): array
729
    {
730
        return property_exists($this, 'defaultMetaValues')
18✔
731
            ? $this->defaultMetaValues
18✔
732
            : [];
18✔
733
    }
734

735
    private function valueToString(mixed $value): string
736
    {
737
        $stringValue = $this->getHandlerForValue($value)->getStringValue($value);
30✔
738

739
        if ($stringValue === null) {
30✔
NEW
UNCOV
740
            throw new \InvalidArgumentException('Cannot convert to a numeric value');
×
741
        }
742

743
        return $stringValue;
30✔
744
    }
745

746
    private function valueToNumeric(mixed $value): int|float
747
    {
748
        $numericValue = $this->getHandlerForValue($value)->getNumericValue($value);
30✔
749

750
        if ($numericValue === null) {
30✔
NEW
UNCOV
751
            throw new \InvalidArgumentException('Cannot convert to a numeric value');
×
752
        }
753

754
        return $numericValue;
30✔
755
    }
756

757
    private function getHandlerForValue(mixed $value): HandlerInterface
758
    {
759
        /** @var Registry $registry */
760
        $registry = app('metable.datatype.registry');
60✔
761
        return $registry->getHandlerForValue($value);
60✔
762
    }
763
}
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