How to use beforeAction in Yii or slug issues

Yii-Jedis!

I am working on an old Yii project and should add some features to them. Yii is a pretty logical structure, but I have some things that I could not understand. Perhaps I have not understood Yii-way yet. Therefore, I will describe my problem step by step. For impatience - a short question at the end.

Introduction: I want to add human-readable URLs to my project. The urls now look like this: www.site.com/article/359
And I want them to look like this: www.site.com/article/how-to-make-pretty-urls
Very important: old articles should be available on old format URLs, and new ones on new URLs.

Step 1: First, I updated the rewrite rules in config / main.php:

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

And I added a new texturl column to the article table. Thus, we will store here the human-readable parts of the URL for new articles. Then I updated one article with text for tests.

Step 2: The application displays the articles in the actionView of the ArticleController control, so I added this code there for the preproccessing ID parameter:

 if (is_numeric($id)) { // User try to get /article/359 $model = $this->loadModel($id); // Article::model()->findByPk($id); if ($model->text_url !== null) { // If article with ID=359 have text url -> redirect to /article/text-url $this->redirect(array('view', 'id' => $model->text_url), true, 301); } } else { // User try to get /article/text-url $model = Article::model()->findByAttributes(array('text_url' => $id)); $id = ($model !== null) ? $model->id : null ; } 

And then run the legacy code:

 $model = $this->loadModel($id); // Load article by numeric ID // etc 

It works great! But...

Step 3: But we have a lot of actions with the ID parameter! What should we do? Refresh all actions with this code? I find this ugly. I found the CController :: beforeAction method . Looks good! So I declare preAccess and place the preprocess ID there:

 protected function beforeAction($action) { $actionToRun = $action->getId(); $id = Yii::app()->getRequest()->getQuery('id'); if (is_numeric($id)) { $model = $this->loadModel($id); if ($model->text_url !== null) { $this->redirect(array('view', 'id' => $model->text_url), true, 301); } } else { $model = Article::model()->findByAttributes(array('text_url' => $id)); $id = ($model !== null) ? $model->id : null ; } return parent::beforeAction($action->runWithParams(array('id' => $id))); } 

Yes, it works with both URL formats, but it executes actionView TWICE and shows the page twice! What can i do with this? I am completely confused. Have I decided to solve my problem correctly?

In short: Can I request an identifier (GET parameter) before performing any action, and then run the requested action (once!) With only the ID parameter changed?

+6
source share
2 answers

The last line should be:

 return parent::beforeAction($action); 

Also, to ask you, I did not receive your step: 3.

As you said, you have many controllers and you do not need to write code in each file, so you use beforeAction: But you only have text_url associated with the article for all controllers?

$ model = Article :: model () → findByAttributes (array ('text_url' => $ id));

===== updated answer ======

I changed this function now.

If $ id is not numeric, we will find its id using the model and set $ _GET ['id'], so in the future the controller will use this numberic identifier.

 protected function beforeAction($action) { $id = Yii::app()->getRequest()->getQuery('id'); if(!is_numeric($id)) // $id = how-to-make-pretty-urls { $model = Article::model()->findByAttributes(array('text_url' => $id)); $_GET['id'] = $model->id ; } return parent::beforeAction($action); } 
+12
source

Sorry, I didn’t read all this carefully, but did you consider using this extension ?

+2
source

Source: https://habr.com/ru/post/922333/


All Articles