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