How to separate front and admin panel in yii-framework

How to separate front and admin panel in yii-framework

In my previous post I demonstrated you how to render different layout for different user role, now lets move a step forward and see how to create separate front and admin panel in a Yii based application.

If you need help in creating admin panel in yii, you can email me at scriptbaker@gmail.com or Skype chat

If you are not familiar with events & behaviors yet, then please, read this tutorial to get basic knowledge about using them.

First, create a new web application with yiic tool. I used an application generated by Yii 1.1.1, but everything described below should work with other versions of Yii Framework (probably with minor changes).

Now let’s modify some directories’ structure to separate front and admin panel related files.

Since application’s ends usually use the same models, but different controllers and views, we will separate them by creating two sub directories under protected/controllers and protected/views directories:

Directory Structure:

webroot/
    themes/
		bootstrap/
            /front
                /layouts
                    column1.php
                    column2.php
                    main.php
                /site
                   /pages
                       about.php
                   contact.php
                   error.php
                   index.php
                   login.php
    protected/
        components/
            Controller.php
            UserIdentity.php
        controllers/
            /front
                SiteController.php
            /back
                SiteController.php
        views/
            /back
                /layouts
                    column1.php
                    column2.php
                    main.php
                /site
                    error.php
                    index.php
                    login.php

Front-end SiteController and all front-end views are files generated by yiic tool. You have to create back-end SiteController and back-end views by yourself (or just copy and modify front-end ones).

Now let’s create different config files for both ends. Since these files usually have much in common, we will “inherit” them from the main.php config:

webroot/protected/config/front.php:

return CMap::mergeArray(
    require(dirname(__FILE__).'/main.php'),
    array(
        'theme' => 'bootstrap',
        'components'=>array(
            'urlManager' => array(
            'urlFormat' => 'path',
            'showScriptName' => false,
            'rules' => array(
                '<controller:\w+>/<id:\d+>' => '<controller>/view',
                '<controller:\w+>/<action:\w+>/<id:\d+>' => '<controller>/<action>',
                '<controller:\w+>/<action:\w+>' => '<controller>/<action>',
            ),
        ),
        )
        // Put front-end settings there
    )
);

webroot/protected/config/back.php:

return CMap::mergeArray(
        require(dirname(__FILE__) . '/main.php'), array(
            'components' => array(
                /*
                'urlManager' => array(
                    'urlFormat' => 'path',
                    'showScriptName' => false,
                    'rules' => array(
                        'backend' => 'admin/login',
                        'backend/<_c>' => '<_c>',
                        'backend/<_c>/<_a>' => '<_c>/<_a>',
                    ),
                ),
                 */
            )
        )
);

By default, Yii will try to find controllers and views in protected/controllers and protected/views directories respectively. We have to change this behavior and force Yii to search controllers and views in the “back” or “front” subdirectories depending on the currently running end.

Actually we can do it in the -end’s config file by setting “viewPath” and “controllerPath” properties, but what if we are going to have some modules like News, Articles, etc.? We’ll need to set these properties for them too. We can also have some back-end modules which don’t need such separation.

Here comes the Yii magic. In protected/components directory create a file “WebApplicationEndBehavior.php” with the following contents:

protected\components\WebApplicationEndBehavior.php

class WebApplicationEndBehavior extends CBehavior
{
    // Web application end's name.
    private $_endName;

    // Getter.
    // Allows to get the current -end's name
    // this way: Yii::app()->endName;
    public function getEndName()
    {
        return $this->_endName;
    }

    // Run application's end.
    public function runEnd($name)
    {
        $this->_endName = $name;

        // Attach the changeModulePaths event handler
        // and raise it.
        $this->onModuleCreate = array($this, 'changeModulePaths');
        $this->onModuleCreate(new CEvent($this->owner));

        $this->owner->run(); // Run application.
    }

    // This event should be raised when CWebApplication
    // or CWebModule instances are being initialized.
    public function onModuleCreate($event)
    {
        $this->raiseEvent('onModuleCreate', $event);
    }

    // onModuleCreate event handler.
    // A sender must have controllerPath and viewPath properties.
    protected function changeModulePaths($event)
    {
        $event->sender->controllerPath .= DIRECTORY_SEPARATOR.$this->_endName;

        if ($event->sender->theme !== null)
            $event->sender->viewPath = $event->sender->theme->basePath.DIRECTORY_SEPARATOR.'views'.DIRECTORY_SEPARATOR.$this->_endName;
        else
            $event->sender->viewPath .= DIRECTORY_SEPARATOR.$this->_endName;
    }
}

Now add some lines to the main config file:
webroot/protected/config/main.php:

'import' => array(
    'application.models.*',
    'application.components.*',
),
...
...
...
'behaviors' => array(
    'runEnd' => array(
       'class' => 'application.components.WebApplicationEndBehavior',
    ),
),

Now our application has a new method runEnd (to run one of the application’s ends) and a new event onModuleCreate. By raising this event from a web module we can change modules’ properties. Controllers and views paths are changed in the attached handler “changeModulePaths”.

If you have a module, which should use different controllers and views for different ends, then just modify it’s init() method:

protected function init()
{
    // ...    

    // We can configure our module depending on the value
    // of Yii::app()->endName.
    $this->foo = (Yii::app()->endName == 'front') ? 'bar1' : 'bar2';

    // Raise onModuleCreate event.
    Yii::app()->onModuleCreate(new CEvent($this));
}

Note that in this case the module’s controllers and views paths must be organized as shown before.

If a module doesn’t need a separation to back-end and front-end controllers and views, then just omit the onModuleCreate event’s raising.

