[SOLVED]list own stuff

I have 3 models

  • Members

  • Company

  • Member staff

  1. I coded member staff, in a way the members staffs will be shown under a company’s detail page.
  • now, whenever I click the company id from the index file, I get redirected to the company’s full view detail page, and underneath it is a list of the member staff with pagination.
  1. I did the same coding with the Company Controller by adding a filter so a Member can only

create a company when he is logged in and view his own companies,

the problem now is, a different member logged in, can view the companies of other members what’s the best approach with this?,

here’s my filter code within the Company controller





	public function filters()

	{

		return array(

			'accessControl', // perform access control for CRUD operations

			'memberContext + create',

		);

	}


	

	public function filterMemberContext($filterChain)

	{

		$member_id = null;

		if(isset($_GET['mid']))

			$member_id = $_GET['mid'];

		else

			if(isset($_POST['mid']))

				$member_id = $_POST['mid'];

				

		$this->loadMember($member_id);

		

		$filterChain->run();

	}		



I am usually doing this kind of check in the model.

I write an afterfind function like:




public function afterFind()

{

   if ($this->owner!= Yii::app()->user->userId)

      throw new Exception('you are not authorized to see this company');


}




This will protect you to unauthorized access to the model itself, so you cannot forget some check in any action you create or you will create in future.

I like this approach because is "putting business logic in models".

In search() function model

==========================

$criteria->compare(‘t.member_id’,Yii::app()->user->id,true);

by the way, I have another problem with this,

I hardcoded the index.php file of the Company view,

  • now whenever I click this link from the right side menu, the ID of the member being saved

is the hardcoded, not the ID of the currently logged in member, what should I do with this ?




