drewclauson/elytus-limoncello-bundle
Installation:
composer require drewclauson/elytus-limoncello-bundle
Add to config/bundles.php (Symfony 4+):
Drewclauson\ElytusLimoncelloBundle\ElytusLimoncelloBundle::class => ['all' => true],
Configuration:
Override default settings in config/packages/elytus_limoncello.yaml:
elytus_limoncello:
serializer: 'App\Serializer\CustomJsonApiSerializer'
resource_classes: ['App\Resource\*']
First Use Case:
Create a JSON:API resource (e.g., app/Resource/PostResource.php):
namespace App\Resource;
use Limoncello\Resource\AbstractResource;
class PostResource extends AbstractResource
{
public function getType()
{
return 'posts';
}
public function getId($model)
{
return $model->id;
}
public function getAttributes($model)
{
return [
'title' => $model->title,
'body' => $model->body,
];
}
}
Routing:
Define a route in routes/api.php:
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
$router->get('/posts', function (Request $request) {
$posts = Post::all();
return new Response(
$this->get('elytus_limoncello.serializer')->serialize($posts, 'posts'),
Response::HTTP_OK,
['Content-Type' => 'application/vnd.api+json']
);
});
Resource-Based Serialization:
posts, users).AbstractResource for custom logic (e.g., filtering, sorting, or nested relationships).public function getRelationships($model)
{
return [
'author' => new AuthorResource($model->author),
];
}
Request Handling:
Limoncello\Request\Request.public function index(Request $request)
{
$request = $this->get('elytus_limoncello.request_factory')->createFromGlobals();
$posts = Post::query()->filter($request)->paginate();
return $this->serialize($posts, 'posts');
}
Pagination:
Limoncello\Pagination\CursorPagination or PagePagination:
# config/packages/elytus_limoncello.yaml
elytus_limoncello:
pagination: 'cursor'
Error Handling:
Limoncello\Error\ErrorHandler:
$this->get('elytus_limoncello.error_handler')->setRenderer(function ($error) {
return new Response(json_encode($error), 400);
});
Symfony Forms:
Use Symfony\Component\Form\FormFactory alongside Limoncello for input validation.
Example:
$form = $this->createForm(PostType::class, $post);
if ($form->isSubmitted() && $form->isValid()) {
$post = $form->getData();
$this->serialize($post, 'posts', 'create');
}
Doctrine ORM:
Leverage Doctrine’s Repository methods for complex queries:
public function getAttributes($model)
{
return [
'comments_count' => $model->getComments()->count(),
];
}
API Versioning:
Use Symfony’s api_platform or api route prefixing:
# config/routes/api_v1.yaml
api_v1_posts:
path: /api/v1/posts
controller: App\Controller\PostController::index
Outdated Dependencies:
~1.0).neomerx/json-api:^2.0) or use neomerx/limoncello-bundle as a drop-in alternative.Missing Documentation:
Service Container Conflicts:
elytus_limoncello.serializer). Override in services.yaml if needed:
services:
App\Serializer\CustomSerializer:
tags: ['elytus_limoncello.serializer']
Caching Headers:
ETag or Last-Modified. Add manually:
$response->setEtag(md5($serializedData));
$response->isNotModified($request);
Request Inspection: Dump the parsed request object:
$request = $this->get('elytus_limoncello.request_factory')->createFromGlobals();
dump($request->all());
Serialization Debugging: Check raw output before JSON encoding:
$data = $this->get('elytus_limoncello.serializer')->serialize($model, 'posts');
file_put_contents('debug.json', json_encode($data, JSON_PRETTY_PRINT));
Common Errors:
ResourceNotFoundException: Verify getType() and getId() in your resource class.InvalidArgumentException: Ensure model data matches expected attributes/relationships.Custom Serializers:
Extend Limoncello\Serializer\Serializer for non-standard JSON:API behavior:
class CustomSerializer extends \Limoncello\Serializer\Serializer
{
protected function createMeta(array $meta)
{
$meta['custom_field'] = 'value';
return parent::createMeta($meta);
}
}
Register in services.yaml:
elytus_limoncello.serializer: '@App\Serializer\CustomSerializer'
Middleware:
Add Limoncello-specific middleware (e.g., CORS, auth) via Symfony’s kernel.middleware:
framework:
middleware:
elytus_limoncello.cors:
before: [symfony.web_link_formatter]
Event Listeners: Hook into Limoncello’s lifecycle (e.g., pre-serialize):
$dispatcher->addListener(
'elytus_limoncello.pre_serialize',
function ($event) {
$event->getData()->add('custom_meta', 'value');
}
);
How can I help you explore Laravel packages today?