Sticky Behavior

March 27th, 2010

This is a sticky behavior. It will cause the models it is attached to to remember the user’s last inputted value. In other words, the last value the user selected will be the default value the next time around the user fills out the form

It’s not perfectly reusable unless you follow the same naming standards as I do, so you may need to modify one or two lines of code (like the relation)

It designed for a multi-user application where users have their own stickies

Table:

CREATE TABLE IF NOT EXISTS `sticky` (
  `user_id` int(11) NOT NULL,
  `name` varchar(255) NOT NULL,
  `lastValue` varchar(255) NOT NULL,
  PRIMARY KEY (`user_id`,`name`)
);

Sticky Model

<?php
class Sticky extends CActiveRecord
{
	/**
	 * The followings are the available columns in table 'sticky':
	 * @var integer $user_id
	 * @var string $name
	 * @var string $lastValue
	 */
 
	/**
	 * Returns the static model of the specified AR class.
	 * @return CActiveRecord 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 'sticky';
	}
 
	/**
	* @param int $user_id
	* @param string $name
	* @return Sticky (may be a new record if none found in database)
	*/
	public static function getSticky($user_id, $name) {
		$stickyAR = self::model()->findByPk(array('user_id'=>$user_id, 'name'=>$name));
 
		if ($stickyAR===null) {
			$stickyAR = new Sticky;
			$stickyAR->user_id = $user_id;
			$stickyAR->name = $name;
		}
		return $stickyAR;
	}
 
 
	/**
	 * THIS IS NOT NEEDED (but hey I'm going to leave it)
	 * @return array relational rules.
	 */
	public function relations()
	{
		return array(
			'user' => array(self::BELONGS_TO, 'User', 'user_id'),
		);
	}
}

Behavior

<?php
class StickyBehavior extends CActiveRecordBehavior
{
	/**
	* @var array array('stickyAttribute1', 'stickyAttribute2', ..)
	*/
	public $stickies = array();
 
	protected $stickyARS = array();
 
	/**
	* May need to modify
	* Gets the user id of the sticky.  Each user has his own stickies
	*/
	protected function getUserId() {
		return Yii::app()->user->id;	
	}
 
	/**
	* Handles filling attributes with stickies
	* Only executes on NEW records
	*/
	public function afterConstruct($event) {
		foreach ($this->stickies as $stickyAttribute) {
			$stickyName = $this->getStickyName($stickyAttribute);
			$stickyAR = Sticky::getSticky($this->getUserId(), $stickyName);
			if (!$stickyAR->getIsNewRecord())
				$this->owner->$stickyAttribute = $stickyAR->lastValue;
 
			$this->stickyARS[$stickyAttribute] = $stickyAR;
		}
	}
 
	/**
	* Updates the sticky value
	* Only does this for NEW RECORDS.  This seemed to make more sense to me,
	* but other people may want to change this
	*/
	public function afterSave($event) {
		if (!$this->owner->getIsNewRecord())
			return;
		foreach ($this->stickies as $stickyAttribute) {
			$stickyAR = $this->stickyARS[$stickyAttribute];
 
			$stickyAR->lastValue = $this->owner->$stickyAttribute;
			$stickyAR->save();
		}
	}
 
	/**
	* Gets the sticky name as stored in the database (prefixes attribute name with the model name)
	* 
	* @param string stickyAttribute
	*/
	protected function getStickyName($stickyAttribute) {
		return get_class($this->owner).'.'.$stickyAttribute;
	}
}

Example of attachment to model

<?php
	public function behaviors() {
		return array(
			'sticky'=>array(
				'class'=>'application.models.StickyBehavior',
				'stickies'=>array('gym_id'),
			),
		);
	}

There is also a forum thread

Enjoy!

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Technorati
  • Reddit
  • RSS
  • Twitter

Categories: Uncategorized

1 Comment

Alternative to the beforeAction() event

January 11th, 2010

I often see that when someone needs something executed on every page request before anything else is executed, they usually put it in the controller beforeAction() method. Things you might want executed on every page request might be, for example (so you know what I’m talking about):

  • Handling the layout
  • Cleaning all GET and POST parameters (I don’t like to do this but some people do)
  • Language handling

