Showing posts with label Yii Framework. Show all posts

Showing posts with label Yii Framework. Show all posts

Yii framework CHtml::image() example



CHtml::image() is helper for generate HTML img tag in Yii framework.

1.Class Reference

public static string image(string $src, 
                           string $alt='', 
                           array $htmlOptions=array ( ))
  • $src: string of image path
  • $alt: html alt tag content, for altenative text display when img lost.
  • $htmlOptions: array of HTML attribute of img

2.Example of Chtml::image()

In the following examples, we assume that image files are located in YII_APP_BASE_PATH/img/ . For example, you have a yii application called : blog, and add all images in blog/img/ folder. Yii have a variable called Yii::app()->request->baseUrl point to application root folder, you can use this variable for base path.
 - Image only:
echo CHtml::image(Yii::app()->request->baseUrl.'/img/image.png'); 
- Image with alt attribute:
 
echo CHtml::image(Yii::app()->request->baseUrl.'/img/image.png',
                                          "this is alt tag of image"); 
Result:
<img src="..." alt="this is alt tag of image">
- Add width and height attribute for image:
echo CHtml::image(Yii::app()->request->baseUrl.'/img/image.png',
      "this is alt tag of image",
      array("width"=>"50px" ,"height"=>"50px"));
Result:
<img alt="this is alt tag of image" height="50px" src="..." width="50px" />
You can also add another html attributes like class, id,etc for image in the similar way to adding width and height attribute for image above.

Gii generate model and CRUD for Module

Gii is a web-based code generator tool for Yii framework to help developer create new source code easier and faster. It save developer's time to develop a web application.
  Yii also support developer build modules in web application which is located in /protected/modules folder. Each module have its own model, controller and view like an application. The followings are some tips to generate model and its CRUD for module.

1.Generate a model for module using Gii. 

In model generator page, after input Table Name, Model Class name,instead of the Model path application.models value, let's place the alias of models in the module that you want to generate like the following image:

As you can see above, we have the alias structure :
application.modules.NAME_OF_MODULE.models
is the model path for all models of module has name :  NAME_OF_MODULE .
Just change the Name_OF_MODULE to generate in which module you want.

2. Generate CRUD for model in a module

CRUD refer to Create , Read, Update, Delete action,the four basic functions of persistent storage. In Gii,CRUD generator generates a controller and views that implement CRUD operations for the specified data model. So, we can can also generate CRUD for  model which locates in module by placing value like the followings:
For Model class, just place alias of Model file similar to [1] generate model class.
application.modules.NAME_OF_MODULE.models.MODEL_CLASS_NAME For controller Id, instead of controller class name, input : NAME_OF_MODULE/CONTROLLER_CLASS_NAME  to specific controller.


yii - role base access control for module

yii framework logo
After adding source code for role base access control validation (RBAC validation )for application. You can check the access role in Module level, Controller level or action level.

For module level, as you know each module have AdminModule class in which init()  likes module configuration method, and  beforeControllerAction() method is called before any module controller action is performed. You may place your customized code in this method to perform the access role checking for all controllers of current Module.

For example, I have an Admin module  in my application. I want to limit access of this module for administrator only.  In AdminModule class, I place checkAccess() like the followings:
class AdminModule extends CWebModule
{
 public function init()
 {
  $this->setImport(array(
   'admin.models.*',
   //'application.models.*',
   'admin.components.*',
  ));
 }
 
 public function beforeControllerAction($controller, $action)
 {
  if(parent::beforeControllerAction($controller, $action))
  {
   // this method is called before any module controller action is performed
   // you may place customized code here
   if ( !Yii::app()->user->checkAccess('admin') ) {
    if(Yii::app()->user->isGuest){
     $url = Yii::app()->createUrl(Yii::app()->user->loginUrl);
     Yii::app()->user->returnUrl = Yii::app()->createUrl('/admin/');
     Yii::app()->request->redirect($url);
    }
    else {
     throw new CHttpException(403,'Have no permission');
    }
   }
   return true;
  }
  else
   return false;
 }
}

yii - customize the error message of a validation rule

