How to properly create a subclass of a class which extends CActiveRecord

Hi,

I’m fairly new in using yii and encountered some problem regarding creation of subclass.

I have 2 classes: Person and Student. The Person class is extending to CActiveRecord and I want to make the Student class to be a subclass of the Person class. Can you tell me how can i properly make Student class a subclass of Person class.

My classes looks like these:

Person class




class Person extends CActiveRecord

{

    ...

}



Student class




class Student extends Person

{

    ...

}



I don’t know what went wrong but every time I do a foreach on the array returned by Student::model->getAttributes() the attributes from the superclass(Person) are not included. It seems to me that Student class was not able to inherit the properties of Person class.

Hope you could help me. Thanks

Here’s the whole codes:

PERSON CLASS




class Person extends CActiveRecord

{

    

	/**

	 * Returns the static model of the specified AR class.

	 * @return Person 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 'person';

	}


	/**

	 * @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('personID, entryYear, firstName, middleName, lastName, gender, birthdate, address, contactNo, contactType', 'required'),

			array('personID, entryYear', 'numerical', 'integerOnly'=>true),

			array('firstName', 'length', 'max'=>50),

			array('middleName, lastName, contactNo', 'length', 'max'=>20),

			array('auxName', 'length', 'max'=>6),

                        array('gender', 'in', 'range' => array('m','f')),

                        array('contactType', 'in', 'range' => array('m','l')),

                        array('gender, contactType', 'length', 'max'=>1),   

			array('address', 'length', 'max'=>100),

                        array('birthdate', 'length', 'max'=>10),

			// The following rule is used by search().

			// Please remove those attributes that should not be searched.

			array('personID, entryYear, firstName, middleName, lastName, auxName, gender, birthdate, address, contactNo, contactType', '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(

			'educationalbackgrounds' => array(self::HAS_MANY, 'EducationalBackground', 'personID, entryYear'),

			'records' => array(self::MANY_MANY, 'Record', 'file(recID,personID, entryYear)'),

			'students' => array(self::HAS_MANY, 'Student', 'studentID, entryYear'),

			'teachers' => array(self::HAS_MANY, 'Teacher', 'teacherID, entryYear'),

		);

	}


	/**

	 * @return array customized attribute labels (name=>label)

	 */

	public function attributeLabels()

	{

		return array(

			'personID' => 'Person',

			'entryYear' => 'Entry Year',

			'firstName' => 'First Name',

			'middleName' => 'Middle Name',

			'lastName' => 'Last Name',

			'auxName' => 'Aux Name',

			'gender' => 'Gender',

                        'birthdate' => 'Birdthdate',

			'address' => 'Address',

			'contactNo' => 'Contact No',

			'contactType' => 'Contact Type',

		);

	}


	/**

	 * 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('personID',$this->personID);

		$criteria->compare('entryYear',$this->entryYear);

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

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

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

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

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

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

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

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

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


		return new CActiveDataProvider($this, array(

			'criteria'=>$criteria,

		));

	}

        

        

}






<?php


/**

 * This is the model class for table "student".

 *

 * The followings are the available columns in table 'student':

 * @property string $placeOfBirth

 * @property string $notes

 * @property string $status

 * @property integer $studentID

 * @property integer $entryYear

 *

 * @property Guardian[] $guardians

 * @property Person $person

 * @property YearLevel[] $yearLevels

 * @property Section[] $sections

 * 

 */

class Student extends Person

{

