Keeping your Yii Models Lean – Use Behaviors

0

Active Record models are fantastic for consolidating “black box” logic and keeping your models self-aware of their business logic, but what do you do when the business rules and object specific operations keep adding up?

Do yourself a favor, and get into the habit of putting those business logic methods into attachable behaviors.

If you’re not familiar with Behaviors at all, you can catch the basics here:

http://www.yiiframework.com/doc/api/1.1/CBehavior


http://www.yiiframework.com/doc/api/1.1/CActiveRecordBehavior

Not only does it make it easier to maintain your code, but it makes it much easier for a team to collaborate within the same area of development. You’ll also end up with a nice library of components which you can reuse.

For example, there is the built in timestamp behavior for updating timestamp fields on CActiveRecord models. See:
http://www.yiiframework.com/doc/api/1.1/CTimestampBehavior/

Need to ensure that some special logging happens each time a model is saved? Create a CActiveRecordBehavior for the model that has an afterSave method defined to run your checks and fire off the required logs/emails/what have you. You can use the same behavior for multiple models, so that if the logic needs to change, you can easily do so by changing just the behavior and not touch your core models.

Even if the logical process only applies to the one model, it’s worth putting it into a behavior just so that you can adjust the business end of it without modifying the core model.

For example, if you have a ‘Blog’ model that requires approval before it can be publicly visible, it makes sense to put the ‘approve’ method, right on the model so that you can access it consistently from multiple controller actions/etc. But even better, is to make that approve method a behavior that is attached to the model, along with the ‘reject’, etc. methods. Then, if you need to regenerate your core model for some reason (yii upgrade perhaps??) you can do so without losing your business logic pieces and conversely, if you need to update the approval process in some way, you can do so without the potential of breaking your blog model or have one person developing the approval process while another person works on the validation routines, etc. without conflict.

This is especially important when you have very complex rules that need to be applied to a model consistently regardless of where it is accessed from, so it’s a good habit to get into early.

One of the rules of thumb for this is, if you find yourself adding extra properties to the model to track information related to some business process, it’s a good bet you should be making that a behavior.

Originally posted at:
http://danaluther.blogspot.com/2011/08/keeping-your-yii-models-lean-use.html

Ajax based Yii login form

1

/protected/view/site/login.php

<?php
/* @var $this SiteController */
/* @var $model LoginForm */
/* @var $form CActiveForm  */

$this->pageTitle = Yii::app()->name . ' - Login';
$this->breadcrumbs = array(
    'Login',
);
?>

<h1>Login</h1>

<p>Please fill out the following form with your login credentials:</p>

<div class="form">
    <?php
    $form = $this->beginWidget('CActiveForm', array(
        'id' => 'login-form',
        'enableClientValidation' => true,
        'clientOptions' => array(
            'validateOnSubmit' => true,
            'afterValidate' => 'js:function(form, data, hasError) {
                if (!hasError){ 
                    str = $("#login-form").serialize() + "&ajax=login-form";

                    $.ajax({
                        type: "POST",
                        url: "' . Yii::app()->createUrl('site/login') . '",
                        data: str,
                        dataType: "json",
                        beforeSend : function() {
                            $("#login").attr("disabled",true);
                        },
                        success: function(data, status) {
                            if(data.authenticated)
                            {
                                window.location = data.redirectUrl;
                            }
                            else
                            {
                                $.each(data, function(key, value) {
                                    var div = "#"+key+"_em_";
                                    $(div).text(value);
                                    $(div).show();
                                });
                                $("#login").attr("disabled",false);
                            }
                        },
                    });
                    return false;
                }
            }',
        ),
    ));
    ?>

    <p class="note">Fields with <span class="required">*</span> are required.</p>

    <div class="row">
        <?php echo $form->labelEx($model, 'username'); ?>
        <?php echo $form->textField($model, 'username'); ?>
        <?php echo $form->error($model, 'username'); ?>
    </div>

    <div class="row">
        <?php echo $form->labelEx($model, 'password'); ?>
        <?php echo $form->passwordField($model, 'password'); ?>
        <?php echo $form->error($model, 'password'); ?>
    </div>

    <div class="row rememberMe">
        <?php echo $form->checkBox($model, 'rememberMe'); ?>
        <?php echo $form->label($model, 'rememberMe'); ?>
        <?php echo $form->error($model, 'rememberMe'); ?>
    </div>

    <div class="row buttons">
        <?php echo CHtml::submitButton('Login', array('id' => 'login')); ?>
    </div>

    <?php $this->endWidget(); ?>
