SlideShare ist ein Scribd-Unternehmen logo
1 von 62
Sonata Project
    AdminBundle
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
Talk

• Sonata Project presentation
• Quick Tour
• Under the hood
• Customize / Advanced features
• Conclusion
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
Sonata Project

• An ecommerce toolbox
• How :
   • avoiding reinvented the wheel
   • contribution to the community
   • built on top of a strong framework
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
http://sonata-project.org
AdminBundle
   why ?
• 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.
Quick Tour




 http://www.flickr.com/photos/38104873@N03/4559985343/
Admin Class

•   An metadata description
    of CRUD operations

•   No code generation

•   Based on Symfony
    services + Sonata Admin
    services
Dashboard



        Actions
       shortcut

       Group +
        Model
Dashboard
Register admin class with the tag “sonata.admin”
  And admin will appears into the dashboard

1.         <services>
2.             <service id="sonata.news.admin.comment" class="%sonata.news.admin.comment.class%">
3.                 <tag name="sonata.admin" manager_type="orm" group="sonata_blog" label="comment"/>
4.                 <argument />
5.                 <argument>%sonata.news.admin.comment.entity%</argument>
6.                 <argument>%sonata.news.admin.comment.controller%</argument>
7.             </service>
8.  
9.                 <service id="sonata.news.admin.post" class="%sonata.news.admin.post.class%">
10.                    <tag name="sonata.admin" manager_type="orm" group="sonata_blog" label="post"/>
11.                    <argument />
12.                    <argument>%sonata.news.admin.post.entity%</argument>
13.                    <argument>%sonata.news.admin.post.controller%</argument>
14.                </service>
15. 
16.            <service id="sonata.news.admin.tag" class="%sonata.news.admin.tag.class%">
17.                <tag name="sonata.admin" manager_type="orm" group="sonata_blog" label="tag"/>
18.                <argument />
19.                <argument>%sonata.news.admin.tag.entity%</argument>
20.                <argument>%sonata.news.admin.tag.controller%</argument>
21.            </service>
22.        </services>
Breadcrumb             List Action
                                          Model
                                          Actions




              Batch
             Actions

                                Filters
List Action




 fields, custom        fields, type
templates, type     detection, based
   detection           on Form
                     Component
List Action
1.     protected function configureDatagridFilters(DatagridMapper $datagridMapper) {
2.                 $datagridMapper
3.  
4.  
5.  
        
        
        
            
            
            
                
                
                
                       ->add('name')
                       ->add('providerReference')
                       ->add('enabled')
                                                    field guesser
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. 
18. 
19. 
        
        
        
            
            
            
                
                
                
                           'required' => false,
                           'multiple' => false,
                           'expanded' => false,
                                                                                            custom filter
20.                    ),
21.                    'field_type'=> 'choice',
22.                ));
23.        }


                                                              edit link
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. 
32. 
        
        
                   ->add('_action', 'actions', array(
                       'actions' => array(                                              custom template
33.                        'view' => array(),
34.                        'edit' => array(),
35.                    )
36.                ))
37. 
38. 
        
        
               ;
           }                                                     row’s actions
Edit/Create Form




side menu


                      Field Group
Edit/Create Form


                        Helper message


                                add relation

                              hide fields




save options          delete action
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.              }

                                                                                             create group
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.  
19.  
         
         
             
             
                 
                 
                                'filter_choice' => array('hierarchy' => 'root'),
                                'required'      => false                                Form Component
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()

                                                                                                             group options
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.  
         
         
                ));
            }
                                                                               Define help messages
Other Features

• Permissions management
• Flash messages
• Nested Admin
• Command lines utilities
• Translated into more than10 languages
Quick Tour Summary
• Dashboard
• Consistent Interface across bundles
• Easy to configure, but powerful for
  advanced users

• Advanced features
• Inspired from the django admin module
  (user interactions)
Under the hood




   http://www.flickr.com/photos/52251564@N08/5937620090
Admin Class Dependencies

                    Security              Builder




                                                      Sonata Admin Bundle
                                             List
Symfony Framework




                    Translator
                                           Datagrid

                                 Admin      Show
                     Routing
                                  class     Form


                    Validator
                                           Model
                                          Manager
                      Form
Security

