Description
Some time ago I've start writing a bundle which allows me to add some custom options to the routing config.
And now I'm finished with it and I'm using it in different projects successfully.
Ok so now here my idea:
Here is one of my basic config which I get from my customized crud generator.
# Basic show action which should basicle render a show.html.twig template...
m3panel_project_show:
pattern: /{id}/show
defaults: { _controller: "M3AppTbBundle:Project:show" }
requirements:
id: \d+
options:
m3args:
template: M3AppTbBundle:Project:show.html.twig
onError:
action: render
flash: { 0:'No Project found!' }
template: M3AppTbBundle:Project:show.html.twig
# Same as above but here defined some default params for the template.
m3panel_project_list:
pattern: /list/{count}/{order}/{opt}
defaults: { _controller: "M3AppTbBundle:Project:show" }
requirements:
count: \d+ | all
order:
opt: ASC | DESC | asc | desc
options:
m3args:
template: M3AppTbBundle:Project:list.html.twig
onError:
action: render
flash: { 0:'No Project found!' }
template: M3AppTbBundle:Project:list.html.twig
params: {'count':'all' 'order':'id' 'opt':'desc'}
# Something advanced: You can add validation_groups to use in current form.
# What should happen after form submit: 2 Options => onSuccess or onError
# after selecting the status of your form you the given action (possible: render or redirect) will be executed.
# The callback is an optional method with get's called to execute some custom code before the data gets persisted.
m3panel_project_new:
pattern: /new
defaults: { _controller: "M3AppTbBundle:Project:new" }
options:
m3args:
form_options:
validation_groups: create
template: M3AppTbBundle:Project:new.html.twig
callback: _newHook
onSuccess:
action: redirect
route: m3panel_project_new
flash: { 0:'Project [%s] succussfully created.' 1:'id' } # Notice: you can here select any method name. By default id is used because every entity has an id!
onError:
action: render
flash: { 0:'Creation of Project failed!' }
template: M3AppTbBundle:Project:new.html.twig
m3panel_project_edit:
pattern: /{id}/edit
defaults: { _controller: "M3AppTbBundle:Project:edit" }
options:
m3args:
template: M3AppTbBundle:Project:edit.html.twig
callback: _editHook
onSuccess:
action: redirect
route: m3panel_project_edit
flash: { 0:'Project [%s] succussfully updated.' 1:'name' }
params: {0:'id'}
onError:
action: render
flash: { 0:'Update failed! Your form is not valid.' }
template: M3AppTbBundle:Project:edit.html.twig
params: {0:'id'}
m3panel_project_delete:
pattern: /delete/{id}
defaults: { _controller: "M3AppTbBundle:Project:delete" }
requirements: { _method: post }
options:
m3args:
onSuccess:
action: redirect
route: m3panel_project_show_all
flash: { 0:'Project [%s] succussfully deleted.' 1:'name' }
onError:
action: redirect
route: m3panel_project_show_all
flash: { 0:'Can not delete Project [%s]!' 1:'id' }
Next I've written an abstract EntityController which handles all this options shown above.
So at this point my customized CRUD generator does also the work for me and a simple controller can look like this:
<?php
namespace M3\App\TbBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
use M3\Bundle\FrameworkBundle\Controller\EntityController;
use M3\App\TbBundle\Entity\Project;
use M3\App\TbBundle\Form\ProjectType;
/**
* Project controller.
*
*/
class ProjectController extends EntityController
{
public function __construct() {
$this->setEntity( new Project() );
$this->setFormType( new ProjectType() );
$this->sEntityRepository = 'M3AppTbBundle:Project';
}
/**
* Finds and displays a Project entity.
*
*/
public function showAction(Request $request)
{
$aResult = parent::showAction($request);
$id = $request->get('id', null);
if (!is_null($id)) {
$deleteForm = $this->createDeleteForm($id);
$aResult['delete_form'] = $deleteForm->createView();
return $this->render('M3AppTbBundle:Project:show.html.twig', $aResult);
}
$aResult['delete_form'] = $this->createFormBuilder(array('action' => 'delete_entities'))
->getForm()
->createView()
;
return $this->render('M3AppTbBundle:Project:list.html.twig', $aResult);
}
/**
* Displays a form to create a new Project entity.
*
*/
public function newAction(Request $request) {
$form = parent::newAction($request);
if ($form instanceof RedirectResponse) {
return $form;
}
if ($form instanceof Response) {
return $form;
}
// Data for the template
$aResult = array( 'entity' => $this->oEntity,
'form' => $form->createView());
// Process m3args template if exists
if (null !== $this->getM3ArgsKey('template')) {
return $this->render($this->getM3ArgsKey('template'), $aResult);
}
// Notice by default it is also possible to return the $form directly instead of $aResult. But we wanna customize the data a little before we give it to the template...
return $this->render('M3AppTbBundle:Project:new.html.twig', $aResult);
}
/**
* New persistence hook. Gets executed before entity is created/persited.
*
* @param Project $entity
* @return Project
*/
protected function _newHook($entity) {
// Place your custom code here. Gets executed before entity gets persited (create)
if (false) {
// Return false to stop entity persistence...
return false; // => executeFormError()
// Return true if you allready have persist the entity manually
return true; // => executeFormSuccess()
}
return $entity; // Do not remove this line!
}
/**
* Displays a form to edit an existing Project entity.
*
*/
public function editAction(Request $request)
{
$aResult = array();
$editForm = parent::editAction($request);
if ($editForm instanceof RedirectResponse) {
return $editForm;
}
if ($editForm instanceof Response) {
return $editForm;
}
$id = $request->get('id');
$aResult['edit_form'] = $editForm->createView();
$aResult['delete_form'] = $this->createDeleteForm($id)->createView();
$aResult['context'] = $editForm->getData();
// Process m3args template if exists
if (null !== $this->getM3ArgsKey('template')) {
return $this->render($this->getM3ArgsKey('template'), $aResult);
}
return $this->render('M3AppTbBundle:Project:edit.html.twig', $aResult);
}
/**
* Edit persistence hook. Gets executed before an entity is updated/persited.
*
* @param Project $entity
* @return Project
*/
protected function _editHook($entity) {
$entity = $this->_newHook($entity, true);
$this->executeFormSuccess($entity, true, true, false);
$this->persist($entity);
return true;
}
public function deleteAction(Request $request)
{
$aResult = parent::deleteAction($request);
return $aResult;
}
}
That's it. No I've have a fully functional CRUD which is confinable in routing config file.
I hope my explanation for the first is enough to understand how it basically works.
My question is now. Does it make sense to implement this feature into the symfony core by adding a new controller (I call it EntityController) which everyone can use if necessary...
Or is a standalone bundle the better choice??
I think it would be a nice feature in the symfony2 core because in future it should be possible to config a big range of things only with the config files and get a really good and working generated skeleton to work with.