</div><!-- form -->

actionlogin in protected/controllers/SiteController.php

     /**
     * Displays the login page
     */
    public function actionLogin()
    {
        $model = new LoginForm;

        // if it is ajax validation request
        if (isset($_POST['ajax']) && $_POST['ajax'] === 'login-form')
        {
            $errors = CActiveForm::validate($model);
            if ($errors != '[]')
            {
                echo $errors;
                Yii::app()->end();
            }
        }

        // collect user input data
        if (isset($_POST['LoginForm']))
        {
            $model->attributes = $_POST['LoginForm'];
            // validate user input and redirect to the previous page if valid
            if ($model->validate() && $model->login())
            {
                if (isset($_POST['ajax']) && $_POST['ajax'] === 'login-form')
                {
                    echo CJSON::encode(array(
                        'authenticated' => true,
                        'redirectUrl' => Yii::app()->user->returnUrl,
                        "param" => "Any additional param"
                    ));
                    Yii::app()->end();
                }
                $this->redirect(Yii::app()->user->returnUrl);
            }
        }
        // display the login form
        $this->render('login', array('model' => $model));
    }

How to save multiple related models in yii [Complete Solution]

1

Table Structure:

CREATE TABLE IF NOT EXISTS `fathers` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

CREATE TABLE IF NOT EXISTS `children` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `father_id` int(11) NOT NULL,
  `name` varchar(255) NOT NULL,
  `age` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `father_id` (`father_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

ALTER TABLE `children`
  ADD CONSTRAINT `children_ibfk_1` FOREIGN KEY (`father_id`) REFERENCES `fathers` (`id`) ON DELETE CASCADE;


Father Model:

/**
 * This is the model class for table "fathers".
 *
 * The followings are the available columns in table 'fathers':
 * @property integer $id
 * @property string $name
 *
 * The followings are the available model relations:
 * @property Children[] $childrens
 */
class Father extends CActiveRecord
{

    /**
     * Returns the static model of the specified AR class.
     * @param string $className active record class name.
     * @return Father the static model class
     */
    public static function model($className=__CLASS__)
    {
        return parent::model($className);
    }

    /**
     * @return string the associated database table name
     */
    public function tableName()
    {
        return 'fathers';
    }

    /**
     * @return array validation rules for model attributes.
     */
    public function rules()
    {
        // NOTE: you should only define rules for those attributes that
        // will receive user inputs.
        return array(
            array('name', 'required'),
            array('name', 'length', 'max' => 255),
            // The following rule is used by search().
            // Please remove those attributes that should not be searched.
            array('id, name', 'safe', 'on' => 'search'),
        );
    }

    /**
     * @return array relational rules.
     */
    public function relations()
    {
        // NOTE: you may need to adjust the relation name and the related
        // class name for the relations automatically generated below.
        return array(
            'children' => array(self::HAS_MANY, 'Child', 'father_id'),
        );
    }

    /**
     * @return array customized attribute labels (name=>label)
     */
    public function attributeLabels()
    {
        return array(
            'id' => 'ID',
            'name' => 'Name',
        );
    }

    /**
     * Retrieves a list of models based on the current search/filter conditions.
     * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
     */
    public function search()
    {
        // Warning: Please modify the following code to remove attributes that
        // should not be searched.

        $criteria = new CDbCriteria;

        $criteria->compare('id', $this->id);
        $criteria->compare('name', $this->name, true);

        return new CActiveDataProvider($this, array(
                    'criteria' => $criteria,
                ));
    }

    public function behaviors()
    {
        return array('ESaveRelatedBehavior' => array(
                'class' => 'application.components.ESaveRelatedBehavior')
        );
    }

}

Child Model:


<?php

/**
 * This is the model class for table "children".
 *
 * The followings are the available columns in table 'children':
 * @property integer $id
 * @property integer $father_id
 * @property string $name
 * @property integer $age
 *
 * The followings are the available model relations:
 * @property Fathers $father
 */
class Child extends CActiveRecord
{

    /**
     * Returns the static model of the specified AR class.
     * @param string $className active record class name.
     * @return Child the static model class
     */
    public static function model($className=__CLASS__)
    {
        return parent::model($className);
    }

    /**
     * @return string the associated database table name
     */
    public function tableName()
    {
        return 'children';
    }

    /**
     * @return array validation rules for model attributes.
     */
    public function rules()
    {
        // NOTE: you should only define rules for those attributes that
        // will receive user inputs.
        return array(
            array('father_id, name, age', 'required'),
            array('father_id, age', 'numerical', 'integerOnly' => true),
            array('name', 'length', 'max' => 255),
            // The following rule is used by search().
            // Please remove those attributes that should not be searched.
            array('id, father_id, name, age', 'safe', 'on' => 'search'),
        );
    }

    /**
     * @return array relational rules.
     */
    public function relations()
    {
        // NOTE: you may need to adjust the relation name and the related
        // class name for the relations automatically generated below.
        return array(
            'father' => array(self::BELONGS_TO, 'Father', 'father_id'),
        );
    }

    /**
     * @return array customized attribute labels (name=>label)
     */
    public function attributeLabels()
    {
        return array(
            'id' => 'ID',
            'father_id' => 'Father',
            'name' => 'Name',
            'age' => 'Age',
        );
    }

    /**
     * Retrieves a list of models based on the current search/filter conditions.
     * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
     */
    public function search()
    {
        // Warning: Please modify the following code to remove attributes that
        // should not be searched.

        $criteria = new CDbCriteria;

        $criteria->compare('id', $this->id);
        $criteria->compare('father_id', $this->father_id);
        $criteria->compare('name', $this->name, true);
        $criteria->compare('age', $this->age);

        return new CActiveDataProvider($this, array(
                    'criteria' => $criteria,
                ));
    }

    

}

Father Controller:

<?php

class FatherController extends Controller
{

    /**
     * @var string the default layout for the views. Defaults to '//layouts/column2', meaning
     * using two-column layout. See 'protected/views/layouts/column2.php'.
     */
    public $layout = '//layouts/column2';

    /**
     * @return array action filters
     */
    public function filters()
    {
        return array(
            'accessControl', // perform access control for CRUD operations
            'postOnly + delete', // we only allow deletion via POST request
        );
    }

    /**
     * Specifies the access control rules.
     * This method is used by the 'accessControl' filter.
     * @return array access control rules
     */
    public function accessRules()
    {
        return array(
            array('allow', // allow all users to perform 'index' and 'view' actions
                'actions' => array('index', 'view'),
                'users' => array('*'),
            ),
            array('allow', // allow authenticated user to perform 'create' and 'update' actions
                'actions' => array('create', 'update', 'loadChildByAjax'),
                'users' => array('@'),
            ),
            array('allow', // allow admin user to perform 'admin' and 'delete' actions
                'actions' => array('admin', 'delete'),
                'users' => array('admin'),
            ),
            array('deny', // deny all users
                'users' => array('*'),
            ),
        );
    }

    /**
     * Displays a particular model.
     * @param integer $id the ID of the model to be displayed
     */
    public function actionView($id)
    {
        $this->render('view', array(
            'model' => $this->loadModel($id),
        ));
    }

    /**
     * Creates a new model.
     * If creation is successful, the browser will be redirected to the 'view' page.
     */
    public function actionCreate()
    {
        $model = new Father;

        // Uncomment the following line if AJAX validation is needed
        $this->performAjaxValidation($model);

        if (isset($_POST['Father']))
        {
            $model->attributes = $_POST['Father'];

            if (isset($_POST['Child']))
            {
                $model->children = $_POST['Child'];
            }
            if ($model->saveWithRelated('children'))
                $this->redirect(array('view', 'id' => $model->id));
            else
                $model->addError('children', 'Error occured while saving children.');
        }

        $this->render('create', array(
            'model' => $model,
        ));
    }

    /**
     * Updates a particular model.
     * If update is successful, the browser will be redirected to the 'view' page.
     * @param integer $id the ID of the model to be updated
     */
    public function actionUpdate($id)
    {
        $model = $this->loadModel($id);

        // Uncomment the following line if AJAX validation is needed
        // $this->performAjaxValidation($model);

        if (isset($_POST['Father']))
        {
            $model->attributes = $_POST['Father'];
            if (isset($_POST['Child']))
            {
                $model->children = $_POST['Child'];
            }
            if ($model->saveWithRelated('children'))
                $this->redirect(array('view', 'id' => $model->id));
            else
                $model->addError('children', 'Error occured while saving children.');
        }

        $this->render('update', array(
            'model' => $model,
        ));
    }

    /**
     * Deletes a particular model.
     * If deletion is successful, the browser will be redirected to the 'admin' page.
     * @param integer $id the ID of the model to be deleted
     */
    public function actionDelete($id)
    {
        $this->loadModel($id)->delete();

        // if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser
        if (!isset($_GET['ajax']))
            $this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));
    }

    /**
     * Lists all models.
     */
    public function actionIndex()
    {
        $dataProvider = new CActiveDataProvider('Father');
        $this->render('index', array(
            'dataProvider' => $dataProvider,
        ));
    }

    /**
     * Manages all models.
     */
    public function actionAdmin()
    {
        $model = new Father('search');
        $model->unsetAttributes();  // clear any default values
        if (isset($_GET['Father']))
            $model->attributes = $_GET['Father'];

        $this->render('admin', array(
            'model' => $model,
        ));
    }

    /**
     * Returns the data model based on the primary key given in the GET variable.
     * If the data model is not found, an HTTP exception will be raised.
     * @param integer the ID of the model to be loaded
     */
    public function loadModel($id)
    {
        $model = Father::model()->findByPk($id);
        if ($model === null)
            throw new CHttpException(404, 'The requested page does not exist.');
        return $model;
    }

    /**
     * Performs the AJAX validation.
     * @param CModel the model to be validated
     */
    protected function performAjaxValidation($model)
    {
        if (isset($_POST['ajax']) && $_POST['ajax'] === 'father-form')
        {
            echo CActiveForm::validate($model);
            Yii::app()->end();
        }
    }

    public function actionLoadChildByAjax($index)
    {
        $model = new Child;
        $this->renderPartial('child/_form', array(
            'model' => $model,
            'index' => $index,
//            'display' => 'block',
        ), false, true);
    }

}

Create Father Form:

<?php
/* @var $this FatherController */
/* @var $model Father */
/* @var $form CActiveForm */
?>

<div class="form">

    <?php
    $form = $this->beginWidget('CActiveForm', array(
        'id' => 'father-form',
        'focus' => array($model, 'name'),
        'enableClientValidation' => true,
        'enableAjaxValidation' => true,
            ));
    ?>

    <p class="note">Fields with <span class="required">*</span> are required.</p>

    <?php echo $form->errorSummary($model); ?>

    <div class="row">
        <?php echo $form->labelEx($model, 'name'); ?>
        <?php echo $form->textField($model, 'name', array('size' => 60, 'maxlength' => 255)); ?>
        <?php echo $form->error($model, 'name'); ?>
    </div>

    <?php
    echo CHtml::link('Add Child', '#', array('id' => 'loadChildByAjax'));
    ?>
    <div id="children">
        <?php
        $index = 0;
        foreach ($model->children as $id => $child):
            $this->renderPartial('child/_form', array(
                'model' => $child,
                'index' => $id,
                'display' => 'block'
            ));
            $index++;
        endforeach;
        ?>
    </div>

    <div style="clear:both;"></div>
    <div class="row buttons">
        <?php echo CHtml::submitButton($model->isNewRecord ? 'Create' : 'Save'); ?>
    </div>

    <?php $this->endWidget(); ?>

</div><!-- form -->

<?php
Yii::app()->clientScript->registerCoreScript('jquery');
Yii::app()->clientScript->registerScript('loadchild', '
var _index = ' . $index . ';
$("#loadChildByAjax").click(function(e){
    e.preventDefault();
    var _url = "' . Yii::app()->controller->createUrl("loadChildByAjax", array("load_for" => $this->action->id)) . '&index="+_index;
    $.ajax({
        url: _url,
        success:function(response){
            $("#children").append(response);
            $("#children .crow").last().animate({
                opacity : 1, 
                left: "+50", 
                height: "toggle"
            });
        }
    });
    _index++;
});
', CClientScript::POS_END);
?>

Child form: views\father\child\_form.php

<div style="margin-bottom: 20px; display: <?php echo!empty($display) ? $display : 'none'; ?>; width:100%; clear:left;" class="crow">

    <div class="row" style="width:200px;float: left;">
        <?php echo CHtml::activeLabelEx($model, '[' . $index . ']name'); ?>
        <?php echo CHtml::activeTextField($model, '[' . $index . ']name', array('size' => 20, 'maxlength' => 255)); ?>
        <?php echo CHtml::error($model, '[' . $index . ']name'); ?>
    </div>

    <div class="row" style="width:200px;float: left;">
        <?php echo CHtml::activeLabelEx($model, '[' . $index . ']age'); ?>
        <?php echo CHtml::activeTextField($model, '[' . $index . ']age'); ?>
        <?php echo CHtml::error($model, '[' . $index . ']age'); ?>
    </div>
    <div class="row" style="width:100px;float: left;">
        <br />
        <?php echo CHtml::link('Delete', '#', array('onclick' => 'deleteChild(this, ' . $index . '); return false;'));
        ?>
    </div>
</div>

<?php
Yii::app()->clientScript->registerScript('deleteChild', "
function deleteChild(elm, index)
{
    element=$(elm).parent().parent();
    /* animate div */
    $(element).animate(
    {
        opacity: 0.25, 
        left: '+=50', 
        height: 'toggle'
    }, 500,
    function() {
        /* remove div */
        $(element).remove();
    });
}", CClientScript::POS_END);

This solution uses esaverelatedbehavior developed by sluderitz for saving related models, you can download it here

http://www.yiiframework.com/extension/esaverelatedbehavior/

Solution: Table ‘myDB.AuthAssignment’ doesn’t exist

1

Problem:
When you upload your Yii website to a Linux server, and you are using yii-rights module you see following error

Table 'yourDB.AuthAssignment' doesn't exist

This is because your tables are in lowercase but in code they are being referred with different capitalization, Linux is case senstive so it treats authassignment and AuthAssignment differently.

Solution:
In your root/protected/config/main.php specify table names as they are in your database.

'components'=>array(
    'authManager'=>array( 
            'defaultRoles'=>array('guest'),
            'class'=>'RDbAuthManager',
            'assignmentTable'=>'authassignment',
            'itemTable'=>'authitem',
            'rightsTable'=>'rights',
            'itemChildTable'=>'authitemchild',
    ), 

How to make Yii checkBoxList selected

0

I Suppose you have created a MAN_MANY relation as given below.

Book Model:

'authors' => array(self::MANY_MANY, 'Author', 'authorbook(book_id,author_id)'),

Author Model:

'books' => array(self::MANY_MANY, 'Book', 'authorbook(author_id, book_id)'),

Note: authorbook is the table name containing ids

Checkbox List in form:

$books = CHtml::listData(Book::model()->findAll(), 'id', 'name');
$selected_keys = array_keys(CHtml::listData( $model->books, 'id' , 'id'));
echo CHtml::checkBoxList('Author[books][]', $selected_keys, $books);

How to separate front and admin panel in yii-framework

1

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-end and back-end related files.

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

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:

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:

'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.

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

mouseover with delay (using hoverIntent plugin)

0

hoverIntent is a plug-in that attempts to determine the user’s intent… like a crystal ball, only with mouse movement! It works like (and was derived from) jQuery’s built-in hover. However, instead of immediately calling the onMouseOver function, it waits until the user’s mouse slows down enough before making the call.

Why? To delay or prevent the accidental firing of animations or ajax calls. Simple timeouts work for small areas, but if your target area is large it may execute regardless of intent.

var config = {    
     over: makeTall, // function = onMouseOver callback (REQUIRED)    
     timeout: 500, // number = milliseconds delay before onMouseOut    
     out: makeShort // function = onMouseOut callback (REQUIRED)    
};

$("#demo3 li").hoverIntent( config )

Download hoverIntent r6 (fully-commented, uncompressed)

Download hoverIntent r6 (minified)

Authorize.net integration with Magento

0

1- Create a test account on Authorize.net (
https://developer.authorize.net/testaccount/
)

2- On successful signup you will see following info, save them at safe place.

  1. API Login ID
  2. Transaction Key

3- Login to your Magento Admin panel and navigate to

  1. System -> Configuration -> Payment Methods
  2. Expand Authorize.net
  3. Insert “API Login ID” and “Transaction Key” into this form and make other settings as shown below

authorize.net

6. Save Configuration and you are DONE!

Add “Home” link in Magento top navigation menu

0

1- Copy following 2 files

design/frontend/base/template/page/html/topmenu.phtml
design/frontend/base/template/catalog/navigation/top.phtml

TO

design/frontend/default/yourtheme/template/page/html/topmenu.phtml
design/frontend/default/yourtheme/template/catalog/navigation/top.phtml

2. Replace the content with following code

<?php $_menu = $this->getHtml('level-top') ?>
<?php if($_menu): ?>
<div class="nav-container">
    <ul id="nav">
         <!-- HOME BUTTON HACK -->
        <?php $_anyActive = false; foreach ($this->getStoreCategories() as $_category) { $_anyActive = $_anyActive || $this->isCategoryActive($_category); } ?>
        <li class="<?php echo !$_anyActive ? 'active' : '' ?>"><a href="<?php echo $this->getUrl('')?>"><?php echo $this->__('Home') ?></a></li>
        <!-- HOME BUTTON HACK -->
        <?php echo $_menu ?>
    </ul>
</div>
<?php endif ?>