PHP中前端页面的URL路由模式

时间:2014-04-07 11:18:09

标签: php url-routing

我正在创建一个遵循MVC模式的MySQL数据库驱动的PHP(W)CMS应用程序。首先来看看框架: MVC框架处理请求并根据URL决定加载/调用的内容,例如:http://domain.com/user/details/121将加载并实例化User控制器对象,并使用用户标识调用其details(121)方法作为参数传递,然后实例化User_Model并使用121用户ID“询问”用户的详细数据,最后用View显示结果。这是MVC架构的基本概念。没什么特别的,此时一切都很清楚。

虽然这将是CMS,但我想处理Page模型。具有neseary权限的用户(主要是admin和/或root)可以在页面上执行基本的CRUD操作和其他内容,例如: 我可以使用:

创建一个页面
  • tile ='关于我们'(这将显示为页面的标题或浏览器标签的标题,例如:HTML标题和h1标签)
  • URL denomination ='* about_us *'(这将是URI端点,如:http://domain.com/about_us
  • 参考名称='我们是谁'(这是菜单栏中显示的文字)
  • page content =' lorem ipsum ... '(页面的实际内容......由WYSIWYG html文本编辑器提供)
  • 以及更多选项,例如构建页面,在父页面下分配子页面或创建页面开始页面(这意味着如果我将'关于我们'设置为起始页,那么{ {1}}将自动加载该页面内容)...

或者我可以修改这些属性,即使我可以删除页面......等等。


MVC框架在处理前端和后端调用之间没有区别。 例如,我们有一些要求:

  • http://domain.com
  • http://domain.com/user/details/121
  • http://domain.com/about_us

第一个将加载后端控制器,如前所述, 但其他人会加载一个前端内容。 当Bootstrap加载适当的控制器/操作时,我们会在上面的示例中查找实际的控制器文件:

  • http://domain.com/our_products/1255
  • /controllers/Users.php
  • /controllers/About_us.php

第一个可以加载因为这是之前编写的“静态”控制器,但是About_us和Our_products不是现有的控制器,所以如果无法加载控制器,则引导程序搜索数据库是否有一个页面包含相同的URL否定(如:about_us,our_products)。如果有,我们加载一个公共的FrontEndController并显示所请求的页面数据,如果没有,则显示404错误。

我这样做是因为我希望引导程序以相同的方式处理所有请求,但我不希望每个前端URL强制包含/controllers/Our_products.php(例如:FrontEndController}。所以这就是我将其隐藏起来的方式,因此URL可以保持更加用户友好。我的问题是:这是一个好习惯吗?或者还有其他正确的方法吗?

1 个答案:

答案 0 :(得分:0)

  

MVC框架处理请求并根据URL

决定加载/调用的内容

您通常拥有的是某种RouterDispatcher类。路由器将接受user/details/121,解析它并返回Route

$route = $router->route( $request->getUri() );

路由器可以保存配置值,例如URI中的允许空格字符,默认允许字符等。

您还可以向路由器添加自定义路由

$router->addRoutes($routes);

自定义路由可以是简单的关联数组

$routes['requested-uri'] = 'custom-route'

在上面的示例中,您说当他们访问网站的根目录时,您希望他们真正看到“关于我们”页面,以便可以这样做:

$router->addRoutes([
    '' => 'about-us
]);

当URI为''(空白)时的含义,然后转到'about-us'路线。它不应该进行重定向,只是透明地加载不同的路由,同时保持客户端Web浏览器中的URI不变。

路由显然可能更复杂,使用添加到路由集合的路由对象来获得更多高级控制的自定义路由。一些框架使用注释和各种不同的方式来实现灵活的路由。

然后,调度员可以接受从路由器返回的路由并发送它。这意味着验证请求的路由是否确实存在,即控制器文件是否存在以及控制器中所请求的方法是否存在。

$view = $dispatcher->dispatch($route);

Dispatcher::Dispatch()方法内:

// Check if the controller file exists.
// Instantiate the controller file, preferably using a controller factory.
// Check if the controller method exists.

// Call the controller method
call_user_func_array([$controller, $route->getMethod()], $route->getParams());

$view = $controller->getView();
$action = $route->getAction();

// Call the view method.
if( method_exists($view, $action) ) {
    $view->$action();
}

return $view;

我发现以下是一种非常容易理解的处理控制器方法/操作的方法。假设您有一个登录控制器,用户首先向其发送GET请求,并在表单中发送登录详细信息时向其发送POST请求。

public function getIndex() { }

public function postIndex() {
    $username = $this->request->post('username');
    $password = $this->request->post('password');
}

方法名称前面的获取帖子是请求类型,这可以防止您必须执行此类操作

public function index() {

    if( $this->request->getType() === 'POST' ) {
        $username = $this->request->post('username');
        $password = $this->request->post('password');
    }
}

它还可以让您更好地控制授权(如果您在路由层执行此操作),因为您可以轻松地允许用户向控制器发送GET请求,但拒绝他们访问发送POST请求。

每个控制器与视图具有一对一的关系。在构造中将视图注入控制器,最好使用控制器工厂。

发送GET请求http://domain.com/user/details/121时会发生什么情况,路由器会分解URI并将其转换为定位User控制器的路由,getDetails()方法带参数121,调度程序检查控制器和方法是否存在,然后调用提供用户ID作为参数的方法,控制器在视图中设置用户ID。以下是User控制器。

public function getDetails($userId) {
    $this->getView()->setUserId( (int)$userId );
}

然后视图有一个名为details()的方法。与控制器中调用的方法名称相同,前面没有请求类型。

然后,调度程序调用视图的details()方法,然后获取所需的数据。

设置页面标题在视图中完成,因为它仅用于演示目的。

与用户控制器相关的部分视图

public function details() {

    // Fetch the user by using the previously set user ID from the controller.
    // If he doesn't exist set an error template, set the response code to 404, 
    // or redirect. Do whatever you want really.

    $this->setTitle('User Details');

    // Build template objects, bind the fetched user data to main template.
}

如何实施setTitle方法以及所有相关内容取决于您。

视图将响应发送回客户端,无论是HTML内容,JSON,XML还是任何其他内容类型。

例如,您的应用程序允许您搜索用户并将其导出到Microsoft Excel工作簿文件(.xlsx)并提示用户下载。

视图将:

  • 获取用户
  • 生成文件
  • 设置HTTP响应标头,如Content-Type
  • 发送回复