Search code examples
phpurlroutesyii2slug

How to use Yii2 Sluggable Behavior?


I have defined this behavior as per documentation instructions.

public function behaviors()
{
    return [
        TimestampBehavior::className(),
        [
            'class' => SluggableBehavior::className(),
            'attribute' => 'title',
        ],
    ];
}

In my config url manager I have defined custom rule like this: example.com/article/1

'urlManager' => [
    'class' => 'yii\web\UrlManager',
    'enablePrettyUrl' => true,
    'showScriptName' => false,
    'rules' => [
        'article/<id:\d+>/<slug>' => 'article/view',
    ],
],

My view action is:

public function actionView($id, $slug = null)
{
    return $this->render('view', [
        'model' => $this->findModel($id),
    ]);
}

In my index view file I am generating URL to view action like this : Url::to(['article/view', 'id' => $model->id, 'slug' => $model->slug])

I would like to output my article title in url like this: example.com/article/1/My-first-post

But I am not getting title in URL.

Soju said that slug is a database attribute. I have created new column in my article table called slug and it is varchar 1024. But I am still not getting slug generated in URL. My URL is: example.com/article/1

What is wrong ? Thanks

EDIT: I have updated my code to insert title value into slug column in my article table. Now I get slug working but I do not get SEO URL-s. I get this: article/1/First+Article, and I would like article/1/First-Article.

I have tried with:

return [
    TimestampBehavior::className(),
    [
        'class' => SluggableBehavior::className(),
        'attribute' => 'title',
        'value' => function ($event) {
            return str_replace(' ', '-', $this->slug);
        }
    ],
];

This doesn't work either: return str_replace(' ', '-', $this->slug);


Solution

  • You could add the following urlManager rule :

    'article/<id:\d+>/<slug>' => 'article/view',
    

    And build url in your views like this :

    \yii\helpers\Url::to(['article/view', 'id'=>$model->id, 'slug'=>$model->slug])
    

    You could also add helpers in your model :

    public function getRoute()
    {
        return ['article/view', 'id'=>$this->id, 'slug'=>$this->slug];
    }
    
    public function getUrl()
    {
        return \yii\helpers\Url::to($this->getRoute());
    }
    

    And then simply use $model->url in your views.