3
3
namespace Kirschbaum \Loop \Filament ;
4
4
5
5
use Exception ;
6
+ use Filament \Pages \Page ;
7
+ use Filament \Resources \Pages \ListRecords ;
8
+ use Filament \Resources \Pages \PageRegistration ;
9
+ use Filament \Resources \Resource ;
6
10
use Filament \Tables \Columns \Column ;
11
+ use Filament \Tables \TableComponent ;
7
12
use Illuminate \Database \Eloquent \Model ;
8
13
use Illuminate \Support \Facades \Log ;
9
14
use JsonException ;
10
15
use Kirschbaum \Loop \Concerns \Makeable ;
11
16
use Kirschbaum \Loop \Contracts \Tool ;
12
17
use Kirschbaum \Loop \Exceptions \LoopMcpException ;
13
18
use Kirschbaum \Loop \Filament \Concerns \ProvidesFilamentResourceInstance ;
19
+ use Kirschbaum \Loop \Filament \Exceptions \FilamentResourceIndexPageDoesNotExist ;
14
20
use Prism \Prism \Tool as PrismTool ;
21
+ use Throwable ;
15
22
16
23
class GetFilamentResourceDataTool implements Tool
17
24
{
@@ -25,17 +32,15 @@ public function build(): PrismTool
25
32
->for ('Gets the data for a given Filament resource, applying optional filters (try to use them). Always call the describe_filament_resource tool before calling this tool. Always try to use the available filters to get the data you need. ' )
26
33
->withStringParameter ('resource ' , 'The resource class name of the resource to get data for, from the list_filament_resources tool. ' , required: true )
27
34
->withStringParameter ('filters ' , 'JSON string of filters to apply (e.g., \'{"status": "published", "author_id": [1, 2]} \'). ' , required: false )
28
- ->using (function (string $ resource , ?string $ filters = null ) {
35
+ ->withNumberParameter ('perPage ' , 'The resource data is paginated. This is the number of records per page. It defaults to 10 ' , required: false )
36
+ ->withNumberParameter ('page ' , 'The resource data is paginated. This is the page the paginated results should be from. ' , required: false )
37
+ ->using (function (string $ resource , ?string $ filters = null , ?int $ perPage = 10 , ?int $ page = null ) {
29
38
$ resource = $ this ->getResourceInstance ($ resource );
30
39
$ filters = $ this ->parseFilters ($ filters );
31
40
32
41
try {
33
- $ listPageClass = $ resource ::getPages ()['index ' ];
34
- $ component = $ listPageClass ->getPage ();
42
+ $ listPage = $ this ->getListPage ($ resource );
35
43
36
- /** @var InteractsWithTable $listPage */
37
- $ listPage = new $ component ;
38
- $ listPage ->bootedInteractsWithTable ();
39
44
$ table = $ listPage ->getTable ();
40
45
$ tableColumns = $ table ->getColumns ();
41
46
@@ -69,42 +74,50 @@ public function build(): PrismTool
69
74
}
70
75
}
71
76
72
- // TODO: Allow the tool to specify the number of results to return with a max
73
- $ results = $ listPage ->getFilteredTableQuery ()->take (10 )->get ();
74
-
75
- $ outputData = $ results ->map (function (Model $ model ) use ($ tableColumns ) {
76
- $ rowData = [
77
- $ model ->getKeyName () => $ model ->getKey (),
78
- ];
79
-
80
- foreach ($ tableColumns as $ column ) {
81
- /** @var Column $column */
82
- $ columnName = $ column ->getName ();
83
-
84
- try {
85
- if (str_contains ($ columnName , '. ' )) {
86
- $ relationName = strtok ($ columnName , '. ' );
87
-
88
- if (method_exists ($ model , $ relationName )) {
89
- $ model ->loadMissing ($ relationName );
90
- $ value = data_get ($ model , $ columnName );
91
- } else {
92
- $ value = null ;
93
- Log::warning ("Relation ' {$ relationName }' not found on model for column ' {$ columnName }'. " );
77
+ $ results = $ listPage ->getFilteredTableQuery ()->paginate (perPage: $ perPage , page: $ page );
78
+
79
+ $ outputData = [
80
+ 'data ' => $ results ->getCollection ()
81
+ ->map (function (Model $ model ) use ($ tableColumns ) {
82
+ $ rowData = [
83
+ $ model ->getKeyName () => $ model ->getKey (),
84
+ ];
85
+
86
+ foreach ($ tableColumns as $ column ) {
87
+ /** @var Column $column */
88
+ $ columnName = $ column ->getName ();
89
+
90
+ try {
91
+ if (str_contains ($ columnName , '. ' )) {
92
+ $ relationName = strtok ($ columnName , '. ' );
93
+
94
+ if (method_exists ($ model , $ relationName )) {
95
+ $ model ->loadMissing ($ relationName );
96
+ $ value = data_get ($ model , $ columnName );
97
+ } else {
98
+ $ value = null ;
99
+ Log::warning ("Relation ' {$ relationName }' not found on model for column ' {$ columnName }'. " );
100
+ }
101
+ } else {
102
+ $ value = $ model ->getAttribute ($ columnName );
103
+ }
104
+
105
+ $ rowData [$ columnName ] = $ value ;
106
+ } catch (Exception $ e ) {
107
+ $ rowData [$ columnName ] = null ;
108
+ Log::error ("Could not retrieve value for column ' {$ columnName }' on model ID {$ model ->getKey ()}': {$ e ->getMessage ()}" );
94
109
}
95
- } else {
96
- $ value = $ model ->getAttribute ($ columnName );
97
110
}
98
111
99
- $ rowData [$ columnName ] = $ value ;
100
- } catch (Exception $ e ) {
101
- $ rowData [$ columnName ] = null ;
102
- Log::error ("Could not retrieve value for column ' {$ columnName }' on model ID {$ model ->getKey ()}': {$ e ->getMessage ()}" );
103
- }
104
- }
112
+ return $ rowData ;
113
+ }),
105
114
106
- return $ rowData ;
107
- });
115
+ 'pagination ' => [
116
+ 'total ' => $ results ->total (),
117
+ 'per_page ' => $ results ->perPage (),
118
+ 'current_page ' => $ results ->currentPage (),
119
+ ],
120
+ ];
108
121
109
122
return json_encode ($ outputData );
110
123
} catch (Exception $ e ) {
@@ -144,4 +157,35 @@ protected function parseFilters(?string $filtersJson = null): array
144
157
145
158
return $ filters ;
146
159
}
160
+
161
+ /**
162
+ * @throws Throwable
163
+ */
164
+ protected function getListPage (Resource $ resource ): ListRecords
165
+ {
166
+ /**
167
+ * @var ?PageRegistration $listPageClass
168
+ */
169
+ $ listPageClass = data_get ($ resource ::getPages (), 'index ' );
170
+
171
+ throw_unless (
172
+ $ listPageClass instanceof PageRegistration,
173
+ FilamentResourceIndexPageDoesNotExist::class,
174
+ 'No index page exists for [ ' .get_class ($ resource ).'] '
175
+ );
176
+
177
+ /**
178
+ * @var class-string<ListRecords> $component
179
+ */
180
+ $ component = $ listPageClass ->getPage ();
181
+
182
+ /**
183
+ * @var ListRecords $listPage
184
+ */
185
+ $ listPage = new $ component ;
186
+
187
+ $ listPage ->bootedInteractsWithTable ();
188
+
189
+ return $ listPage ;
190
+ }
147
191
}
0 commit comments