Skip to content

Commit e600b34

Browse files
committed
fix: actions
1 parent b44d8cc commit e600b34

File tree

7 files changed

+256
-149
lines changed

7 files changed

+256
-149
lines changed

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
composer update --prefer-stable --prefer-dist --no-interaction
3535
3636
- name: Execute tests
37-
run: ./vendor/bin/testbench package:test --no-coverage
37+
run: composer test
3838

3939
- name: Get next version
4040
id: get_version

src/Actions/Action.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,21 @@ public static function indexQuery(RestifyRequest $request, $query)
5858
*/
5959
public ?Closure $runCallback = null;
6060

61+
/**
62+
* Action description, usually used in the UI or MCP.
63+
*/
64+
public string $description = '';
65+
6166
public function name()
6267
{
6368
return Restify::humanize($this);
6469
}
6570

71+
public function description(RestifyRequest $request): string
72+
{
73+
return $this->description;
74+
}
75+
6676
/**
6777
* Get the URI key for the action.
6878
*/
@@ -196,6 +206,7 @@ public function jsonSerialize()
196206
{
197207
return array_merge([
198208
'name' => $this->name(),
209+
'description' => $this->description(app(RestifyRequest::class)),
199210
'destructive' => $this instanceof DestructiveAction,
200211
'uriKey' => $this->uriKey(),
201212
'payload' => $this->payload(),

src/Fields/Field.php

Lines changed: 0 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -769,135 +769,6 @@ public function image(): Image
769769
return Image::make($this->attribute);
770770
}
771771

772-
/**
773-
* Guess the field type based on validation rules, field class, and attribute patterns.
774-
*/
775-
public function guessFieldType(): string
776-
{
777-
$ruleType = $this->guessTypeFromValidationRules();
778-
if ($ruleType) {
779-
return $ruleType;
780-
}
781-
782-
// Check attribute name patterns
783-
$attributeType = $this->guessTypeFromAttributeName();
784-
if ($attributeType) {
785-
return $attributeType;
786-
}
787-
788-
// Default to string
789-
return 'string';
790-
}
791-
792-
/**
793-
* Guess type from validation rules.
794-
*/
795-
protected function guessTypeFromValidationRules(): ?string
796-
{
797-
$allRules = array_merge($this->rules, $this->storingRules, $this->updatingRules);
798-
799-
// Convert rule objects to strings for checking
800-
$ruleStrings = collect($allRules)->map(function ($rule) {
801-
if (is_string($rule)) {
802-
return $rule;
803-
}
804-
if (is_object($rule)) {
805-
return get_class($rule);
806-
}
807-
808-
return (string) $rule;
809-
})->toArray();
810-
811-
// Check for specific types
812-
if ($this->hasAnyRule($ruleStrings, ['boolean', 'bool'])) {
813-
return 'boolean';
814-
}
815-
816-
if ($this->hasAnyRule($ruleStrings, ['email', 'url', 'ip', 'uuid', 'string', 'regex', 'array'])) {
817-
return 'string';
818-
}
819-
820-
if ($this->hasAnyRule($ruleStrings, ['date', 'date_format:', 'before:', 'after:', 'before_or_equal:', 'after_or_equal:'])) {
821-
return 'string'; // Dates are typically handled as strings in schemas
822-
}
823-
824-
if ($this->hasAnyRule($ruleStrings, ['file', 'image', 'mimes:', 'mimetypes:'])) {
825-
return 'string'; // Files are typically handled as strings (paths/URLs)
826-
}
827-
828-
if ($this->hasAnyRule($ruleStrings, ['integer', 'int', 'numeric', 'between:'])) {
829-
return 'number';
830-
}
831-
832-
return null;
833-
}
834-
835-
/**
836-
* Guess type from attribute name patterns.
837-
*/
838-
protected function guessTypeFromAttributeName(): ?string
839-
{
840-
$attribute = $this->attribute;
841-
842-
if (! is_string($attribute)) {
843-
return null;
844-
}
845-
846-
$attribute = strtolower($attribute);
847-
848-
// Boolean patterns
849-
if (preg_match('/^(is_|has_|can_|should_|will_|was_|were_)/', $attribute) ||
850-
in_array($attribute, ['active', 'enabled', 'disabled', 'verified', 'published', 'featured', 'public', 'private'])) {
851-
return 'boolean';
852-
}
853-
854-
// Number patterns
855-
if (preg_match('/_(id|count|number|amount|price|cost|total|sum|quantity|qty)$/', $attribute) ||
856-
in_array($attribute, ['id', 'age', 'year', 'month', 'day', 'hour', 'minute', 'second', 'weight', 'height', 'size'])) {
857-
return 'number';
858-
}
859-
860-
// Date patterns
861-
if (preg_match('/_(at|date|time)$/', $attribute) ||
862-
in_array($attribute, ['created_at', 'updated_at', 'deleted_at', 'published_at', 'birthday', 'date_of_birth'])) {
863-
return 'string';
864-
}
865-
866-
// Email pattern
867-
if (str_contains($attribute, 'email')) {
868-
return 'string';
869-
}
870-
871-
// Password pattern
872-
if (str_contains($attribute, 'password')) {
873-
return 'string';
874-
}
875-
876-
// Array patterns (JSON fields)
877-
if (preg_match('/_(json|data|metadata|config|settings|options)$/', $attribute) ||
878-
str_contains($attribute, 'tags')) {
879-
return 'array';
880-
}
881-
882-
return null;
883-
}
884-
885-
/**
886-
* Check if any of the given rules exist in the rule strings.
887-
*/
888-
protected function hasAnyRule(array $ruleStrings, array $rulesToCheck): bool
889-
{
890-
foreach ($ruleStrings as $rule) {
891-
foreach ($rulesToCheck as $check) {
892-
if ($rule === $check || str_starts_with($rule, $check)) {
893-
return true;
894-
}
895-
}
896-
}
897-
898-
return false;
899-
}
900-
901772
/**
902773
* Set a custom callback for defining the tool schema.
903774
*

src/MCP/Concerns/FieldMcpSchemaDetection.php

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
use Illuminate\JsonSchema\JsonSchema;
88
use Illuminate\JsonSchema\Types\Type;
99

10+
/**
11+
* @mixin \Binaryk\LaravelRestify\Fields\Field
12+
*/
1013
trait FieldMcpSchemaDetection
1114
{
1215
/**
@@ -51,6 +54,26 @@ public function resolveJsonSchema(JsonSchema $schema, Repository $repository): ?
5154
return $schemaField;
5255
}
5356

57+
/**
58+
* Guess the field type based on validation rules, field class, and attribute patterns.
59+
*/
60+
public function guessFieldType(): string
61+
{
62+
$ruleType = $this->guessTypeFromValidationRules();
63+
if ($ruleType) {
64+
return $ruleType;
65+
}
66+
67+
// Check attribute name patterns
68+
$attributeType = $this->guessTypeFromAttributeName();
69+
if ($attributeType) {
70+
return $attributeType;
71+
}
72+
73+
// Default to string
74+
return 'string';
75+
}
76+
5477
/**
5578
* Generate a comprehensive description for the field.
5679
*/
@@ -213,4 +236,117 @@ protected function getStringExamples(string $attribute): array
213236

214237
return ['sample text', 'example value'];
215238
}
239+
240+
/**
241+
* Guess type from validation rules.
242+
*/
243+
protected function guessTypeFromValidationRules(): ?string
244+
{
245+
$allRules = array_merge($this->rules, $this->storingRules, $this->updatingRules);
246+
247+
// Convert rule objects to strings for checking
248+
$ruleStrings = collect($allRules)->map(function ($rule) {
249+
if (is_string($rule)) {
250+
return $rule;
251+
}
252+
if (is_object($rule)) {
253+
return get_class($rule);
254+
}
255+
256+
return (string) $rule;
257+
})->toArray();
258+
259+
// Check for specific types
260+
if ($this->hasAnyRule($ruleStrings, ['boolean', 'bool'])) {
261+
return 'boolean';
262+
}
263+
264+
if ($this->hasAnyRule($ruleStrings, ['array'])) {
265+
return 'array';
266+
}
267+
268+
if ($this->hasAnyRule($ruleStrings, ['email', 'url', 'ip', 'uuid', 'string', 'regex'])) {
269+
return 'string';
270+
}
271+
272+
if ($this->hasAnyRule($ruleStrings, ['date', 'date_format:', 'before:', 'after:', 'before_or_equal:', 'after_or_equal:'])) {
273+
return 'string'; // Dates are typically handled as strings in schemas
274+
}
275+
276+
if ($this->hasAnyRule($ruleStrings, ['file', 'image', 'mimes:', 'mimetypes:'])) {
277+
return 'string'; // Files are typically handled as strings (paths/URLs)
278+
}
279+
280+
if ($this->hasAnyRule($ruleStrings, ['integer', 'int', 'numeric', 'between:'])) {
281+
return 'number';
282+
}
283+
284+
return null;
285+
}
286+
287+
/**
288+
* Check if any of the given rules exist in the rule strings.
289+
*/
290+
protected function hasAnyRule(array $ruleStrings, array $rulesToCheck): bool
291+
{
292+
foreach ($ruleStrings as $rule) {
293+
foreach ($rulesToCheck as $check) {
294+
if ($rule === $check || str_starts_with($rule, $check)) {
295+
return true;
296+
}
297+
}
298+
}
299+
300+
return false;
301+
}
302+
303+
/**
304+
* Guess type from attribute name patterns.
305+
*/
306+
protected function guessTypeFromAttributeName(): ?string
307+
{
308+
$attribute = $this->attribute;
309+
310+
if (! is_string($attribute)) {
311+
return null;
312+
}
313+
314+
$attribute = strtolower($attribute);
315+
316+
// Boolean patterns
317+
if (preg_match('/^(is_|has_|can_|should_|will_|was_|were_)/', $attribute) ||
318+
in_array($attribute, ['active', 'enabled', 'disabled', 'verified', 'published', 'featured', 'public', 'private'])) {
319+
return 'boolean';
320+
}
321+
322+
// Number patterns
323+
if (preg_match('/_(id|count|number|amount|price|cost|total|sum|quantity|qty)$/', $attribute) ||
324+
in_array($attribute, ['id', 'age', 'year', 'month', 'day', 'hour', 'minute', 'second', 'weight', 'height', 'size'])) {
325+
return 'number';
326+
}
327+
328+
// Date patterns
329+
if (preg_match('/_(at|date|time)$/', $attribute) ||
330+
in_array($attribute, ['created_at', 'updated_at', 'deleted_at', 'published_at', 'birthday', 'date_of_birth'])) {
331+
return 'string';
332+
}
333+
334+
// Email pattern
335+
if (str_contains($attribute, 'email')) {
336+
return 'string';
337+
}
338+
339+
// Password pattern
340+
if (str_contains($attribute, 'password')) {
341+
return 'string';
342+
}
343+
344+
// Array patterns (JSON fields)
345+
if (preg_match('/_(json|data|metadata|config|settings|options)$/', $attribute) ||
346+
str_contains($attribute, 'tags')) {
347+
return 'array';
348+
}
349+
350+
return null;
351+
}
216352
}

src/MCP/Concerns/McpDestroyTool.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,16 @@ public function deleteTool(McpDestroyRequest $request): array
1616

1717
$model = static::query($request)->findOrFail($id);
1818

19-
return static::resolveWith($model)->destroy($request, $id);
19+
static::resolveWith($model)->destroy($request, $id);
20+
21+
return [
22+
'id' => $id,
23+
'deleted' => true,
24+
];
2025
}
2126

2227
public static function destroyToolSchema(JsonSchema $schema): array
2328
{
24-
$key = static::uriKey();
2529
$modelName = class_basename(static::guessModelClassName());
2630

2731
return [

0 commit comments

Comments
 (0)