Validators extending from CValidator all have a property named message. You can set this property in the corresponding validation rule to customize the error message. For example, the following validation rule uses an error message that is different from the default one:
class Post extends CActiveRecord{
    public function rules(){
        return array(
            array('title, content', 'required',
                  'message'=>'Please enter a value for {attribute}.'),
            // ... other rules
        );
    }
}

In the above, the customized error message contains a predefined placeholder {attribute}. The CRequiredValidator (whose alias is required) will replace this placeholder with the actual attribute name that fails the validation.
Reference:
http://www.yiiframework.com/wiki/1/

yii - register client script adding javascript & css file in view example

yii logo
Yii have CClientScript package which supports us register client script like javascript and css file in view. For better performance, we should use CClientScript to include js, css file instead of append html tag in layout.
We should do that in some cases:
  1. Write client script without using any widgets or built-in components of Yii
  2. Using ajax calling: some time we return the result in html type by using renderPartial() method. It's will return all clientscript that is written in that view, without register clientscript it will render every time we return the view
  3. Loading any yii widget with ajax request and we need to call this multiple time then what happens, ajax call each time load the js file or jquery file, which slows down your application.
So, we can do something below to get your app better:

Register core script

Yii have built-in client script packages which locate in yii/framework/web/js/source folder. The list of all supporting client script is listed in yii/framework/web/js/packages.php file. You can take a look at that file to see how to see the name of them. For example, I register 'jquery' as a core script like the followings
Yii::app()->clientScript->registerCoreScript('jquery');
Yii will render jquery into /assets folder. Here is the result:
<script type="text/javascript" src="/assets/3869f222/jquery.js"></script>

Register a javascript file

For register a javascript file in Yii. We use registerScriptFile method which path of file as parameter.

Yii::app()->clientScript->registerScriptFile(
Yii::app()->theme->baseUrl.'/assets/js/default.js',
CClientScript::POS_END);

You can also specific the position of include tag in script by using CClientScript:POS_* ( with * is the specific position).
- At the bottom of html page (before tag)
Yii::app()->clientScript->registerScriptFile(
Yii::app()->theme->baseUrl.'/assets/js/default.js',
CClientScript::POS_END);
result:
<script type="text/javascript" src="/themes/summer/assets/js/default.js"></script>
-At the begin of page (right after body tag)
Yii::app()->clientScript->registerScriptFile(
Yii::app()->theme->baseUrl.'/assets/plugin/bootstrap/js/bootstrap.min.js',
CClientScript::POS_BEGIN);

- In the header of page :
 Yii::app()->clientScript->registerScriptFile(
Yii::app()->theme->baseUrl.'/assets/plugin/jquery/datetime-ja.js',
CClientScript::POS_HEAD);
result:
<script type="text/javascript" src="/themes/summer/assets/plugin/jquery/datetime-ja.js"></script>
You also use POS_LOAD and POS_READY option, to include script when page loading or when all DOM is ready.

Register css file

To register a css file in Yii, you just have to use registerCssFile method of clientScript class like the followings.
 Yii::app()->clientScript->registerCssFile(
             Yii::app()->theme->baseUrl.'/assets/css/style.css'
           );
As the above, we specific the path of css file as a parameter of registerCssFile method. That style.css is in /assets/css of theme folder of yii application. And the result (summer is name of current theme of app):
<link rel="stylesheet" type="text/css" href="/themes/summer/assets/css/style.css" />
We can also specific css file for media type. See more media type at: reference
For example, I include print.css file for print media type :
 Yii::app()->clientScript->registerCssFile(
             Yii::app()->theme->baseUrl.'/assets/css/print.css',
             'print'
           );
and here is the result:
<link rel="stylesheet" type="text/css" href="/themes/summer/assets/css/style.css" media="print" />

Yii migration insert data to table

To insert data into any table using yii migration. You can use insert method of CDbMigration class.
For example, I have table called user in DB which have 3 fields including email, username and password. Now, we want to have some user for testing, you can write down in up() method of Yii migration like following:
 class m130726_010519_insert_user extends CDbMigration
{
 public function up()
 { 
  $this->insert('tbl_user',array(
         'email'=>'test1@notanaddress.com',
         'username' =>'User One',
         'password' => md5('test1'),
  ));
  $this->insert('tbl_user',array(
    'email'=>'test2@notanaddress.com',
    'username' =>'User Two',
    'password' => md5('test2'),
  ));
 }

