Appearance
Anatomía de FormSchema 📝
El motor de formularios de SchemaBuilder resuelve de raíz el problema de duplicidad más costoso del desarrollo web: tener que definir las reglas de validación en el backend (FormRequest) y volver a escribir manualmente los inputs, placeholders, tipos y validaciones en el frontend (Vue, React o Blade).
Con FormSchema, defines la estructura, comportamiento visual y reglas de validación en un único punto canónico.
💡 El Problema Tradicional vs. FormSchema
😫 El Enfoque Tradicional (Fragilidad & Desincronización)
- Creas un
UpdateUserRequesten Laravel con 15 reglas de validación. - Abres un componente de Vue/React y programas a mano 15 campos
<VTextField>,<VSelect>, con sus labels y validaciones en VeeValidate. - Si cambias un campo de
nullablearequired, debes acordarte de actualizar el backend y el frontend. - En endpoints
PATCH, si el usuario sólo actualiza el teléfono, las reglasrequiredde Laravel lanzan un error422 Unprocessable Entityporque faltan el resto de campos.
🚀 La Solución de SchemaBuilder (Fuente Única de Verdad)
- Un solo esquema: Declaras el formulario una sola vez en PHP.
- Frontend agnóstico: El endpoint
/schemaexpone la especificación JSON completa. Tu componente dinámico (<DynamicForm />) renderiza los inputs automáticamente. - Validación nativa compilada: El controlador extrae las reglas directamente del esquema mediante
$schema->toValidationRules(). - Soporte transparente para PATCH: Las mutaciones parciales convierten automáticamente reglas
requiredasometimes|required.
🏗️ Anatomía de una Definición de Formulario
Veamos un ejemplo de un formulario completo con diseño en grid y validaciones:
php
namespace App\Schemas;
use Warrior\SchemaBuilder\Enums\FieldType;
use Warrior\SchemaBuilder\Form\Field;
use Warrior\SchemaBuilder\Form\FormSchema;
class UserSchema
{
public static function form(): FormSchema
{
return FormSchema::make('user-form', 'Gestión de Usuario')
->description('Complete los datos personales y de acceso del usuario.')
->endpoint('/api/v1/users')
->httpMethod('POST')
->submitLabel('Guardar Usuario')
->cancelLabel('Cancelar')
->fields([
Field::text('first_name', 'Nombres')
->placeholder('Ej. Carlos')
->required()
->min(2)
->cols(12)
->md(6),
Field::text('last_name', 'Apellidos')
->placeholder('Ej. Mendoza')
->required()
->min(2)
->cols(12)
->md(6),
Field::email('email', 'Correo Electrónico')
->placeholder('carlos@empresa.com')
->required()
->unique('users', 'email')
->cols(12)
->md(6),
Field::password('password', 'Contraseña')
->placeholder('Mínimo 8 caracteres')
->required()
->min(8)
->cols(12)
->md(6),
Field::select('role_id', 'Rol Asignado')
->options([
['label' => 'Administrador', 'value' => 1],
['label' => 'Operador', 'value' => 2],
['label' => 'Auditor', 'value' => 3],
])
->required()
->cols(12)
->md(6),
Field::switch('is_active', 'Estado Activo')
->defaultValue(true)
->cols(12)
->md(6),
]);
}
}📐 Modos de Maquetación del Formulario
FormSchema soporta 3 estrategias de organización visual según la complejidad de la entidad:
| Estrategia | Método | Cuándo Usarlo | Salida JSON |
|---|---|---|---|
| Plano (Flat) | ->fields([...]) | Formularios simples o modales rápidos (login, contacto, CRUD básico). | "inputs": [...] |
| Pestañas (Tabs) | ->tabs([...]) | Entidades densas con muchas áreas (Datos Generales, Facturación, Seguridad). | "tabs": [...] |
| Secciones (Sections) | ->sections([...]) | Formularios largos verticales divididos en bloques temáticos o tarjetas. | "sections": [...] |
NOTE
Cada una de estas estructuras implementa el patrón de diseño Composite: sin importar si agrupas campos en pestañas o secciones, $form->getFields() y $form->toValidationRules() siempre resuelven la lista plana de todos los campos contenidos automáticamente.
⚙️ Métodos Principales de FormSchema
Configuración del Formulario
FormSchema::make(?string $id = null, ?string $title = null): Factoría estática para instanciar el esquema.->id(string $id): Asigna el identificador único del formulario.->title(string $title): Asigna el título visible en el encabezado o modal.->description(string $description): Texto descriptivo o instrucciones de llenado.->endpoint(string $endpoint): URL a la que el frontend enviará la mutación (POST,PUToPATCH).->httpMethod(string $method): Método HTTP esperado (POST,PUT,PATCH).->submitLabel(string $label): Texto del botón principal (ej. "Crear Registro", "Actualizar Datos").->cancelLabel(string $label): Texto del botón secundario o cancelar.->tabsPosition(TabsPosition|string $position): Ubicación de las pestañas (TabsPosition::TopoTabsPosition::Left).
Agrupación de Campos
->fields(array $fields): Define una lista plana de campos (FieldContract[]).->addField(FieldContract $field): Agrega un campo individual a la lista.->tabs(array $tabs): Define una lista de pestañas (FormTab[]).->addTab(FormTab $tab): Agrega una pestaña individual.->sections(array $sections): Define una lista de secciones (FormSection[]).->addSection(FormSection $section): Agrega una sección individual.
Extracción de Reglas y Serialización
->toValidationRules(bool $isUpdate = false): array: Compila las reglas de todos los campos a un formato entendible porValidator::make(). En modo$isUpdate = true, convierterequiredensometimes|required.->getFields(): array: Retorna todos los campos recursivamente sin importar su nivel de anidación.->toArray(): array: Serializa el esquema a JSON Schema cumpliendo el contrato SPEC-002.->jsonSerialize(): array: Implementación de la interfazJsonSerializablede PHP.
🚀 Uso en Controladores de Laravel
En tu controlador API no necesitas clases FormRequest redundantes si no lo deseas. Puedes validar directamente con el esquema:
php
use App\Models\User;
use App\Schemas\UserSchema;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UserController extends Controller
{
// 1. Endpoint que entrega la especificación al frontend
public function schema(): JsonResponse
{
return response()->json([
'form' => UserSchema::form()->toArray(),
]);
}
// 2. Creación con validación estricta (POST)
public function store(Request $request): JsonResponse
{
$schema = UserSchema::form();
$validated = $request->validate($schema->toValidationRules(isUpdate: false));
$user = User::create($validated);
return response()->json($user, 201);
}
// 3. Edición parcial con Dirty Tracking (PATCH)
public function update(Request $request, User $user): JsonResponse
{
$schema = UserSchema::form();
// isUpdate = true convierte las reglas required en sometimes|required
$validated = $request->validate($schema->toValidationRules(isUpdate: true));
$user->update($validated);
return response()->json($user);
}
}TIP
Si tu controlador utiliza el trait HasDynamicCrudSchema, todo este proceso se reduce a llamar a $this->validateWithSchema($request, isUpdate: true).