Monday, January 7, 2013

Symfony2.1 Setup Sonata Admin bundle


 
This post is specially for create basic administrator panel for symfony2.1 project with authentication, user management and beautiful admin interface. We will use FOSUserBundle and SonataAdminBundle and their supported bundle for create our admin application. This post explain installation and minimum configuration for each bundle. For detail visit official documentation of particular bundle.


Before starting you should create basic symfony2.1 package and create virtual host for your project.


My Server configuration :

PHP 5.3.18-1~dotdeb.0 with Suhosin-Patch (cli) (built: Oct 19 2012 08:17:21)

Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2012 Zend Technologies
   with Xdebug v2.1.0, Copyright (c) 2002-2010, by Derick Rethans
   with Suhosin v0.9.33, Copyright (c) 2007-2012, by SektionEins GmbH

My Symfony version :
Symfony version 2.1.3 - app/dev/debug

Step : 1 - Add following requirements in your composer.json
php composer.phar require friendsofsymfony/user-bundle (version :  *)
php composer.phar require sonata-project/admin-bundle (version : dev-master)
php composer.phar require sonata-project/doctrine-orm-admin-bundle (version : dev-master)
php composer.phar require sonata-project/intl-bundle (version : dev-master)
php composer.phar require sonata-project/user-bundle
(version : dev-master)


Step : 2 - Active following bundle in app/AppKernel.php
new FOS\UserBundle\FOSUserBundle(),
new Sonata\jQueryBundle\SonatajQueryBundle(),
new Sonata\AdminBundle\SonataAdminBundle(),
new Sonata\DoctrineORMAdminBundle\SonataDoctrineORMAdminBundle(),
new Knp\Bundle\MenuBundle\KnpMenuBundle(),
new Sonata\BlockBundle\SonataBlockBundle(),
new Sonata\UserBundle\SonataUserBundle('FOSUserBundle'),
new Sonata\EasyExtendsBundle\SonataEasyExtendsBundle(),
new Application\Sonata\UserBundle\ApplicationSonataUserBundle(),
new Sonata\IntlBundle\SonataIntlBundle(),


Step : 3 - Configure fos_user
in app/config/config.yml
fos_user:
   db_driver: orm
   firewall_name: main
   user_class: Application\Sonata\UserBundle\Entity\User


Step : 4 - Generate user bundle in app/Application/Sonata/UserBundle
php app/console sonata:easy-extends:generate SonataUserBundle


Step : 5 - Register application sonata user bundle in app/autoload.php
$loader->add('Application', __DIR__);



Step : 6 - Active new Bundle in app/AppKernel.php
new Application\Sonata\UserBundle\ApplicationSonataUserBundle(),


Step : 7 - Add routing in app/config.routing.yml
fos_user_security:
   resource: "@FOSUserBundle/Resources/config/routing/security.xml"
fos_user_profile:
   resource: "@FOSUserBundle/Resources/config/routing/profile.xml"
   prefix: /profile
fos_user_register:
   resource: "@FOSUserBundle/Resources/config/routing/registration.xml"
   prefix: /register
fos_user_resetting:
   resource: "@FOSUserBundle/Resources/config/routing/resetting.xml"
   prefix: /resetting
fos_user_change_password:
   resource: "@FOSUserBundle/Resources/config/routing/change_password.xml"
   prefix: /change-password
admin:
   resource: '@SonataAdminBundle/Resources/config/routing/sonata_admin.xml'
   prefix: /admin
_sonata_admin:
   resource: .
   type: sonata_admin
   prefix: /admin
soanata_user:
   resource: '@SonataUserBundle/Resources/config/routing/admin_security.xml'
   prefix: /admin
sonata_user_impersonating:
   pattern: /
   defaults: { _controller: SonataPageBundle:Page:catchAll }# app/config/routing.yml
fos_user_security:
   resource: "@FOSUserBundle/Resources/config/routing/security.xml"
fos_user_profile:
   resource: "@FOSUserBundle/Resources/config/routing/profile.xml"
   prefix: /profile
fos_user_register:
   resource: "@FOSUserBundle/Resources/config/routing/registration.xml"
   prefix: /register
fos_user_resetting:
   resource: "@FOSUserBundle/Resources/config/routing/resetting.xml"
   prefix: /resetting
fos_user_change_password:
   resource: "@FOSUserBundle/Resources/config/routing/change_password.xml"
   prefix: /change-password
