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

conedevelopment / root / 18488901767

14 Oct 2025 07:27AM UTC coverage: 76.317% (+0.02%) from 76.301%
18488901767

push

github

iamgergo
version

3361 of 4404 relevant lines covered (76.32%)

34.46 hits per line

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

73.02
/src/Fields/Select.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Cone\Root\Fields;
6

7
use Closure;
8
use Cone\Root\Filters\Filter;
9
use Cone\Root\Filters\RenderableFilter;
10
use function Illuminate\Support\enum_value;
11
use Illuminate\Database\Eloquent\Builder;
12
use Illuminate\Database\Eloquent\Model;
13
use Illuminate\Http\Request;
14
use Illuminate\Support\Arr;
15
use Illuminate\Support\Collection;
16

17
class Select extends Field
18
{
19
    /**
20
     * The Blade template.
21
     */
22
    protected string $template = 'root::fields.select';
23

24
    /**
25
     * The options resolver callback.
26
     */
27
    protected ?Closure $optionsResolver = null;
28

29
    /**
30
     * Indicates if the field should be nullable.
31
     */
32
    protected bool $nullable = false;
33

34
    /**
35
     * Set the nullable attribute.
36
     */
37
    public function nullable(bool $value = true): static
1✔
38
    {
39
        $this->nullable = $value;
1✔
40

41
        return $this;
1✔
42
    }
43

44
    /**
45
     * Determine if the field is nullable.
46
     */
47
    public function isNullable(): bool
3✔
48
    {
49
        return $this->nullable;
3✔
50
    }
51

52
    /**
53
     * Set the "multiple" HTML attribute.
54
     */
55
    public function multiple(bool $value = true): static
2✔
56
    {
57
        return $this->setAttribute('multiple', $value);
2✔
58
    }
59

60
    /**
61
     * Set the "size" HTML attribute.
62
     */
63
    public function size(int $value): static
1✔
64
    {
65
        return $this->setAttribute('size', $value);
1✔
66
    }
67

68
    /**
69
     * {@inheritdoc}
70
     */
71
    public function resolveFormat(Request $request, Model $model): ?string
4✔
72
    {
73
        if (is_null($this->formatResolver)) {
4✔
74
            $this->formatResolver = function (Request $request, Model $model, mixed $value): string {
4✔
75
                $options = array_column(
4✔
76
                    $this->resolveOptions($request, $model), 'label', 'value'
4✔
77
                );
4✔
78

79
                return Collection::make($value)
4✔
80
                    ->map(static function (mixed $value) use ($options): string {
4✔
81
                        $value = enum_value($value);
2✔
82

83
                        return $options[$value] ?? $value;
2✔
84
                    })
4✔
85
                    ->implode(', ');
4✔
86
            };
4✔
87
        }
88

89
        return parent::resolveFormat($request, $model);
4✔
90
    }
91

92
    /**
93
     * Set the options attribute.
94
     */
95
    public function options(array|Closure $value): static
197✔
96
    {
97
        $this->optionsResolver = is_callable($value) ? $value : static fn (): array => $value;
197✔
98

99
        return $this;
197✔
100
    }
101

102
    /**
103
     * Resolve the options for the field.
104
     */
105
    public function resolveOptions(Request $request, Model $model): array
5✔
106
    {
107
        if (is_null($this->optionsResolver)) {
5✔
108
            return [];
2✔
109
        }
110

111
        $options = call_user_func_array($this->optionsResolver, [$request, $model]);
4✔
112

113
        $value = Arr::wrap($this->resolveValue($request, $model));
4✔
114

115
        return array_map(function (mixed $label, mixed $option) use ($value): array {
4✔
116
            $option = $label instanceof Option ? $label : $this->newOption($option, $label);
4✔
117

118
            $option->selected(in_array(
4✔
119
                $option->getAttribute('value'),
4✔
120
                array_map(fn (mixed $v): mixed => enum_value($v), $value)
4✔
121
            ));
4✔
122

123
            return $option->toArray();
4✔
124
        }, $options, array_keys($options));
4✔
125
    }
126

127
    /**
128
     * Make a new option instance.
129
     */
130
    public function newOption(mixed $value, string $label): Option
4✔
131
    {
132
        return new Option($value, $label);
4✔
133
    }
134

135
    /**
136
     * {@inheritdoc}
137
     */
138
    public function toInput(Request $request, Model $model): array
2✔
139
    {
140
        return array_merge(parent::toInput($request, $model), [
2✔
141
            'nullable' => $this->isNullable(),
2✔
142
            'options' => $this->resolveOptions($request, $model),
2✔
143
        ]);
2✔
144
    }
145

146
    /**
147
     * Get the filter representation of the field.
148
     */
149
    public function toFilter(): Filter
×
150
    {
151
        return new class($this) extends RenderableFilter
×
152
        {
×
153
            protected Select $field;
154

155
            public function __construct(Select $field)
156
            {
157
                parent::__construct($field->getModelAttribute());
×
158

159
                $this->field = $field;
×
160
            }
161

162
            public function apply(Request $request, Builder $query, mixed $value): Builder
163
            {
164
                return $this->field->resolveFilterQuery($request, $query, $value);
×
165
            }
166

167
            public function toField(): Field
168
            {
169
                return Select::make($this->field->getLabel(), $this->getRequestKey())
×
170
                    ->value(fn (Request $request): mixed => $this->getValue($request))
×
171
                    ->nullable()
×
172
                    ->options(function (Request $request, Model $model): array {
×
173
                        return array_column(
×
174
                            $this->field->resolveOptions($request, $model),
×
175
                            'label',
×
176
                            'value',
×
177
                        );
×
178
                    });
×
179
            }
180
        };
×
181
    }
182
}
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