$30 off During Our Annual Pro Sale. View Details »

sfDay - Sonata Admin Bundle

Thomas R.
October 21, 2011

sfDay - Sonata Admin Bundle

Thomas R.

October 21, 2011
Tweet

Other Decks in Programming

Transcript

  1. Sonata Project
    AdminBundle

    View Slide

  2. Who am I ?
    • Thomas Rabaix
    • Speaker at Symfony Live Conferences
    • Author of many symfony1 plugins
    • lead developer of the sonata project
    • Working at Ekino, a french web agency

    View Slide

  3. Talk
    • Sonata Project presentation
    • Quick Tour
    • Under the hood
    • Customize / Advanced features
    • Conclusion

    View Slide

  4. Sonata Project
    • A not so young project
    • Based on symfony1 plugins
    • Recoded with the best practices of
    Symfony2
    • Built on top on very strong and powerful
    framework

    View Slide

  5. Sonata Project
    • An ecommerce toolbox
    • How :
    • avoiding reinvented the wheel
    • contribution to the community
    • built on top of a strong framework

    View Slide

  6. Sonata’s bundles
    • PageBundle : a page manager with block
    as service and strong caching mechanism
    • MediaBundle : a media manager on
    steroid, you don’t have to worry about
    managing files or videos
    • UserBundle, IntlBundle, etc ...
    • AdminBundle : A backend generator

    View Slide

  7. http://sonata-project.org

    View Slide

  8. AdminBundle
    why ?

    View Slide

  9. • No admin generator for Symfony 2.0
    • Frustrating by the admin generator provided by
    symfony1
    • Admin is not only about Model; but about
    providing a consistent and rich user
    experience for managing data.

    View Slide

  10. Quick Tour
    http://www.flickr.com/photos/38104873@N03/4559985343/

    View Slide

  11. Admin Class
    • An metadata description
    of CRUD operations
    • No code generation
    • Based on Symfony
    services + Sonata Admin
    services

    View Slide

  12. Actions
    shortcut
    Group +
    Model
    Dashboard

    View Slide

  13. Dashboard
    1.
    2.
    3.
    4.
    5. %sonata.news.admin.comment.entity%
    6. %sonata.news.admin.comment.controller%
    7.
    8.
    9.
    10.
    11.
    12. %sonata.news.admin.post.entity%
    13. %sonata.news.admin.post.controller%
    14.
    15.
    16.
    17.
    18.
    19. %sonata.news.admin.tag.entity%
    20. %sonata.news.admin.tag.controller%
    21.
    22.
    Register admin class with the tag “sonata.admin”
    And admin will appears into the dashboard

    View Slide

  14. Filters
    Model
    Actions
    List Action
    Batch
    Actions
    Breadcrumb

    View Slide

  15. List Action
    fields, custom
    templates, type
    detection
    fields, type
    detection, based
    on Form
    Component

    View Slide

  16. List Action
    1. protected function configureDatagridFilters(DatagridMapper $datagridMapper) {
    2. $datagridMapper
    3. ->add('name')
    4. ->add('providerReference')
    5. ->add('enabled')
    6. ->add('context')
    7. ;
    8. $providers = array();
    9.
    10. foreach($this->pool->getProviderNamesByContext('default') as $name) {
    11. $providers[$name] = $name;
    12. }
    13.
    14. $datagridMapper->add('providerName', 'doctrine_orm_choice', array(
    15. 'field_options'=> array(
    16. 'choices' => $providers,
    17. 'required' => false,
    18. 'multiple' => false,
    19. 'expanded' => false,
    20. ),
    21. 'field_type'=> 'choice',
    22. ));
    23. }
    24.
    25. protected function configureListFields(ListMapper $listMapper) {
    26. $listMapper
    27. ->addIdentifier('id')
    28. ->add('image', 'string', array('template' => 'SonataMediaBundle:MediaAdmin:list_image.html.twig'))
    29. ->add('custom', 'string', array('template' => 'SonataMediaBundle:MediaAdmin:list_custom.html.twig'))
    30. ->add('enabled')
    31. ->add('_action', 'actions', array(
    32. 'actions' => array(
    33. 'view' => array(),
    34. 'edit' => array(),
    35. )
    36. ))
    37. ;
    38. }
    field guesser
    custom filter
    edit link
    custom template
    row’s actions

    View Slide

  17. Edit/Create Form
    side menu
    Field Group

    View Slide

  18. Helper message
    Edit/Create Form
    add relation
    hide fields
    save options delete action

    View Slide

  19. Edit/Create Form
    1. protected function configureFormFields(FormMapper $formMapper)
    2. {
    3. $templates = array();
    4. foreach ($this->cmsManager->getPageManager()->getTemplates() as $code => $template) {
    5. $templates[$code] = $template->getName();
    6. }
    7.
    8. $formMapper
    9. ->with($this->trans('form_page.group_main_label'))
    10. ->add('name')
    11. ->add('enabled', null, array('required' => false))
    12. ->add('position')
    13. ->add('templateCode', 'choice', array('required' => true, 'choices' => $templates))
    14. ->add('parent', 'sonata_page_selector', array(
    15. 'page' => $this->getSubject() ?: null,
    16. 'model_manager' => $this->getModelManager(),
    17. 'class' => $this->getClass(),
    18. 'filter_choice' => array('hierarchy' => 'root'),
    19. 'required' => false
    20. ))
    21. ->end()
    22. ;
    23.
    24. $formMapper
    25. ->with($this->trans('form_page.group_seo_label'), array('collapsed' => true))
    26. ->add('metaKeyword', 'textarea', array('required' => false))
    27. ->add('metaDescription', 'textarea', array('required' => false))
    28. ->end()
    29. ;
    30.
    31. $formMapper
    32. ->with($this->trans('form_page.group_advanced_label'), array('collapsed' => true))
    33. ->add('javascript', null, array('required' => false))
    34. ->add('stylesheet', null, array('required' => false))
    35. ->add('rawHeaders', null, array('required' => false))
    36. ->end()
    37. ;
    38.
    39. $formMapper->setHelps(array(
    40. 'name' => $this->trans('help_page_name')
    41. ));
    42. }
    create group
    Form Component
    Define help messages
    group options

    View Slide

  20. • Permissions management
    • Flash messages
    • Nested Admin
    • Command lines utilities
    • Translated into more than10 languages
    Other Features

    View Slide

  21. • Dashboard
    • Consistent Interface across bundles
    • Easy to configure, but powerful for
    advanced users
    • Advanced features
    • Inspired from the django admin module
    (user interactions)
    Quick Tour Summary

    View Slide

  22. Under the hood
    http://www.flickr.com/photos/52251564@N08/5937620090

    View Slide

  23. Admin
    class
    Routing
    Translator
    Model
    Manager
    Symfony Framework
    Security
    Validator
    Form
    Sonata Admin Bundle
    List
    Datagrid
    Show
    Form
    Builder
    Admin Class Dependencies

    View Slide

  24. Security
    • Based on the SecurityHandlerInterface
    • 2 built-in implementations
    • NoopSecurityHandler : use the
    Symfony’s firewall
    • AclSecurityHandler : based on ACL
    - Advanced users only

    View Slide

  25. Security
    • Admin Usage
    1. protected function configureFormFields(FormMapper $formMapper)
    2. {
    3. $formMapper
    4. ->with('General')
    5. ->add('enabled', null, array('required' => false))
    6. ->add('author', 'sonata_type_model', array(), array('edit' => 'list'))
    7. ->add('title')
    8. ->end()
    9. ;
    10.
    11. if (!$this->isGranted('CREATE')) {
    12. // do specific code if the user cannot create a new object
    13. }
    14. }
    1. {% if admin.isGranted('CREATE') %}
    2. // DO YOUR STUFF
    3. {% endif %}
    • Template Usage

    View Slide

  26. Security : ACL
    • Required to have a custom external bundle to
    manage permissions and user : see FOS/
    UserBundle and Sonata/UserBundle
    • Built on top of a custom MaskBuilder (basic
    roles : List, View, Edit, Create, Delete)
    • Command lines :
    • php app/console init:acl
    • php app/console sonata:admin:setup-acl

    View Slide

  27. Routing
    • Definition set from the Admin class
    • Can be tweaked by the configureRoute
    1. /**
    2. * @param \Sonata\AdminBundle\Route\RouteCollection $collection
    3. * @return void
    4. */
    5. protected function configureRoutes(RouteCollection $collection)
    6. {
    7. $collection->add('snapshots');
    8. $collection->remove('edit');
    9.
    10. $collection->add('test', $this->getRouterIdParameter().'/test');
    11. }
    Add the id parameter
    1. reference
    2. reference
    • Template Usage

    View Slide

  28. Admin Model Manager
    • Persistency layer abstraction for Admin Bundle.
    • All Persistencies actions are done in the Model
    Manager
    • delete, query, pagination, etc..
    • form type manipulation delegation
    • For now only Doctrine ORM (Propel and
    Doctrine ODM are work in progress by external
    contributors)

    View Slide

  29. Admin Model Manager
    • Some bundle provides custom Model Manager
    • You can define your own proxy Admin Model
    Manager to reuse the Bundle Model Manager
    • Use case : Sonata Media Bundle (delete action)

    View Slide

  30. Model Manager
    Sonata Media Bundle
    2 Model Managers :
    - entity : deal with deletion and so on ...
    - admin : proxy some methods to the entity
    How to ?
    1. create a dedicated Admin Model Manager
    2. create a Bundle Model Manager
    3. redefine only required methods
    4. define services
    1. class AdminModelManager extends ModelManager {
    2. protected $manager;
    3.
    4. public function __construct($entityManager, $manager) {
    5. parent::__construct($entityManager);
    6. $this->manager = $manager;
    7. }
    8.
    9. public function delete($object) {
    10. $this->manager->delete($object);
    11. }
    12. }
    1.
    2.
    3.
    4. %sonata.media.admin.media.entity%
    5. %sonata.media.admin.media.controller%
    6.
    7.
    8.
    9.
    10.
    11.
    12.
    13.
    14.
    15.
    1. class BundleMediaManager extends AbstractMediaManager {
    1. public function delete(MediaInterface $media) {
    2. $this->pool
    3. ->getProvider($media->getProviderName())
    4. ->preRemove($media);
    5. $this->em->remove($media);
    6. $this->em->flush();
    7.
    8. $this->pool
    9. ->getProvider($media->getProviderName())
    10. ->postRemove($media);
    11. $this->em->flush();
    12. }
    2. }
    Delete thumbnails

    View Slide

  31. Translator
    • 2 catalogues
    • SonataAdminBundle used to translate
    shared messages
    • messages used to translate current Admin
    1. $formMapper
    2. ->with($this->trans('form_page.group_main_label'))
    3. ->add('name')
    4. ->end()
    5. ;
    • Can be set by updating the translationDomain
    property

    View Slide

  32. Form
    • Originally built on the the first implementation
    • Too bad ..... major refactoring 3 months later
    • Some admin features has been removed or still
    broken :(
    • But the new form implementation is pretty
    awesome .... once you know how to use it.

    View Slide

  33. Form Mapper
    • Interact with the FormMapper
    • Proxy class between the Admin Class and the
    Symfony Form Component
    • Act as the Symfony FormBuilder component
    • You can use your custom field types

    View Slide

  34. Form Type
    • AdminType : used to embedded form from
    another Admin class
    • CollectionType : use by one-to-many association
    • ModelType : select choice (like EntityType)
    • ModelReferenceType : handle an model id
    • ImmutableArrayType : specify a form type per
    array element
    1. $formMapper->add('settings', 'sonata_type_immutable_array', array(
    2. 'keys' => array(
    3. array('layout', 'textarea', array()),
    4. array('action', 'text', array()),
    5. array('parameters', 'text', array()),
    6. )
    7. ));
    Core types
    Model Manager Types
    Form Types

    View Slide

  35. Validator
    • Assert rules can be defined in the validation.
    [xml|yml] files (validator component)
    nothing new ...
    • Conditional Validation

    View Slide

  36. Conditional Validation
    • Not mandatory, but allow to add inline validation
    a runtime.
    • ex : check only if a value is set
    • Validate method inside the admin class
    • Interact with a new ErrorElement object
    • The ErrorElement is just a validator service based
    on the Validator Component

    View Slide

  37. Validator
    1. /**
    2. * @param \Sonata\AdminBundle\Validator\ErrorElement $errorElement
    3. * @param $object
    4. * @return void
    5. */
    6. public function validate(ErrorElement $errorElement, $object)
    7. {
    8. $errorElement
    9. ->with('name')
    10. ->assertMaxLength(array('limit' => 32))
    11. ->end()
    12. ;
    13.
    14. if ($object->getFoo()) {
    15. $errorElement
    16. ->with('test')
    17. ->addViolation('my_message')
    18. ->end()
    19. ;
    20. }
    21. }
    symfony constraint
    custom error

    View Slide

  38. Menu
    • Based on KnpMenu lib
    • Used for Breadcrumb and Side Menu
    • No magic for sidemenu, need to code your
    own menu per admin (if required)

    View Slide

  39. Menu
    1. class PostAdmin extends Admin
    2. {
    3. protected function configureSideMenu(MenuItemInterface $menu, $action, Admin $childAdmin = null)
    4. {
    5. if (!$childAdmin && !in_array($action, array('edit'))) {
    6. return;
    7. }
    8.
    9. $admin = $this->isChild() ? $this->getParent() : $this;
    10.
    11. $id = $admin->getRequest()->get('id');
    12.
    13. $menu->addChild(
    14. $this->trans('view_post'),
    15. array('uri' => $admin->generateUrl('edit', array('id' => $id)))
    16. );
    17.
    18. $menu->addChild(
    19. $this->trans('link_view_comment'),
    20. array('uri' => $admin->generateUrl('sonata.news.admin.comment.list', array('id' => $id)))
    21. );
    22. }
    23.}

    View Slide

  40. customize
    http://www.flickr.com/photos/7552532@N07/449769140/

    View Slide

  41. Form : one-to-many
    • Type : sonata_type_collection (CollectionType)
    •Form Option
    by_reference => false
    • Sonata Options
    • edit : standard / inline
    • inline : table | list
    • position : field name (if exists)

    View Slide

  42. Form : many-to-many
    • Type : sonata_type_model (ModelType)
    • Sonata Options
    • no options

    View Slide

  43. Form : many-to-one
    • Type : sonata_type_model (ModelType)
    • Form Options :
    • expanded : true|false
    • Sonata Options
    • edit : standard (select box) / list (popup)
    • link_parameters : add extra link parameters to
    the link

    View Slide

  44. Form : many-to-one
    • Type : sonata_type_admin (AdminType)
    • Embed an admin form for an entity into the current
    admin
    • Sonata Options
    • no option!

    View Slide

  45. Form Theme
    • Based on the form theme mechanism
    • Define a getFormTheme()
    • a set of form templates
    • allows to customize an admin form

    View Slide

  46. Form Theme
    • Just define a custom block with the correct name ...
    • How to know the block name ... ?
    • Provide a custom `block_name` option
    • or use a defined built-in pattern :
    admin_service_id_[type]_[widget|label|errors|row]
    admin_service_id_[fieldName]_[widget|label|errors|row]

    View Slide

  47. Form block
    1.{% block sonata_user_admin_user_credentialsExpired_text_widget %}
    2. PUT HERE THE WIDGET ...
    3.{% endblock %}
    1. protected $formTheme = array(
    2. 'SonataAdminBundle:Form:form_admin_fields.html.twig',
    3. 'SonataNewsBundle:Form:form.html.twig'
    4. );
    • Theme definition
    • Block definition
    • Et voila!

    View Slide

  48. Custom List Template
    1.->add('custom', 'string', array('template' =>
    'SonataMediaBundle:MediaAdmin:list_custom.html.twig'))
    • Field definition
    • Template
    • Et voila!
    1.{% extends 'SonataAdminBundle:CRUD:base_list_field.html.twig' %}
    2.
    3.{% block field %}
    4.
    5. {{ object.name }}

    6. {{ object.providerName|trans({}, 'SonataMediaBundle') }}:
    {{ object.width }}x{{ object.height }}

    7.
    8.{% endblock %}

    View Slide

  49. CRUD Controller
    • Use the admin class to generate required
    objects
    • contains create, edit, update, delete and
    batch actions
    • can be extended to change some logic
    • use case : Sonata Media Bundle

    View Slide

  50. Custom CRUD Controller
    1. namespace Sonata\MediaBundle\Controller;
    2.
    3. use Sonata\AdminBundle\Controller\CRUDController as Controller;
    4. use Symfony\Component\Security\Core\Exception\AccessDeniedException;
    5.
    6. class MediaAdminController extends Controller {
    7. public function createAction() {
    8. if (false === $this->admin->isGranted('CREATE')) {
    9. throw new AccessDeniedException();
    10. }
    11.
    12. $parameters = $this->admin->getPersistentParameters();
    13.
    14. if (!$parameters['provider']) {
    15. return $this-
    >render('SonataMediaBundle:MediaAdmin:select_provider.html.twig', array(
    16. 'providers' => $this->get('sonata.media.pool')
    17. ->getProvidersByContext($this->get('request')-
    >get('context', 'default')),
    18. 'base_template' => $this->getBaseTemplate(),
    19. 'admin' => $this->admin,
    20. 'action' => 'create'
    21. ));
    22. }
    23.
    24. return parent::createAction();
    25. }
    26.}
    Grant check
    Custom Template
    Parent action

    View Slide

  51. Nested Admin
    • clean url : /admin/sonata/news/post/1/comment/list
    • reuse other admin definition
    • autofilter with the targeted elements
    • only work on one level
    • You don’t need to know routing name, as long as
    you use the admin class

    View Slide

  52. Nested Admin
    1. class CommentAdmin extends Admin
    2. {
    3. protected $parentAssociationMapping = 'post';
    4.
    5. protected function configureFormFields(FormMapper $formMapper)
    6. {
    7. if(!$this->isChild()) {
    8. $formMapper->add('post', 'sonata_type_model', array(), array('edit' => 'list'));
    9. }
    10.
    11. $formMapper
    12. ->add('name')
    13. ->add('email')
    14. ->add('url', null, array('required' => false))
    15. ->add('message')
    16. ->add('status', 'choice', array('choices' => Comment::getStatusList(), 'expanded' => true, 'multiple' => false))
    17. ;
    18. }
    19.
    20. protected function configureListFields(ListMapper $listMapper)
    21. {
    22. $listMapper
    23. ->addIdentifier('name')
    24. ->add('getStatusCode', 'text', array('label' => 'status_code', 'sortable' => 'status'))
    25. ;
    26.
    27. if (!$this->isChild()) {
    28. $listMapper->add('post');
    29. }
    30.
    31. $listMapper
    32. ->add('email')
    33. ->add('url')
    34. ->add('message');
    35. }
    36. }
    Display custom
    field if the
    current admin is
    nested or not
    Display custom
    field if the
    current admin is
    nested or not

    View Slide

  53. Nested Admin
    Comment Admin Nested Comment Admin

    View Slide

  54. Admin Extension
    • Allow to add extra feature or redefine some field to
    the admin
    • Good entry point if you extends some entities
    • Add extension must implement the
    AdminExtensionInterface and define as
    service with the sonata.admin.extension

    View Slide

  55. Debug
    • Check out external configurations
    • validator configuration
    • doctrine schema definition
    • use firebug to check Ajax errors (missing toString method or
    type hinting)
    • Get information from the Admin command tools
    • sonata:admin:list
    • sonata:admin:explain

    View Slide

  56. sonata:admin:list
    service name can be used to
    explain the admin configuration

    View Slide

  57. sonata:admin:explain

    View Slide

  58. conclusion
    http://www.flickr.com/photos/rv-bordeaux/5909437215/

    View Slide

  59. small numbers
    • First commit in
    november 2010
    • 650 commits
    • 49 Contributors!
    • 14 Translations
    Thanks!

    View Slide

  60. What’s next ?
    • Version 1
    • Stabilize the AdminBundle
    • Add more tests... : 56 tests, 145
    assertions
    • Version 1.1
    • Add missing features from the original
    form factoring
    • Add more layer persistency
    (contribution)

    View Slide

  61. Resources
    • http://sonata-project.org
    • irc : #symfony
    • twitter : @sonataproject
    • symfony google groups

    View Slide

  62. Questions
    http://www.flickr.com/photos/colinkinner/2200500024/

    View Slide