How To Model A Complex Object Oriented Design In Yii

Hello Guys,

Quick question.

How do you guys represent for example abstract classes or interfaces in PHP in the database?

How should I organize all this?

I know it is a very broad question but if someone could share their experience or way of doing it it will help me a lot.

Thank you very much!

Andrés

Hi,

Do you mean model inheritance? If so there is this wiki entry:

Single Table Inheritance

If you were referring to mixing abstract classes and interfaces with the CActiveRecord object, this is relatively easy. This is the abstract class I currently use in my inheritance structure:




<?php


/**

 * CActiveRecord derivative that encapsulates some behaviours specific to this project.

 *

 * @author Luke Jurgs

 * @version 0.0.1-2012-10-05

 *

 * The following are virtual properties

 * @property bool isEmpty are the attributes belonging to this empty?

 *

 * The following are properties and methods added by behaviors:

 * @see PopulateBehavior

 * @method mixed populateFromPost(string $postIndex = null)

 * @method mixed populateFromGet(string $getIndex = null)

 * @method mixed populateFromRequest(string $requestIndex = null)

 */

abstract class ActiveRecord extends CActiveRecord

{


	/**

	 * Overrides the parent implementation to be composite friendly, can return composite attributes if the

	 * composite behaviour is found.

	 * @param mixed $names names of attributes whose value needs to be returned.

	 * If this is true (default), then all attribute values will be returned, including

	 * those that are not loaded from DB (null will be returned for those attributes).

	 * If this is null, all attributes except those that are not loaded from DB will be returned.

	 * @return array attribute values indexed by attribute names.

	 */

	public function getAttributes($names = true)

	{

		$attributes = parent::getAttributes($names);

		if (null !== ($compositeBehavior = $this->asa('composite')))

		{

			$attributes = CMap::mergeArray($attributes, $compositeBehavior->getAttributes($names));

		}

		return $attributes;

	}


	/**

	 * Overrides the parent implementation to be composite friendly, can return composite attributes if the

   * composite behaviour is found.

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

	 */

	public function attributeLabels()

	{

		if (null === ($compositeBehavior = $this->asa('composite')))

		{

			return array();

		}

		return $compositeBehavior->attributeLabels();

	}


	/**

	 * Create a new ActiveRecord from the supplied attributes.

	 * @param array $attributes attribute values to be set to the new ActiveRecord.

	 * @return ActiveRecord

	 */

	public static function fromAttributes($attributes)

	{

		$model = new static;

		$model->attributes = $attributes;

		return $model;

	}


	/**

	 * Determines if the column attributes in this record are all empty.

	 * @see StringHelper::isEmpty

	 * @param bool $excludePrimaryKey exclude the primary key from the operation.

	 * @return bool this record is empty.

	 */

	public function getIsEmpty($excludePrimaryKey = false)

	{

		$attributes = $this->attributes;

		if ($excludePrimaryKey)

		{

			$primaryKey = $this->tableSchema->primaryKey;

			if (is_string($primaryKey))

			{

				$primaryKey = array($primaryKey);

			}

			$primaryKey = array_flip($primaryKey);

			$attributes = array_diff_key($attributes, $primaryKey);

		}

		foreach ($attributes as $attribute)

		{

			if (!StringHelper::isEmpty($attribute))

			{

				return false;

			}

		}

		return true;

	}


	public function behaviors()

	{

		return array(

			//DbUnixTime - Converts between unix timestamps and db timestamps

			'dbUnixTime' => array(

				'class' => 'DbUnixTimeBehavior',

			),

			//Populate - Allows for the easy capture of attributes from http submitted data

			'populate' => array(

				'class' => 'PopulateBehavior',

			),

		);

	}


	public function afterConstruct()

	{

		if (0 !== strcmp('search', $this->scenario) && $this->isNewRecord)

		{ //add and update the timestamps where appropriate

			if ($this->isDateTimeAttribute('created') && (null === $this->created))

			{

				$this->setAttribute('created', time());

			}

			if ($this->isDateTimeAttribute('timestamp') && (null === $this->timestamp))

			{

				$this->setAttribute('timestamp', time());

			}

		}

		parent::afterConstruct();

	}


	public function beforeSave()

	{

		if ($this->isNewRecord && $this->isDateTimeAttribute('updated'))

		{

			$this->setAttribute('updated', time());

		}

		if ($this->isDateTimeAttribute('timestamp'))

		{

			$this->setAttribute('timestamp', time());

		}

		return parent::beforeSave();

	}


	private function isDateTimeAttribute($attribute)

	{

		if ($this->hasAttribute($attribute) && in_array(strtolower($this->tableSchema->columns[$attribute]->dbType),

			array('datetime', 'timestamp', 'timestamp without time zone'))

		)

		{

			return true;

		}

		return false;

	}

}



Obviously this is only abstract because I don’t want it being instantiated, not because it has abstract members.

As you can see it just sits between CActiveRecord and my database models. I don’t currently implement any interfaces, I generally find the Yii bundled ones (ArrayAccess and Transverse) sufficient for my needs.

Cheers