Lines 100.00% 9 / 9
Functions and Methods 100.00% 2 / 2
Classes and Traits 100.00% 1 / 1
Name Lines Functions and Methods CRAP Classes and Traits
ModelNotFoundException 100.00% 9 / 9 100.00% 2 / 2 4 100.00% 1 / 1
 __construct 100.00% 6 / 6 100.00% 1 / 1 2
 renderKey 100.00% 3 / 3 100.00% 1 / 1 2
1<?php
2
3declare(strict_types=1);
4
5namespace BlueprintAU\Radiant\Exceptions;
6
7/**
8 * Thrown by the fail-fast retrieval family (`firstOrFail()`, `findOrFail()`,
9 * `sole()`) when a query that must produce a model row produces none.
10 *
11 * The exception carries the model class that was queried and, when the
12 * caller looked up by key, that key — so the message identifies exactly
13 * which lookup came up empty:
14 *
15 * - no key:   `No query results for model [App\Models\User].`
16 * - scalar:   `No query results for model [App\Models\User] 42.`
17 * - composite: `No query results for model [App\Models\Region] {"id":1,"country":"FR"}.`
18 *
19 * Composite keys render as the JSON encoding of the caller's column map
20 * (order-preserving). Values pass through `json_encode` verbatim — keys
21 * come from `whereKey()` validation, never from user SQL.
22 *
23 * @phpstan-import-type KeyValue from \BlueprintAU\Radiant\Model
24 */
25final class ModelNotFoundException extends \RuntimeException
26{
27    /**
28     * The class-string of the model that had no matching row.
29     *
30     * @var class-string<\BlueprintAU\Radiant\Model>
31     */
32    public readonly string $model;
33
34    /**
35     * The key used for the lookup: null when no key was involved, a scalar
36     * or a composite column map otherwise.
37     *
38     * @var KeyValue
39     */
40    public readonly int|string|null|array $key;
41
42    /**
43     * @param  class-string<\BlueprintAU\Radiant\Model>  $modelClass
44     * @param  KeyValue  $key  Null when no key was involved; a scalar or a column => value map otherwise.
45     */
46    public function __construct(string $modelClass, int|string|null|array $key = null)
47    {
48        $this->model = $modelClass;
49        $this->key = $key;
50
51        $message = 'No query results for model ['.$modelClass.']';
52
53        if ($key !== null) {
54            $message .= ' '.self::renderKey($key);
55        }
56
57        parent::__construct($message.'.');
58    }
59
60    /**
61     * Renders the lookup key for the exception message.
62     *
63     * @param  KeyValue  $key
64     * @return string
65     */
66    private static function renderKey(int|string|null|array $key): string
67    {
68        if (\is_array($key)) {
69            return (string) json_encode($key);
70        }
71
72        return (string) $key;
73    }
74}