admin:
   resource: '@SonataAdminBundle/Resources/config/routing/sonata_admin.xml'
   prefix: /admin
_sonata_admin:
   resource: .
   type: sonata_admin
   prefix: /admin
soanata_user:
   resource: '@SonataUserBundle/Resources/config/routing/admin_security.xml'
   prefix: /admin
sonata_user_impersonating:
   pattern: /
   defaults: { _controller: SonataPageBundle:Page:catchAll }


Step : 8 - Add the following to app/config/security.yml
security:
   encoders:
       FOS\UserBundle\Model\UserInterface: sha512
   role_hierarchy:
       ROLE_ADMIN:       ROLE_USER
       ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_SONATA_ADMIN, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
       SONATA:
           - ROLE_SONATA_PAGE_ADMIN_PAGE_EDIT  # if you are not using acl then this line must be uncommented
   providers:
       fos_userbundle:
           id: fos_user.user_manager
   firewalls:
       # ---> custom firewall for the admin area of the URL
       admin:
           pattern:      /admin(.*)
           form_login:
               provider:       fos_userbundle
               login_path:     /admin/login
               use_forward:    false
               check_path:     /admin/login_check
               failure_path:   null
           logout:
               path:           /admin/logout
           anonymous:    true
       # ---> end custom configuration
       # defaut login area for standard users
       main:
           pattern:      .*
           form_login:
               provider:       fos_userbundle
               login_path:     /login
               use_forward:    false
               check_path:     /login_check
               failure_path:   null
           logout:       true
           anonymous:    true