I’ve seen people do this with CakePHP as well as with Yii. I find that beforeAction() is actually not an optimal place to put this sort of code. Imagine you put code for all of the examples I gave above plus three more in the beforeAction() method. You might image that the beforeAction() method would become cluttered and hard to read. I prefer lower coupling than this. We want these scripts split up into logical places. And guess what? With Yii this is easy. Application Components!

Let me write an example. Lets say we need to figure out what layout to display to the user on each request. We would like to execute some logic for this before the controller action is called. We do not use beforeFilter(). We instead create an application component. An application component is simply a class that extends CApplicationComponent.

<?php
class LayoutHandler extends CApplicationComponent {
 
	public function init() {
		parent::init();
 
		//Put code here.
 
	}
}

Now everything in the init() method will be executed when this application component is instantiated. So now, we just need to get it to instantiate on every request, before the action is executed. This is done in the application configuration using the preload property.

<?php
// This is the main Web application configuration. Any writable
// CWebApplication properties can be configured here.
return array(
	'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..',
 
	// The 'layoutHandler' component will pre-load
	'preload'=>array('layoutHandler'),
 
	// application components
	'components'=>array(
		'layoutHandler'=>array(
			'class'=>'path.to.LayoutHandler',
		),
	),
);

Now there are two main things I have done here:

  1. Defined the LayoutHandler class as an application component in the components property
  2. Set the layoutHandler to preload with the preload property

You may find that this method is much more organized than simply stuffing code in CController::beforeAction(). It also leaves your code more modular.

Note that now you can even access the LayoutHandler class anywhere within your app via Yii::app()->layoutHandler. Not useful in this example, but this is often very handy.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Technorati
  • Reddit
  • RSS
  • Twitter

Categories: Yii

Tags: , 8 Comments

Table prefixes

April 9th, 2009

One question I hear many people ask around the Yii forum is how to use table prefixes with ActiveRecord. I believe the best way to solve this problem is to extend CActiveRecord::tableName(). Now you can either extend this method in every active record class you would like to use a prefix manually, or you can create a new active record class that supports this functionality, and then have all your other active record classes extend this new class. This is what I mean:

Normally your active record classes would have the following inheritance:
[...] -> CModel -> CActiveRecord -> YourARModels

Instead, you may create a new active record class with custom functionality that you want all your active record classes to have, such as the table prefix functionality. So the inheritance would look like this:
[...] -> CModel -> CActiveRecord -> ActiveRecord -> YourARModels

To do this simply create a ActiveRecord class and save it in a directory that is set to auto-load classes on demand (probably /protected/models or /protected/components should work). It could look something like this:

<?php
class ActiveRecord extends CActiveRecord
{
	public $tablePrefix = 'myPrefix_';
 
	public function tableName()
	{
		return $this->tablePrefix.parent::tableName();
	}
}

Then you would have all your active record classes simply extend ActiveRecord instead of CActiveRecord. If you do not want a single active record to have a prefix, you can set the $tablePrefix attribute to an empty string in that active record.

You may of course add other useful functionalities that you would like your active record models to share in this class.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Technorati
  • Reddit
  • RSS
  • Twitter

Categories: Yii

Tags: , 5 Comments

CDbExpression

February 23rd, 2009

Ever want to set an attribute in Active Record with a MySQL function? For instance, often times you need to set an attribute to the well known MySQL function “NOW()”. Most people first attempt this in the following way:

<?php
$model->createdDate = 'NOW()';

The above, however, will most definitely not work. Why not? Because Yii will first escape the value and then enclose it in quotes, like the following:

... `createdDate`= 'NOW()' ...

Since it is enclosed in quotes, it is treated as a string and not a function. If Yii did not clean the data like this, you would have to, and that would be very annoying.

As of version 1.0.2 of Yii however, there is a way to get around this:

<?php
$model->createdDate = new CDbExpression('NOW()');

CDbExpression is a special class for using MySQL expressions in your queries. You use it just like in the above example.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Technorati
  • Reddit
  • RSS
  • Twitter

Categories: Uncategorized

4 Comments

Safe attributes tip

February 19th, 2009

