Controller Redirect Problem/query

Just when I thought I was understanding Yii a bit better I came across the following problem. Although I have solved this problem I am not particularly happy with my solution as I don’t really understand it so I was hoping somebody on here would be able to explain it to me properly.

I have a controller called UserMaintenanceController and within this controller I have an action - actionResetPassword.

Here is a (edited) snippet of the code from this controller. I apologise in advance for any poor coding technique!




	public function actionResetPassword()

	{

		

		 // non-relevant code to retrieve a user	

                   .... 


                   $model = new UserModel();

		   $model->resetUserPassword($user);

	 	   $this->redirect(array('userMaintenance/default')); 

		

	}



the redirect is to another action in the same controller - default which is my default action for this conroller (replacing index) as I have defined:-


public $defaultAction = 'default';

within the class

Here is some edited code from this default action (which displays a list of users using a view called userList)




	public function actionDefault()

	{

				

		$model = new UserModel();

		$this->render('userList', array('model'=>$model));

	}



The resetPassword redirect to actionDefault is, in effect, just a way of reloading the current page after the resetPassword has been carried out. I tried using the refresh() method instead but this doesn’t do quite what I want as I want control to be passed back to the other action so that the correct URL gets displayed.

The problem I have here is with the redirect call within the resetPasswordAction. Using the code above, the first time I call the redirect, it works fine but the next time I call it I get an error along the lines of - Cannot find action UserMaintenance - this is odd as UserMaintenance is the controller and not the action! Within the browser address bar I can see that it is attempting to call a URL of {application root}/UserMaintenance/UserMaintenance/default when I want it to call {application root}/UserMaintenance/default.

As I stated above, it seems to work correctly on the first redirect and the only difference I can spot is that the URL before the first redirect is {application root}/UserMaintenance and on the second redirect it is {application root}/UserMaintenance/ with an extra ‘/’ at the end.

I have tried using


$this->redirect(array('userMaintenance'));

and get the same problem apart from the fact that this doesn’t even work on the first redirect!

I have also tried using createURL and absoluteURL (not the correct full name - I know!) but I get the same issue each time.

In the end I found that if I use this line




  $this->redirect(array('userMaintenance/')); 



with an extra slash at the end but no action then it works correctly but I have no idea why!!

I believe it may have something to do with my URLmanager setup. This is more that likely as I have never really understood this and just copied code in from elsewhere!

Here for reference is my URLmanager code (from main.php in config)




		'urlManager'=>array(

			'urlFormat'=>'path',

			'showScriptName' => false,

			'rules'=>array(

				'<action:(home|index|login|logout|about)>'=>'site/<action>', 

				'<controller:\w+>/<id:\d+>'=>'<controller>/view',

				'<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',

				'<controller:\w+>/<action:\w+>'=>'<controller>/<action>',

			),

		),



The first rule here is meant to remove the site part of the URL for all my actions that use the site controller and this seems to work ok. I am not sure exactly what the next three rules are but they seem to be fairly standard rules that other coders use.

I also have logic to remove the index.php part of the address in a .htaccess file. Here it is




deny from all


RewriteEngine on

 

# if a directory or a file exists, use it directly

RewriteCond %{REQUEST_FILENAME} !-f

RewriteCond %{REQUEST_FILENAME} !-d

 

# otherwise forward it to index.php

RewriteRule . index.php



I don’t know if this is relevant but I thought I best include it just in case.

As I stated above, I have a working version of this using the final example of the redirect code but I am not happy with why this works.

Hopefully if someone has managed to read through all this and can provide an explanation then I would be extremely grateful!

Regards,

Martin C

It looks like a bug, especially since it doesn’t behave the same way at the first and second request.

Another workaround which I find more readable than yours is to write array('/userMaintenance/default'), i.e. starting the route with a slash.

It would still be great if you could debug your problem and confirm if it is or not a bug. If yoou don’t feel like using a debugger (like Netbeans+Xdebug), I suggest you modify “framework/web/CController.php” to insert a die(&#036;route); before the last line of createUrl().

Second rule: if the path is like "/sometext/12345" (i.e. alphanum chars, a slash, then digits), then "sometext" is the name of the controller, and the action is "view".

The other rules follow the same patterns.

Thank you for the reply Francois.

I did the debugging that you asked for and what it revealed to me was it was a mistake in my javascript code that was causing the problem!

I was submitting (within the javascript) using a relative path of ‘userMaintenance/resetPassword’. Sorry - I neglected to mention this! It appears that this works the first time when the URL was {app name}/userMaintenance. But then the URL was set to {app name}/userMaintenance/default and so using the relative path again sets the URL to {appname}/userMaintenance/userMaintenance/default!

So the path was wrong before it even got to my php action code!!

I have changed the javascript to use a path of /{appname}/userMaintenance/resetPassword and now it works correctly every time.

So thanks for your help and sorry for my ignorance!

One last question. What is the easiest way in Yii to get the {appname} part of the URL? I would rather not hard code it into my Javascript if I can help it.

Thanks in advance,

Martin C

The best solution is probably to use an absolute URL, built using


Yii::app()->createAbsoluteUrl('userMaintenance/resetPassword');

In your js, you could use something like


var url = <?= CJavaScript::encode(

    Yii::app()->createAbsoluteUrl('userMaintenance/resetPassword')); ?>;

Great, Thanks Keith I will give this a try.

Cheers,

Martin C