1+ <?php
2+
3+ namespace Vormkracht10 \FilamentFields \Filament \RelationManagers ;
4+
5+ use Filament \Tables ;
6+ use Filament \Forms \Get ;
7+ use Filament \Forms \Set ;
8+ use Livewire \Component ;
9+ use Filament \Forms \Form ;
10+ use Filament \Tables \Table ;
11+ use Illuminate \Support \Str ;
12+ use Filament \Forms \Components \Grid ;
13+ use Filament \Forms \Components \Select ;
14+ use Filament \Forms \Components \Section ;
15+ use Illuminate \Database \Eloquent \Model ;
16+ use Filament \Forms \Components \TextInput ;
17+ use Vormkracht10 \FilamentFields \Models \Field ;
18+ use Filament \Resources \RelationManagers \RelationManager ;
19+ use Vormkracht10 \Fields \Facades \Fields ;
20+ use Vormkracht10 \FilamentFields \Concerns \HasFieldTypeResolver ;
21+ use Vormkracht10 \FilamentFields \Concerns \HasConfigurableFields ;
22+
23+ class FieldsRelationManager extends RelationManager
24+ {
25+ use HasConfigurableFields;
26+ use HasFieldTypeResolver;
27+
28+ protected static string $ relationship = 'fields ' ;
29+
30+ public function form (Form $ form ): Form
31+ {
32+ return $ form
33+ ->schema ([
34+ Grid::make ()
35+ ->columns (3 )
36+ ->schema ([
37+ Section::make ('Field ' )
38+ ->columns (3 )
39+ ->schema ([
40+ TextInput::make ('name ' )
41+ ->label (__ ('Name ' ))
42+ ->required ()
43+ ->placeholder (__ ('Name ' ))
44+ ->live (debounce: 250 )
45+ ->afterStateUpdated (fn (Set $ set , ?string $ state ) => $ set ('slug ' , Str::slug ($ state ))),
46+
47+ TextInput::make ('slug ' )
48+ ->readonly (),
49+
50+ Select::make ('field_type ' )
51+ ->searchable ()
52+ ->preload ()
53+ ->label (__ ('Field Type ' ))
54+ ->live (debounce: 250 )
55+ ->reactive ()
56+ ->options (
57+ function () {
58+ $ options = array_merge (
59+ Field::array (),
60+ $ this ->prepareCustomFieldOptions (Fields::getFields ())
61+ );
62+
63+ asort ($ options );
64+
65+ return $ options ;
66+ }
67+ )
68+ ->required ()
69+ ->afterStateUpdated (function ($ state , Set $ set ) {
70+ $ set ('config ' , []);
71+
72+ $ set ('config ' , $ this ->initializeConfig ($ state ));
73+ }),
74+ ]),
75+ Section::make ('Configuration ' )
76+ ->columns (3 )
77+ ->schema (fn (Get $ get ) => $ this ->getFieldTypeFormSchema (
78+ $ get ('field_type ' )
79+ ))
80+ ->visible (fn (Get $ get ) => filled ($ get ('field_type ' ))),
81+ ]),
82+ ]);
83+ }
84+
85+ private function formatCustomFields (array $ fields ): array
86+ {
87+ return collect ($ fields )->mapWithKeys (function ($ field , $ key ) {
88+ $ parts = explode ('\\' , $ field );
89+ $ lastPart = end ($ parts );
90+ $ formattedName = Str::title (Str::snake ($ lastPart , ' ' ));
91+
92+ return [$ key => $ formattedName ];
93+ })->toArray ();
94+ }
95+
96+ private function initializeDefaultConfig (string $ fieldType ): array
97+ {
98+ $ className = 'Vormkracht10 \\FilamentFields \\Fields \\' . Str::studly ($ fieldType );
99+
100+ if (! class_exists ($ className )) {
101+ return [];
102+ }
103+
104+ $ fieldInstance = app ($ className );
105+
106+ return $ fieldInstance ::getDefaultConfig ();
107+ }
108+
109+ private function initializeCustomConfig (string $ fieldType ): array
110+ {
111+ $ className = Fields::getFields ()[$ fieldType ] ?? null ;
112+
113+ if (! class_exists ($ className )) {
114+ return [];
115+ }
116+
117+ $ fieldInstance = app ($ className );
118+
119+ return $ fieldInstance ::getDefaultConfig ();
120+ }
121+
122+ public function table (Table $ table ): Table
123+ {
124+ return $ table
125+ ->recordTitleAttribute ('name ' )
126+ ->reorderable ('position ' )
127+ ->defaultSort ('position ' , 'asc ' )
128+ ->columns ([
129+ Tables \Columns \TextColumn::make ('name ' )
130+ ->label (__ ('Name ' ))
131+ ->searchable ()
132+ ->limit (),
133+
134+ Tables \Columns \TextColumn::make ('field_type ' )
135+ ->label (__ ('Type ' ))
136+ ->searchable (),
137+ ])
138+ ->filters ([])
139+ ->headerActions ([
140+ Tables \Actions \CreateAction::make ()
141+ ->slideOver ()
142+ ->mutateFormDataUsing (function (array $ data ) {
143+ return [
144+ ...$ data ,
145+ 'position ' => Field::where ('model_key ' , $ this ->ownerRecord ->id )->get ()->max ('position ' ) + 1 ,
146+ 'model_type ' => 'setting ' ,
147+ 'model_key ' => $ this ->ownerRecord ->slug ,
148+ ];
149+ })
150+ ->after (function (Component $ livewire ) {
151+ $ livewire ->dispatch ('refreshFields ' );
152+ }),
153+ ])
154+ ->actions ([
155+ Tables \Actions \EditAction::make ()
156+ ->slideOver ()
157+ ->mutateRecordDataUsing (function (array $ data ) {
158+ return [
159+ ...$ data ,
160+ 'model_type ' => 'setting ' ,
161+ 'model_key ' => $ this ->ownerRecord ->slug ,
162+ ];
163+ })
164+ ->mutateFormDataUsing (fn (array $ data , Model $ record ): array => $ this ->transferValuesOnSlugChange ($ data , $ record ))
165+ ->after (function (Component $ livewire ) {
166+ $ livewire ->dispatch ('refreshFields ' );
167+ }),
168+ Tables \Actions \DeleteAction::make ()
169+ ->after (function (Component $ livewire , array $ data , Model $ record , array $ arguments ) {
170+ $ this ->ownerRecord ->update ([
171+ 'values ' => collect ($ this ->ownerRecord ->values )->forget ($ record ->slug )->toArray (),
172+ ]);
173+ $ livewire ->dispatch ('refreshFields ' );
174+ }),
175+ ])
176+ ->bulkActions ([
177+ Tables \Actions \BulkActionGroup::make ([
178+ Tables \Actions \DeleteBulkAction::make ()
179+ ->after (function (Component $ livewire ) {
180+ $ livewire ->dispatch ('refreshFields ' );
181+ }),
182+ ]),
183+ ]);
184+ }
185+
186+ public static function getTitle (Model $ ownerRecord , string $ pageClass ): string
187+ {
188+ return __ ('Fields ' );
189+ }
190+
191+ public static function getModelLabel (): string
192+ {
193+ return __ ('Field ' );
194+ }
195+
196+ public static function getPluralModelLabel (): string
197+ {
198+ return __ ('Fields ' );
199+ }
200+
201+ private function transferValuesOnSlugChange (array $ data , Model $ record ): array
202+ {
203+ $ oldSlug = $ record ->slug ;
204+ $ newSlug = $ data ['slug ' ];
205+
206+ if ($ newSlug === $ oldSlug ) {
207+ return $ data ;
208+ }
209+
210+ $ existingValues = $ this ->ownerRecord ->values ;
211+
212+ // Handle slug update in existing values
213+ if (isset ($ existingValues [$ oldSlug ])) {
214+ // Transfer value from old slug to new slug
215+ $ existingValues [$ newSlug ] = $ existingValues [$ oldSlug ];
216+ unset($ existingValues [$ oldSlug ]);
217+
218+ $ this ->ownerRecord ->update ([
219+ 'values ' => $ existingValues ,
220+ ]);
221+ } else {
222+ $ existingValues [$ newSlug ] = null ;
223+ }
224+
225+ return $ data ;
226+ }
227+ }
0 commit comments