In my last two posts [1, 2] I explained how to define scenario-based validation rules and safe attributes. Something I have noted is that whenever I end up specifying an attribute as “required” in the validation rules(), I also always end up specifying it as “safe” in safeAttributes() under the same scenario. This got me thinking – is it possible that every “required” attribute must also be “safe” on a given scenario? The answer to that seems to be yes. So I thought, why be redundant? So I went about the task of teaching Yii that all “required” attributes are also “safe”. It seems the most elegant way to do this is by extending getSafeAttributeNames() in your model. So that’s what I did. Now, I’ll share with you. Just drop this code in any model that you would like to have this behavior.

<?php
/*
* I extended this method so that yii will "automagically" understand that
* 'required' attributes (in the given scenario) are also 'safe'.  This way,
* when defining 'safe' attributes in the safeAttributes() method, you can
* neglect to define attributes as safe that you have already defined at "required"
* in your rules() method.  This basically saves typing (and in some cases stupid
* mistakes), which I am always a fan of.  This method could be moved to another model
* from which other models like this could inherit from if you wish.
* 
* You should NOT call this method directly but it is used by Yii internally
*/
public function getSafeAttributeNames($scenario='') {
	$safe = parent::getSafeAttributeNames($scenario);
 
	foreach ($this->validators as $validator) {
		if ((get_class($validator) != 'CRequiredValidator') || !$validator->applyTo($scenario)) continue;
		$safe = array_merge($safe, $validator->attributes);
	}
	return array_unique($safe);
}

Enjoy if you wish and give feedback.

One thing to worry about is speed however. Every time this method is called, it loops through all the validators. If you have a lot of validation rules this could be unwanted. On the other hand, yii only checks the safe attributes on CModel::setAttributes(), which is generally only called on requests with submitted POST data (e.g. forms, and users don’t often expect those pages to be lightning fast). Anyways, I’m making this code snipped sound slower than it actually is. It might be interesting to check how many times this method is called on a given request.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Technorati
  • Reddit
  • RSS
  • Twitter

Categories: Enhancement, Yii

Tags: No Comments

Safe attribute scenarios

February 17th, 2009

If you read my last article on validation scenarios then you may understand why in different scenarios you may need different attributes to be required. However you may have noticed a missing link – what if in different scenarios you also need different attributes to be considered as “safe”?

If you have no idea about what I am taking about then you probably don’t know that in your model you can specify which attributes are “safe” to massively assign to a model via CModel::setAttributes().

<?php
public function safeAttributes() {
	return array(
		//these attributes are safe to massively assign
		'attribute1, attribute2',
	);
}
?>

By default, all columns in the table are considered safe except the primary key column (attributes defined in the model are not considered safe by default)

The reason you might not want all attributes to be safe is if for instance you have fields which determine things such as access level. For instance what if you had a User model with a `is_admin` field. If you let `is_admin` be defined as safe, you have a security hole, as someone can take a tool such as urlparams and easily set himself as an admin.

Now you may actually want “is_admin” to be defined as safe in certain scenarios, such as an user administrative page. Thus, as of Yii 1.0.2, you can define scenarios through safeAttributes() which was the initial reason for writing this article.

I will simply use a code example taken from the Yii Class Reference this time.

<?php
public function safeAttributes() {
	return array(
	   // these attributes can be massively assigned in any scenario
	   // that is not explicitly specified below
	   'attr1, attr2, ...',
 
	   // these attributes can be massively assigned only in scenario 1
	   'scenario1' => 'attr2, attr3, ...', //Eg in this scenario attr1 is NOT safe
 
	   // these attributes can be massively assigned only in scenario 2
	   'scenario2' => 'attr1, attr3, ...',
	);
}

Now you may set the scenario to use via CModel::setAttributes()

<?php
$user->setAttributes(array <data>, string <scenario name>);
 
//Example:
$user->setAttributes($_POST['User'], 'update');
Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Technorati
  • Reddit
  • RSS
  • Twitter

Categories: Yii

Tags: 3 Comments

Validation scenarios

February 16th, 2009

As of Yii 1.0.2 you may now define validation scenarios. This is very useful if for instance you have multiple places in your application that you validate a model, but in each instance you may want different validation rules. For instance, perhaps in your user registration form you want to have the “username”, “email” and “password” fields to be required, while on your “user recovery” page, you only want the “email” field to be required. You may see a problem here. If you set all the fields to be required, then your user recovery page won’t work, as it does not allow a user to supply neither a password nor a username.

