Installation Add the package via Composer:
composer require becklyn/rad
Enable the bundle in config/bundles.php (Symfony) or register the service provider in config/app.php (Laravel via Symfony bridge):
Becklyn\RadBundle\RadBundle::class => ['all' => true],
First Use Case
Use the AjaxResponseBuilder to return standardized AJAX responses. Example in a Symfony controller:
use Becklyn\RadBundle\AjaxResponseBuilder;
public function someAction(Request $request, AjaxResponseBuilder $builder)
{
try {
// Business logic here
return $builder->success('ok', ['data' => 'your_data']);
} catch (\Exception $e) {
return $builder->error('invalid-id', [], $e->getMessage());
}
}
Frontend Integration
Use the mojave library (TypeScript) to handle responses. Example:
const response = await fetch('/some-endpoint', { method: 'POST' });
const data = await response.json();
if (!data.ok) {
// Handle error (e.g., show toast)
mojave.toast(data.message);
}
Consistent Structure: Always return responses matching the AjaxResponse interface. Use AjaxResponseBuilder for boilerplate:
// Success with redirect
$builder->success('user_created', ['id' => 123], '/dashboard');
// Error with toast
$builder->error('validation_failed', [], 'Invalid input', 'negative');
Workflow Integration:
AjaxResponseBuilder for all AJAX endpoints.mojave to handle ok/status/data triad.status field for granular error handling:
return $builder->error('not_found', [], 'Resource not found');
Frontend checks data.ok and data.status to route errors.message field for user feedback:
return $builder->success('updated', [], null, [
'text' => 'Profile saved!',
'impact' => 'positive',
'action' => ['label' => 'View', 'url' => '/profile']
]);
Render in frontend with:
mojave.toast(data.message);
redirect field to trigger client-side navigation:
return $builder->success('created', [], '/dashboard');
Handle in frontend:
if (data.redirect) window.location.href = data.redirect;
Symfony-Centric Design:
symfony/http-foundation) or adapt controllers to return JSON manually.return response()->json([
'ok' => true,
'status' => 'success',
'data' => $data,
]);
TypeScript Dependency:
AjaxResponse interface assumes TypeScript (mojave). For vanilla JS, manually type-check responses:
if (!response.ok || !response.data) throw new Error('Invalid response');
HTTP Status Codes:
Response objects directly:
return response()->json([...], 404);
Response Validation:
Ensure all responses include ok, status, and data. Use a middleware to validate:
public function handle(Request $request, Closure $next)
{
$response = $next($request);
if ($response->isJson()) {
$data = json_decode($response->getContent(), true);
if (!isset($data['ok'], $data['status'], $data['data'])) {
throw new \RuntimeException('Invalid AJAX response format');
}
}
return $response;
}
Frontend Debugging: Log raw responses to verify structure:
console.log('AJAX Response:', data);
Custom Response Builders:
Extend AjaxResponseBuilder to add project-specific fields:
class CustomResponseBuilder extends AjaxResponseBuilder
{
public function withMeta(array $meta): self
{
$this->data['meta'] = $meta;
return $this;
}
}
Override Default Protocol:
Replace AjaxResponseBuilder with a custom implementation if the interface doesn’t fit your needs.
Laravel Integration: For Laravel, create a facade or helper to wrap the Symfony builder:
// app/Helpers/AjaxHelper.php
use Becklyn\RadBundle\AjaxResponseBuilder;
class AjaxHelper
{
public static function success(string $status, array $data, ?string $redirect = null): array
{
return (new AjaxResponseBuilder())->success($status, $data, $redirect)->toArray();
}
}
AjaxResponseBuilder.Becklyn\RadBundle doesn’t conflict with other Rad-named packages. Use fully qualified namespaces.How can I help you explore Laravel packages today?