beefeater / crud-event-bundle
Event-based CRUDL bundle with configurable filtering, pagination, and sorting for Symfony applications
Installs: 25
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 0
Forks: 0
Open Issues: 0
Type:symfony-bundle
Requires
- php: >=8.1
- doctrine/doctrine-bundle: ^2.10
- doctrine/orm: ^3.0
- doctrine/persistence: ^3.3
- symfony/dependency-injection: ^7.2
- symfony/event-dispatcher: ^7.2
- symfony/framework-bundle: ^7.2
- symfony/http-foundation: ^7.2
- symfony/http-kernel: ^7.2
- symfony/routing: ^7.2
- symfony/serializer: ^7.2
- symfony/validator: ^7.2
- symfony/yaml: ^7.2
Requires (Dev)
- phpunit/phpunit: ^12.2
- squizlabs/php_codesniffer: ^3.13
README
Beefeater CRUD Event Bundle is a powerful Symfony bundle for rapid REST API generation with built-in support for CRUD operations, events, pagination, sorting, and filtering.
π¦ Key Features
- π Auto-generation of CRUD routes (
Create
,Read
,Update
,Delete
,List
,Patch
) based on YAML configuration - π API versioning support (e.g.,
v1
,v2
) - π Pagination, sorting, and filtering for
List
operations - π§©
before
andafter
events forpersist
,update
,delete
,patch
, andlist
- βοΈ Extensible via custom
EventListeners
(e.g., for logging, notifications, etc.) - β Symfony Validator integration for request data validation
- π§ Built-in support for Doctrine ORM
- βοΈ Partial updates via
PATCH
- π Route parameters support including nested resources and UUIDs
π§ Installation
Install the bundle via Composer:
composer require beefeater/crud-event-bundle
π Usage
Register Routes
Add the following to config/routes.yaml
:
crud_api_v1: resource: '%kernel.project_dir%/config/crud_routes_v1.yaml' type: crud_routes
Example: crud_routes_v1.yaml
version: v1 resources: tournaments: entity: App\Entity\Tournament operations: [C, R, U, D, L, P] path: /tournaments categories: entity: App\Entity\Category operations: [C, R, U, D, L, P] path: /tournaments/{tournament}/categories params: tournament: App\Entity\Tournament
Routes generated for tournaments
:
Route Name | Method | Path |
---|---|---|
api_v1_tournaments_C | POST | /api/v1/tournaments |
api_v1_tournaments_R | GET | /api/v1/tournaments/{id} |
api_v1_tournaments_U | PUT | /api/v1/tournaments/{id} |
api_v1_tournaments_D | DELETE | /api/v1/tournaments/{id} |
api_v1_tournaments_L | GET | /api/v1/tournaments |
api_v1_tournaments_P | PATCH | /api/v1/tournaments/{id} |
Routes generated for categories
:
Route Name | Method | Path |
---|---|---|
api_v1_categories_C | POST | /api/v1/tournaments/{tournament}/categories |
api_v1_categories_R | GET | /api/v1/tournaments/{tournament}/categories/{id} |
api_v1_categories_U | PUT | /api/v1/tournaments/{tournament}/categories/{id} |
api_v1_categories_D | DELETE | /api/v1/tournaments/{tournament}/categories/{id} |
api_v1_categories_L | GET | /api/v1/tournaments/{tournament}/categories |
api_v1_categories_P | PATCH | /api/v1/tournaments/{tournament}/categories/{id} |
β οΈ If the
version:
key is not specified in the configuration file (e.g.crud_routes_v1.yaml
), the route paths will be built without any version prefix, for example:/api/categories/{id}
.
π How It Works
- Routes are auto-generated from YAML config and handled by a central
CrudEventController
- Symfony events are dispatched before and after each operation
- Incoming data is deserialized and validated using validation groups:
fromJson()
accepts validation groups that control which fields are deserializedvalidate()
runs validation based on those groups
- Validation groups can be set using PHP attributes/annotations:
#[Assert\NotBlank(groups: ['create'])] #[Groups(['create', 'update'])] private string $name;
This allows flexible validation rules depending on the operation.
π§© EventListeners
You can register event listeners to:
- Log actions
- Send notifications
- Modify or enrich data
- Handle errors
π Pagination, Sorting, Filtering
Pagination Parameters
Parameter | Default |
---|---|
page |
1 |
pageSize |
25 |
Example:
GET /api/v1/tournaments?page=2&pageSize=10
π Sorting
sort=+field1,-field2
β ascending/descending- Example:
GET /api/v1/tournaments?sort=-age,+name
π§° Filtering
filter[field]=value
filter[field][operator]=value
Supported operators:
Operator | Description |
---|---|
eq | equals (default) |
like | substring match |
gte | greater or equal |
lte | less or equal |
gt | greater than |
lt | less than |
Boolean values supported: true
, false
, none
Examples:
GET /api/v1/tournaments?filter[isActive]=true GET /api/v1/tournaments?filter[status][eq]=active GET /api/v1/tournaments?filter[rating][gte]=3&filter[rating][lte]=5
π¦ Nested Resources
If a parent ID (e.g., UUID) is present in the path (e.g., /api/v1/tournaments/{tournament}/categories
), it is:
- Automatically resolved and injected
- Available for filtering
You can combine all parameters:
GET /api/v1/tournaments/{tournament}/categories?page=2&pageSize=10&sort=-age,+name&filter[rating][gte]=3&filter[rating][lte]=5
π’ Dispatched Events
Create
{resource}.create.before_persist
crud_event.create.before_persist
{resource}.create.after_persist
crud_event.create.after_persist
Update
{resource}.update.before_persist
crud_event.update.before_persist
{resource}.update.after_persist
crud_event.update.after_persist
Patch
{resource}.patch.before_persist
crud_event.patch.before_persist
{resource}.patch.after_persist
crud_event.patch.after_persist
Delete
{resource}.delete.before_remove
crud_event.delete.before_remove
{resource}.delete.after_remove
crud_event.delete.after_remove
List
{resource}.list.list_settings
crud_event.list.filter_build
π Example Event Listener Registration
App\EventListener\TournamentCrudListener: tags: - { name: kernel.event_listener, event: 'tournaments.create.after_persist', method: onAfterPersist }
β Custom Exceptions
-
PayloadValidationException
Thrown when validation fails; includesConstraintViolationListInterface
for detailed violation info. -
ResourceNotFoundException
Thrown when the requested resource is not found by ID.
You can register listeners to handle these exceptions globally.
π Logging
The Beefeater CRUD Event Bundle supports logging of key operations such as:
- Route creation
- Error logging
- Warning logging
How to Enable Logging in Your Project
To enable logging for this bundle, follow these steps:
- Install the Symfony Monolog Bundle if you havenβt already:
composer require symfony/monolog-bundle
- Configure a dedicated logging channel and handler for
crud_event
in yourconfig/packages/monolog.yaml
file. For example, in thedev
environment:
monolog: channels: - crud_event # add this channel alongside your existing ones when@dev: monolog: handlers: crud_event: # add this handler alongside your existing ones type: stream path: "%kernel.logs_dir%/crud_event.log" level: debug channels: ["crud_event"]
- You can similarly add configurations for
when@test
just change log file path%kernel.logs_dir%/crud_event_test.log
. For thewhen@prod
environment, it's recommended to keep the default logging setup using thefingers_crossed
handler
All logs related to the Beefeater CRUD Event Bundle will be saved in:
var/log/crud_event.log
This setup allows you to conveniently monitor important bundle actions and errors separately from other Symfony logs.