Access Rule not working

Hello, I have the following code that is supposed to allow a regular user to be able to edit a Story ONLY if the user was the creator of the story:


$story_by = Stories::model()->findByPk((int)$_GET['id'])->entered_by;


                // THIS WORKS!!!!

		if(Yii::app()->user->isOwner($story_by)) {

			echo "AAAAAAAA";

		}

		

		return array(

			array('allow',

				'actions'=>array('index','view','create'),

				'users'=>array('@'),

			),

			array('allow', 

				'actions'=>array('update','delete'),

				'expression'=>'$user->isAdmin() || $user->isOwner($story_by)', // isOwner here DOESN'T WORK!!!!

			),

			array('deny',

				'users'=>array('*'),

			),

I have an isOwner function in my WebUser.php file, which works great everywhere except in the ‘expression’ for the access rules array. You can see where I commented the isOwner function, the first one works (just a test call to isOwner), but the second one in the expression doesn’t…I guess it’s returning false…why would that be???

[s]Which users?

include them like this:

array(‘allow’,

     'actions'=>array('update','delete'),


    'expression'=>'$user->isAdmin() || $user->isOwner($story_by)', // isOwner here DOESN'T WORK!!!!


    'users'=>array('*') // or registered '@'[/s]


                    ),

or maybe is because you need to include it lik this

Yii::app()->user->isAdmin() || Yii::app()->user->isOwner($story_by)

I have personally never used this approach, but after seen its function code:

http://www.yiiframework.com/doc/api/1.1/CComponent#evaluateExpression-detail

I wonder if it recognizes $user or not…

Nah that’s not it, because my $user->isAdmin() function is working. I think it might have to do something with passing a parameter in to the isOwner function in the expression but I don’t see how else I could do it. Here’s that function just for reference:


function isOwner($story_by){

		$user_id = Yii::app()->user->id;

		return $user_id == $story_by;

	}

Yeah, you may be right, could you test it with an integer value instead of a variable name? lets see what happens

wow that worked…hmm okay now how can I pass a variable in there…

Where is the $story variable is set?

Can you set it up inside isOwner function (without parameters). If it is a $_GET value, get it inside the property function instead

Thanks! I did


'expression'=>'$user->isAdmin() || $user->isOwner(Stories::model()->findByPk((int)$_GET[\'id\'])->entered_by)',



and it works!!!

Congratulations! That is also great hint for others…

Hm… I’m just curious if this is best approach - i.e. if using ActiveRecord as expression in accessRules will not degrade application performance significantly?

Wouldn’t be easier (faster) to let in (allow to pass accessRules) all authenticated user (’@’) and then check, if a particular user is story owner inside proper action. What do you think?

I think the "cleanest" approach would be to create a new separate filter for checking if the user is the story owner. That way you could avoid doing complicated access control checks and you could reuse the code wherever necessary.

I was suggesting creating a property like this in User model:

public getIsOwner(){

return isset($_GET[‘id’]) && Stories::model()->findByPk((int)$_GET[‘id’])->entered_by;

}

and then use it in the accessRule as

‘expression’=>’$user->isAdmin() || $user->isOwner’


Another good way is creating a filter… I agree

I don’t like this approach, because you are writing functions in model that relies on $GET, that breaks mvc.

I think that the check on the owner can be better done in the loadModel function (or, better, in the afterFind of the model).

Take a look at this post

Okay I added the afterFind function and changed it to fit my model attributes, but this method is invoked on every page, even the index page, which I want any logged in user to be able to access. How would I go about performing the check only on the delete and edit views? Thanks

I had a similar scenario, here what I did:




	public function accessRules()

	{

		return array(

			array('allow',  // allow all users to perform 'index' and 'view' actions

				'actions'=>array('index','view'),

				'users'=>array('*'),

			),

			array('allow', // allow authenticated user to perform 'create' and 'update' actions

				'actions'=>array('create'),

				'users'=>array('@'),

			),

			array('allow',// allow user to update their own content

				'actions'=>array('update', 'delete'),

				'expression'=>'PostController::checkIfRecordAuthor( (int)$_GET["id"], Yii::app()->user->id);',

			),

			array('allow', // allow admin user to perform 'admin' and 'delete' actions

				'actions'=>array('admin','delete', 'update'),

				'users'=>array('admin', 'theAdmin', 'the Boss'),   

				'expression' => '($user->isAdmin) )', // this is a custom method mapped to a bool field in db

			),

			array('deny',  // deny all users

				'users'=>array('*'),

			),

		);

	}






// this is in PostController

	public static function checkIfRecordAuthor($id, $user_id) 

	{

		$model=Post::model()->findByPk($id);

		if($user_id == $model->author_id)	{ return true; } 

		else 					{ return false;}

	}