 public function down()
 {
  echo "m130726_010519_insert_user does not support migration down.\n";
  return false;
 }


}

List of mysql column type declaration in Yii migration

Yii supports database migration via the yiic migrate command line tool. This tool supports creating new migrations, applying/reverting/redoing migrations, and showing migration history and new migrations.In this entry, we will know more about the data column types that is supported in Yii, and have some tips on defining some columns types.

Basic column type which is defined from Yii

From CDbSchema schema abstract class which is the base class for retrieving metadata information. It contains a method called getColumnType($type) which get available column type that is defined for Yii migration to support creating database schema.
For MySQL database, we have a class called CMysqlSchema which extends CDbSchema base class, defined column types array that Yii is supporting for MySQL. It's defined as below:
 public $columnTypes=array(
  'pk' => 'int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY',
  'string' => 'varchar(255)',
  'text' => 'text',
  'integer' => 'int(11)',
  'float' => 'float',
  'decimal' => 'decimal',
  'datetime' => 'datetime',
  'timestamp' => 'timestamp',
  'time' => 'time',
  'date' => 'date',
  'binary' => 'blob',
  'boolean' => 'tinyint(1)',
  'money' => 'decimal(19,4)',
 );
  • pk: an auto-incremental primary key type, will be converted into "int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY"
  • string: string type, will be converted into "varchar(255)"
  • text: a long string type, will be converted into "text"
  • integer: integer type, will be converted into "int(11)"
  • float: float number type, will be converted into "float"
  • decimal: decimal number type, will be converted into "decimal"
  • datetime: datetime type, will be converted into "datetime"
  • timestamp: timestamp type, will be converted into "timestamp"
  • time: time type, will be converted into "time"
  • date: date type, will be converted into "date"
  • boolean: boolean type, will be converted into "tinyint(1)"
  • binary: binary data type, will be converted into "blob"
  • money: will be converted into decimal(19,4)

Using Yii migration to create new table

