Site building and maintenance

Blog. Yii. Tips for Yii. Chapter 12

Search

Tips for Yii. Chapter 12.

  1. primaryKey.

    If there is not any primary key in the table, for example: `id` int(11) NOT NULL AUTO_INCREMENT + PRIMARY KEY (`id`), so we can redefine the primaryKey() method in the model.

    For instance: there is a `users_tel_nums` table with the following structure:

    1. CREATE TABLE IF NOT EXISTS `users_tel_nums` (  
    2.   `userId` int(11) NOT NULL COMMENT 'user ID',  
    3.   `number` varchar(20) NOT NULL COMMENT 'Phone number',  
    4.   KEY `userId` (`userId`)  
    5. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;  

    If only one phone number of a user is stored in the table, so the primaryKey method will look like:

    1. public function primaryKey() {  
    2.     return 'userId';  
    3. }  

    But if ona and the same user can have some phone numbers, we should use a composite primary key, and the primaryKey method will look like:

    1. public function primaryKey() {  
    2.     return array('userId''number');  
    3. }  

     

  2. Search by a HAS_MANY relation.

    We have an ‘Objects’ model (the list of objects), ‘Users’ (the list of users) and ‘UsersTelNums’ (the list of users’ phone numbers). With the appropriate table names.

    The structure of `objects` table is the following:

    1. CREATE TABLE IF NOT EXISTS `objects` (  
    2.   `id` int(11) NOT NULL AUTO_INCREMENT,  
    3.   `status` tinyint(1) NOT NULL COMMENT 'Status',  
    4.   ....  
    5.   `ownerId` int(11) NOT NULL COMMENT 'ID of object's owner',  
    6.   ...  
    7.   PRIMARY KEY (`id`),  
    8.   KEY `ownerId` (`ownerId`)  
    9. ) ENGINE=InnoDB  DEFAULT CHARSET=utf8;  

    Here is the ‘users’ table:

    1. CREATE TABLE IF NOT EXISTS `users` (  
    2.   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,  
    3.   `firstName` varchar(64) NOT NULL,  
    4.   ...  
    5.   PRIMARY KEY (`id`),  
    6.   UNIQUE KEY `email` (`email`)  
    7. ) ENGINE=InnoDB  DEFAULT CHARSET=utf8;  

    And here is the ‘users_tel_nums’ table:

    1. CREATE TABLE IF NOT EXISTS `users_tel_nums` (  
    2.   `userId` int(11) NOT NULL COMMENT 'user ID',  
    3.   `number` varchar(20) NOT NULL COMMENT 'Phone number',  
    4.   KEY `userId` (`userId`)  
    5. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;  

    In the ‘UsersTelNums’ model (a ‘users_tel_nums’ table) a composite key is used in the ‘primaryKey’ method. We have described it above.

    Here is the ‘relations’ method of the ‘Objects’ model:

    1. public function relations() {  
    2.     return array(  
    3.         ...  
    4.         'user' => array(self::BELONGS_TO, 'Users''ownerId'),  
    5.         'usersTelNums' => array(self::HAS_MANY, 'UsersTelNums'array('userId' => 'ownerId')),  
    6.     );  
    7. }  

    Here the ‘objects’ table relates via a ‘ownerId’ field to a primary key (id) of the ‘users’ table. And the ‘objects’ table relates via a field ‘ownerId’ to ‘userId (array('userId' => 'ownerId'))’ of the ‘users_tel_nums’ table.

    Now, when the structure and relations are described, let's see into the ‘search’ method of the ‘Objects’ model.

    Let's announce a variable ‘ownerPhone’ in the ‘Objects’ model:

    1. public $ownerPhone;  

    Add a name to the field:

    1. public function attributeLabels() {  
    2.     ...  
    3.     'ownerPhone' => 'Owner phone number(s)',  
    4. }  

    Let's save the entered value by search:

    1. public function rules() {  
    2.     ...  
    3.     array('ownerPhone''safe''on' => 'search'),  
    4. }  

    Here is the ‘search()’ method:

    1. public function search() {  
    2.     $criteria = new CDbCriteria;  
    3.   
    4.     $criteria->compare($this->getTableAlias().'.id'$this->id);  
    5.     $criteria->compare($this->getTableAlias().'.status'$this->status, true);  
    6.   
    7.     if ($this->ownerPhone) {  
    8.         $criteria->compare('usersTelNums.number'$this->ownerPhone, true);  
    9.     }  
    10.   
    11.     $criteria->order = $this->getTableAlias().'.id DESC';  
    12.     $criteria->with = array(  
    13.         'usersTelNums' => array(  
    14.             'select'=>'usersTelNums.number',  
    15.             'together'=>true  
    16.         ),  
    17.     );  
    18.   
    19.   
    20.     return new CActiveDataProvider($thisarray(  
    21.         'criteria' => $criteria,  
    22.         'pagination'=>array(  
    23.             'pageSize'=>50,  
    24.         ),  
    25.     ));  
    26. }  

    Please, pay attention on how you should specify ‘with’ for $criteria.

    And how to set relation with the ‘UsersTelNums’ model:

    1. 'usersTelNums' => array(self::HAS_MANY, 'UsersTelNums'array('userId' => 'ownerId')),  

     

  3. CSRF and CMenu.

    There is a ‘view.php’ view for data viewing of an object.

    On the page there is a menu with links for editing and deleting the current object:

    1. $this->widget('zii.widgets.CMenu'array(  
    2.     'items'=>array(  
    3.         array('label'=>tc('Update object'), 'url'=>'#''linkOptions'=>array('submit'=>array('update','id'=>$model->id))),  
    4.         array('label'=>tc('Delete object'), 'url'=>'#''linkOptions'=>array('submit'=>array('delete','id'=>$model->id),'confirm'=>'Are you sure want to remove the chosen element?')),  
    5.     ),  
    6. ));  

    In a period of time you have decided to add a protection from CSRF (http://www.yiiframework.com/doc/guide/1.1/en/topics.security#cross-site-request-forgery-prevention)

    And after clicking on such links an error appears: Error 400 "The CSRF token could not be verified".

    The solution for the problem is to add 'csrf' => true.

    So we will get as a result the following:

    1. $this->widget('zii.widgets.CMenu'array(    
    2.     'items'=>array(    
    3.         array('label'=>tc('Update object'), 'url'=>'#''linkOptions'=>array('submit'=>array('update','id'=>$model->id), 'csrf' => true)),    
    4.         array('label'=>tc('Delete object'), 'url'=>'#''linkOptions'=>array('submit'=>array('delete','id'=>$model->id),'confirm'=>'Are you sure want to remove the chosen element?''csrf' => true)),    
    5.     ),    
    6. ));   

     

Discuss the article in the forum