Showing posts with label Yii. Show all posts
Showing posts with label Yii. Show all posts

Wednesday, January 15, 2014

CTabcontrol with each tab containing a widget (Yii)

Suppose in Yii, we want to pass the content of a widget to a tab in the tab control

<?php
ob_start();
$this->widget('zii.widgets.CListView', array(
    'dataProvider'=>$vulnerdataProvider,
    'itemView'=>'_latest_vulner'
));
$tab1Content=ob_get_contents();
ob_end_clean();

$this->widget('zii.widgets.jui.CJuiTabs',array(
    'tabs'=>array(
        'Tab1'=> array('content' => $tab1Content,'id' => 'tab1'),
        'tab2'=>array('content'=>'Content for tab 2', 'id'=>'tab2'),
    ),
    // additional javascript options for the tabs plugin
    'options'=>array(
        'collapsible'=>true,
    ),
));
?>

CTabView with partial view in each tab (Yii)

Suppose using Yii framework and we want to add a tab control in which each tab shows a partial view, the following codes shows how this can be done:

<?php
$nc_view=$this->renderPartial('_viewNodeConfig', array('project'=>$model), $return=true);
$user_view=$this->renderPartial('_viewUser', array('project'=>$model), $return=true);
$sim_view=$this->renderPartial('_viewSimulation', array('project'=>$model), $return=true);

$this->widget('CTabView',array(
    'activeTab'=>'tab2',
    'tabs'=>array(
        'tab1'=>array(
            'title'=>'Users',
            'content'=>$user_view,
        ),
        'tab2'=>array(
            'title'=>'Node Types',
            'content'=>$nc_view,
        ),
        'tab3'=>array(
            'title'=>'Simulations',
            'content'=>$sim_view,
        )
    ),
    'htmlOptions'=>array(
        //'style'=>'width:500px;'
    )
));
?>
In the above codes, the _viewNodeConfig.php is a partial view which looks like the following:
<?php 
$node_configs=new CActiveDataProvider('NodeConfig', 
    array(
     'criteria'=>array( 
      'condition'=>'audit_project_id=:projectId', 
      'params'=>array(':projectId'=>$project->id),
     ),
     'pagination'=>array( 
      'pageSize'=>4,
     ), 
    )
   );
   
$this->widget('zii.widgets.CListView', array(
 'dataProvider'=>$node_configs,
 'viewData'=>array('project'=>$project),
 'itemView'=>'/nodeConfig/_view',
)); 
?>

Sunday, January 12, 2014

Cascade delete in Yii model by overriding beforeDelete() and afterDelete() method

Yii provides Cascade using relations with the cascade constraint defined in database, which allows the user to delete cascade data when a model is deleted. However, in some cases, the user may want to perform this on his own (e.g. there may be some sophisticated conditioning involved during the cascade delete, or other resources such as images to be deleted associated with the model). In such a case, the user can override the beforeDelete() and afterDelete() method to perform the clean up (e.g. delete images and cascaded objects associated with the deleted model). Suppose we have a model class Project, and we want to delete a set of users as well as an image associated with the deleted Project model:

Step 1: Override beforeDelete()