The perfect solution to this are validation scenarios. You can attach a validation scenario to a validation rule through the ‘on’ property. You may already know you can set the ‘on’ property to either ‘insert’ or ‘update’, which will automatically cause the rule to only be used on the corresponding type of save. However sometimes these two options are not enough. So now with this new enhancement, you may set it to any value you want. Let me show an example:

<?php
//in user model
public function rules() {
	return array(
		//Set required fields
 		//Applies to 'register' scenario
 		//Note 'on' property
		array('username, password, password_repeat, email', 'required', 'on' => 'register'),
 
		//Applies to 'recover' scenario
		array('email', 'required', 'on' => 'recover'),
 
		//Applies to all scenarios
		array('username, password', 'length', 'max'=>35, 'min'=>3),
 
		//This rule checks if the username is unique in the database in
		//the 'register' scenario (we don't want it to check for uniqueness
		//on the login page for instance)
		array('username', 'unique', 'on' => 'register'),
 
		//This rule applies to 'register' and 'update' scenarios
		//Compares 'password' field to 'password_repeat' to make sure they are the same
		array('password', 'compare', 'on' => 'register, update'),
	);
}

With this setup Yii will be able to tell which fields are required in which scenarios. As a bonus I threw some other rules for example. Reading the comments will give you an understanding of that. You may also note from the ‘compare’ rule that you may define a rule to be used on multiple scenarios by separating them with commas.

Now when you wish to run validation under a specific scenario you must define it in when calling CModel::validate(), as so

<?php
$user->validate('<scenarioName>'); //runs validation under the given scenario
 
//example:
if ($user->validate('register')) {
	$user->save(false);
}

So the above example will validate the user under the ‘register’ scenario.

Leave a comment if I have left any unanswered questions on this enhancement

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Technorati
  • Reddit
  • RSS
  • Twitter

Categories: Yii

Tags: 22 Comments

PHP Code shortcuts to if/else statements

January 1st, 2009

Here are some very useful PHP code shortcuts that I have learned. You may have seen them before or you may not have, but if you didn’t understand them, hopefully you will after reading this article.

The first is the Ternary Operator

<?php
$var = (expression) ? 'value if true' : 'value if false';
 
//The above does the same as the following:
 
if (expression)
	$var = 'value if true';
else
	$var = 'value if false';
 
//Example use:
$name = empty($me) ? $you : $me; //sets $name to $me if $me is not empty, or to $you if $me is empty

The next two examples show how to use the “or” and “and” operators (also known as || and &&) as shortcuts

<?php
(expression1) or (expression2);
 
//The above does the same as the following:
 
if (!expression1)
	expression2;
 
//Example use:
//I actually found this line of code in the Yii framework
defined('YII_DEBUG') or define('YII_DEBUG',true); //Defines the constant YII_DEBUG if it has not been defined already

The above works because in the or operator, the right hand expression is not evaluated unless the left hand expression is evaluated to false (if it evaluates to true, there is no need for the right-hand side to be solved anyways – and PHP tries to be efficient)

The and operator does the exact opposite thing:

<?php
(expression1) and (expression2);
 
//The above does the same as the following:
 
if (expression1)
	expression2;
 
//Example use:
($page > LAST_PAGE) and ($page = LAST_PAGE) //does not allow the page number to be set past the last page

The reason you may want to use these would be to save typing, and to increase readability (in the case of the Ternary Operator anyways, you can argue the other two are less readable). Even if you do not like to use these, it is important to know them in case you ever find yourself reading other people’s code.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Technorati
  • Reddit
  • RSS
  • Twitter

Categories: Web Development

5 Comments

Running your Yii app and configuring it

December 29th, 2008

Unlike in CakePHP, it is mandatory to use the shell tool (called yiic, similar to CakePHP’s “Bake” script) to start off your application as it creates the workspace architecture (The Yii package does not come with an application bare-bones, only framework code). Yiic generates .htaccess files with rules that forwards user requests to index.php where the application runs (cake does this too). When I checked my index.php file to see what was in it, I was amazed with the possibilities of what I saw.

<?php
// change the following paths if necessary
$yii = 'C:\wamp\www\yiiRepo\framework\yii.php';
$config = dirname(__FILE__) . '/protected/config/main.php';
 
// remove the following line when in production mode
defined('YII_DEBUG') or define('YII_DEBUG',true);
 