	/**

	 * Returns the static model of the specified AR class.

	 * @return Student 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 'student';

	}


	/**

	 * @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('status, studentID, entryYear', 'required'),

			array('studentID, entryYear', 'numerical', 'integerOnly'=>true),

			array('placeOfBirth', 'length', 'max'=>50),

			array('notes', 'length', 'max'=>250),

			array('status', 'length', 'max'=>1),

                        array('dept', 'in', 'range' => array('x','t','e','d','u','g')),

			// The following rule is used by search().

			// Please remove those attributes that should not be searched.

			array('placeOfBirth, notes, status, studentID, entryYear', '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(

			'guardians' => array(self::HAS_MANY, 'Guardian', 'studentID'),

			'person' => array(self::BELONGS_TO, 'Person', 'studentID, entryYear'),

                        'yearLevels'=>array(self::MANY_MANY, 'YearLevel', 'enrollment(level, dept, studentID, entryYear)'),

                        'sections'=>array(self::MANY_MANY, 'Section', 'enrollment(sectionName, studentID, entryYear, yearStart, yearEnd)'),

                        'enrollments'=>array(self::MANY_MANY, 'YearLevel, Section', 'enrollment(level, dept, studentID, entryYear, sectionName, yearStart, yearEnd)'),

		);

	}


	/**

	 * @return array customized attribute labels (name=>label)

	 */

	public function attributeLabels()

	{

		return array(

			'placeOfBirth' => 'Place Of Birth',

			'notes' => 'Notes',

			'status' => 'Status',

			'studentID' => 'Student',

			'entryYear' => 'Entry Year',

		);

	}

        

        public function scopes(){

                return array(

                    "enrolled"=>array(

                        "condition"=>"t.status='e'",

                    ),

                    "unenrolled"=>array(

                        "condition"=>"t.status='u'",

                    ),

                    "expelled"=>array(

                        "condition"=>"t.status='x'",

                    ),

                    "graduated"=>array(

                        "condition"=>"t.status='g'",

                    ),

                    "transferred"=>array(

                        "condition"=>"t.status='t'",

                    ), 

                    "dropped"=>array(

                        "condition"=>"t.status='d'",

                    ),

                    "male"=>array(

                        "join"=>"inner join person p",

                        "condition"=>"p.personID = t.studentID 

                            and p.entryYear = t.entryYear and p.gender = 'm'"

                    ),

                    "female"=>array(

                        "join"=>"inner join person p",

                        "condition"=>"p.personID = t.studentID 

                            and p.entryYear = t.entryYear and p.gender = 'f'"

                    ),

                    "terminal"=>array(

                        "join"=>"inner join enrollment e, yearlevel y",

                        "condition"=>"(y.nextLevel is null and y.nextDept is null)

                    and (e.level=y.level and e.level=y.level) 

                    and (e.studentID = t.studentID and e.entryYear = t.entryYear)",

                    ),

                );

        }

        

        public function attrToValidate(){

            $attr = array();

            foreach ($this->attributeNames() as $name){

                if($name!=='personID' || $name!=='entryYear'){

                    array_push($attr, $name);

                }

            }

            return $attr;

        }


	/**

	 * 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('placeOfBirth',$this->placeOfBirth,true);

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

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

		$criteria->compare('studentID',$this->studentID);

		$criteria->compare('entryYear',$this->entryYear);


		return new CActiveDataProvider($this, array(

			'criteria'=>$criteria,

		));

	}

}



You have two tables? student and person… how do you wish have the attributes from the parent? Maybe, this is better for you: http://www.yiiframework.com/wiki/198/single-table-inheritance/

yup i have two database table. i just want to have the attributes of the parent class to be inherited by the subclass so that when i use Student::model()->getAttributes() i will also get the inherited attributes from the superclass.

I’m not sure the link you gave will solve my problem but I will try it. Thank you very much for your reply. I greatly appreciate it.

Though it doesn’t exactly answer your question, part of a solution will involve using parent’s definitions of rules, labels, and relations with something like the following:


class Student extends Person {

  ...


  function attributeLabels() {

    $labels = array(

      'placeOfBirth' => 'Place Of Birth',

      'notes' => 'Notes',

      'status' => 'Status',

      'studentID' => 'Student',

      'entryYear' => 'Entry Year',

    );


    return array_merge($labels, parent::attributeLabels());

  }


  ...

}

At the very least, it allows you to reuse some code. It does not resolve the problem of there being multiple tables mind you.