Add a variable idCache to the User model class in protected/models/User.php:
private $idCache;
Next override the beforeDelete() method to assign User->id to idCache:
public function beforeDelete()
{
 $this->idCache = $this->id;

 return parent::beforeDelete();
}
The purpose of having idCache is to cache the User->id attribute in the beforeDelete() method and use it in the afterDelete() method (since the $User->id will no longer be available in the afterDelete() method

Step 2: Override afterDelete()

Next we will delete the associated users and image to the deleted Project model by overriding the afterDelete() method:
public function afterDelete()
{
 $criteria = new CDbCriteria(array(
   'condition' => 'project_id=:projectId',
   'params' => array(
    ':projectId' => $this->idCache),
  ));

 $users_associated_with_project = User::model()->findAll($criteria);

 foreach ($users_associated_with_project as $user)
 {
  $user->delete();
 }
 
 $filename=$this->getImagePath($this->idCache);
 if(file_exists($filename))
 {
  unlink($filename);
 }

 parent::afterDelete();
}

Create CListView of a model class in another model's view (Yii)

Suppose we have two models: Project and User, in which each Project owns a number of Users. We wish to display a list of associated users in the project instance's view

Modify the protected/views/project/view.php by adding the following line in the script file:

<?php $this->renderPartial('_viewUser', array('project'=>$model)); ?>

Next create a partial view protected/views/project/_viewUser.php with the following codes for its implementation:

<?php 
$users=new CActiveDataProvider('User', 
    array(
     'criteria'=>array( 
      'condition'=>'audit_project_id=:projectId', 
      'params'=>array(':projectId'=>$project->id),
     ),
    ),
    array( 
     'pagination'=>array( 
      'pageSize'=>20,
     ), 
    )
   );
   
$this->widget('zii.widgets.CListView', array(
 'dataProvider'=>$users,
 'viewData'=>array('project'=>$project),
 'itemView'=>'/user/_view',
)); 
?>

Cascade create a model and attach it to another model in Controller in a One-to-Many relationship (Yii)

Suppose we have a situation where we a set of users, each of which belong to a particular project. In Yii, we already create two models, namely Project and User. The User model class contains an attribute project_id, which is the id attribute value of the associated Project model. Now a user cannot be created without knowing the project_id it is associated with

Step 1:

In the protected/views/project/view.php, add a link to create user associated with the project:

<?php echo CHtml::link(CHtml::encode('Create user under the project'), array('user/create', 'project_id'=>$model->id)); ?>
The project_id allows the UserController (i.e. the controller associated with the User model) to identify the project_id to which the created user should be associated with.

Step 2:

In the protected/controllers/UserController.php, add a private member variable _project:

private $_project = null;

Next in the UserController.php, find the method filters(), and add one line for projectContext filter:

/**
 * @return array action filters
 */
public function filters()
{
 return array(
  'accessControl', // perform access control for CRUD operations
  'projectContext + create index admin', //check to ensure valid event context
 );
}

Next in the UserController.php, defines the following methods:

public function filterProjectContext($filterChain) 
{
 //set the project identifier based on either the GET or POST input
 //request variables, since we allow both types for our actions 
 $project_id = null;
 if(isset($_GET['project_id'])) 
  $project_id = $_GET['project_id'];
 else
  if(isset($_POST['project_id'])) 
   $project_id = $_POST['project_id'];
 $this->loadProject($project_id);
 //complete the running of other filters and execute the requested action
 $filterChain->run();
}

protected function loadProject($project_id) 
{ 
 //if the project property is null, create it based on input id 
 if($this->_project===null) 
 {
  $this->_project=Project::model()->findbyPk($project_id); 
  if($this->_project===null)
  { 
   throw new CHttpException(404,'The requested project does not exist.'); 
  }
 }
 return $this->_project;
}
The above method allows Yii code to create and assign the _project with the content from database using the project_id passed in from Step 1. As a result, before the actionCreate() method is invoked, the _project is already properly initialized based project_id attribute passed in. The final step is to assign $user->project_id in the actionCreate() method of the UserController class, as shown below:
public function actionCreate()
{
 $model=new User;
 $model->project_id=$this->_project->id;

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

 if(isset($_POST['User']))
 {
  $model->attributes=$_POST['User'];
  if($model->save())
   $this->redirect(array('view','id'=>$model->id));
 }

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

Use of beforeSave() and beforeValidate() for Yii models when writing to database

beforeValidate() is very handy for performing validation of the model before it is save to the database in Yii, below shows an example of how it is used in a Yii model class Project

protected function beforeValidate() 
{
 if($this->isNewRecord)
 {
  // set the create date, last updated date and the user doing the creating
  $this->audit_create_time=$this->audit_update_time=new CDbExpression('NOW()');
  $this->audit_update_time=new CDbExpression('NOW()'); 
  
  $existing_proj=Project::model()->find('projname=?', array($this->projname));
  if(isset($existing_proj))
  {
   return false;
  }
 }
 else
 {
  //not a new record, so just set the last updated time and last updated user id
  $this->audit_update_time=new CDbExpression('NOW()'); 
 }
 
 return parent::beforeValidate();
}
The above code checks whether a project with the same projname already exist in the database, if yes, then the validation return false, it also updates the create time and update time depending on whether the action is to create or update a project.

beforeSave() is useful to perform additional data processing before a model is saved to the database, below shows an example of how it is used in a Yii model class User

public function beforeSave()
{  
 if($this->isNewRecord)
 {
  $this->audit_db_create_time=$this->audit_db_update_time=new CDbExpression('NOW()');
 }
 else
 {
  $this->audit_db_update_time=new CDbExpression('NOW()'); 
 }
 
 $this->password=$this->encrypt($this->password);
 
 return TRUE;
}
The above code encrypt the password before it is saved to the database, it also updates the create time and update time for writing the model to the database depending on whether the action is to create or update a user

Some useful HTML elements in Yii

Create Html Link in Yii

  1. The code below creates a html link to user view which has id = 23
    <?php echo CHtml::link(CHtml::encode('View User with ID = 23'), array('user/view', 'id'=>23)); ?>
    
  2. The code below creates a html link to the html form for creating a user
  3. <?php echo CHtml::link(CHtml::encode('Create User'), array('user/create')); ?>
    

Create Html Label in Yii

The code below creates a html label

<?php echo CHtml::label(CHtml::encode('Some Text'), 'Some Text'); ?>

Create Html ComboBox in Yii

The code below creates a html combobox

<?php echo $form->dropDownList($model, 'field_name', array(1=>'test1', 2=>'test2'));?>
The code belows creates a html combobox with list data populating dropdown from database values
<?php echo $form->dropDownList($model,'node_types_id', CHtml::listData(NodeTypes::model()->findAll(array('order' => 'name')),'id','name'));?>

Monday, July 15, 2013

Yii Themes

To change the Yii default themes, download the theme from one of the Yii theme sites such as:

http://yii.themefactory.net/

After download, extract and copy the theme folder into the "themes" folder at your Yii application root folder. Suppose that the theme folder you name it as "MyNewTheme". Next in the protected/config/main.php, add or change the line:

'theme'=>"MyNewTheme",

within the returned array.


Resolve the PDO disabling issues for Yii on Godaddy hosting

My Yii application uses PDO for database access, which requires the server to have the PDO enabled. However, I am having some problem hosting my Yii application on GoDaddy, since hosting providers suych as GoDaddy disable PDO. After some searching, I found an alternative PHPPDO for Yii, which can be downloaded from:

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

This extension allow you to use PHP-emulated PDO class on that hostings. The process of including PHPPDO for Yii application is very simple:

Step 1: download and extract the content of PHPPDO to protected/extensions of your Yii application
Step 2: in the protected/config/main.php, commented out the original db connection configuration and replaced with the PHPPDO one, just as in the following:

                /*
'db'=>array(
'connectionString' => 'sqlite:'.dirname(__FILE__).'/../data/testdrive.db',
),
// uncomment the following to use a MySQL database
'db'=>array(
'connectionString' => $ps_connectionString,
'emulatePrepare' => true,
'username' => $ps_dbusername,
'password' => $ps_dbpassword,
'charset' => 'utf8',
),*/
'db'=>array(
'class'=>'application.extensions.PHPPDO.CPdoDbConnection',
'pdoClass' => 'PHPPDO',
'connectionString' => $ps_connectionString,
'emulatePrepare' => true,
'username' => $ps_dbusername,
'password' => $ps_dbpassword,
'charset' => 'utf8',
),

500 (Internal Server Error) on GoDaddy when running Yii application

I have encountered and a problem with GoDaddy when running Yii application on the server. On the local machine, everything run smoothly for the Yii application. However, after I transfer the Yii application to Godaddy web hosting, I encountered the "500 (Internal Server Error)" when trying to visit the Yii application, no other information about the error is given. The error goes away after I set the permission for the Yii application's "assets" and "protected/runtime" to Read/Write.

During testing, i found another possible source of code errors that may cause the "500 (Internal Server Error)", which is when the developer does not specify the correct database host name when configure the protected/config/main.php

When the "500 (Internal Server Error)" happened on GoDaddy for Yii application, the best way to discover the error is to examine the protected/runtime/application.log, which may log the error.