require_once($yii);
Yii::createWebApplication($config)->run();

The last two lines are the important ones. In the second-last line, it includes the main Yii class file, so that it can actually run the application as seen in the last line. createWebApplication() accepts one argument: the path to the configuration file for the application. In the configuration file you can configure things such as your database, error and mysql logging, and url routing. The configurations are stored in the form of an array. It’s a much simpler approach than cake’s, which uses a heavy configuration class. Personally I am liking Yii’s array configuration syntax much better than cake’s (I will show you my Yii configuration file in a second).

Since in Yii you define the configuration file used in your index.php file, you can greatly simplify the synchronization between your development and production server – you simply need different index files and separate configuration files. So I thought up a inheritance/tree system for configuration files.

/protected
	/config
		/main.php
		/production.php
		/development.php

Here, the production and development configuration files will simply extent the main configuration file which holds the configurations that are consistent across both production and development servers such as the url routing rules. Possible examples of each file:

protected/config/main.php:

<?php
// This is the main Web application configuration.
return array(
	'basePath' => dirname(__FILE__).DIRECTORY_SEPARATOR.'..',
	'name' => 'My Web Application',
 
	// Tell's Yii is can auto-load model and component classes on-demand (lazy loading)
	'import' => array(
		'application.models.*',
		'application.components.*',
	),
	'preload' => array('log'), //preload the log component right away (eager loading)
 
	// application components
	'components' => array(
		'user' => array(
			// user component settings here (similar to CakePHP's auth component)
		),
		//log class can output errors, mysql quarry summaries, etc.  The specific
		//settings are extended in the production and development config files
		'log' => array(
	        	'class' => 'CLogRouter',
		),
		'urlManager' => array(
			'urlFormat'=>'path',
			'showScriptName' => false,
			'rules' => array(
				// some generic url routes I often use
				'user/register/*' => 'user/create',
				'user/settings/*' => 'user/update',
			),
		),
	),
);

protected/config/development.php:

<?php
//import main configurations
$main = include "main.php";
 
// Development configurations
$development = array(
	'components' => array(
		'db' => array(
			'class' => 'CDbConnection',
			'connectionString' => 'mysql:host=localhost;dbname=yiitestdrive',
			'username' => 'root',
			'password' => '',
		),
		'log' => array(
			'routes' => array(
				//set the log component to show logs on the bottom of the page - similar to CakePHP
				array(
					'class' => 'CWebLogRoute',
					'levels' => 'trace, info, error, warning',
					'categories' => 'system.db.*',
				),
			),
		),
        ),
);
//merge both configurations and return them
return CMap::mergeArray($main, $development);

protected/config/production.php:

<?php
//import main configurations
$main = include "main.php";
 
