Saturday, August 7, 2010

Using Controller Filters

So, I'm sure by now everyone's used the very familiar "accessControl" filter, but so much of that happens behind the scenes. This post goes into how to create your own filters and how they can be useful.

Information about how to set up filters can be found here: http://www.yiiframework.com/doc/guide/basics.controller#filter

The method-based implementation of the filters is extremely straight forward, simply add the method to the controller in the form of public function filterXYZ( $c ) then add XYZ to your array of filters:

Thursday, June 24, 2010

Adding Foreign Keys Manually

Using MyISAM tables (in MySQL), I'm unable to set foreign keys in the database. However, I'm working with several tables which utilize foreign key type relationships. The problem was how to get Yii to recognize those relationships properly.

This one took me a while to figure out. With the help of the experts over at the Yii Forums, I was able to put together this solution.

Tuesday, June 22, 2010

Saving encrypted passwords for new users

When using PASSWORD() encrypted passwords for users, I need to save the encrypted version when the file is created or when the password is changed. However, I don't want it to run the encryption every time the file is saved if it's pulled in the encrypted value already.

Putting the job of encrypting the password on the User model, I've added an encryptPassword() function to the model, which can be called by the controller after it receives the post data as such:

public function encryptPassword()
{
    $p = $this->userpass;
    $this->userpass = new CDbExpression('PASSWORD(:up)', array(':up'=>$p));
}

And modify the actionCreate as such:
...
$model->attributes = $_POST['User']; // existing line
if ( $model->validate()){    
   $model->encryptPassword();
   if ( $model->save( false )){   // modify existing line to pass in false param
      // .. existing code here
   }
} 
- OR -
To automate the process, alter the User model further by adding:
protected function beforeSave()
{
  if ( $this->isNewRecord )
     $this->encryptPassword();
  return parent::beforeSave();
}

Then, if you have a change password form, you can handle it in the same fashion.

Thursday, June 10, 2010

Yii User Authentication using MySQL PASSWORD()

This is a pretty simple thing, but it hitched me up for a while, so I thought it worth sharing/recording the solution.

If you use passwords stored with the MySQL PASSWORD() function, the suggested methods of authentication with UserIdentity need to be tweaked.

There are two ways that I have come up with to run the comparison. The first way is more secure, as it doesn't ever send the encrypted password back through the connection, but the second way allows you a more specific 'user found, but password is wrong' error.

Wednesday, May 12, 2010

Using Gii

This feature is new to the 1.1.2 release of Yii. I finally had a chance to look at it today, and I'm quite impressed thus far. This module allows for web access to the old yiic shell commands, and is extremely straight forward and easy to use. It shows you previews of the files to be generated, including whether the file is new or overwriting an existing file. It comes with 5 default Generators: Controller, crud, Form, Model and Module.

To use it, you need to first enable it in your config for the site. Be sure to note that it's only set to work on a localhost by default, so if you need to use it on a remote machine make sure to enter in your IP to the IP filters array.  Also note that if you're configured for path urls, you're going to have to modify the settings there as directed in the guide.

The link to the guide for Gii is here:
http://www.yiiframework.com/doc/guide/topics.gii

Wednesday, April 14, 2010

LoginRequired and Ajax Updates

My Issue:
If my user session times out while an access restricted page is visible (say I left it open overnight), and the user then clicks on a button that performs an ajax call, the login required display appears within the div that the ajax update should happen in, rather than replacing the entire current page.

Potential Solutions:
Option 1) Extend the CWebUser and override the loginRequired() function to check for $request->isAjaxRequest (this would then need to redirect to a page which causes a javascript redirect)

Option 2) Modify the Site actionLogin to check the request type and render a different page which causes a javascript redirect.

Option 2 is the least invasive method, so I am going to go with that option and see how things work out ;)

Site Note: Could override the controller->redirect method, but I don't want to necessarily block all redirects -- I can forsee needing to have one ajax view action redirect to another ajax view action. If the controller override was used, it would have to be done on every controller - hardly efficient.

Wednesday, March 31, 2010

Posting with multiple models

I spent a good bit of time trying to figure out how to render multiple models in a form and have them each validate properly.

Knowing the solution, it seems quite obvious, but it took a while to track down the proper syntax.

In this example I have a custom CForm which contains a few different $model properties, in addition to the base form data.

To call the validation on multiple models in the form, simply modify any calls of
CActiveForm::validate($model);
to use an array of models as the first parameter as such:
CActiveForm::validate( array($model, $model->subModel, $model->subModel2) );