• Based on the SecurityHandlerInterface
• 2 built-in implementations
   • NoopSecurityHandler : use the
      Symfony’s firewall
   • AclSecurityHandler : based on ACL
      - Advanced users only
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.    }




          • Template Usage
                        1. {% if admin.isGranted('CREATE') %}
                        2.    // DO YOUR STUFF
                        3. {% endif %}
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
Routing
          • Definition set from the Admin class
          • Can be tweaked by the configureRoute
        1.         /**
        2.          * @param SonataAdminBundleRouteRouteCollection $collection
        3.          * @return void
        4.          */
        5.         protected function configureRoutes(RouteCollection $collection)
        6.         {
        7.             $collection->add('snapshots');                                Add the id parameter
        8.             $collection->remove('edit');
        9.
        10.          $collection->add('test', $this->getRouterIdParameter().'/test');
        11.      }




          • Template Usage
1. <a href="{{ admin.generateUrl('view', { 'id' : media.id, 'format' : 'reference'}) }}">reference</a>
2. <a href="{{ admin.generateObjectUrl(media, 'view', {'format' : 'reference'}) }}">reference</a>
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)
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)
Model Manager                              1. class AdminModelManager extends ModelManager {
                                                                           2.     protected $manager;

Sonata Media Bundle                                                        3.  
                                                                           4.     public function __construct($entityManager, $manager) {
                                                                           5.         parent::__construct($entityManager);
  2 Model Managers :                                                       6.         $this->manager = $manager;
     - entity : deal with deletion and so on ...                           7.     }
                                                                           8.  
     - admin : proxy some methods to the entity                            9.     public function delete($object) {
                                                                           10.         $this->manager->delete($object);
                                                                           11.     }
  How to ?                                                                 12. }

    1. create a dedicated Admin Model Manager                              1. class BundleMediaManager extends AbstractMediaManager {  
    2. create a Bundle Model Manager                                       1.      public function delete(MediaInterface $media) {
                                                                           2.         $this->pool
    3. redefine only required methods                                       3.              ->getProvider($media->getProviderName())
    4. define services                                                      4.              ->preRemove($media);
                                                                           5.         $this->em->remove($media);
                                                                           6.         $this->em->flush();

                                    Delete thumbnails
                                                                           7.  
                                                                           8.         $this->pool
                                                                           9.              ->getProvider($media->getProviderName())
                                                                           10.             ->postRemove($media);
                                                                           11.         $this->em->flush();
                                                                           12.     }
                                                                           2. }

   1.              <service id="sonata.media.admin.media" class="SonataMediaBundleEntityBundleMediaManager">
   2.                    <tag name="sonata.admin" manager_type="orm" group="sonata_media" label="media"/>
   3.                    <argument />
   4.                    <argument>%sonata.media.admin.media.entity%</argument>
   5.                    <argument>%sonata.media.admin.media.controller%</argument>
   6.  
   7.                      <call method="setModelManager">
   8.                          <argument type="service" id="sonata.media.admin.media.manager" />
   9.                      </call>
   10.                 </service>
   11.  
   12.                 <service id="sonata.media.admin.media.manager" class="SonataMediaBundleAdminManagerDoctrineModelManager">
   13.                     <argument type="service" id="doctrine.orm.default_entity_manager" />
   14.                     <argument type="service" id="sonata.media.manager.media" />
   15.                 </service>
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
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.
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
Core types


                                   Form Type                                                Model Manager Types

                                                                                                Form Types



• 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.                   ));
Validator


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




