Yii advanced url rewrite

yii
11,515

Solution 1

I shall explain step by step how to get this working.

Step 1 - Create an Yii web app

Navigate to your Yii framework path in your console and create a new webapp. In my case I used this in my console:

cd c:\zeus\yii-1.1.10.r3566\framework
yiic webapp c:\zeus\www\yiiblog

where c:\zeus\yii-1.1.10.r3566\framework is my path to Yii php framework and c:\zeus\www\yiiblog is the path to my Yii webapp test folder

Stept 2 - fake my domain to dev.yiiblog.com

Go to C:\Windows\System32\drivers\etc and edit your hosts file by adding this line:

127.0.0.1 dev.yiiblog.com

Step 3 - alter apache httpd.conf file

<VirtualHost *:80>
    DocumentRoot "c:/zeus/www/yiiblog"
    ServerName dev.yiiblog.com
    ErrorLog "logs/dev.yiiblog.com-error.log"
    CustomLog "logs/dev.yiiblog.com-access.log" common
</VirtualHost>

and restart apache service. I used in my windows console:

net stop apache
net start apache

where my Apache 2 service is named "apache" not "apache2.2" like the default one.

Step 4 - create a database and configure a database connection into Yii

I've created a database yiitest and a user yiitest. Then I opened my Yii configuration file located ad /protected/config/main.php and edited the connection to MySQL:

'db'=>array(
  'connectionString' => 'mysql:host=localhost;dbname=yiitest',
  'emulatePrepare' => true,
  'username' => 'yiitest',
  'password' => 'password',
  'charset' => 'utf8',
),

Step 5 - download dburlmanager Yii extension

Go to Yii dburlmanager, download the Yii dburlmanager extension http://www.yiiframework.com/extension/dburlmanager/ and extract it to your /protected/extensions folder

Step 6 - Create MySQL database tables and add dummy data

CREATE TABLE IF NOT EXISTS `articles` (
  `seoURL` varchar(100) NOT NULL
) ENGINE=InnoDB;

INSERT INTO `articles` (`seoURL`) VALUES
('first-post'),
('another-post'),
('post/value'),
('website/page1');

CREATE TABLE IF NOT EXISTS `pages` (
  `seoURL` varchar(100) NOT NULL
) ENGINE=InnoDB;

INSERT INTO `pages` (`seoURL`) VALUES
('page-first-post'),
('page-another-post'),
('page/post/value.html'),
('page-website/page1');

Step 7 - Create your Yii custom Controllers

Create under /protected/controllers folder two php files named ArticleController.php and PageController.php:

ArticleController.php content:

<?php
/**
 * @filename ArticleController.php
 */

class ArticleController extends CController {
  public function actionView() {
    $this->render('view', array(
      'article' => isset($_GET['article'])?$_GET['article']:'',
    ));
  }
}

PageController.php content:

<?php
/**
 * @filename PageController.php
 */
class PageController extends CController {
  public function actionView() {
    $this->render('view', array(
      'page' => isset($_GET['page'])?$_GET['page']:'',
    ));
  }
}

Step 8 - create your custom Yii views

Create your view files corresponding to those controllers above with the path /protected/views/article/view.php and /protected/views/page/view.php:

Article view content:

<h1>Article View Test</h1>
<br />
<?php
    if (isset ($article)) echo "article: $article";
?>

Page view content:

<h1>Page View Test</h1>
<br />
<?php
    if (isset ($page)) echo "page: $page";
?>

Step 9 - add custom Yii url rules

Open again your main.php Yii config file and set your urlManager to something similar to:

'urlManager'=>array(
  'urlFormat'=>'path',
  'class'=>'ext.DbUrlManager.EDbUrlManager',
  'connectionID'=>'db',
  'rules'=>array(
    '<article:[\w\/.-]+>'=>array(
      'article/view',
      'type'=>'db',
      'fields'=>array(
        'article'=>array(
          'table'=>'articles',
          'field'=>'seoURL'
        ),
      ),
    ),

    '<page:[\w\/.-]+>'=>array(
      'page/view',
      'type'=>'db',
      'fields'=>array(
        'page'=>array(
          'table'=>'pages',
          'field'=>'seoURL'
        ),
      ),
    ),

    '<controller:\w+>/<id:\d+>' => '<controller>/view',
    '<controller:\w+>/<action:\w+>/<id:\d+>' => '<controller>/<action>',
    '<controller:\w+>/<action:\w+>' => '<controller>/<action>',
  ),
  'showScriptName'=>false,
),

Step 10 - create .htaccess file

Create a .htaccess file under your web app root and etid its content to:

Options +FollowSymLinks
IndexIgnore */*
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

Step 11 - test your SEO Friendly URLs

dev.yiiblog.com/first-post
dev.yiiblog.com/page-first-post

etc

Have fun creating awesome blogs or other web apps with complete url managing power.

Solution 2

If I've realized you correctly, you may use something like this:

  'rules' => array(
    //You should define all the controllers exactly:
    '<controller:user|archive|office>/<action:\w+>' => '<controller>/<action>',
    //Or more complicated rule:
    '<lang:(es|it|en)>/(turismo|visita|travel)/<slug:>' => array('visit/page', 'urlSuffix' => '.html'),

    //After that you can process all remaining urls as you want:
    '<alias:[\w\d\-_\/]+>' => array('blog/view', 'urlSuffix' => '.html'),
  ),

And the controller:

class BlogController extends Controller
{
    public function actionView($alias)
    {
        echo $alias;
    }
}

Solution 3

Read my article on how to handle that specific scenario (plus other things) with Wordpress: http://www.yiiframework.com/wiki/322/integrating-wordpress-and-yii-still-another-approach-using-yii-as-the-router-controller/

In essence, in order to handle a default like that (and hand it off to a different system), tr easiest way to do it is to override Yii's exception handling system, catch 404 errors and hand those to your blog controller.

If you send people to your blog controller by setting your controller action as an error handler, Yii sends a 404 error header (even if your properly handle the error). Yes, I've dug into this a lot. No, I don't believe there is a simpler answer :-). I'd love to know if you do find something simpler ...

Share:
11,515

Related videos on Youtube

Marian Zburlea
Author by

Marian Zburlea

I translate geek into English and my passion is to innovate and design for the future. Meet me live on WoW DoP or on YouTube

Updated on September 14, 2022

Comments

  • Marian Zburlea
    Marian Zburlea over 1 year

    pay attention to that ANYTHING_ELSE So, I have my controllers and actions that I want to behave as normal in response to examples like this:

    // for UserContoller with actionList and actionEdit
    user/list
    user/edit/25
    

    But for everything that doesn't fall under specific controllers and actions i want them to fall under one default controller and action like: BlogController and actionView. That is where ANYTHING_ELSE comes.

    // ANYTHING_ELSE can be:
    this-is-a-test-page
    this/is/another/page/with/lots/of/slashes
    this-has-extension.html
    
    
    'urlManager' => array(
      'urlFormat' => 'path',
      'showScriptName' => false,
      'rules' => array(
        '<controller:\w+>/<id:\d+>' => '<controller>/view',
        '<controller:\w+>/<action:\w+>/<id:\d+>' => '<controller>/<action>',
        '<controller:\w+>/<action:\w+>' => '<controller>/<action>',
        'ANYTHING_ELSE' => 'blog/view',
       ),
    ),