44
55namespace Relaticle \Flowforge \Adapters ;
66
7- use Filament \Forms \Form ;
87use Illuminate \Database \Eloquent \Builder ;
9- use Illuminate \Database \Eloquent \Model ;
10- use Illuminate \Support \Collection ;
118use Livewire \Wireable ;
129use Relaticle \Flowforge \Config \KanbanConfig ;
1310use Relaticle \Flowforge \Contracts \KanbanAdapterInterface ;
14-
11+ use Relaticle \Flowforge \Concerns \CardFormattingTrait ;
12+ use Relaticle \Flowforge \Concerns \CrudOperationsTrait ;
13+ use Relaticle \Flowforge \Concerns \FormHandlingTrait ;
14+ use Relaticle \Flowforge \Concerns \QueryHandlingTrait ;
15+
16+ /**
17+ * Abstract base class for Kanban adapters.
18+ *
19+ * This class has been refactored to use traits for better separation of concerns:
20+ * - QueryHandlingTrait: For database query operations
21+ * - CardFormattingTrait: For formatting models as cards
22+ * - CrudOperationsTrait: For card CRUD operations
23+ * - FormHandlingTrait: For form generation and handling
24+ */
1525abstract class AbstractKanbanAdapter implements KanbanAdapterInterface, Wireable
1626{
27+ use QueryHandlingTrait;
28+ use CardFormattingTrait;
29+ use CrudOperationsTrait;
30+ use FormHandlingTrait;
31+
1732 /**
1833 * The base Eloquent query builder.
1934 *
@@ -28,132 +43,7 @@ public function __construct(
2843 Builder $ query ,
2944 public KanbanConfig $ config
3045 ) {
31- }
32-
33- /**
34- * Get a new query builder, cloned from the base query.
35- */
36- protected function newQuery (): Builder
37- {
38- return clone $ this ->baseQuery ;
39- }
40-
41- /**
42- * Find a model by its ID.
43- *
44- * @param mixed $id The model ID
45- */
46- public function getModelById (mixed $ id ): ?Model
47- {
48- // Just find by ID without additional filters from the base query
49- // This ensures we can find models by ID regardless of the base query filters
50- return $ this ->baseQuery ->getModel ()::query ()->find ($ id );
51- }
52-
53- /**
54- * Get all items for the Kanban board.
55- */
56- public function getItems (): Collection
57- {
58- $ query = $ this ->newQuery ();
59- $ orderField = $ this ->config ->getOrderField ();
60-
61- if ($ orderField !== null ) {
62- $ query ->orderBy ($ orderField );
63- }
64-
65- $ models = $ query ->get ();
66-
67- return $ this ->formatCardsForDisplay ($ models );
68- }
69-
70- /**
71- * Get items for a specific column with pagination.
72- *
73- * @param string|int $columnId The column ID
74- * @param int $limit The number of items to return
75- */
76- public function getItemsForColumn (string |int $ columnId , int $ limit = 10 ): Collection
77- {
78- $ columnField = $ this ->config ->getColumnField ();
79- $ orderField = $ this ->config ->getOrderField ();
80-
81- $ query = $ this ->newQuery ()->where ($ columnField , $ columnId );
82-
83- if ($ orderField !== null ) {
84- $ query ->orderBy ($ orderField );
85- }
86-
87- $ models = $ query ->limit ($ limit )->get ();
88-
89- return $ this ->formatCardsForDisplay ($ models );
90- }
91-
92- /**
93- * Get the total count of items for a specific column.
94- *
95- * @param string|int $columnId The column ID
96- */
97- public function getColumnItemsCount (string |int $ columnId ): int
98- {
99- $ columnField = $ this ->config ->getColumnField ();
100-
101- return $ this ->newQuery ()
102- ->where ($ columnField , $ columnId )
103- ->count ();
104- }
105-
106- /**
107- * Create a new card with the given attributes.
108- *
109- * @param array<string, mixed> $attributes The card attributes
110- */
111- public function createCard (array $ attributes ): ?Model
112- {
113- $ model = $ this ->baseQuery ->getModel ()->newInstance ();
114-
115- // Apply any scopes from the base query if applicable
116- // For example, if the base query filters by user_id, we want to set that on the new model
117- $ wheres = $ this ->baseQuery ->getQuery ()->wheres ;
118-
119- foreach ($ wheres as $ where ) {
120- if (isset ($ where ['column ' ]) && isset ($ where ['value ' ]) && $ where ['type ' ] === 'Basic ' ) {
121- // If the filter is a basic where clause, apply it to the new model
122- // This ensures models created through this adapter respect the base query conditions
123- $ model ->{$ where ['column ' ]} = $ where ['value ' ];
124- }
125- }
126-
127- $ model ->fill ($ attributes );
128-
129- if ($ model ->save ()) {
130- return $ model ;
131- }
132-
133- return null ;
134- }
135-
136- /**
137- * Update an existing card with the given attributes.
138- *
139- * @param Model $card The card to update
140- * @param array<string, mixed> $attributes The card attributes to update
141- */
142- public function updateCard (Model $ card , array $ attributes ): bool
143- {
144- $ card ->fill ($ attributes );
145-
146- return $ card ->save ();
147- }
148-
149- /**
150- * Delete an existing card.
151- *
152- * @param Model $card The card to delete
153- */
154- public function deleteCard (Model $ card ): bool
155- {
156- return $ card ->delete ();
46+ $ this ->baseQuery = $ query ;
15747 }
15848
15949 /**
@@ -165,135 +55,7 @@ public function getConfig(): KanbanConfig
16555 }
16656
16757 /**
168- * Get the form for creating cards.
169- *
170- * @param Form $form The form instance
171- * @param mixed $activeColumn The active column
172- */
173- public function getCreateForm (Form $ form , mixed $ activeColumn ): Form
174- {
175- // Fall back to default create form implementation
176- $ titleField = $ this ->config ->getTitleField ();
177- $ descriptionField = $ this ->config ->getDescriptionField ();
178-
179- $ schema = KanbanConfig::getDefaultCreateFormSchema ($ titleField , $ descriptionField );
180-
181- // For create form, set the column field value based on the active column
182- // but hide it from the form as it's determined by where the user clicked
183- if ($ activeColumn ) {
184- $ form ->statePath (null );
185- }
186-
187- return $ form ->schema ($ schema );
188- }
189-
190- /**
191- * Get the form for editing cards.
192- *
193- * @param Form $form The form instance
194- */
195- public function getEditForm (Form $ form ): Form
196- {
197- // Fall back to default edit form implementation
198- $ titleField = $ this ->config ->getTitleField ();
199- $ descriptionField = $ this ->config ->getDescriptionField ();
200- $ columnField = $ this ->config ->getColumnField ();
201- $ columnValues = $ this ->config ->getColumnValues ();
202-
203- $ schema = KanbanConfig::getDefaultEditFormSchema (
204- $ titleField ,
205- $ descriptionField ,
206- $ columnField ,
207- $ columnValues
208- );
209-
210- return $ form ->schema ($ schema );
211- }
212-
213- /**
214- * Format a model as a card for display.
215- *
216- * @param Model $model The model to format
217- * @return array<string, mixed> The formatted card
218- */
219- protected function formatCardForDisplay (Model $ model ): array
220- {
221- $ titleField = $ this ->config ->getTitleField ();
222- $ descriptionField = $ this ->config ->getDescriptionField ();
223- $ cardAttributes = $ this ->config ->getCardAttributes ();
224- $ columnField = $ this ->config ->getColumnField ();
225-
226- $ card = [
227- 'id ' => $ model ->getKey (),
228- 'title ' => $ model ->{$ titleField },
229- 'column ' => $ model ->{$ columnField },
230- ];
231-
232- if ($ descriptionField !== null && isset ($ model ->{$ descriptionField })) {
233- $ card ['description ' ] = $ model ->{$ descriptionField };
234- }
235-
236- foreach ($ cardAttributes as $ key => $ label ) {
237- $ field = is_string ($ key ) ? $ key : $ label ;
238- $ card ['attributes ' ][$ field ] = [
239- 'label ' => is_string ($ key ) ? $ label : $ field ,
240- 'value ' => $ model ->{$ field },
241- ];
242- }
243-
244- return $ card ;
245- }
246-
247- /**
248- * Format a collection of models as cards for display.
249- *
250- * @param Collection $models The models to format
251- * @return Collection The formatted cards
252- */
253- protected function formatCardsForDisplay (Collection $ models ): Collection
254- {
255- return $ models ->map (fn (Model $ model ) => $ this ->formatCardForDisplay ($ model ));
256- }
257-
258- /**
259- * Update the order of cards in a column.
260- *
261- * @param string|int $columnId The column ID
262- * @param array<int, mixed> $cardIds The card IDs in their new order
263- * @return bool Whether the operation was successful
264- */
265- public function updateCardsOrderAndColumn (string |int $ columnId , array $ cardIds ): bool
266- {
267- $ orderField = $ this ->config ->getOrderField ();
268- $ columnField = $ this ->config ->getColumnField ();
269- $ success = true ;
270-
271- foreach ($ cardIds as $ index => $ cardId ) {
272- $ model = $ this ->getModelById ($ cardId );
273-
274- if ($ model === null ) {
275- $ success = false ;
276- continue ;
277- }
278-
279- if ($ orderField !== null ) {
280- $ model ->{$ orderField } = $ index + 1 ;
281- }
282- $ model ->{$ columnField } = $ columnId ;
283-
284- if (!$ model ->save ()) {
285- $ success = false ;
286- }
287- }
288-
289- return $ success ;
290- }
291-
292-
293- /**
294- * Convert the adapter to a Livewire-compatible array.
295- *
296- * @return array<string, mixed>
58+ * @return array
29759 */
29860 public function toLivewire (): array
29961 {
@@ -304,9 +66,7 @@ public function toLivewire(): array
30466 }
30567
30668 /**
307- * Create a new adapter instance from a Livewire-compatible array.
308- *
309- * @param array<string, mixed> $value The Livewire-compatible array
69+ * @param $value
31070 * @return static
31171 */
31272 public static function fromLivewire ($ value ): static
0 commit comments