• Conditional Validation
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
Validator
1.     /**
2.        * @param SonataAdminBundleValidatorErrorElement $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.          ;

                                                      symfony constraint
13.         
14.          if ($object->getFoo()) {
15.              $errorElement
16.                  ->with('test')
17.                      ->addViolation('my_message')
18.                  ->end()
19.              ;
20.          }
21.      }                                                  custom error
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)
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.}
customize




http://www.flickr.com/photos/7552532@N07/449769140/
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)
Form : many-to-many


• Type : sonata_type_model (ModelType)
• Sonata Options
     • no options
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
Form : many-to-one

• Type : sonata_type_admin (AdminType)
• Embed an admin form for an entity into the current
  admin
• Sonata Options
     • no option!
Form Theme


• Based on the form theme mechanism
• Define a getFormTheme()
   • a set of form templates
   • allows to customize an admin form
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]
Form block
  •       Theme definition

1.        protected $formTheme = array(
2.            'SonataAdminBundle:Form:form_admin_fields.html.twig',
3.            'SonataNewsBundle:Form:form.html.twig'
4.        );


  •       Block definition

1.{% block sonata_user_admin_user_credentialsExpired_text_widget %}
2.   PUT HERE THE WIDGET ...
3.{% endblock %}



  •       Et voila!
Custom List Template
 •   Field definition
1.->add('custom', 'string', array('template' =>
  'SonataMediaBundle:MediaAdmin:list_custom.html.twig'))

 •   Template
1.{% extends 'SonataAdminBundle:CRUD:base_list_field.html.twig' %}
2. 
3.{% block field %}
4.    <div>
5.        <strong>{{ object.name }}</strong> <br />
6.        {{ object.providerName|trans({}, 'SonataMediaBundle') }}:
  {{ object.width }}x{{ object.height }} <br />
7.    </div>
8.{% endblock %}


 •   Et voila!
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
Custom CRUD Controller
1. namespace SonataMediaBundleController;
2.  
3. use SonataAdminBundleControllerCRUDController as Controller; Grant check
4. use SymfonyComponentSecurityCoreExceptionAccessDeniedException;
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']) {
                                                         Custom Template
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.}

                                   Parent action
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
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.     }                                                                                     Display custom
                                                                                                field if the
19.  
20.     protected function configureListFields(ListMapper $listMapper)
21.     {
22.         $listMapper
23.             ->addIdentifier('name')                                                      current admin is
                                                                                              nested or not
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. }
Nested Admin




Comment Admin   Nested Comment Admin
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
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
sonata:admin:list




 service name can be used to
explain the admin configuration
sonata:admin:explain
conclusion




 http://www.flickr.com/photos/rv-bordeaux/5909437215/
small numbers
•   First commit in
    november 2010

•   650 commits

•   49 Contributors!

•   14 Translations



           Thanks!
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)
Resources


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




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

Weitere ähnliche Inhalte

Was ist angesagt?

Symfony CoP: Form component
Symfony CoP: Form componentSymfony CoP: Form component
Symfony CoP: Form componentSamuel ROZE
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patternsSamuel ROZE
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Leonardo Proietti
 
First Steps in Drupal Code Driven Development
First Steps in Drupal Code Driven DevelopmentFirst Steps in Drupal Code Driven Development
First Steps in Drupal Code Driven DevelopmentNuvole
 
The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010Fabien Potencier
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mockingKonstantin Kudryashov
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & RESTHugo Hamon
 
Apostrophe
ApostropheApostrophe
Apostrophetompunk
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful softwareJorn Oomen
 
Keeping It Small with Slim
Keeping It Small with SlimKeeping It Small with Slim
Keeping It Small with SlimRaven Tools
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixturesBill Chang
 
Decoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDDecoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDAleix Vergés
 

Was ist angesagt? (20)

Symfony CoP: Form component
Symfony CoP: Form componentSymfony CoP: Form component
Symfony CoP: Form component
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patterns
 
Twig tips and tricks
Twig tips and tricksTwig tips and tricks
Twig tips and tricks
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5
 
First Steps in Drupal Code Driven Development
First Steps in Drupal Code Driven DevelopmentFirst Steps in Drupal Code Driven Development
First Steps in Drupal Code Driven Development
 
The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mocking
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
 
Apostrophe
ApostropheApostrophe
Apostrophe
 
Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010
 
Zero to SOLID
Zero to SOLIDZero to SOLID
Zero to SOLID
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful software
 
Keeping It Small with Slim
Keeping It Small with SlimKeeping It Small with Slim
Keeping It Small with Slim
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixtures
 
Decoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDDecoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDD
 
Symfony tips and tricks
Symfony tips and tricksSymfony tips and tricks
Symfony tips and tricks
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 
Silex Cheat Sheet
Silex Cheat SheetSilex Cheat Sheet
Silex Cheat Sheet
 
PhpBB meets Symfony2
PhpBB meets Symfony2PhpBB meets Symfony2
PhpBB meets Symfony2
 

Andere mochten auch

Easy backends with Symfony2 and the Sonata Admin bundle
Easy backends with Symfony2 and the Sonata Admin bundleEasy backends with Symfony2 and the Sonata Admin bundle
Easy backends with Symfony2 and the Sonata Admin bundlephpassionate
 
Back-end with SonataAdminBundle (and Symfony2, of course...)
Back-end with SonataAdminBundle (and Symfony2, of course...)Back-end with SonataAdminBundle (and Symfony2, of course...)
Back-end with SonataAdminBundle (and Symfony2, of course...)Andrea Delfino
 
Have you played this Symfony? Why Symfony is great choice for Web development
Have you played this Symfony? Why Symfony is great choice for Web developmentHave you played this Symfony? Why Symfony is great choice for Web development
Have you played this Symfony? Why Symfony is great choice for Web developmentMike Taylor
 
Mastering Twig (DrupalCon Barcelona 2015)
Mastering Twig (DrupalCon Barcelona 2015)Mastering Twig (DrupalCon Barcelona 2015)
Mastering Twig (DrupalCon Barcelona 2015)Javier Eguiluz
 
8 Simple Ways to Hack Your Joomla
8 Simple Ways to Hack Your Joomla8 Simple Ways to Hack Your Joomla
8 Simple Ways to Hack Your JoomlaSiteGround.com
 
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years laterSymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years laterHaehnchen
 
(株)農業情報設計社の取り組みついて
(株)農業情報設計社の取り組みついて(株)農業情報設計社の取り組みついて
(株)農業情報設計社の取り組みついてShinya TODORI
 
Semester 7 - Industrial Training (Final Presentation)
Semester 7 - Industrial Training (Final Presentation) Semester 7 - Industrial Training (Final Presentation)
Semester 7 - Industrial Training (Final Presentation) Nur Aisyah Khor
 
IoTt時代のERPに求められる条件とは2017Mar.
IoTt時代のERPに求められる条件とは2017Mar.IoTt時代のERPに求められる条件とは2017Mar.
IoTt時代のERPに求められる条件とは2017Mar.Keiichiro Nabeno
 
Industrial training presentation
Industrial training presentationIndustrial training presentation
Industrial training presentationisamhasbi
 
Contoh Presentation Latihan Industri (PIS)
Contoh Presentation Latihan Industri (PIS)Contoh Presentation Latihan Industri (PIS)
Contoh Presentation Latihan Industri (PIS)Syafwan Laili
 
Webの仕組みとプログラミング言語
Webの仕組みとプログラミング言語Webの仕組みとプログラミング言語
Webの仕組みとプログラミング言語Yossy Taka
 
Website people-our-workplace
Website people-our-workplaceWebsite people-our-workplace
Website people-our-workplaceSonata Software
 
MySQLerの7つ道具 plus
MySQLerの7つ道具 plusMySQLerの7つ道具 plus
MySQLerの7つ道具 plusyoku0825
 
Io tプラットフォーム主要ベンダ相関図2017mar.
Io tプラットフォーム主要ベンダ相関図2017mar.Io tプラットフォーム主要ベンダ相関図2017mar.
Io tプラットフォーム主要ベンダ相関図2017mar.Keiichiro Nabeno
 
Contoh Laporan Latihan Industri (FULL)
Contoh Laporan Latihan Industri (FULL)Contoh Laporan Latihan Industri (FULL)
Contoh Laporan Latihan Industri (FULL)Rizalshah Zulkifli
 
Social Media Workshop at Jordan University
Social Media Workshop at Jordan UniversitySocial Media Workshop at Jordan University
Social Media Workshop at Jordan UniversityDigiArabs
 

Andere mochten auch (20)

Easy backends with Symfony2 and the Sonata Admin bundle
Easy backends with Symfony2 and the Sonata Admin bundleEasy backends with Symfony2 and the Sonata Admin bundle
Easy backends with Symfony2 and the Sonata Admin bundle
 
Back-end with SonataAdminBundle (and Symfony2, of course...)
Back-end with SonataAdminBundle (and Symfony2, of course...)Back-end with SonataAdminBundle (and Symfony2, of course...)
Back-end with SonataAdminBundle (and Symfony2, of course...)
 
Have you played this Symfony? Why Symfony is great choice for Web development
Have you played this Symfony? Why Symfony is great choice for Web developmentHave you played this Symfony? Why Symfony is great choice for Web development
Have you played this Symfony? Why Symfony is great choice for Web development
 
Mastering Twig (DrupalCon Barcelona 2015)
Mastering Twig (DrupalCon Barcelona 2015)Mastering Twig (DrupalCon Barcelona 2015)
Mastering Twig (DrupalCon Barcelona 2015)
 
Symfony Components
Symfony ComponentsSymfony Components
Symfony Components
 
8 Simple Ways to Hack Your Joomla
8 Simple Ways to Hack Your Joomla8 Simple Ways to Hack Your Joomla
8 Simple Ways to Hack Your Joomla
 
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years laterSymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
 
Symfony Best Practices
Symfony Best PracticesSymfony Best Practices
Symfony Best Practices
 
30 Symfony Best Practices
30 Symfony Best Practices30 Symfony Best Practices
30 Symfony Best Practices
 
(株)農業情報設計社の取り組みついて
(株)農業情報設計社の取り組みついて(株)農業情報設計社の取り組みついて
(株)農業情報設計社の取り組みついて
 
Semester 7 - Industrial Training (Final Presentation)
Semester 7 - Industrial Training (Final Presentation) Semester 7 - Industrial Training (Final Presentation)
Semester 7 - Industrial Training (Final Presentation)
 
IoTt時代のERPに求められる条件とは2017Mar.
IoTt時代のERPに求められる条件とは2017Mar.IoTt時代のERPに求められる条件とは2017Mar.
IoTt時代のERPに求められる条件とは2017Mar.
 
Industrial training presentation
Industrial training presentationIndustrial training presentation
Industrial training presentation
 
Contoh Presentation Latihan Industri (PIS)
Contoh Presentation Latihan Industri (PIS)Contoh Presentation Latihan Industri (PIS)
Contoh Presentation Latihan Industri (PIS)
 
Webの仕組みとプログラミング言語
Webの仕組みとプログラミング言語Webの仕組みとプログラミング言語
Webの仕組みとプログラミング言語
 
Website people-our-workplace
Website people-our-workplaceWebsite people-our-workplace
Website people-our-workplace
 
MySQLerの7つ道具 plus
MySQLerの7つ道具 plusMySQLerの7つ道具 plus
MySQLerの7つ道具 plus
 
Io tプラットフォーム主要ベンダ相関図2017mar.
Io tプラットフォーム主要ベンダ相関図2017mar.Io tプラットフォーム主要ベンダ相関図2017mar.
Io tプラットフォーム主要ベンダ相関図2017mar.
 
Contoh Laporan Latihan Industri (FULL)
Contoh Laporan Latihan Industri (FULL)Contoh Laporan Latihan Industri (FULL)
Contoh Laporan Latihan Industri (FULL)
 
Social Media Workshop at Jordan University
Social Media Workshop at Jordan UniversitySocial Media Workshop at Jordan University
Social Media Workshop at Jordan University
 

Ähnlich wie Sonata AdminBundle: A backend generator for Symfony projects

ZF2 for the ZF1 Developer
ZF2 for the ZF1 DeveloperZF2 for the ZF1 Developer
ZF2 for the ZF1 DeveloperGary Hockin
 
Magento Dependency Injection
Magento Dependency InjectionMagento Dependency Injection
Magento Dependency InjectionAnton Kril
 
Symfony2 - from the trenches
Symfony2 - from the trenchesSymfony2 - from the trenches
Symfony2 - from the trenchesLukas Smith
 
Optimization in django orm
Optimization in django ormOptimization in django orm
Optimization in django ormDenys Levchenko
 
Working With The Symfony Admin Generator
Working With The Symfony Admin GeneratorWorking With The Symfony Admin Generator
Working With The Symfony Admin GeneratorJohn Cleveley
 
Digital Mayflower - Data Pilgrimage with the Drupal Migrate Module
Digital Mayflower - Data Pilgrimage with the Drupal Migrate ModuleDigital Mayflower - Data Pilgrimage with the Drupal Migrate Module
Digital Mayflower - Data Pilgrimage with the Drupal Migrate ModuleErich Beyrent
 
Symfony2 from the Trenches
Symfony2 from the TrenchesSymfony2 from the Trenches
Symfony2 from the TrenchesJonathan Wage
 
Building Large jQuery Applications
Building Large jQuery ApplicationsBuilding Large jQuery Applications
Building Large jQuery ApplicationsRebecca Murphey
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ EtsyNishan Subedi
 
Django Class-based views (Slovenian)
Django Class-based views (Slovenian)Django Class-based views (Slovenian)
Django Class-based views (Slovenian)Luka Zakrajšek
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf Conference
 
jQuery UI Widgets, Drag and Drop, Drupal 7 Javascript
jQuery UI Widgets, Drag and Drop, Drupal 7 JavascriptjQuery UI Widgets, Drag and Drop, Drupal 7 Javascript
jQuery UI Widgets, Drag and Drop, Drupal 7 JavascriptDarren Mothersele
 

Ähnlich wie Sonata AdminBundle: A backend generator for Symfony projects (20)

ZF2 for the ZF1 Developer
ZF2 for the ZF1 DeveloperZF2 for the ZF1 Developer
ZF2 for the ZF1 Developer
 
Magento Dependency Injection
Magento Dependency InjectionMagento Dependency Injection
Magento Dependency Injection
 
Symfony2 - from the trenches
Symfony2 - from the trenchesSymfony2 - from the trenches
Symfony2 - from the trenches
 
Django at the Disco
Django at the DiscoDjango at the Disco
Django at the Disco
 
Django at the Disco
Django at the DiscoDjango at the Disco
Django at the Disco
 
Django at the Disco
Django at the DiscoDjango at the Disco
Django at the Disco
 
Django at the Disco
Django at the DiscoDjango at the Disco
Django at the Disco
 
Optimization in django orm
Optimization in django ormOptimization in django orm
Optimization in django orm
 
WordCamp Praga 2015
WordCamp Praga 2015WordCamp Praga 2015
WordCamp Praga 2015
 
Working With The Symfony Admin Generator
Working With The Symfony Admin GeneratorWorking With The Symfony Admin Generator
Working With The Symfony Admin Generator
 
Django at the Disco
Django at the DiscoDjango at the Disco
Django at the Disco
 
Clean Javascript
Clean JavascriptClean Javascript
Clean Javascript
 
Digital Mayflower - Data Pilgrimage with the Drupal Migrate Module
Digital Mayflower - Data Pilgrimage with the Drupal Migrate ModuleDigital Mayflower - Data Pilgrimage with the Drupal Migrate Module
Digital Mayflower - Data Pilgrimage with the Drupal Migrate Module
 
Symfony2 from the Trenches
Symfony2 from the TrenchesSymfony2 from the Trenches
Symfony2 from the Trenches
 
Building Large jQuery Applications
Building Large jQuery ApplicationsBuilding Large jQuery Applications
Building Large jQuery Applications
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
 
Django Class-based views (Slovenian)
Django Class-based views (Slovenian)Django Class-based views (Slovenian)
Django Class-based views (Slovenian)
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
 
Migrare da symfony 1 a Symfony2
 Migrare da symfony 1 a Symfony2  Migrare da symfony 1 a Symfony2
Migrare da symfony 1 a Symfony2
 
jQuery UI Widgets, Drag and Drop, Drupal 7 Javascript
jQuery UI Widgets, Drag and Drop, Drupal 7 JavascriptjQuery UI Widgets, Drag and Drop, Drupal 7 Javascript
jQuery UI Widgets, Drag and Drop, Drupal 7 Javascript
 

Kürzlich hochgeladen

IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsRoshan Dwivedi
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 

Kürzlich hochgeladen (20)

IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 

Sonata AdminBundle: A backend generator for Symfony projects

  • 1. Sonata Project AdminBundle
  • 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
  • 3. Talk • Sonata Project presentation • Quick Tour • Under the hood • Customize / Advanced features • Conclusion
  • 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
  • 5. Sonata Project • An ecommerce toolbox • How : • avoiding reinvented the wheel • contribution to the community • built on top of a strong framework
  • 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
  • 8. AdminBundle why ?
  • 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.
  • 11. Admin Class • An metadata description of CRUD operations • No code generation • Based on Symfony services + Sonata Admin services
  • 12. Dashboard Actions shortcut Group + Model
  • 13. Dashboard Register admin class with the tag “sonata.admin” And admin will appears into the dashboard 1.     <services> 2.         <service id="sonata.news.admin.comment" class="%sonata.news.admin.comment.class%"> 3.             <tag name="sonata.admin" manager_type="orm" group="sonata_blog" label="comment"/> 4.             <argument /> 5.             <argument>%sonata.news.admin.comment.entity%</argument> 6.             <argument>%sonata.news.admin.comment.controller%</argument> 7.         </service> 8.   9.         <service id="sonata.news.admin.post" class="%sonata.news.admin.post.class%"> 10.            <tag name="sonata.admin" manager_type="orm" group="sonata_blog" label="post"/> 11.            <argument /> 12.            <argument>%sonata.news.admin.post.entity%</argument> 13.            <argument>%sonata.news.admin.post.controller%</argument> 14.        </service> 15.  16.        <service id="sonata.news.admin.tag" class="%sonata.news.admin.tag.class%"> 17.            <tag name="sonata.admin" manager_type="orm" group="sonata_blog" label="tag"/> 18.            <argument /> 19.            <argument>%sonata.news.admin.tag.entity%</argument> 20.            <argument>%sonata.news.admin.tag.controller%</argument> 21.        </service> 22.    </services>
  • 14. Breadcrumb List Action Model Actions Batch Actions Filters
  • 15. List Action fields, custom fields, type templates, type detection, based detection on Form Component
  • 16. List Action 1.     protected function configureDatagridFilters(DatagridMapper $datagridMapper) { 2.         $datagridMapper 3.   4.   5.                         ->add('name')     ->add('providerReference')     ->add('enabled') field guesser 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.  18.  19.                            'required' => false,         'multiple' => false,         'expanded' => false, custom filter 20.            ), 21.            'field_type'=> 'choice', 22.        )); 23.    } edit link 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.  32.              ->add('_action', 'actions', array(             'actions' => array( custom template 33.                    'view' => array(), 34.                    'edit' => array(), 35.                ) 36.            )) 37.  38.          ; } row’s actions
  • 18. Edit/Create Form Helper message add relation hide fields save options delete action
  • 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.         } create group 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.   19.                           'filter_choice' => array('hierarchy' => 'root'),             'required'      => false Form Component 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() group options 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.           )); } Define help messages
  • 20. Other Features • Permissions management • Flash messages • Nested Admin • Command lines utilities • Translated into more than10 languages
  • 21. Quick Tour Summary • Dashboard • Consistent Interface across bundles • Easy to configure, but powerful for advanced users • Advanced features • Inspired from the django admin module (user interactions)
  • 22. Under the hood http://www.flickr.com/photos/52251564@N08/5937620090
  • 23. Admin Class Dependencies Security Builder Sonata Admin Bundle List Symfony Framework Translator Datagrid Admin Show Routing class Form Validator Model Manager Form
  • 24. Security • Based on the SecurityHandlerInterface • 2 built-in implementations • NoopSecurityHandler : use the Symfony’s firewall • AclSecurityHandler : based on ACL - Advanced users only
  • 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.    } • Template Usage 1. {% if admin.isGranted('CREATE') %} 2.    // DO YOUR STUFF 3. {% endif %}
  • 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
  • 27. Routing • Definition set from the Admin class • Can be tweaked by the configureRoute 1.     /** 2.      * @param SonataAdminBundleRouteRouteCollection $collection 3.      * @return void 4.      */ 5.     protected function configureRoutes(RouteCollection $collection) 6.     { 7.         $collection->add('snapshots'); Add the id parameter 8.         $collection->remove('edit'); 9. 10.        $collection->add('test', $this->getRouterIdParameter().'/test'); 11.    } • Template Usage 1. <a href="{{ admin.generateUrl('view', { 'id' : media.id, 'format' : 'reference'}) }}">reference</a> 2. <a href="{{ admin.generateObjectUrl(media, 'view', {'format' : 'reference'}) }}">reference</a>
  • 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)
  • 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)
  • 30. Model Manager 1. class AdminModelManager extends ModelManager { 2.     protected $manager; Sonata Media Bundle 3.   4.     public function __construct($entityManager, $manager) { 5.         parent::__construct($entityManager); 2 Model Managers : 6.         $this->manager = $manager; - entity : deal with deletion and so on ... 7.     } 8.   - admin : proxy some methods to the entity 9.     public function delete($object) { 10.         $this->manager->delete($object); 11.     } How to ? 12. } 1. create a dedicated Admin Model Manager 1. class BundleMediaManager extends AbstractMediaManager {   2. create a Bundle Model Manager 1. public function delete(MediaInterface $media) { 2.         $this->pool 3. redefine only required methods 3. ->getProvider($media->getProviderName()) 4. define services 4. ->preRemove($media); 5.         $this->em->remove($media); 6.         $this->em->flush(); Delete thumbnails 7.   8.         $this->pool 9. ->getProvider($media->getProviderName()) 10. ->postRemove($media); 11.         $this->em->flush(); 12.     } 2. } 1.       <service id="sonata.media.admin.media" class="SonataMediaBundleEntityBundleMediaManager"> 2.             <tag name="sonata.admin" manager_type="orm" group="sonata_media" label="media"/> 3.             <argument /> 4.             <argument>%sonata.media.admin.media.entity%</argument> 5.             <argument>%sonata.media.admin.media.controller%</argument> 6.   7.             <call method="setModelManager"> 8.                 <argument type="service" id="sonata.media.admin.media.manager" /> 9.             </call> 10.         </service> 11.   12.         <service id="sonata.media.admin.media.manager" class="SonataMediaBundleAdminManagerDoctrineModelManager"> 13.             <argument type="service" id="doctrine.orm.default_entity_manager" /> 14.             <argument type="service" id="sonata.media.manager.media" /> 15.         </service>
  • 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
  • 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.
  • 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
  • 34. Core types Form Type Model Manager Types Form Types • 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.         ));
  • 35. Validator • Assert rules can be defined in the validation. [xml|yml] files (validator component) nothing new ... • Conditional Validation
  • 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
  • 37. Validator 1.   /** 2.      * @param SonataAdminBundleValidatorErrorElement $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.        ; symfony constraint 13.        14.        if ($object->getFoo()) { 15.            $errorElement 16.                ->with('test') 17.                    ->addViolation('my_message') 18.                ->end() 19.            ; 20.        } 21.    } custom error
  • 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)
  • 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.}
  • 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)
  • 42. Form : many-to-many • Type : sonata_type_model (ModelType) • Sonata Options • no options
  • 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
  • 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!
  • 45. Form Theme • Based on the form theme mechanism • Define a getFormTheme() • a set of form templates • allows to customize an admin form
  • 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]
  • 47. Form block • Theme definition 1.    protected $formTheme = array( 2.        'SonataAdminBundle:Form:form_admin_fields.html.twig', 3.        'SonataNewsBundle:Form:form.html.twig' 4.    ); • Block definition 1.{% block sonata_user_admin_user_credentialsExpired_text_widget %} 2.   PUT HERE THE WIDGET ... 3.{% endblock %} • Et voila!
  • 48. Custom List Template • Field definition 1.->add('custom', 'string', array('template' => 'SonataMediaBundle:MediaAdmin:list_custom.html.twig')) • Template 1.{% extends 'SonataAdminBundle:CRUD:base_list_field.html.twig' %} 2.  3.{% block field %} 4.    <div> 5.        <strong>{{ object.name }}</strong> <br /> 6.        {{ object.providerName|trans({}, 'SonataMediaBundle') }}: {{ object.width }}x{{ object.height }} <br /> 7.    </div> 8.{% endblock %} • Et voila!
  • 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
  • 50. Custom CRUD Controller 1. namespace SonataMediaBundleController; 2.   3. use SonataAdminBundleControllerCRUDController as Controller; Grant check 4. use SymfonyComponentSecurityCoreExceptionAccessDeniedException; 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']) { Custom Template 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.} Parent action
  • 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
  • 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.     } Display custom field if the 19.   20.     protected function configureListFields(ListMapper $listMapper) 21.     { 22.         $listMapper 23.             ->addIdentifier('name') current admin is nested or not 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. }
  • 53. Nested Admin Comment Admin Nested Comment Admin
  • 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
  • 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
  • 56. sonata:admin:list service name can be used to explain the admin configuration
  • 59. small numbers • First commit in november 2010 • 650 commits • 49 Contributors! • 14 Translations Thanks!
  • 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)
  • 61. Resources • http://sonata-project.org • irc : #symfony • twitter : @sonataproject • symfony google groups