Posts categorized “Yii”.

Yii (and Yii2) wildcard / catch all url rules

Sometimes you might want to do various checks of the url in yii config main and then send every other request to a particular controller.

The rule you need to add last to the urlManager is…

'(.*)' => 'controller/action',

… and now any rule that isn’t matched previously will end up being sent to your defined controller and action.

In Yii2 you can do the following:

'<url:(.*)>' => 'controller/action',

Reordering Yii Results Without Another Select

fetchit-21

In case you weren’t aware, you can reorder the results you already have from a previous Yii call. For example…

 
$users = User::model()->findByPk(2);
$posts = $user->posts(array('order'=>' created Desc '));

There were just ordered our users posts by created date descending.

We can also do filtering…

 
$users = User::model()->findByPk(2);
$posts = $user->posts(array('condition'=>' status=1 '));

So now we only have active posts. We could also combine a condition and a status.

You can find out more here: http://www.yiiframework.com/doc/guide/1.1/en/database.arr#dynamic-relational-query-options

Yii (and Yii2) UpdateAll Example

fetchit-21

This is a simple example of how to use Yii’s updateAll():

In this example we want to set status = 1 WHERE type_id = 1 AND status = 0

Note this is a simple example where we are only updating one column and using a string for our condition. There are more complex options available.

Comment::model()->updateAll(array( 'status' => 1 ), 'type_id = 1 AND status = 0' );

So as you can see first comes an array of column => new_value pairs, then a condition string which is pretty much used as the WHERE clause.

An example of updating more than one column:

Comment::model()->updateAll(array( 'status' => 1, 'updated' => '2011-08-25 09:33:23' ), 'type_id = 1 AND status = 0 ' );

Update. Yii2 example:

Updating a single column:

Comment::updateAll(['status' => 1], 'type_id = 1 AND status = 0');

Updating multiple columns:

Comment::updateAll(['status' => 1, 'updated' => '2011-08-25 09:33:23'], 'type_id = 1 AND status = 0' );

Yii – “Model.id” not defined for CArrayDataProvider and CSqlDataProvider etc

fetchit-21

There is a Yii error I come across every now and again, and each time it stumps me.

If you ever get SomeModel.id not defined error when trying to put your dataprovider results into a cgridview or similar then it’s likely because

1) Your model doesn’t have an id column, it might use file_id or user_id etc instead and

2) You haven’t defined which other column should be used.

We do this using what’s known as keyField:


new CArrayDataProvider($users, array('keyField' => 'user_id'));
new CSqlDataProvider($users, array('keyField' => 'user_id'));

Yii – Rewrite file or image urls for download or display

fetchit-21

I recently had a need to track files and images which were uploaded and for their urls to be secret. This meant that they couldn’t sit in a folder waiting to be found and had to be saved below the site root.

To get access to them I wanted to the check the user permissions followed by forcing download of all files (including images). Here are the steps I took to accomplish this…

For the sake of this page, my (fake) file urls are something like:

example.com/user/123/file/456.pdf

Update the urlmanager to rewrite files to my filemanager/view:

 
	'user/<user_id:\d+>/file/<id:\d+>.[a-z0-9]+' => 'filemanager/view',

Update the filemanager class’ actionView function:

 
	public function actionView($id)
	{
		$file = $this->loadModel($id);
 
		header("Pragma: public"); // required
		header("Expires: 0");
		header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
		header("Cache-Control: private",false); // required for certain browsers 
		//header("Content-Type: " . $file->mime_type);
		header("Content-Disposition: attachment; filename=\"" . str_replace(" ", "-", preg_replace("@[^a-z0-9 ]@", "", strtolower($file->file_name))) . '.' . $file->file_extension . "\";" );
		header("Content-Transfer-Encoding: binary");
		header("Content-Length: ".filesize(Yii::app()->basePath . '/../../uploads/user_files/' . $file->file_id . '.' . $file->file_extension));
		readfile(Yii::app()->basePath . '/../../uploads/user_files/' . $file->file_id . '.' . $file->file_extension);
		exit();
 
	}

I also of course required filemanager access to be strict:

 
	public function accessRules()
	{
		return array(
			array('allow', 
				'actions'=>array('view', 'create','delete'),
				'users'=>array(),
				'expression' => 'User::model()->hasRightsToFile()',
			),
			array('deny',  // deny all users
				'users'=>array('*'),
			),
		);
	}

And that’s about it. Controlled and forced file download with rewritten file urls.