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

luttje / filament-user-attributes / 7254443569

18 Dec 2023 10:14PM UTC coverage: 73.72% (-0.2%) from 73.873%
7254443569

push

github

web-flow
Feature/custom config field support (#6)

* refactor so configs related to user attributes can be fetched + better livewire support

* let devs add custom config fields

* remove changelog workflow

43 of 67 new or added lines in 8 files covered. (64.18%)

1 existing line in 1 file now uncovered.

1296 of 1758 relevant lines covered (73.72%)

30.13 hits per line

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

85.84
/src/Filament/UserAttributeComponentFactoryRegistry.php
1
<?php
2

3
namespace Luttje\FilamentUserAttributes\Filament;
4

5
use Closure;
6
use Filament\Forms;
7
use Filament\Forms\Get;
8
use Luttje\FilamentUserAttributes\EloquentHelper;
9
use Luttje\FilamentUserAttributes\EloquentHelperRelationshipInfo;
10
use Luttje\FilamentUserAttributes\Facades\FilamentUserAttributes;
11
use Luttje\FilamentUserAttributes\Models\UserAttributeConfig;
12

13
class UserAttributeComponentFactoryRegistry
14
{
15
    protected static $factories = [];
16

17
    protected static $relatedAmountMap = [
18
        '__self' => 1,
19
        'belongsTo' => 1,
20
        'belongsToMany' => 99,
21
        'hasMany' => 99,
22
        'hasOne' => 1,
23
        'morphMany' => 99,
24
        'morphOne' => 1,
25
        'morphTo' => 1,
26
        'morphToMany' => 99,
27
        'morphedByMany' => 99,
28
    ];
29

30
    public static function register(string $type, string $factory): void
292✔
31
    {
32
        static::$factories[$type] = $factory;
292✔
33
    }
34

35
    public static function getFactory(string $type, string $modelType): UserAttributeComponentFactoryInterface
16✔
36
    {
37
        if (!isset(static::$factories[$type])) {
16✔
38
            throw new \Exception("Factory for type {$type} not registered.");
×
39
        }
40

41
        return new static::$factories[$type]($modelType);
16✔
42
    }
43

44
    public static function getRegisteredTypes(): array
36✔
45
    {
46
        return array_keys(static::$factories);
36✔
47
    }
48

49
    /**
50
     * Looks at the config resource and gets the model relations that can be inherited from.
51
     * It can only inherit from related models whose resource is also configurable.
52
     */
53
    public static function getInheritRelationOptions(UserAttributeConfig $configModel): array
36✔
54
    {
55
        // TODO: Clean this up, possibly moving it somewhere else
56
        $resources = FilamentUserAttributes::getConfigurableResources();
36✔
57
        $modelsMappedToResources = FilamentUserAttributes::getResourcesByModel();
36✔
58

59
        $model = $configModel->model_type;
36✔
60
        $relations = [];
36✔
61

62
        $self = new EloquentHelperRelationshipInfo();
36✔
63
        $self->name = '__self';
36✔
64
        $self->relationTypeShort = '__self';
36✔
65
        $self->relatedType = $model;
36✔
66
        $relations[] = $self;
36✔
67

68
        $relations = [...$relations, ...EloquentHelper::discoverRelations($model)];
36✔
69

70
        $options = [];
36✔
71
        $nameTransformer = config('filament-user-attributes.discovery_model_name_transformer');
36✔
72

73
        foreach ($relations as $relation) {
36✔
74
            $relatedModel = $relation->relatedType;
36✔
75
            $relatedResource = $modelsMappedToResources[$relatedModel] ?? null;
36✔
76

77
            if (!$relatedResource) {
36✔
78
                continue;
36✔
79
            }
80

81
            $relationAmount = static::$relatedAmountMap[$relation->relationTypeShort];
×
82
            $languageKey = 'filament-user-attributes::user-attributes.inherit_relation_option_label';
×
83

84
            if ($relation->name === '__self') {
×
85
                $languageKey = 'filament-user-attributes::user-attributes.inherit_relation_option_label_self';
×
86
            }
87

88
            $options[$relation->name] = __($languageKey, [
×
89
                'related_name' => $resources[$relatedResource],
×
90
                'resource' => $nameTransformer($model),
×
91
                'relationship' => __('filament-user-attributes::user-attributes.relationships.' . $relation->relationTypeShort),
×
92
                'related_resource' => $nameTransformer($relatedModel, $relationAmount),
×
93
            ]);
×
94
        }
95

96
        return $options;
36✔
97
    }
98

99
    public static function getConfigurationSchemas(UserAttributeConfig $configModel): array
36✔
100
    {
101
        $schemas = [];
36✔
102

103
        $schemas[] = Forms\Components\Fieldset::make('common')
36✔
104
            ->label(ucfirst(__('filament-user-attributes::user-attributes.common')))
36✔
105
            ->schema(function () {
36✔
106
                return [
36✔
107
                    // TODO: Make configs for these, so developers can tweak which default fields are shown
108
                    Forms\Components\TextInput::make('name')
36✔
109
                        ->label(ucfirst(__('filament-user-attributes::user-attributes.attributes.name')))
36✔
110
                        ->required()
36✔
111
                        ->rules([
36✔
112
                            function (Get $get) {
36✔
113
                                $otherNames = $get('../../config.*.name');
36✔
114

115
                                return function (string $attribute, $value, Closure $fail) use ($otherNames) {
36✔
116
                                    $userAttributeConfigs = collect($otherNames)->filter(function ($item) use ($value) {
36✔
117
                                        return $item === $value;
36✔
118
                                    });
36✔
119

120
                                    if ($userAttributeConfigs->count() > 1) {
36✔
121
                                        $fail(__('filament-user-attributes::user-attributes.name_already_exists'));
×
122
                                    }
123
                                };
36✔
124
                            },
36✔
125
                        ])
36✔
126
                        ->helperText(ucfirst(__('filament-user-attributes::user-attributes.name_help')))
36✔
127
                        ->maxLength(255),
36✔
128
                    Forms\Components\Select::make('type')
36✔
129
                        ->options(array_combine(static::getRegisteredTypes(), static::getRegisteredTypes()))
36✔
130
                        ->label(ucfirst(__('filament-user-attributes::user-attributes.attributes.type')))
36✔
131
                        ->required()
36✔
132
                        ->live(),
36✔
133
                    Forms\Components\TextInput::make('label')
36✔
134
                        ->label(ucfirst(__('filament-user-attributes::user-attributes.attributes.label')))
36✔
135
                        ->required()
36✔
136
                        ->maxLength(255),
36✔
137
                ];
36✔
138
            });
36✔
139

140
        $inheritRelationOptions = static::getInheritRelationOptions($configModel);
36✔
141

142
        $schemas[] = Forms\Components\Fieldset::make(__('filament-user-attributes::user-attributes.default_value_config'))
36✔
143
            ->schema([
36✔
144
                Forms\Components\Checkbox::make('required')
36✔
145
                    ->label(ucfirst(__('filament-user-attributes::user-attributes.attributes.required'))),
36✔
146

147
                Forms\Components\Grid::make()
36✔
148
                    ->columns([
36✔
149
                        'lg' => 3
36✔
150
                    ])
36✔
151
                    ->schema([
36✔
152
                        Forms\Components\Checkbox::make('inherit')
36✔
153
                            ->label(ucfirst(__('filament-user-attributes::user-attributes.inherit')))
36✔
154
                            ->helperText(ucfirst(__('filament-user-attributes::user-attributes.inherit_help')))
36✔
155
                            ->live(),
36✔
156
                        Forms\Components\Select::make('inherit_relation')
36✔
157
                            ->options($inheritRelationOptions)
36✔
158
                            ->label(ucfirst(__('filament-user-attributes::user-attributes.inherit_relation')))
36✔
159
                            ->required(fn (Get $get) => $get('inherit'))
36✔
160
                            ->disabled(fn (Get $get) => !$get('inherit'))
36✔
161
                            ->live(),
36✔
162
                        Forms\Components\Select::make('inherit_attribute')
36✔
163
                            ->options(function (Get $get) use ($configModel) {
36✔
164
                                $inheritRelationName = $get('inherit_relation');
36✔
165

166
                                if (!$inheritRelationName) {
36✔
167
                                    return [];
36✔
168
                                }
169

170
                                if ($inheritRelationName === '__self') {
×
NEW
171
                                    $inheritRelatedModelType = $configModel->model_type;
×
172
                                } else {
NEW
173
                                    $model = $configModel->model_type;
×
174
                                    $inheritRelationInfo = EloquentHelper::getRelationInfo($model, $inheritRelationName);
×
175

176
                                    if (!$inheritRelationInfo) {
×
177
                                        return [];
×
178
                                    }
179

180
                                    $inheritRelatedModelType = $inheritRelationInfo->relatedType;
×
181
                                }
182

NEW
183
                                $resource = FilamentUserAttributes::getResourcesByModel()
×
184
                                    ->filter(function ($class, $model) use ($inheritRelatedModelType) {
×
185
                                        return $model === $inheritRelatedModelType;
×
186
                                    })
×
187
                                    ->first();
×
188

189
                                if (!$resource) {
×
190
                                    return [];
×
191
                                }
192

193
                                $attributes = $resource::getAllFieldComponents();
×
194
                                $attributes = array_combine(array_column($attributes, 'statePath'), array_column($attributes, 'label'));
×
195
                                return $attributes;
×
196
                            })
36✔
197
                            ->label(ucfirst(__('filament-user-attributes::user-attributes.inherit_attribute')))
36✔
198
                            ->required(fn (Get $get) => $get('inherit'))
36✔
199
                            ->disabled(fn (Get $get) => !$get('inherit')),
36✔
200
                    ])
36✔
201
            ]);
36✔
202

203
        $customConfigFields = FilamentUserAttributes::getUserAttributeConfigComponents($configModel);
36✔
204

205
        foreach ($customConfigFields as $customConfigField) {
36✔
NEW
206
            $schemas[] = $customConfigField;
×
207
        }
208

209
        foreach (static::$factories as $type => $factoryClass) {
36✔
210
            /** @var UserAttributeComponentFactoryInterface */
211
            $factory = new $factoryClass($configModel->model_type);
36✔
212
            $factorySchema = $factory->makeConfigurationSchema();
36✔
213

214
            $schemas[] = Forms\Components\Fieldset::make('customizations_for_' . $type)
36✔
215
                ->label(ucfirst(__('filament-user-attributes::user-attributes.customizations_for', ['type' => $type])))
36✔
216
                ->statePath('customizations')
36✔
217
                ->schema($factorySchema)
36✔
218
                ->mutateDehydratedStateUsing(function (Get $get, $state) use ($type, $factorySchema) {
36✔
219
                    if ($get('type') !== $type) {
32✔
220
                        return null;
×
221
                    }
222

223
                    // Unset all names that are not in the schema
224
                    // TODO: Why doesn't filament just ignore things that are hidden or disabled?
225
                    $names = collect($factorySchema)->map(function ($item) {
32✔
226
                        return $item->getName();
32✔
227
                    });
32✔
228
                    $state = collect($state)
32✔
229
                        ->filter(function ($value, $name) use ($names) {
32✔
230
                            return $names->contains($name);
32✔
231
                        })
32✔
232
                        ->toArray();
32✔
233

234
                    return $state;
32✔
235
                })
36✔
236
                ->hidden(fn (Get $get) => $get('type') !== $type || count($factorySchema) === 0)
36✔
237
                ->disabled(fn (Get $get) => $get('type') !== $type || count($factorySchema) === 0);
36✔
238
        }
239

240
        $schemas[] = Forms\Components\Fieldset::make('ordering')
36✔
241
            ->label(ucfirst(__('filament-user-attributes::user-attributes.ordering')))
36✔
242
            ->schema([
36✔
243
                Forms\Components\Fieldset::make('ordering_form')
36✔
244
                    ->label(ucfirst(__('filament-user-attributes::user-attributes.ordering_form')))
36✔
245
                    ->schema(function () use ($configModel) {
36✔
246
                        return [
36✔
247
                            Forms\Components\Select::make('order_position_form')
36✔
248
                                ->options([
36✔
249
                                    'before' => __('filament-user-attributes::user-attributes.attributes.order_position_before'),
36✔
250
                                    'after' => __('filament-user-attributes::user-attributes.attributes.order_position_after'),
36✔
251
                                    'hidden' => __('filament-user-attributes::user-attributes.attributes.order_position_hidden'),
36✔
252
                                ])
36✔
253
                                ->placeholder(ucfirst(__('filament-user-attributes::user-attributes.attributes.order_sibling_at_end')))
36✔
254
                                ->selectablePlaceholder()
36✔
255
                                ->live()
36✔
256
                                ->label(ucfirst(__('filament-user-attributes::user-attributes.attributes.order_position')))
36✔
257
                                ->required(function (Get $get) {
36✔
258
                                    $sibling = $get('order_sibling_form');
36✔
259
                                    return $sibling !== null && $sibling !== '';
36✔
260
                                }),
36✔
261
                            Forms\Components\Select::make('order_sibling_form')
36✔
262
                                ->selectablePlaceholder()
36✔
263
                                ->live()
36✔
264
                                ->disabled(function (Get $get) {
36✔
265
                                    return $get('order_position_form') === 'hidden'
36✔
266
                                        || $get('order_position_form') == null;
36✔
267
                                })
36✔
268
                                ->placeholder(ucfirst(__('filament-user-attributes::user-attributes.select_sibling')))
36✔
269
                                ->options(function () use ($configModel) {
36✔
270
                                    $fields = $configModel->resource_type::getFieldsForOrdering();
36✔
271
                                    $fields = array_combine(array_column($fields, 'label'), array_column($fields, 'label'));
36✔
272
                                    return $fields;
36✔
273
                                })
36✔
274
                                ->helperText(ucfirst(__('filament-user-attributes::user-attributes.order_sibling_help')))
36✔
275
                                ->label(ucfirst(__('filament-user-attributes::user-attributes.attributes.order_sibling'))),
36✔
276
                        ];
36✔
277
                    }),
36✔
278
                Forms\Components\Fieldset::make('ordering_table')
36✔
279
                    ->label(ucfirst(__('filament-user-attributes::user-attributes.ordering_table')))
36✔
280
                    ->schema(function () use ($configModel) {
36✔
281
                        return [
36✔
282
                            Forms\Components\Select::make('order_position_table')
36✔
283
                                ->options([
36✔
284
                                    'before' => __('filament-user-attributes::user-attributes.attributes.order_position_before'),
36✔
285
                                    'after' => __('filament-user-attributes::user-attributes.attributes.order_position_after'),
36✔
286
                                    'hidden' => __('filament-user-attributes::user-attributes.attributes.order_position_hidden'),
36✔
287
                                ])
36✔
288
                                ->placeholder(ucfirst(__('filament-user-attributes::user-attributes.attributes.order_sibling_at_end')))
36✔
289
                                ->selectablePlaceholder()
36✔
290
                                ->live()
36✔
291
                                ->label(ucfirst(__('filament-user-attributes::user-attributes.attributes.order_position')))
36✔
292
                                ->required(function (Get $get) {
36✔
293
                                    $sibling = $get('order_sibling_table');
36✔
294
                                    return $sibling !== null && $sibling !== '';
36✔
295
                                }),
36✔
296
                            Forms\Components\Select::make('order_sibling_table')
36✔
297
                                ->selectablePlaceholder()
36✔
298
                                ->live()
36✔
299
                                ->disabled(function (Get $get) {
36✔
300
                                    return $get('order_position_table') === 'hidden'
36✔
301
                                        || $get('order_position_table') == null;
36✔
302
                                })
36✔
303
                                ->placeholder(ucfirst(__('filament-user-attributes::user-attributes.select_sibling')))
36✔
304
                                ->options(function () use ($configModel) {
36✔
305
                                    $columns = $configModel->resource_type::getColumnsForOrdering();
36✔
306
                                    $columns = array_combine(array_column($columns, 'label'), array_column($columns, 'label'));
36✔
307
                                    return $columns;
36✔
308
                                })
36✔
309
                                ->helperText(ucfirst(__('filament-user-attributes::user-attributes.order_sibling_help')))
36✔
310
                                ->label(ucfirst(__('filament-user-attributes::user-attributes.attributes.order_sibling'))),
36✔
311
                        ];
36✔
312
                    }),
36✔
313
            ]);
36✔
314

315
        return $schemas;
36✔
316
    }
317
}
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

© 2026 Coveralls, Inc