phpyii

Yii custom CRUD. Extending of common model for different tables


I have project with 20 tables. Managing of data in all tables will be the same. Only columns in tables will be different. So I want to to make common model, common Controller and common view folder for all tables And after that only extend all this classes for each table

models/Crud.php

<?php

class Crud extends CActiveRecord
{
    public $crudTable = '';
    public $crudColumns = array();

    public static function model($className=__CLASS__)
    {
        return parent::model($className);
    }

    public function tableName()
    {
        return '{{'.$this->crudTable.'}}';        
    }

    public function rules()
    {
        $rules = array();

        foreach ($this->crudColumns as $k=>$v) {
            foreach ($v ['rules'] as $vv) {
                $rules[] = array_merge(array($k), $vv);    
            }
            if($v['search']) $rules[] = array_merge(array($k), array('safe', 'on'=>'search'));
        }

        return $rules;
    }

    public function relations()
    {
        return array(
        );
    }

    public function attributeLabels()
    {
        $attributeLabels = array();

        foreach ($this->crudColumns as $k=>$v) 
        {
            $attributeLabels[$k] = $v['attributeLabel'];
        }
        return $attributeLabels;
    }

    public function search()
    {
        $criteria=new CDbCriteria;

        foreach ($this->crudColumns as $k=>$v) 
        {
            if($v['search'])
            {
                $criteria->compare($k,$this->$k,(($v['search'] == 'partial') ? 'partial' : false));                
            }
        }

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

models/Country.php

class Country extends Crud
{
    public $crudTable = 'country';
    public $crudColumns = array(    
        'id' => array(
            'atributeLabel' =>'ID',
            'rules' => array (
                array('numerical', 'integerOnly'=>true)
            ),
            'search'=>true,
            'grid'=>true,                 
            'view'=>true,
            'form'=>true,                
        ),
        'title' => array(
            'atributeLabel' =>'Title',
            'rules' => array (
                array('required'),
                array('length', 'max'=>128)                                    
            ),
            'search'=>'partial',
            'grid'=>true,
            'view'=>true,
            'form'=>true,                                            
        ),                                 
        'code' => array(
            'atributeLabel' =>'Code',
            'rules' => array (
                array('required'),
                array('length', 'max'=>2)                                    
            ),
            'search'=>'partial',
            'grid'=>true,
            'view'=>true,
            'form'=>true,                                            
        ),        
        'description' => array( 
            'atributeLabel' =>'Description',
            'rules' => array (
                array('safe'),
            ),
            'search'=>'partial',
            'view'=>true,
            'form'=>true,                            
        ),                                 
        'onoff' => array(
            'atributeLabel' =>'Onoff',
            'rules' => array (
                array('numerical', 'integerOnly'=>true),
            ),
            'search'=>true,
            'grid'=>true,                
            'view'=>true,
            'form'=>true,                            
        )
    );

    public static function model($className=__CLASS__)
    {
        return parent::model($className);
    }

    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(
            'providers' => array(self::HAS_MANY, 'Provider', 'country_id'),
        );
    }
}

components/CrudController.php

class CrudController extends CController
{
    public $crudModel='';    
    public $crudModelString='';
    public $menu=array();
    public $breadcrumbs=array();

    public function filters()
    {
        return array(
            'accessControl', // perform access control for CRUD operations
        );
    }

    public function accessRules()
        {
        return array(
            array('allow',  // allow all users to perform 'list' and 'show' actions
                'actions'=>array('index', 'view'),
                'users'=>array('*'),
            ),
            array('allow', // allow authenticated users to perform any action
                'users'=>array('@'),
            ),
            array('deny',  // deny all users
                'users'=>array('*'),
            ),
        );
    }

    public function actionIndex()
    {
        $model=new $this->crudModel('search');
        $model->unsetAttributes();  // clear any default values
        if(isset($_GET[$this->crudModel]))
            $model->attributes=$_GET[$this->crudModel];

        $this->render('/crud/index',array(
            'model'=>$model,
        ));
    }        

    public function actionView($id)
    {
        $this->render('/crud/view',array(
            'model'=>$this->loadModel($id),
        ));
    }

...
Some code
...

    public function loadModel($id)
    {
        $model=Crud::model()->findByPk($id);
        if($model===null)
            throw new CHttpException(404,'The requested page does not exist.');
        return $model;
    }

...
Some code
...}

controllers/CountryController.php

class CountryController extends CrudController
{
    public $crudModel='Country';
    public $crudModelString='country';    
}

It works properly in index action, but ?r=country/view&id=278 send me error

The table "Crud" for active record class "Crud" cannot be found in the database.

How to send table name to static method and make this code to work properly?


Solution

  • Change the loadModel like this:

    public function loadModel($id)
    {
        $model=Crud::model($this->crudModel)->findByPk($id);
        if($model===null)
            throw new CHttpException(404,'The requested page does not exist.');
        return $model;
    }
    

    This will load the model of the appropriate table.