#--------------
   access_control:
       # URL of FOSUserBundle which need to be available to anonymous users
       - { path: ^/_wdt, role: IS_AUTHENTICATED_ANONYMOUSLY }
       - { path: ^/_profiler, role: IS_AUTHENTICATED_ANONYMOUSLY }
       - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
       # -> custom access control for the admin area of the URL
       - { path: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
       - { path: ^/admin/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }
       - { path: ^/admin/login-check$, role: IS_AUTHENTICATED_ANONYMOUSLY }
       # -> end
       - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
       - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
       # Secured part of the site
       # This config requires being logged for the whole site and having the admin role for the admin part.
       # Change these rules to adapt them to your needs
       - { path: ^/admin, role: [ROLE_ADMIN, ROLE_SONATA_ADMIN] }
       - { path: ^/.*, role: IS_AUTHENTICATED_ANONYMOUSLY }
#--------------


Step : 9 - Update db schema
php app/console doctrine:schema:update --force

NOTE : if symfony give 'Unknown column type "json" requested.......'  error, add custom type in Doctrine configuration see below code

doctrine:
   dbal:
       #for SonataNotificationBundle
       types:
         json: Sonata\Doctrine\Types\JsonType
       #----


Step : 10 - Install assets and clear cache
php app/console assets:install web
php app/console cache:clear


Step : 11 - Lets create admin user
php app/console fos:user:create admin admin@admin.com rajesh --super-admin



Step : 12 - Add sonata admin configuration in app/config/config.yml
sonata_admin:
 title:      <your application title>
 title_logo: /path/to/logo_title.png
 
 dashboard:
     blocks:
         #          # display a dashboard block
         - { position: left, type: sonata.admin.block.admin_list }



Step : 13 - Add sonata block configuration in app/config/config.yml
sonata_block:
   default_contexts: [cms]
   blocks:
       sonata.admin.block.admin_list:
           contexts:   [admin]

       #sonata.admin_doctrine_orm.block.audit:
       #    contexts:   [admin]

       sonata.block.service.text:
       sonata.block.service.rss:

       # Some specific block from the SonataMediaBundle
       #sonata.media.block.media:
       #sonata.media.block.gallery:
       #sonata.media.block.feature_media:


Step : 13 - Enable your translator in /app/config.yml
framework:
   translator: ~


Step : 14 - Add SonataIntl configuration in app/config/config.yml
sonata_intl:
   timezone:
       # default timezone used as fallback
       default: Europe/Paris

       # locale specific overrides
       locales:
           fr: Europe/Paris
           en_UK: Europe/London


Step : 15 - Now open and login
http://yourdomain/app_dev.php/admin/dashboard
User : admin
Paassword : rajesh



  
Now, your fully functional symfony 2.1 admin panel is ready.
For more reference see http://sonata-project.org


Please share your ideas, comments and join my blog

Thanks,
Rajesh Meniya
Symfony Developer
 

Wednesday, November 21, 2012

Get all error messages from symfony 1.4 form class

Hello symfonians

This is special post for symfony developers, who struggling for get all error message from symfony-1.4 form object.


It's very easy for normal form object, see below code block :

1:  <?php
2:  $errors = array(); 
3:  foreach ($Form->getErrorSchema() as $key => $err) {  
4:    if ($key) {  
5:      $errors[$key] = $err->getMessage();  
6:    }  
7:  }
8:  ?>  


See errors array :
1:  <?php   
2:    print_r($errors);  
3:  ?>  




But what for embedded forms, continue reading for solution.




Create formUtility class in project lib directory :

1:  <?php   
2:  class formUtility {  
3:    /**  
4:     * Process Form object and return array of errors  
5:     *   
6:     * @param object $form Form object  
7:     * @param array $embedded_forms String array of embedded form names  
8:     * @return array Array of error messages and total errors count.  
9:     * @author Rajesh Meniya<rjmeniya@gmail.com>  
10:     */  
11:    public static function getErrors($form = false, $embedded_forms = array()) {  
12:      if (!$form){  
13:        return false;  
14:      }  
15:      $errors = array();  $total_error++;
16:      // individual widget errors  
17:      foreach ($form as $form_field) {  
18:        if ($form_field->hasError()) {  
19:          $error_obj = $form_field->getError();  
20:          if ($error_obj instanceof sfValidatorErrorSchema) {  
21:            foreach ($error_obj->getErrors() as $error) {  
22:              // add namespace for embedded form erros  
23:              if ($form->getName() != $form->getName()) {  
24:                $errors[$form->getName()][$form_field->getName()][] = $error->getMessage();  $total_error++;
25:              } else {  
26:                $errors[$form_field->getName()][] = $error->getMessage();  
27:              }  
28:            }  
29:          } else {  
30:            if ($form->getName() != $form->getName()) {  
31:              $errors[$form->getName()][$form_field->getName()][] = $error_obj->getMessage();  $total_error++;
32:            } else {  
33:              $errors[$form_field->getName()] = $error_obj->getMessage();  $total_error++;
34:            }  
35:          }  
36:        }  
37:      }  
38:      // for global errors  
39:      foreach ($form->getGlobalErrors() as $validator_error) {  
40:        $errors[] = $validator_error->getMessage();  
41:      }  
42:      // for embedded form error processing  
43:      $count_embedded_error = 0;  
44:      if (count($embedded_forms) && is_array($embedded_forms) ) {  
45:        foreach($embedded_forms as $key => $embedded_form_name){  
46:          if (isset($errors[$embedded_form_name])) {  
47:            if(is_array($errors[$embedded_form_name])){  
48:              foreach($errors[$embedded_form_name] as $key1=>$errors_embedded){  
49:                $error_embedded_form = array();  
50:                $asEFRawErrors = explode("]", $errors_embedded);  
51:                foreach($asEFRawErrors as $ssRawError){  
52:                  if ($ssRawError!=null) {  
53:                    $raw_error = explode("[",$ssRawError);  
54:                    $error_embedded_form[trim($raw_error[0])] = trim($raw_error[1]);  $total_error++;
55:                    //$error_embedded_form[] = $ssRawError;  
56:                  }  
57:                }  
58:                $errors[$embedded_form_name][$key1] = $error_embedded_form;  
59:                $count_embedded_error += count($error_embedded_form);  
60:              }  
61:            }  
62:          }  
63:        }  
64:      }  
65:      $errors_final['error_message'] = $errors;  
66:      // count errors  
67:      $errors_final['error_count'] = $total_error;
68:      return $errors_final;  
69:    }  
70:  }  
71:  ?>  



Let's use our formUtility class in action for get array of all errors.

1:  <?php  
2:  /**  
3:   * Action class   
4:   */  
5:  class companyActions extends sfActions {  
6:    /**  
7:     * Action for handle posted form   
8:     */  
9:    public function executeCreate(sfWebRequest $request) {  
10:      $form = new BlogForm();  
11:      if ($request->isMethod("post")) {  
12:        $form->bind($request->getParameter($form->getName()));  
13:        // user of our formUtility class  
14:        $errors = formUtility::getErrors($form, array('comments'));  
15:        print_r($errors);
16:      }  
17:    }  
18:  }  
19:  ?>  



Please, give your valuable comments and +1

Thanks