$this->menu=array(

	array('label'=>'Create Company Details', 'url'=>array('create','mid'=>2)),



ok, i did it like this




$this->menu=array(

	array('label'=>'Create Company Details', 'url'=>array('create','mid'=>Yii::app()->user->id)),



question: what’s $this->owner is “owner” some sort of built-in property of yii ?

this doesn’t work, I even placed it in both Company and Member search()




$criteria->compare('MemberShipID', Yii::app()->user->id,true);



No no, it is just a field in the table company in wich there is the owner of the company.

I just copied a snipped from a project. Instead of this you should write a condition for check if the user is authorized to see this company.

The advice was: write an after find for each model you wish to protect againd unauthorized access, and if the user has not right, throw an exception.

This will give you 100% safety against any user that will try to edit the url (changing the id of the company).

ok here’s what I did, I placed it inside the Company model




	public function afterFind()

	{

		if($this->MemberShipID != Yii::app()->user->id)

			throw new CHttpException('404','You are not authorized');

	}



and now, both of my test accounts can’t view their own companies, why is that ?

does your table contain the field membershipid and which is contain the value of userid(which is in login table)

this is what my company table has

-MemberShipID

-CompanyID

-Company name and etc…

the user id is the MemberShipID itself,

are you trying this in your company model? because im using this code and its working fine for me…

public function search()

{


	// Warning: Please modify the following code to remove attributes that


	// should not be searched.





	$criteria=new CDbCriteria;


            


            





	$criteria->compare('t.membershipid=',Yii::app()->user->id,true);

return new CActiveDataProvider(get_class($this), array(

		'criteria'=>$criteria,


	));

It will show filtered result in gridview

yeah i was using it in the company model,

after I login, and click the "My Companies" from the menu,

I get redirected to this

[code]

http://yii/app/index.php?r=wsmembersdetails/index

[code]

My

  • Test1 account = has 3 companies

  • Test2 account = has 1 company

when I log in Test2 account, I can still view the 3 companies created by Test1

and vice versa

check whether you have another $creiteria->compare with membershipid if you have remove that

give ur full search function code

these are the $criteria that I have




		//$criteria->compare('MemberShipID',$this->MemberShipID);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		$criteria->compare('MemberShipID=', Yii::app()->user->id,true);



still it doesn’t work, even if I commented all of them except for the bottom line of code

Verify whether your table have membershipid correctly

yeah it does have

i dont know whether am i correct or not verify login table userid and useridentity

There can be many possibily: maybe the Yii::app()->user->id is not correct, check it.

Another option is that you are querying all the companyies, including the companies that a user is not allowed to see. In that case the exception is the expected behaviour, you have to query only the right models.

In the bottom line of the code there is an error, the = is not needed in compare.

Check the query that yii generates, for be sure that you have configured all criteria in a correct way.

here’s my UserIdentity class




class UserIdentity extends CUserIdentity

{

	/**

	 * Authenticates a user.

	 * The example implementation makes sure if the username and password

	 * are both 'demo'.

	 * In practical applications, this should be changed to authenticate

	 * against some persistent user identity storage (e.g. database).

	 * @return boolean whether authentication succeeds.

	 */

	private $_id;

	const ERROR_EMAIL_INACTIVE = 3;

	

	public function authenticate()

	{


		$record = Wsmembers::model()->findByAttributes(array('WSLoginName' => $this->username));

		$email = Wsmembers::model()->findByAttributes(array('WSEmailConfirmed' => 0));

		if($record === null)

			$this->errorCode = self::ERROR_USERNAME_INVALID;

		else if($record->WSLoginPassword !== sha1($this->password))

			$this->errorCode = self::ERROR_PASSWORD_INVALID;

		else if($email)

			$this->errorCode = self::ERROR_EMAIL_INACTIVE;

		else 

		{

			$this->_id = $record->MemberShipID;

			$this->setState('name', $record->WSLoginName);

			$this->errorCode = self::ERROR_NONE;

		}

		return !$this->errorCode;

	}

	

	public function getId()

	{

		return $this->_id;

	}


}



This one is responsible for displaying the companies for an existing User

I applied what I learned from the yii book





<?php


class WsmembersdetailsController extends Controller

{

	

	private $_member = null;

	/**

	 * @var string the default layout for the views. Defaults to '//layouts/column2', meaning

	 * using two-column layout. See 'protected/views/layouts/column2.php'.

	 */

	public $layout='//layouts/column2';


	/**

	 * @return array action filters

	 */

	public function filters()

	{

		return array(

			'accessControl', // perform access control for CRUD operations

			'memberContext + create',

		);

	}


	/**

	 * Specifies the access control rules.

	 * This method is used by the 'accessControl' filter.

	 * @return array access control rules

	 */

	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','update'),

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

			),

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

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

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

			),

			array('deny',  // deny all users

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

			),

		);

	}


	/**

	 * Displays a particular model.

	 * @param integer $id the ID of the model to be displayed

	 */

	public function actionView($id)

	{

		$staffDataProvider = new CActiveDataProvider('Wsmembersstaff', array(

			'criteria' => array(

				'condition' => 'CompanyID=:CompanyID',

				'params' =>array(':CompanyID'=>$this->loadModel($id)->CompanyID),

			),

			'pagination' => array(

				'pageSize' => 1,

			),

		));

		

		$this->render('view',array(

			'model'=>$this->loadModel($id),

			'staffDataProvider'=>$staffDataProvider,

		));

	}


	/**

	 * Creates a new model.

	 * If creation is successful, the browser will be redirected to the 'view' page.

	 */

	public function actionCreate()

	{

		$model=new Wsmembersdetails;

		

		$model->MemberShipID = $this->_member->MemberShipID;


		// Uncomment the following line if AJAX validation is needed

		// $this->performAjaxValidation($model);


		if(isset($_POST['Wsmembersdetails']))

		{

			$model->attributes=$_POST['Wsmembersdetails'];

			if($model->save())

				$this->redirect(array('view','id'=>$model->CompanyID));

		}


		$this->render('create',array(

			'model'=>$model,

		));

	}


	/**

	 * Updates a particular model.

	 * If update is successful, the browser will be redirected to the 'view' page.

	 * @param integer $id the ID of the model to be updated

	 */

	public function actionUpdate($id)

	{

		$model=$this->loadModel($id);


		// Uncomment the following line if AJAX validation is needed

		// $this->performAjaxValidation($model);


		if(isset($_POST['Wsmembersdetails']))

		{

			$model->attributes=$_POST['Wsmembersdetails'];

			if($model->save())

				$this->redirect(array('view','id'=>$model->CompanyID));

		}


		$this->render('update',array(

			'model'=>$model,

		));

	}


	/**

	 * Deletes a particular model.

	 * If deletion is successful, the browser will be redirected to the 'index' page.

	 * @param integer $id the ID of the model to be deleted

	 */

	public function actionDelete($id)

	{

		if(Yii::app()->request->isPostRequest)

		{

			// we only allow deletion via POST request

			$this->loadModel($id)->delete();


			// if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser

			if(!isset($_GET['ajax']))

				$this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));

		}

		else

			throw new CHttpException(400,'Invalid request. Please do not repeat this request again.');

	}


	/**

	 * Lists all models.

	 */

	public function actionIndex()

	{

		$dataProvider=new CActiveDataProvider('Wsmembersdetails');

		$this->render('index',array(

			'dataProvider'=>$dataProvider,

		));

	}


	/**

	 * Manages all models.

	 */

	public function actionAdmin()

	{

		$model=new Wsmembersdetails('search');

		$model->unsetAttributes();  // clear any default values

		if(isset($_GET['Wsmembersdetails']))

			$model->attributes=$_GET['Wsmembersdetails'];


		$this->render('admin',array(

			'model'=>$model,

		));

	}


	/**

	 * Returns the data model based on the primary key given in the GET variable.

	 * If the data model is not found, an HTTP exception will be raised.

	 * @param integer the ID of the model to be loaded

	 */

	public function loadModel($id)

	{

		$model=Wsmembersdetails::model()->findByPk((int)$id);

		if($model===null)

			throw new CHttpException(404,'The requested page does not exist.');

		return $model;

	}


	/**

	 * Performs the AJAX validation.

	 * @param CModel the model to be validated

	 */

	protected function performAjaxValidation($model)

	{

		if(isset($_POST['ajax']) && $_POST['ajax']==='wsmembersdetails-form')

		{

			echo CActiveForm::validate($model);

			Yii::app()->end();

		}

	}

	

	protected function loadMember($member_id)

	{

		if($this->_member === null)

		{

			$this->_member = Wsmembers::model()->findByPk($member_id);

			if($this->_member === null)

			{

				throw new CHttpException(404, 'The requested project does not exist.');

			}

		}

		return $this->_member;

	}

	

	public function filterMemberContext($filterChain)

	{

		$member_id = null;

		if(isset($_GET['mid']))

			$member_id = $_GET['mid'];

		else

			if(isset($_POST['mid']))

				$member_id = $_POST['mid'];

				

		$this->loadMember($member_id);

		

		$filterChain->run();

	}

	


}



and this is the index of the Company Model




<?php

$this->breadcrumbs=array(

	'Company Details',

);


$this->menu=array(

	array('label'=>'Create Company Details', 'url'=>array('create','mid'=>Yii::app()->user->id)),

	#array('label'=>'Manage Company Details', 'url'=>array('admin','mid')),

);

?>


<h1>Company Details</h1>


<?php $this->widget('zii.widgets.CListView', array(

	'dataProvider'=>$dataProvider,

	'itemView'=>'_view',

)); ?>




can you help me or point the thing that I missed ? or lacking at ?

I don’t know what is filterMemberContext, never used.

I can give you some advices:

  • never pass the ‘mid’=>Yii::app()->user->id, is meaningless because you can whereever use Yii::app()->user->id for check

  • check (echo Yii::app()->user->id) that the userId is correct, it should be.

If the user->id is correct, just add to the search() of the model one more check:


 $criteria->compare('MemberShipID=', Yii::app()->user->id,true);

That’s all. No changes to default gii generated controllers and views are required, you have to change exatly 1 line in the model.