// Production configurations
$production = array(
	'components' => array(
		'db' => array(
			'class' => 'CDbConnection',
			'connectionString' => 'mysql:host=mysql@example.com;dbname=productionDatabase',
			'username' => 'admin',
			'password '=> 'password123',
		),
		'log' => array(
			'routes' => array(
				// Configures Yii to email all errors and warnings to an email address
				array(
					'class' => 'CEmailLogRoute',
					'levels' => 'error, warning',
					'emails' => 'admin@example.com',
				),
		),
        ),
);
//merge both configurations
return CMap::mergeArray($main, $production);

As you can see, in the main config file we have the consistent settings such as URL routing, and in the production and development files we have inconsistent things such as database settings. Note also in the production config I have errors and warnings sent to an email while in the development config I have all logs outputted at the bottom of the page. Nifty, huh? Now we can set up the index files for the production and development servers like so:

Development index.php file:

<?php
$yii = 'C:\wamp\www\yiiRepo\framework\yii.php';
$config = dirname(__FILE__) . '/protected/config/';
 
// turns debug on
defined('YII_DEBUG') or define('YII_DEBUG',true);
 
require_once($yii);
Yii::createWebApplication($config . 'development.php')->run();

Production index.php file:

<?php
$yii = 'framework/yii.php';
$config = dirname(__FILE__) . '/protected/config/';
 
require_once($yii);
Yii::createWebApplication($config . 'production.php')->run();

Now you can easily set different settings for production and development set-ups without redundancy. Enjoy.

UPDATE: Qiang wrote his own version of this method in the Yii Cookbook here. He recommends you merge the configurations with CMap::mergeArray() instead of array_merge_recursive(). I have changed this article to use CMap also. CMap::mergeArray() is a helper method that comes from the Yii core.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Technorati
  • Reddit
  • RSS
  • Twitter

Categories: Yii

366 Comments

My findings in Yii and comparisons to CakePHP

December 20th, 2008

Since I have found out about Yii I have been using it to work on a “dummy” website with features that are generally used across a large variety of websites (e.g. news system, user system, authorization, etc). This is also exactly what I did with CakePHP when I first started learning it, and the reason I do this is not only so I have a set of re-usable resources but also to help learn the framework. Although I still consider myself a novice in Yii I have learned a lot of things about it, some things very similar to CakePHP while other things very different. It’s a learning experience and I must say Yii so far seems a better alternative to CakePHP for many reasons. I will outline a few reasons/differences here.

PHP 5 features included in the core
First, and most importantly, what allows for most of the stuff that I love in Yii over CakePHP is that it is PHP 5 only. PHP 4 is not supported. Because of this, Yii is able to take use of many PHP 5 features that Cake is not able to. Mainly, that would be the PHP 5 magic overloading functions, which leads to the next point:

OOP style AR and lazy loading
Yii takes use of PHP 5’s overloading functions in its AR implantation in a very beautiful manner. Instead of storing results from quarries in an array as Cake does, in Yii you can access the quarries in an OOP manner. Here is an simple example of accessing AR in Yii, taken out of the Yii documentation.

//Database scheme is 'post' BELONGS_TO 'user'.  Each row in the 'posts' table has a corresponding row in the 'users' table.
// retrieve the post whose ID is 10
$post = Post::model()->findByPk(10);
// retrieve the post's author: a relational query will be performed here
$user = $post->user;

Note the last line. What actually happens is that the related user data is loaded dynamically by simply calling the variable. The reason for this is because Yii takes use of lazy loading (and of course PHP 5’s magic). This means the data is not retrieved until it is actually needed, increasing performance and ease of programming. If lazy loading does not fit you, you can use eager loading too, which will work similar to Cake’s ContainableBehavior. Example:

$posts = Post::model()->with('user')->findByPk(10);

Now that is what I call beautiful code. You can probably tell what the above does implicitly, but if you can’t, it simply pulls the post with id of 10 along with its corresponding user (a mysql JOIN will be used). Beautiful? I think yes.

Excellent Documentation
And you can find that out for yourself.

Fast and useful developer feedback
Along with the documentation the Yii forum is also an excellent place to get help. I have posted a few questions/bug reports there and have gotten very fast feedback, from the lead developer himself if from no one else. The bug reports and enchantments I requested there [1, 2, 3] were all fixed/implanted within 24 hours of reporting. Therefore I give Yii two thumbs up for developer feedback. Arguably the user feedback is not as good has Cake’s user feedback however, as Cake is much more well known and more widely in use (Yii only just came out with a stable version I believe this month). But developer feedback is more valuable than user feedback in my opinion.

Faster
Benchmarks.

Integration with jQuery
Cake uses prototype. Booo!

More easily extended
One example I have for this so far and that I have tested are the validation rules. Not only can you define a action in the model as a validation as in Cake, but you can can define a whole class to be a validation type. For instance, you could create a authenticatePass class that works as a validator that you can easily drop into your projects. Then you could use it in your model as so:

public function rules() {
	return array(
		array('password', 'authenticatePass'),
		//more rules...
	);
}

The above validator could be designed to validate the password to the username (if sent) in the users table.

Regarding the design pattern
As far as the structure, e.g. the MVC design pattern, Yii and CakePHP are very similar. They both have “components” for example. Yii also has “widgets”, which can represent anything from a form calendar to a navigational menu. Widgets consist of both components and views, so in a way, they are similar to Cake’s “plugins” I suppose, but they are not so intimidating to create. Yii also has their own version of the Bakery for sharing extensions.

Since this post is quite long enough, I will stop here. In future articles I will try to focus on more narrow topics as I don’t feel this post is nearly long enough to satisfy my given subject line. Oh well. Hope you learned something useful!

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Technorati
  • Reddit
  • RSS
  • Twitter

Categories: CakePHP, Yii

99 Comments

Feed

http://php-thoughts.cubedwater.com /