Finally, let’s protect back-end by creating a parent controller for all back-end controllers:

webroot/protected/components/BackEndController.php:

class BackEndController extends CController
{
    public $layout='layout_name';
    public $menu=array();
    public $breadcrumbs=array();

    public function filters()
    {
        return array(
            'accessControl',
        );
    }

    public function accessRules()
    {
        return array(
            array('allow',
                'users'=>array('*'),
                'actions'=>array('login'),
            ),
            array('allow',
                'users'=>array('@'),
            ),
            array('deny',
                'users'=>array('*'),
            ),
        );
    }
}

webroot/protected/controllers/back/SiteController.php must extend this controller to perform access checking.

Everything’s done. New index.php and backend.php files are:

webroot/index.php:

$yii = dirname(__FILE__).'/../yii/framework/yii.php';
$config = dirname(__FILE__).'/protected/config/front.php';

// Remove the following lines when in production mode
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL', 3);

require_once($yii);
Yii::createWebApplication($config)->runEnd('front');

webroot/backend.php:

$yii = dirname(__FILE__).'/../yii/framework/yii.php';
$config = dirname(__FILE__).'/protected/config/back.php';

// Remove the following lines when in production mode
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL', 3);

require_once($yii);
Yii::createWebApplication($config)->runEnd('back');

Back-end url rules:

AddDefaultCharset utf-8

Options +FollowSymLinks
IndexIgnore */*
RewriteEngine on

# Make the backend accessible via url: http://site/backend.
RewriteRule ^backend backend.php

# If a directory or a file exists, use it directly.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# Otherwise forward it to index.php.
RewriteRule . index.php

Then, in the back.php config file un-comment url manager component:

Now you can generate beautiful urls using CHtml::link() method.

If you have a module (e.g. news), then you’ll need to add 3 more rules before existing ones:

'backend/news'=>'news',
'backend/news/<_c>'=>'news/<_c>',
'backend/news/<_c>/<_a>'=>'news/<_c>/<_a>',

Also, you still can add own rules:

'backend/news/<id:\d+>'=>'news/newsReport/update',

But make sure that you insert these rules before news rules containing and . Otherwise the latter rules will be used instead.

Download

If you are having any difficulty in understanding/implementing this tutorial, I baked two applications for you using above recipe. Just unpack them and start eating! 😉

Yii Admin Panel

Yii Admin Panel with Rights Module

Rights enabled application uses a database for user authentication, you can find the DB in protected/data folder

Ref: http://www.yiiframework.com/…

Author: Tahir Yasin

Tahir is a Passionate Web Developer from Lahore, Pakistan and a guy with NEVER-STOP-LEARNING attitude who keeps an eye on emerging technologies and customer trends.

34 thoughts on “How to separate front and admin panel in yii-framework”

  1. Hi i have followed your front and backend steps but there is problem with layouts. Layouts is not working with front folder structure

    1. @pawandeep. I think Tahir has given you sufficient information to get you started. This should not a forum for solving problems in details. Look at the Yii forums or stackoverflow for assistance. (Tahir, I hope I am not speaking for you, but I don’t want your site to degrade into one-line discussiond trying to solve problems. Feel free to delete this post after some time)

  2. Hello,
    Nice tutorial. Everything seems to work fine excepting for “$this->foo = (Yii::app()->endName == ‘front’) ? ‘bar1’ : ‘bar2’;” which I do not understand.
    To be exact, I have the “Rights” module installed but I want it accessible only from ‘back’ (while doing its job on boths ends). Everything is fine, excepting the fact I can access “?r=rights” both from front and end. Where and what do I have to change for this? Thanks a lot!

  3. Is there a flexible admin. system for administering websites that can be changed and expanded MANUALLY to fit the website to which it is applied?
    Or do i have to make my own from scratch?

    NOT CMS, i dont need a way to change the site. ONLY MANAGE

  4. Hello, Sir.
    I have managed to follow your tutorial but I’m confused how to make a new controller for back side.
    I had tried to render a new controller (let say : ArticleController) then I put it in folder “controller/back/”.
    The result is error When I tried to access localhost/mySite/back/article.

    What should I do to solve it?
    Thank you.

      1. Thank for your reply, Sir.
        I had copied some script from your sample then run it. It works.

        Actually, I have that problem because I tought that the URL for back-panels is :
        localhost/mySite/back/controllerName/action

        now, I run my back-panel using url :
        localhost/mySite/back.php?r=controllerName/action.

        Now, I have a new problem 😀
        I use YIIBooster for my application but when I tried use widget CKeditor, The widget was not working.
        The problem is some javascript file not loaded.

        When I tried to load same widget in another aplication witch is not applied back-front separated, it was working.

        What should I change for make it right?
        Thanks a lot!

  5. Hi, I’ve downloaded sample with rights, but to my localhost/appName it return me “Internal Server Error
    The server encountered an internal error or misconfiguration and was unable to complete your request” I config database too … what the issue ? (ubuntu machine) thanks

  6. if it helps someone else, I had to edit the .htaccess file
    instead of
    Options + FollowSymlinks
    I wrote:
    Options FollowSymLinks Indexes

    and in the Apache configuration file I pointed AllowOvrride All

  7. Hello Sir,
    I have just started working on Yii. i have different modules like, news, articles, events. i have done all backend task. Now i want to create user pannel for events means when user login the user direct reach on event dasboard. please help me step by step.

    Thank You

    1. You can render different layouts & views based on current user role.

      if(Yii::app()->user->checkAccess('events.index'))
      {
       // this user can access index action of events controller 
      }
      

Leave a Reply

Your email address will not be published. Required fields are marked *