Foreword
I read a technical article about Zend Framework2 "ZF2 Multi-level Tree Routing Route Configuration Example", which introduces routing configuration. I find it very interesting, this is the demand:
/user corresponding user list page
/user/:user_id corresponds to the user's personal homepage. For example, /user/AlloVince corresponds to the AlloVince user's personal homepage
/user/:user_id/blog/ corresponds to the user’s blog list page, for example, /user/AlloVince/blog will list the blogs written by AlloVince
/user/:user_id/blog/:blog_id corresponds to a blog post of the user
The plan is quoted from the original text:
'router' => array( 'routes' => array( 'user' => array( 'type' => 'Segment', 'options' => array( 'route' => '/user[/]', 'defaults' => array( 'controller' => 'UserController', 'action' => 'index', ), ), 'may_terminate' => true, 'child_routes' => array( 'profile' => array( 'type' => 'Segment', 'options' => array( 'route' => '[:id][/]', 'constraints' => array( 'id' => '[a-zA-Z0-9_-]+' ), 'defaults' => array( 'action' => 'get' ), ), 'may_terminate' => true, 'child_routes' => array( 'blog' => array( 'type' => 'Segment', 'options' => array( 'route' => 'blog[/]', 'constraints' => array( ), 'defaults' => array( 'action' => 'blog' ) ), 'may_terminate' => true, 'child_routes' => array( 'post' => array( 'type' => 'Segment', 'options' => array( 'route' => '[:post_id][/]', 'constraints' => array( 'post_id' => '[a-zA-Z0-9_-]+' ), 'defaults' => array( 'action' => 'post' ) ), 'may_terminate' => true, ), ), ), ), //profile child_routes end ), //profile end ), //user child_routes end ), //user end ), ),
After reading this article, I plan to use the PHP framework I have used to implement this routing requirement.
ThinkPHP
Create a new ThinkPHP project:
Copy code The code is as follows:
composer create-project topthink/thinkphp tp --prefer-dist
The command line shows that I installed 3.2.2
Installing topthink/thinkphp (3.2.2)
I see that the latest stable version on the ThinkPHP official website is 3.2.3.
I went to the official packagist website to check and found that the stable version in the library is indeed 3.2.2.
I have to use 3.2.3. Why am I so obsessed with this? Because:
The routing function of 3.2 is set for modules, so the module name in the URL cannot be routed, and the routing definition is usually placed in the module configuration file. Version 3.2.3 has added global route definition support, and routes can be defined in the project's public configuration file.
In other words, the routing rewritten part is the Controller and Action parts, and Moudle still exists.
I want /user, not home/user. (The default Module in ThinkPHP is Home, 'DEFAULT_MODULE' => 'Home', which can be modified)
Of course, this problem can also be solved by modifying the .htaccess file. However, I decided to install 3.2.3.
Download the latest package from the ThinkPHP official website and unzip it.
Use a browser to access the entry file of the project and let ThinkPHP automatically generate a default application module Home.
Modify the public configuration file tpApplicationCommonConfconfig.php:
<?php return array( // 开启路由 'URL_ROUTER_ON' => true, // URL访问模式,可选参数0、1、2、3,代表以下四种模式: // 0 (普通模式); 1 (PATHINFO 模式); 2 (REWRITE 模式); 3 (兼容模式) 默认为PATHINFO 模式 'URL_MODEL' => 2, // URL伪静态后缀设置,为空表示可以支持所有的静态后缀 // 使用U函数生成URL时会不带后缀 'URL_HTML_SUFFIX' => '', // URL变量绑定到Action方法参数,默认为true 'URL_PARAMS_BIND' => true, // URL变量绑定的类型 0 按变量名绑定 1 按变量顺序绑定,默认为0 'URL_PARAMS_BIND_TYPE' => 0, // 路由配置 'URL_ROUTE_RULES' => array( '/^url$/' => 'Home/User/url', '/^user$/' => 'Home/User/index', '/^user\/([a-zA-Z0-9_-]+)$/' => 'Home/User/show?name=:1', '/^user\/([a-zA-Z0-9_-]+)\/blog$/' => 'Home/Blog/index?name=:1', '/^user\/([a-zA-Z0-9_-]+)\/blog\/([0-9]+)$/' => 'Home/Blog/show?name=:1&blog_id=:2', ), ); ?>
Create file tpApplicationHomeControllerUserController.class.php:
<?php namespace Home\Controller; use Think\Controller; class UserController extends Controller { public function url() { $name = 'jing'; $blogId = 1; $urls = array( U('/user'), U("/user/{$name}"), U("/user/{$name}/blog"), U("/user/{$name}/blog/{$blogId}"), ); foreach ($urls as $url) { echo "<a href=\"{$url}\">{$url}<a/><br />\n"; } } public function index() { echo '我是用户列表^_^'; } public function show($name) { echo "欢迎你,{$name}"; } } ?>
Create file tpApplicationHomeControllerBlogController.class.php:
<?php namespace Home\Controller; use Think\Controller; class BlogController extends Controller { public function index($name) { echo "这是{$name}的博客列表"; } public function show($blog_id, $name) { echo "{$name}的这篇博客的id为{$blog_id}"; } } ?>
Visit: http://127.0.0.1/tp/url
Output:
Copy code The code is as follows:
//m.sbmmt.com/tp/user
//m.sbmmt.com/tp/user/jing
//m.sbmmt.com/tp/user/jing/blog
//m.sbmmt.com/tp/user/jing/blog/1
Visit the above 4 links and return in order:
I am a user list^_^
Welcome, jing
This is jing’s blog list
The ID of this blog by jing is 1
Other frameworks below also output the above content.
Zend Framework 2
Create a ZF2 project using the ZF2 skeleton program:
composer create-project --stability="dev" zendframework/skeleton-application zf2
Modify the configuration file zf2moduleApplicationconfigmodule.config.php of the default module Application:
<?php /** * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/ZendSkeletonApplication for the canonical source repository * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ return array( 'router' => array( 'routes' => array( 'home' => array( 'type' => 'Zend\Mvc\Router\Http\Literal', 'options' => array( 'route' => '/url', 'defaults' => array( 'controller' => 'Application\Controller\User', 'action' => 'url', ), ), ), // The following is a route to simplify getting started creating // new controllers and actions without needing to create a new // module. Simply drop new controllers in, and you can access them // using the path /application/:controller/:action 'application' => array( 'type' => 'Literal', 'options' => array( 'route' => '/application', 'defaults' => array( '__NAMESPACE__' => 'Application\Controller', 'controller' => 'Index', 'action' => 'index', ), ), 'may_terminate' => true, 'child_routes' => array( 'default' => array( 'type' => 'Segment', 'options' => array( 'route' => '/[:controller[/:action]]', 'constraints' => array( 'controller' => '[a-zA-Z][a-zA-Z0-9_-]*', 'action' => '[a-zA-Z][a-zA-Z0-9_-]*', ), 'defaults' => array( ), ), ), ), ), 'user_list' => array( 'type' => 'Segment', 'options' => array( 'route' => '/user[/]', 'defaults' => array( '__NAMESPACE__' => 'Application\Controller', 'controller' => 'User', 'action' => 'index', ), ), 'may_terminate' => true, 'child_routes' => array( 'user' => array( 'type' => 'Segment', 'options' => array( 'route' => '[:name][/]', 'constraints' => array( 'name' => '[a-zA-Z0-9_-]+', ), 'defaults' => array( 'action' => 'show', ), ), 'may_terminate' => true, 'child_routes' => array( 'blog_list' => array( 'type' => 'Segment', 'options' => array( 'route' => 'blog[/]', 'constraints' => array( ), 'defaults' => array( 'controller' => 'Blog', 'action' => 'index', ) ), 'may_terminate' => true, 'child_routes' => array( 'blog' => array( 'type' => 'Segment', 'options' => array( 'route' => '[:blog_id]', 'constraints' => array( 'blog_id' => '[0-9]+', ), 'defaults' => array( 'action' => 'show', ) ), 'may_terminate' => true, ), ), ), ), ), ), ), ), ), 'service_manager' => array( 'abstract_factories' => array( 'Zend\Cache\Service\StorageCacheAbstractServiceFactory', 'Zend\Log\LoggerAbstractServiceFactory', ), 'aliases' => array( 'translator' => 'MvcTranslator', ), ), 'translator' => array( 'locale' => 'en_US', 'translation_file_patterns' => array( array( 'type' => 'gettext', 'base_dir' => __DIR__ . '/../language', 'pattern' => '%s.mo', ), ), ), 'controllers' => array( 'invokables' => array( 'Application\Controller\Index' => 'Application\Controller\IndexController', 'Application\Controller\User' => 'Application\Controller\UserController', 'Application\Controller\Blog' => 'Application\Controller\BlogController', ), ), 'view_manager' => array( 'display_not_found_reason' => true, 'display_exceptions' => true, 'doctype' => 'HTML5', 'not_found_template' => 'error/404', 'exception_template' => 'error/index', 'template_map' => array( 'layout/layout' => __DIR__ . '/../view/layout/layout.phtml', 'application/index/index' => __DIR__ . '/../view/application/index/index.phtml', 'error/404' => __DIR__ . '/../view/error/404.phtml', 'error/index' => __DIR__ . '/../view/error/index.phtml', ), 'template_path_stack' => array( __DIR__ . '/../view', ), ), // Placeholder for console routes 'console' => array( 'router' => array( 'routes' => array( ), ), ), ); ?>
This file comes with the skeleton program. I just modified the router part and the controllers part. It would be too difficult for me to write such a long document. This is also the reason why ZF officially released a skeleton program.
Create file zf2moduleApplicationsrcApplicationControllerUserController.php:
<?php namespace Application\Controller; use Zend\Mvc\Controller\AbstractActionController; use Zend\View\Model\ViewModel; class UserController extends AbstractActionController { public function urlAction() { $name = 'jing'; $blogId = 1; $urls = array( $this->url()->fromRoute('user_list'), $this->url()->fromRoute('user_list/user', array('name' => $name)), $this->url()->fromRoute('user_list/user/blog_list', array('name' => $name)), $this->url()->fromRoute('user_list/user/blog_list/blog', array('name' => $name, 'blog_id' => $blogId)), ); $view = new ViewModel(compact('urls')); $view->setTerminal(true); return $view; } public function indexAction() { $view = new ViewModel(); // 禁用布局模板 $view->setTerminal(true); return $view; } public function showAction() { $username = $this->params()->fromRoute('name'); $view = new ViewModel(compact('username')); $view->setTerminal(true); return $view; } } ?>
Create the file zf2moduleApplicationsrcApplicationControllerBlogController.php:
<?php namespace Application\Controller; use Zend\Mvc\Controller\AbstractActionController; use Zend\View\Model\ViewModel; class BlogController extends AbstractActionController { public function indexAction() { $username = $this->params()->fromRoute('name'); $view = new ViewModel(compact('username')); $view->setTerminal(true); return $view; } public function showAction() { $username = $this->params()->fromRoute('name'); $blogId = $this->params()->fromRoute('blog_id'); $view = new ViewModel(compact('username', 'blogId')); $view->setTerminal(true); return $view; } } ?>
zf2 does not support Action parameter binding. ThinkPHP not only supports binding, but also supports 2 binding methods: binding by variable name and binding by variable order.
Action in zf2 must return the view unless exit(). If you know of a way to disable the view, please let me know.
Create the file zf2moduleApplicationviewapplicationuserurl.phtml:
<?php foreach ($urls as $url): ?> <a href="<?php echo $url;?>"><?php echo $url;?><a/><br /> <?php endforeach; ?>
Create the file zf2moduleApplicationviewapplicationuserindex.phtml:
I am a user list^_^
Create the file zf2moduleApplicationviewapplicationusershow.phtml:
Welcome,
Create the file zf2moduleApplicationviewapplicationblogindex.phtml:
This is the blog list of
Create the file zf2moduleApplicationviewapplicationblogshow.phtml:
Copy code The code is as follows:
The ID of this blog is
Yaf
Install Yaf
Create a Yaf project using code generation tools
Modify the startup file yafapplicationBootstrap.php and modify the _initRoute method:
$router = Yaf_Dispatcher::getInstance()->getRouter(); $route0 = new Yaf_Route_Rewrite('url', array( 'controller' => 'User', 'action' => 'url', ), array() ); $route1 = new Yaf_Route_Rewrite('user', array( 'controller' => 'User', 'action' => 'index', ), array() ); $route2 = new Yaf_Route_Regex('#user/([a-zA-Z0-9_-]+)#', array( 'controller' => 'User', 'action' => 'show', ), array(1 => 'name',) ); $route3 = new Yaf_Route_Regex('#user/([a-zA-Z0-9_-]+)/blog#', array( 'controller' => 'Blog', 'action' => 'index', ), array(1 => 'name',) ); $route4 = new Yaf_Route_Regex('#user/([a-zA-Z0-9_-]+)/blog/([0-9]+)#', array( 'controller' => 'Blog', 'action' => 'show', ), array(1 => 'name', 2 => 'blogId',) ); $router->addRoute('url', $route0); $router->addRoute('user_list', $route1); $router->addRoute('user', $route2); $router->addRoute("blog_list", $route3); $router->addRoute("blog", $route4);
Yaf有路由功能,但是没有根据路由名生成URL的方法。所以我定义了一个项目名,用于拼接URL。
在配置文件中添加配置项yaf\conf\application.ini:
复制代码 代码如下:
project.name = 'yaf'
创建文件yaf\application\controllers\User.php:
<?php class UserController extends Yaf_Controller_Abstract { public function urlAction() { $name = 'jing'; $blogId = 1; $app = Yaf_Application::app(); $projectName = $app->getConfig()->project->name; $urls = array( "/{$projectName}/user", "/{$projectName}/user/{$name}", "/{$projectName}/user/{$name}/blog", "/{$projectName}/user/{$name}/blog/{$blogId}", ); foreach ($urls as $url) { echo "<a href=\"{$url}\">{$url}<a/><br />\n"; } return false; } public function indexAction() { echo '我是用户列表^_^'; // 禁用视图模板 return false; } public function showAction($name) { echo "欢迎你,{$name}"; return false; } }
创建文件yaf\application\controllers\Blog.php:
复制代码 代码如下:
<?php
class BlogController extends Yaf_Controller_Abstract {
public function indexAction($name) {
echo "这是{$name}的博客列表";
return false;
}
public function showAction($blogId, $name) {
echo "{$name}的这篇博客的id为{$blogId}";
return false;
}
}
Yaf的Action支持参数绑定,是按变量名绑定的。$name、$blogId要和路由中配置的名称一样,而和参数顺序无关。
Laravel
新建Laravel项目:
复制代码 代码如下:
composer create-project laravel/laravel --prefer-dist
清除合并文件。在目录laravel\vendor\下有个文件compiled.php,这个文件是为了减少IO提高框架性能,将很多类文件合并到一个文件中而生存的。在开发环境下,应该删除该文件,否则修改了一些文件发现没有效果,其实是因为文件已经合并缓存了。
清除命令:
复制代码 代码如下:
php artisan clear-compiled
在生产环境中应该开启,以提升性能:
复制代码 代码如下:
php artisan optimize --force
修改路由文件laravel\app\Http\routes.php:
复制代码 代码如下:
<?php
Route::get('/url', array('uses' => 'UserController@getUrl'));
Route::get('/user', array('uses' => 'UserController@getIndex'));
Route::get('/user/{username}', array('uses' => 'UserController@getShow'));
Route::get('/user/{username}/blog', array(
'as' => 'blog_list',
'uses' => 'BlogController@getIndex',
));
Route::get('/user/{username}/blog/{blogId}', array(
'as' => 'blog',
'uses' => 'BlogController@getShow',
))->where(array('blogId' => '[0-9]+'));
查看路由定义情况:
复制代码 代码如下:
php artisan route:list
输出:
复制代码 代码如下:
-------- ---------- ------------------------------- ----------- ---------------------------------------------- ------------
| Domain | Method | URI | Name | Action | Middleware |
-------- ---------- ------------------------------- ----------- ---------------------------------------------- ------------
| | GET|HEAD | url | | AppHttpControllersUserController@getUrl | |
| | GET|HEAD | user | | AppHttpControllersUserController@getIndex | |
| | GET|HEAD | user/{username} | | AppHttpControllersUserController@getShow | |
| | GET|HEAD | user/{username}/blog | blog_list | AppHttpControllersBlogController@getIndex | |
| | GET|HEAD | user/{username}/blog/{blogId} | blog | AppHttpControllersBlogController@getShow | |
-------- ---------- ------------------------------- ----------- ---------------------------------------------- ------------
定义路由变量全局模式,修改文件laravelappProvidersRouteServiceProvider.php中的boot方法:
复制代码 代码如下:
public function boot(Router $router) {
$router->pattern('username', '[a-zA-Z0-9_-] ');
parent::boot($router);
}
创建UserController控制器:
复制代码 代码如下:
php artisan make:controller UserController
Laravel帮我们在laravelappHttpControllers目录下创建了文件UserController.php,文件中已经为我们写好一部分骨架代码。修改文件laravelappHttpControllersUserController.php:
Copy code The code is as follows:
namespace AppHttpControllers;
use AppHttpControllersController;
class UserController extends Controller {
Public function getUrl() {
$name = 'jing';
$blogId = 1;
$urls = array(
url('/user'),
action('UserController@getShow', array($name)),
route('blog_list', array($name)),
route('blog', array($name, $blogId)),
);
foreach ($urls as $url) {
echo "{$url}
n";
}
}
Public function getIndex() {
echo 'I am a user list^_^';
}
Public function getShow($name) {
echo "Welcome, {$name}";
}
}
Create BlogController:
Copy code The code is as follows:
php artisan make:controller BlogController
Modify the file laravelappHttpControllersBlogController.php:
Copy code The code is as follows:
namespace AppHttpControllers;
use AppHttpControllersController;
class BlogController extends Controller {
Public function getIndex($name) {
echo "This is {$name}'s blog list";
}
Public function getShow($name, $blogId) {
echo "The id of {$name}'s blog is {$blogId}";
}
}
Laravel's Action also supports parameter binding, which is bound in variable order, regardless of variable name.
Postscript
I am a Laravel fan, but I have no intention of hacking other frameworks. If you are interested, you can use your own familiar framework to implement this small example. Remember to @me if you write it. There is no language limit.
The above is the entire content of this article, I hope you all like it.
Please take a moment to share the article with your friends or leave a comment. We will sincerely thank you for your support!