33namespace Kirschbaum \Loop \Filament ;
44
55use Exception ;
6+ use Filament \Pages \Page ;
7+ use Filament \Resources \Pages \ListRecords ;
8+ use Filament \Resources \Pages \PageRegistration ;
9+ use Filament \Resources \Resource ;
610use Filament \Tables \Columns \Column ;
11+ use Filament \Tables \TableComponent ;
712use Illuminate \Database \Eloquent \Model ;
813use Illuminate \Support \Facades \Log ;
914use JsonException ;
1015use Kirschbaum \Loop \Concerns \Makeable ;
1116use Kirschbaum \Loop \Contracts \Tool ;
1217use Kirschbaum \Loop \Exceptions \LoopMcpException ;
1318use Kirschbaum \Loop \Filament \Concerns \ProvidesFilamentResourceInstance ;
19+ use Kirschbaum \Loop \Filament \Exceptions \FilamentResourceIndexPageDoesNotExist ;
1420use Prism \Prism \Tool as PrismTool ;
21+ use Throwable ;
1522
1623class GetFilamentResourceDataTool implements Tool
1724{
@@ -25,17 +32,15 @@ public function build(): PrismTool
2532 ->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. ' )
2633 ->withStringParameter ('resource ' , 'The resource class name of the resource to get data for, from the list_filament_resources tool. ' , required: true )
2734 ->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 ) {
2938 $ resource = $ this ->getResourceInstance ($ resource );
3039 $ filters = $ this ->parseFilters ($ filters );
3140
3241 try {
33- $ listPageClass = $ resource ::getPages ()['index ' ];
34- $ component = $ listPageClass ->getPage ();
42+ $ listPage = $ this ->getListPage ($ resource );
3543
36- /** @var InteractsWithTable $listPage */
37- $ listPage = new $ component ;
38- $ listPage ->bootedInteractsWithTable ();
3944 $ table = $ listPage ->getTable ();
4045 $ tableColumns = $ table ->getColumns ();
4146
@@ -69,42 +74,50 @@ public function build(): PrismTool
6974 }
7075 }
7176
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 ()}" );
94109 }
95- } else {
96- $ value = $ model ->getAttribute ($ columnName );
97110 }
98111
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+ }),
105114
106- return $ rowData ;
107- });
115+ 'pagination ' => [
116+ 'total ' => $ results ->total (),
117+ 'per_page ' => $ results ->perPage (),
118+ 'current_page ' => $ results ->currentPage (),
119+ ],
120+ ];
108121
109122 return json_encode ($ outputData );
110123 } catch (Exception $ e ) {
@@ -144,4 +157,35 @@ protected function parseFilters(?string $filtersJson = null): array
144157
145158 return $ filters ;
146159 }
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+ }
147191}
0 commit comments