33namespace Kirschbaum \Loop \Filament ;
44
55use Exception ;
6+ use Filament \Resources \Pages \ListRecords ;
7+ use Filament \Resources \Pages \PageRegistration ;
8+ use Filament \Resources \Resource ;
69use Filament \Tables \Columns \Column ;
710use Illuminate \Database \Eloquent \Model ;
811use Illuminate \Support \Facades \Log ;
1114use Kirschbaum \Loop \Contracts \Tool ;
1215use Kirschbaum \Loop \Exceptions \LoopMcpException ;
1316use Kirschbaum \Loop \Filament \Concerns \ProvidesFilamentResourceInstance ;
17+ use Kirschbaum \Loop \Filament \Exceptions \FilamentResourceIndexPageDoesNotExist ;
1418use Prism \Prism \Tool as PrismTool ;
19+ use Throwable ;
1520
1621class GetFilamentResourceDataTool implements Tool
1722{
@@ -23,19 +28,17 @@ public function build(): PrismTool
2328 return app (PrismTool::class)
2429 ->as ($ this ->getName ())
2530 ->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. ' )
2732 ->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 ) {
2936 $ resource = $ this ->getResourceInstance ($ resource );
3037 $ filters = $ this ->parseFilters ($ filters );
3138
3239 try {
33- $ listPageClass = $ resource ::getPages ()['index ' ];
34- $ component = $ listPageClass ->getPage ();
40+ $ listPage = $ this ->getListPage ($ resource );
3541
36- /** @var InteractsWithTable $listPage */
37- $ listPage = new $ component ;
38- $ listPage ->bootedInteractsWithTable ();
3942 $ table = $ listPage ->getTable ();
4043 $ tableColumns = $ table ->getColumns ();
4144
@@ -69,42 +72,50 @@ public function build(): PrismTool
6972 }
7073 }
7174
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 ()}" );
94107 }
95- } else {
96- $ value = $ model ->getAttribute ($ columnName );
97108 }
98109
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+ }),
105112
106- return $ rowData ;
107- });
113+ 'pagination ' => [
114+ 'total ' => $ results ->total (),
115+ 'per_page ' => $ results ->perPage (),
116+ 'current_page ' => $ results ->currentPage (),
117+ ],
118+ ];
108119
109120 return json_encode ($ outputData );
110121 } catch (Exception $ e ) {
@@ -144,4 +155,35 @@ protected function parseFilters(?string $filtersJson = null): array
144155
145156 return $ filters ;
146157 }
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+ }
147189}
0 commit comments