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
- /create
edit_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.