## Getting Started
### Minimal Setup
1. **Install the Bundle**
Add the package via Composer:
```bash
composer require atoolo/form-bundle
Enable the bundle in config/bundles.php:
return [
// ...
Atoolo\FormBundle\AtooloFormBundle::class => ['all' => true],
];
Configure the Bundle
Define a basic configuration in config/packages/atoolo_form.yaml:
atoolo_form:
jsonforms:
renderer: 'default' # or 'react' if using React-based rendering
assets_path: '%kernel.project_dir%/public/build/jsonforms' # Path to JSON Forms assets
First Use Case: Render a Basic Form
Create a JSON form schema (e.g., config/forms/example.json):
{
"type": "VerticalLayout",
"elements": [
{
"type": "Control",
"scope": "#/properties/name",
"label": "Name",
"input": {
"type": "text"
}
}
]
}
Render it in a controller:
use Atoolo\FormBundle\Controller\FormController;
class ExampleController extends AbstractController
{
public function renderForm(FormController $formController)
{
return $formController->render('example', [
'name' => 'default_value'
]);
}
}
Route it in config/routes.yaml:
app_example_form:
path: /example-form
controller: App\Controller\ExampleController::renderForm
Verify the Output
Visit /example-form to see the rendered form. The bundle handles both rendering and processing via JSON Forms.
Define JSON Schema
Store form schemas in config/forms/ (or a custom directory). Example:
{
"type": "Object",
"properties": {
"email": {
"type": "string",
"format": "email"
}
},
"required": ["email"]
}
Render the Form
Use the FormController to render forms dynamically:
return $formController->render('user_registration', $initialData);
$initialData to pre-fill fields.renderAsJson() for API responses.Handle Form Submission Submit data via HTTP POST to the same endpoint. The bundle validates and processes data automatically:
public function submitForm(Request $request, FormController $formController)
{
$result = $formController->process('user_registration', $request->request->all());
if ($result->isValid()) {
// Save data to DB or perform actions
return $this->json(['success' => true]);
}
return $this->json(['errors' => $result->getErrors()], 400);
}
Customize Rendering
Override the default renderer by implementing Atoolo\FormBundle\Renderer\RendererInterface:
namespace App\Form\Renderer;
use Atoolo\FormBundle\Renderer\RendererInterface;
class CustomRenderer implements RendererInterface
{
public function render(array $formConfig, array $data): string
{
// Custom logic (e.g., Twig template)
return $this->twig->render('forms/custom.html.twig', [
'form' => $formConfig,
'data' => $data
]);
}
}
Register it in config/packages/atoolo_form.yaml:
atoolo_form:
jsonforms:
renderer: 'custom'
Reuse Forms Across Projects
Use the bundle’s FormLoader service to load forms from external sources (e.g., database or API):
$formLoader = $this->container->get('atoolo_form.form_loader');
$schema = $formLoader->load('dynamic_form_key');
Symfony UX Turbo/Stimulus Combine with Symfony UX for real-time updates:
// assets/controllers/form_controller.js
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
connect() {
this.element.addEventListener('submit', (e) => {
e.preventDefault();
fetch(this.element.action, {
method: 'POST',
body: new FormData(this.element)
})
.then(response => response.json())
.then(data => {
if (data.success) Turbo.visit('/thank-you');
});
});
}
}
Validation Customization
Extend validation rules by implementing Atoolo\FormBundle\Validator\ConstraintValidatorInterface:
namespace App\Form\Validator;
use Atoolo\FormBundle\Validator\ConstraintValidatorInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class CustomValidator implements ConstraintValidatorInterface
{
public function validate($value, Constraint $constraint)
{
if (!preg_match('/^[A-Z]+$/', $value)) {
$this->context->buildViolation('Must be uppercase.')
->addViolation();
}
}
}
Register it in services.yaml:
services:
App\Form\Validator\CustomValidator:
tags: ['atoolo_form.validator']
Localization
Support multiple languages by configuring the translator in atoolo_form.yaml:
atoolo_form:
jsonforms:
translator: 'app.translator' # Custom translator service
Asset Path Configuration
assets_path in atoolo_form.yaml is incorrect.node_modules/@jsonforms/core/dist/). For production, use a build step (e.g., Webpack Encore) to copy assets to public/build/jsonforms.CORS for API Usage
config/packages/nelmio_cors.yaml:
nelmio_cors:
paths:
'^/api/form/':
allow_origin: ['*']
allow_methods: ['POST']
allow_headers: ['Content-Type']
Validation Overrides
ConstraintValidatorInterface and are tagged in services.yaml:
tags: ['atoolo_form.validator']
Data Binding
{
"type": "Control",
"scope": "#/properties/user/address/street"
}
Performance with Large Forms
framework:
cache:
pools:
atoolo_form.cache_pool:
adapter: cache.adapter.apcu
Enable Debug Mode
Set atoolo_form.debug: true in config/packages/atoolo_form.yaml to log form processing details:
atoolo_form:
debug: true
Validate JSON Schema Use tools like JSON Schema Validator to test schemas before integration.
Check Browser Console For frontend issues, inspect the network tab for failed asset loads or 404s on JSON Forms JS/CSS.
Log Form Data Add a subscriber to log processed data:
namespace App\EventSubscriber;
use Atoolo\FormBundle\Event\FormProcessedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class FormLoggerSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
FormProcessedEvent::class => 'onFormProcessed',
];
}
public function onFormProcessed(FormProcessedEvent $event)
{
\Log::info('Form processed:', [
'form' => $event->getFormName(),
'data' => $event->getData(),
'errors' => $event->getErrors()
]);
}
}
Custom Renderers Extend the renderer to support:
Dynamic Form Loading
Implement Atoolo\FormBundle\Loader\FormLoaderInterface to fetch schemas from
How can I help you explore Laravel packages today?