I'm not sure how exactly you need to manage your rules so I'll go for a general use case and I'll base my answer on what I did understand from Paddy Moogan's Article which I will resume within the following example and I hope it helps on designing your required solution:
requirement:
Assuming a Search Engine did send a robot to check page B
in my website and I'm not fine with people getting to page B
instead of page A
. So this is how I can clarify my point to the robot:
Forcing a 301
redirect to page A
:
Telling the Search Engine that this page is permanently moved to page A. So please don't send more people to it. Send them to page A instead.
Forcing a 302
redirect to page A
:
Telling the Search Engine that this page is temporary moved to page A. So do whatever you think it
is appropriate.
Opening page B
(200 status code) but insert a Canonical
link element
pointing to page A
:
Telling the Search Engine that this page is working fine but it is to me a secondary page and I would suggest sending the next visitors to page
A instead.
design:
So based on that this is how I would see a possible structure to my rules configuration:
'rules' => [
[
// by default: 'class' => 'yii\web\UrlRule',
'pattern' => '/',
'route' => 'site/index',
],
[
// the custom class
'class' => 'app\components\SEOUrlRule',
'pattern' => 'about',
'route' => 'site/about',
'permanents' => [
'deprecated-about',
'an-older-deprecated-about'
],
'temporaries' => [
'under-construction-about',
],
'secondaries' => [
'about-page-2'
]
],
[
// different route with own action but canonical should be injected
'class' => 'app\components\SEOUrlRule',
'pattern' => 'experimental-about',
'route' => 'whatever/experimental',
'canonical' => 'about'
],
]
This way I can chain as much arrays as I need to use Yii's default class yii\web\UrlRule while I can have a custom one in my app components folder dedicated to SEO related controllers.
Before going to code, this is how I would expect my website to behave :
- You visit the /about page you get a
200
response (no
canonical added).
- You visit the /deprecated-about page you get redirected to
/about with
301
status code.
- You visit the /under-construction-about page you get redirected to
/about with
302
status code.
- You visit the /about-page-2 page you get a
200
response (rendered by index/about
action). No redirections except a similar tag to this is automatically injected into source code:
<link href="http://my-website/about" rel="canonical">
- You visit the /experimental-about page you get a
200
response (rendered by its own action whatever/experimental
) but with that same canonical tag above injected.
code:
The SEOUrlRule will simply extend \yii\web\UrlRule and override its parseRequest method to define the extra attributes based on which we will force a HTTP redirection or call parent::parseRequest()
after registering the canonical link tag to the Yii::$app->view
:
namespace app\components;
use Yii;
class SEOUrlRule extends \yii\web\UrlRule
{
public $permanents = [];
public $temporaries = [];
public $secondaries = [];
public $canonical = null;
public function parseRequest($manager, $request)
{
$pathInfo = $request->getPathInfo();
if(in_array($pathInfo, $this->permanents))
{
$request->setPathInfo($this->name);
Yii::$app->response->redirect($this->name, 301);
}
else if(in_array($pathInfo, $this->temporaries))
{
$request->setPathInfo($this->name);
Yii::$app->response->redirect($this->name, 302);
}
else if($this->canonical or in_array($pathInfo, $this->secondaries))
{
$route = $this->name;
if ($this->canonical === null) $request->setPathInfo($route);
else $route = $this->canonical;
Yii::$app->view->registerLinkTag([
'rel' => 'canonical',
'href' => Yii::$app->urlManager->createAbsoluteUrl($route)
]);
}
return parent::parseRequest($manager, $request);
}
}
And that is all what it needs. Note that Yii::$app->controller
or its related actions won't be yet available at this early stage of solving routes as it is shown in this lifecycle diagram but it seems that Yii::$app->view
is already initialized and you can use its $params property to set custom parameters (as it is done in this example) which may be useful for more advenced cases where more data should be shared or populated to final output.
yii\web\UrlManager
and I do not see any means to define a canonical URL which groups others inrules[]
. – Toon'urlManager'=>['class' => 'app\components\myUrlManager'
that extendsyii\web\UrlManager
and overrides or add extra methods to it – Bronderyii\rest\UrlRule
which extendsyii\web\CompositeUrlRule
, an implementation of theUrlRuleInterface
. So it is a custom child UrlRule class after all. I didn't even notice that but it should be a good example to check for a start. – Bronder