Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Yii2: How to redirect to with UrlManager?

In my Yii2 config I have:

'components' => [
    'urlManager' => [

        'baseUrl'         => '',
        'enablePrettyUrl' => true,
        'showScriptName'  => false,

        'rules' => [
            'search' => 'site/index',
            ...
        ],
    ...

If I go to site.com/search it works. If I go to site.com/site/index it also works and shows the same content. How to redirect the call instead of just showing the response of site/index? It must also redirect with params (site.com/site/index?param=1 -> site.com/search?param=1)

like image 572
sirjay Avatar asked Jun 03 '18 19:06

sirjay


3 Answers

The UrlManager does not redirect. It rather does a rewrite like a web server. It is called routing.

If you would like to do a redirect in your code you can use Response::redirect(). If you don't have a SearchController where you can put this statement in an action, you can place it into the beforeAction event. You can do this in your configuration array:

Option #1

[
    'components' = [
        ...
    ],
    'on beforeAction' => function ($event) {
        if(Yii::$app->request->pathInfo === 'search') {
            $url = 'site/index?' . Yii::$app->request->queryString;
            Yii::$app->response->redirect($url)->send();
            $event->handled = true;
        }
    }
]

Option #2

Or if you have SearchController use:

class SearchController extends \yii\web\Controller {
    public function actionIndex() {
        $url = 'site/index?' . Yii::$app->request->queryString;
        return $this->redirect($url);
    }
}

Option #3

Third option is to configure the web server to do the redirect. That would be the fastest solution.

like image 120
robsch Avatar answered Oct 08 '22 11:10

robsch


You may use UrlManager::$enableStrictParsing to disable matching by route. If you set it to true, request to /site/index URL will not match anything and app will return 404 error.

'components' => [
    'urlManager' => [
        'baseUrl' => '',
        'enablePrettyUrl' => true,
        'showScriptName' => false,
        'enableStrictParsing' => true,
        'rules' => [
            'search' => 'site/index',
            // ...
        ],
    // ...

But this may be not an option if you actually want to use routes as URLs in other cases.


You may also be interested in the UrlNormalizer class. This is still a relatively simple component and does not (yet) support your use case, but in fact it was designed for such tasks. You may consider extending it and add redirection logic for your use case - it should be much more clean solution than using events or dedicated actions and rules for redirections. It may be also a good material for PR and pushing this feature to core framework.


Lazy solution would be to create redirection action and add rules to match URLs that needs to be redirect:

class RedirectController extends Controller {

    public function actionRedirect($action, $controller, $module = null) {
        if ($action === $this->action->id && $controller === $this->id && $module === null) {
            // prevent to access action directly and redirection loops
            throw new NotFoundHttpException();
        }

        $url = Yii::$app->request->get();
        unset($url['action'], $url['controller'], $url['module']);
        array_unshift($url, '/' . ltrim(implode('/', [$module, $controller, $action]), '/'));

        return $this->redirect($url);
    }
}

And rules:

'urlManager' => [
    // ...
    'rules' => [
        'search' => 'site/index',
        [
            'pattern' => '<controller:(site)>/<action:(index)>',
            'route' => 'redirect/redirect',
            'model' => UrlRule::PARSING_ONLY,
        ],
        // ...
    ],
],
like image 31
rob006 Avatar answered Oct 08 '22 10:10

rob006


You can simply use redirect that's much easier and it solves your problem, it's just like the render. See the example below:

 return $this->redirect(['/site/index']);

P.S. The path can be an absolute or relative, you could also use an alias or anything else, here is an example:

// an alias of for home page
Yii::setAlias('@home', 'site/index');
like image 2
Ammar Dje Avatar answered Oct 08 '22 11:10

Ammar Dje