All crud classes must implement Perform\BaseBundle\Crud\CrudInterface and define services tagged with perform_base.crud.
If a service implementing this interface is auto-configured, the tag will be added for you.
Implementing CrudInterface requires creating several methods.
For most cases, extending Perform\BaseBundle\Crud\AbstractCrud saves coding time.
The only required code is implementing configureFields().
Suppose we created the Doctrine entity AppBundle\Entity\Bike, with the fields model (a string) and wheelCount (an integer).
An example crud class could be:
<?php
class BikeCrud extends AbstractCrud
{
public function configureFields(FieldConfig $config)
{
$config
->add('model', ['type' => 'string'])
->add('wheelCount', ['type' => 'integer'])
;
}
}
Note
What are types anyway? Read more in the next chapter.
To tell perform about the crud, it needs to be a service with the perform_base.crud tag:
AppBundle\Crud\BikeCrud:
tags:
- {name: perform_base.crud, crud_name: "bike"}
This will define a crud named bike that you will reference elsewhere.
This name must be unique across your application, but you can use multiple tags with different names for a single service (e.g. for routing multiple times, see below).
Note
If you autowire and auto-configure your services, Perform will normally do the ‘right’ thing and configure your service with a sensible crud_name.
To see the new crud definition, run the perform:debug:crud console command:
$ ./bin/console perform:debug:crud
+------+-------------------------+-----------------------+
| Name | Class | Entity Class |
+------+-------------------------+-----------------------+
| bike | AppBundle\Crud\BikeCrud | AppBundle\Entity\Bike |
...
The base bundle provides a crud route loader to create routes for a crud service.
To add routes for the bike crud we defined earlier:
# app/config/routing.yml
bike_crud:
resource: bike
type: crud
prefix: "/admin/bikes"
Be sure to include a prefix for the routes.
This will create new routes:
$ ./bin/console debug:router | grep bike
bike_list ANY ANY ANY /admin/bikes/
bike_view ANY ANY ANY /admin/bikes/view/{id}
bike_create ANY ANY ANY /admin/bikes/create
bike_edit ANY ANY ANY /admin/bikes/edit/{id}
Visiting /admin/bikes in your browser will reveal a complete CRUD interface for the bike entity!
The four letters of CRUD are mapped to different ‘contexts’:
By default, routing a crud service gives you all of these routes.
What about the delete in CRUD? See Actions.
You’ll learn more about contexts, and how to customise each of them, in types, Filters, and Actions.
The behaviour of crud routing can be customised by tweaking the perform_base.crud service tag.
Note
If the tag has been auto-configured, you’ll need to explicitly create it to add these customisations.
List, view, create, and edit contexts are nice, but we may not need all of them for every crud service.
To change them, explicitly set the {list|view|create|edit}_context attributes on the service tag.
The values of these attributes are the URL fragments to use on the route, which default to:
list_context - /view_context - /view/{id}create_context - /createedit_context - /edit/{id}When none of these contexts are set on the tag, all contexts will be used. Otherwise, only the defined contexts will have routes created for them.
For example, this tag:
AppBundle\Crud\BikeCrud:
tags:
- {name: perform_base.crud, crud_name: "bike", list_context: "/", view_context: "/inspect/{id}"}
would create these routes:
bike_list ANY ANY ANY /admin/bikes/
bike_view ANY ANY ANY /admin/bikes/inspect/{id}
Sometimes the generated route names may conflict with other routes in the application. In our case, the bike crud is designed for an ‘admin area’, and messes with public routes for viewing bikes.
Use the route_prefix_name tag attribute to change the names of the generated routes.
AppBundle\Crud\BikeCrud:
tags:
- {name: perform_base.crud, crud_name: "bike", route_name_prefix: "admin_bike_"}
admin_bike_list ANY ANY ANY /admin/bikes/
admin_bike_view ANY ANY ANY /admin/bikes/view/{id}
admin_bike_create ANY ANY ANY /admin/bikes/create
admin_bike_edit ANY ANY ANY /admin/bikes/edit/{id}
A crud name may only be routed once, but there is no limit to the number of tags you can add to the same service.
For example, to route the list context of our bike crud to another url:
AppBundle\Crud\BikeCrud:
tags:
- {name: perform_base.crud, crud_name: "bike"}
- {name: perform_base.crud, crud_name: "extra_bike", list_context: "/"}
# app/config/routing.yml
bike_crud:
resource: bike
type: crud
prefix: "/admin/bikes"
extra_bike_list:
resource: extra_bike
type: crud
prefix: "/admin/extra-bike-listing"
Here we defined the extra_bike crud name and routed the list context to it, giving these routes:
bike_list ANY ANY ANY /admin/bikes/
bike_view ANY ANY ANY /admin/bikes/view/{id}
bike_create ANY ANY ANY /admin/bikes/create
bike_edit ANY ANY ANY /admin/bikes/edit/{id}
extra_bike_list ANY ANY ANY /admin/extra-bike-listing/
When visiting a route managed by a crud class, you’ll notice a new item on the debug bar:
Clicking on this data collector shows useful information about the active crud class, as well as some general information about all loaded crud classes.
The template used for a crud context can be overridden in many different ways.
Here are all the possible ways of overriding a template, in order of priority:
If an action returns a Symfony Response object, no template is
needed.
Use render() or the @Template annotation to
explicitly render a template in the controller action.
A crud class may implement CrudInterface#getTemplate() to return a
custom template name.
The template @<Bundle>/crud/<entity>/<context>.html.twig will be used
automatically if available,
e.g. @PerformContact/crud/message/view.html.twig.
Note that the entity class will be snake cased, so the entity BookPublisher in the AppBundle will search for @App/crud/book_publisher/list.html.twig in the list context.
If nothing else has been specified, the template
@PerformBase/crud/<context>.html.twig will be used.