As you know, to create a table in database by using Yii migration, we have to config db component in /config/console.php, run yiic migrate create command on console, fill out up(), down() method in new file that is generated by Yii migration. In this entry, I will not explain how to use Yii migration step by step. I just want to focus on some tips to define a table in mysql database in Yii migration file. For example, we have to create a table which have the structure like the following:
  CREATE TABLE IF NOT EXISTS `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(150) NOT NULL,
  `password` varchar(32) NOT NULL,
  `email` varchar(255) NOT NULL,
  `description` text NOT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP,
  `isvalid` boolean DEFAULT 1,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

We will try to use Yii columns types to define first
class m130827_034420_create_user extends CDbMigration
{
 public function up()
 {
  $this -> createTable ('user', array(
    'id' => 'pk',
    'name' => 'string NOT NULL',
    'password'=> 'string NOT NULL',
    'email' =>'string NOT NULL',
    'description' =>'text  NOT NULL',
    'created_at' => 'datetime NOT NULL',
    'updated_at'=> 'timestamp DEFAULT CURRENT_TIMESTAMP',
    'isvalid' => 'boolean DEFAULT 1'
  ),'ENGINE=InnoDB DEFAULT CHARSET=utf8');
  
 }
 public function down()
 {
  $this->dropTable('user');
 }

}

and here is the result:

There are two problems we need to resolve:
  • The primary key type is int(11), not bigint(20)
  • The length of name and password is 255

Defining Big integer primary key

just change
  'id' => 'pk',
become
   'id' => 'bigint(20) AUTO_INCREMENT PRIMARY KEY',
because we just have pk column type which is defined in Yii. It's will become "int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY" as mentioned before in CMysqlSchema class. We do not have bigpk to become "bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY " , so we have to define it directly in colums array.

Specifying The Length Of String In Yii Migration


  'name' => 'string NOT NULL',
become
   'name' => 'varchar(150) NOT NULL',
and do it again with what varchar field you want to specific length, because string type is converted into varchar(255) in Yii. Now, we have new m130827_034420_create_user class:
 
 class m130827_034420_create_user extends CDbMigration
{
 public function up()
 {
  $this -> createTable ('user', array(
    'id' => 'bigint(20) AUTO_INCREMENT PRIMARY KEY',
    'name' => 'varchar(150) NOT NULL',
    'password'=> 'varchar(32) NOT NULL',
    'email' =>'string NOT NULL',
    'description' =>'text  NOT NULL',
    'created_at' => 'datetime NOT NULL',
    'updated_at'=> 'timestamp DEFAULT CURRENT_TIMESTAMP',
    'isvalid' => 'boolean DEFAULT 1'
  ),'ENGINE=InnoDB DEFAULT CHARSET=utf8');
  
 }
 public function down()
 {
  $this->dropTable('user');
 }

}

which will create the table like the followings:

Yii framework - CHtml::link() example

Yii framework - CHtml::link() example  some spaghetti code
In this post, i try to make some spaghetti code for Yii Chtml::link() method, to get familiar with Yii Chtml::link() fast. It's may be helpful for some one who is new in Yii.
     /**
       link() method
     */

     public static string link(string $text, 
                                      mixed $url='#', 
                                      array $htmlOptions=array ( ))

     /**
       @params: $text: anchord text (also called link text, link title)
                $url : value of href attribute
                $htmlOptions : array of other html attributes
    */
    

Basic using of CHtml::link()

echo CHtml::link('Link Text',array('controller/action')); 
Basing on your urlManager config, the output href may be different, but will be like the following in HTML output:
<a href="index.php?r=controller/action">Link Text</a>
or
<a href="controller/action">Link Text</a>

2. Link to an action with parameter

Sometime, we need to include some parameter when sending request to an url. To do that, you just have to add more element to url array like:
echo CHtml::link('Link Text',array('controller/action',
                                         'param1'=>'value1',
                                         'param2'=>'value2')); 
It's will include all parameters in url like
<a href="index.php?r=controller/action&param1=value1&param2=value2">
Link Text</a>

3. Link to an action have the same controller

echo CHtml::link('Link Text',array('action')); 

4.Link to an action in specific module

For controller in the same module, you also declare in this way to set the absolute path link to controller.
echo CHtml::link('Link Text',array('/module-name/controller/action')); 

5. Link to an action in root

With slash ('/') at the beginning of url array, it's set the absolute path for url
echo CHtml::link('Link Text',array('/controller/action')); 

Customizing $htmlOptions with CHtml::link()

6.Open link in new tab

 echo CHtml::link('Link Text',array('controller/action',
                   'param1'=>'value1'), array('target'=>'_blank');

7. Add class and id for link

 echo CHtml::link('Link Text',array('controller/action',
                   'param1'=>'value1'), 
                    array('class'=>'class_name','id'=>'id_name');

Linking to a controller action via POST

- Delete via Post method, by clicking on link :
    echo CHtml::link('Delete',
                     "#",
                     array("submit"=>array('delete', 'id'=>$data->ID), 
                           'confirm' => 'Are you sure?')); 
Reference:
  •  http://www.yiiframework.com/wiki/48/by-example-chtml/
  • http://www.yiiframework.com/doc/api/1.1/CHtml#link-detail

yii Framework - calling model class from another module

Found a question from Yii framework forum. It's a bit late to answer, copy here and save my solution.
I have 3 modules in my application. Is there anyway share models between modules. How to call models defined in another modules.Within same module I can do something like User::model() but what if this model is defined in another module. Any suggestion.




You can import model class from another module by setImport in  init method of module default class. For example, you want to use model class of TestModule in  AdminModule ( Controller class in AdminModule will call model class of TestModule). In /modules/admin/AdminModule.php class (extends from CWebModule) , find init method and setImport like following:
        public function init()
        {
                // this method is called when the module is being created
                // you may place code here to customize the module or the application

                // import the module-level models and components
                $this->setImport(array(
                        'admin.models.*',
                        'application.modules.test.models.*',
                        'admin.components.*',
                ));
        }
By this way, you just have to import model class from specific module you want.

Multiple Database connection in Yii framework

Some ways to use multiple database connection in Yii framework.

1. Declare more database Connection in config file

To use multiple database connection you can try putting another db component into the configuration file at protected/config/main.php

array(
'components'=>array(
    'db'=>array(
  'connectionString' => 'mysql:host=localhost;dbname=yii_blog',
  'emulatePrepare' => true,
  'username' => 'YOUR_USERNAME',
  'password' => '*************',
  'charset' => 'utf8',
  'tablePrefix' => 'tbl_',
  ),
    'anotherDb' => array(
            'connectionString' => 'mysql:host=adserver2;dbname=anotherDB',
            'username'         => 'YOUR_USERNAME',
            'password'         => '***********',
            ...
            'class'            => 'CDbConnection'          // DO NOT FORGET THIS!
             ),
),
The parameters should generally follow the pattern of the first entry, but you must include the class parameter ('class' => 'CDbConnection' ) in the second so that Yii knows you're defining a DB Connection object. It will fail without this.

You can access them by calling like that

$firstDb = Yii::app()->db;
$firstDb->active = true;
// etc, then
$secondDb = Yii::app()->anotherDb;
$secondDb->active = true;

or GetDbConnection() override in model class like the following:
    class YourModel extends CActiveRecord {
    ...
    private $anotherDb = null;
 
    protected function getDbConnection()
    {
        if (self::$anotherDb !== null)
            return self::$anotherDb;
        else
        {
            self::$anotherDb = Yii::app()->anotherDb;
            if (self::$anotherDb instanceof CDbConnection)
            {
                self::$anotherDb->setActive(true);
                return self::$anotherDb;
            }
            else
                throw new CDbException(Yii::t('yii','Active Record requires'.
                           'a "db" CDbConnection application component.'));
        }
    }

Note: This entry will be update more if We know another way to do

[2002] No such file or directory (trying to connect via unix:///var/mysql/mysql.sock)

I tried Yii Framework migration by using yiic in console. when yiic migrate database, it try to connect to db following the information that be configured like below:
        'db'=>array(
   'connectionString' => 'mysql:host=localhost;dbname=YOURDBNAME',
   'emulatePrepare' => true,
   'username' => 'DBUSER',
   'password' => 'DBPASS',
   'charset' => 'utf8',
  ),
and faced an exception:
[2002] No such file or directory (trying to connect via unix:///var/mysql/mysql.sock)
Based on error message I checked the location of mysql.sock file in my computer, by using the following command in terminal (I typed sudo to make sure I have sufficient permission)
sudo find /  -name mysql.sock

Oops ! It's in  '/Applications/MAMP/tmp/mysql/mysql.sock' 


1. Resolve in  Yii Framework configure file 

  'db'=>array(
   'connectionString' => 'mysql:host=localhost;dbname=YOURDBNAME;
    unix_socket=/Applications/MAMP/tmp/mysql/mysql.sock',
   'emulatePrepare' => true,
   'username' => 'DBUSER',
   'password' => 'DBPASS',
   'charset' => 'utf8',
  ),

As you can see, I add more parameter 'unix_socket=/Applications/MAMP/tmp/mysql/mysql.sock' to set the unix_socket option for connectionString. It worked !

But when you contribute with other in the same project and have to synchronize source code with other ( by git or svn) , it may be make some confuse if their mysql.sock file is located in different path. So, let's turn to next solutions

2. Create new link for mysql.sock in your system 

 We need to check /var/mysql folder has existed or not.
cd /var
if it does not existed use
mkdir  /var 
to create new folder
and
cd mysql
if not
mkdir mysql

Using ln command to create new link

sudo ln -s  {SOURCE} {DESTINATION}
In my computer, the command like this:
sudo ln -s /Applications/MAMP/tmp/mysql/mysql.sock /var/mysql/mysql.sock

It's worked, too !

3. Make some configuration in php.ini file

Open the php.ini file and find this line:
mysql.default_socket
And make it
mysql.default_socket = /path/to/mysql.sock
Yeah ! It's worked and I don't like this way so much ^^.

 There are 3 ways to resolve this exceptions that I mentioned above ! Good luck !