4.phpBB Extension Controllers and Routes

行业资讯 admin 发布时间:2024-03-19 浏览:53 次

介绍

phpBB 3.1引入了Symfony的HttpKernel,控制器和路由系统,允许扩展来处理用户能够查看和交互的自定义“前端”页面。

本教程介绍如何创建面向用户的页面:

控制器:面向用户的文件

路由:面向用户面向文件的URL

控制器

控制器是一个类,其功能集合根据URL中请求的内容提供内容和处理来自用户的交互。例如,显示一个或多个博客条目的博客扩展。

目前,我们的Acme Demo扩展在导航栏中没有目标链接。我们将使用控制器创建用户将看到的页面,并使用路由来管理我们的控制器的URL。

控制器文件可以放置在扩展目录结构中的任何位置,尽管要将事物组织起来,最好将它们放在名为controller /的单独目录中。控制器文件也可以给出任何名称。对于Acme Demo扩展,我们将使用ext \ acme \ demo \ controller \ main.php。

每个控制器应至少包含两种方法:

一个public __construct()方法。如果您的控制器没有依赖关系,这是可选的。

一个public handle()方法。这个方法可以取任何名称,但是“句柄”是常见的。此方法必须返回Symfony Response对象。

<?php use \Symfony\Component\HttpFoundation\Response; namespace acme\demo\controller; class main { /* @var \phpbb\config\config */ protected $config; /* @var \phpbb\controller\helper */ protected $helper; /* @var \phpbb\language\language */ protected $language; /* @var \phpbb\template\template */ protected $template; /** * Constructor * * @param \phpbb\config\config $config * @param \phpbb\controller\helper $helper * @param \phpbb\language\language $language * @param \phpbb\template\template $template */ public function __construct(\phpbb\config\config $config, \phpbb\controller\helper $helper, \phpbb\language\language $language, \phpbb\template\template $template) { $this->config = $config; $this->helper = $helper; $this->language = $language; $this->template = $template; } /** * Demo controller for route /demo/{name} * * @param string $name * @throws \phpbb\exception\http_exception * @return \Symfony\Component\HttpFoundation\Response A Symfony Response object */ public function handle($name) { if ($name === bertie) { throw new \phpbb\exception\http_exception(403, NO_AUTH_SPEAKING, array($name)); } $l_message = !$this->config[acme_demo_goodbye] ? DEMO_HELLO : DEMO_GOODBYE; $this->template->assign_var(DEMO_MESSAGE, $this->language->lang($l_message, $name)); return $this->helper->render(demo_body.html, $name); } }

依赖

现在让我们看看控制器的构造函数,然后再看看handle()方法中的实际控制器代码。

我们的控制器有几个依赖phpBB对象。 我们必须告诉phpBB关于我们的控制器,它的依赖是通过在我们的config / services.yml文件中定义一个服务,这是在“教程:事件和监听器”中介绍的。 完整的services.yml文件应如下所示:

services:acme.demo.controller:class:acme\demo\controller\mainarguments:- @config- @controller.helper- @language- @templateacme.demo.listener:class:acme\demo\event\main_listenertags:- {name:event.listener }

警告

请记住,参数的顺序必须与构造函数方法定义中的参数顺序相匹配。

请求处理

handle()方法负责处理显示页面的请求。注意它接受参数$ name。这是一个从URL参数传入的变量,如路由配置文件中定义的。

句柄方法有一个特殊的条件,用于检查用户是否尝试使用bertie。我们不想授权这个,因为人们不应该与Bertie互动。所以我们抛出一个带有403错误代码的http_exception,这将向用户显示一个不错的“未授权”错误消息。

使用有效的名称,handle方法将创建一个简单的消息,向用户显示并将其分配给控制器的模板变量数组。

然后我们使用phpbb \ controller \ helper Helper对象来渲染我们的render()方法的页面。它将模板文件名,页面标题和状态代码作为参数。页面标题默认为空字符串,状态代码默认为200.我们正在使用Controller模板demo_body.html。

注意

phpbb \ controller \ helper:render()方法为我们返回一个Symfony Response对象。 如果您选择不使用Helper对象,则需要手动返回Symfony Response对象。 Reponse对象有两个参数:

响应消息 - 这应该是将在屏幕上输出的完整的,呈现的页面源。

状态码 - 默认为200,状态码为“OK”。 如果您发送的响应无法找到某些信息,您将使用404(“未找到”)状态。 如果用户缺少适当的权限,将使用403,而500将是未知错误。

return new \Symfony\Component\HttpFoundation\Response($template_file, 200);

警告

控制器不应该调用trigger_error()来生成输出。 相反,它应该总是返回Symfony Response或JsonResponse对象,或者抛出一个phpBB http_exception。

控制器模板

每个控制器都需要一个HTML模板文件。 Acme Demo扩展使用位于styles / prosilver / template /目录中的demo_body.html,其中包含以下内容,包括phpBB页眉和页脚:

<!-- INCLUDE overall_header.html --> <h2>{DEMO_MESSAGE}</h2> <!-- INCLUDE overall_footer.html -->

注意

这个简单的模板文件可以存储在all/style文件夹中,因为它显然没有特定于prosilver风格的HTML标记。

路由

在这一点上,我们现在有一个控制器可以创建和提供面向用户的页面,但是我们还没有一个访问该页面的URL。

为了解决这个问题,每个控制器必须在扩展的config / routing.yml文件中定义一个路由。 该文件负责将控制器的访问名称(即URL中的内容)与其服务(即我们在依赖关系中涵盖的内容)相关联。

回想一下,我们的控制器期望一个URL参数作为$ name变量传递给它。 因此,我们希望我们的URL看起来像:/app.php/demo/ <name>。

注意

所有扩展控制器文件都可以通过app.php访问。 但是,主板可以打开ACP中的启用URL重写功能,以隐藏URL的app.php /组件。

我们的routing.yml文件应如下所示:

acme_demo_route:path:/demo/{name}defaults:{_controller: acme.demo.controller:handle, name:"world"}

上面的路由定义说,当用户转到URL /app.php/demo/ <name>时,它应该加载acme.demo.controller服务并调用handle方法,给出{name}“slug” 到$ name参数(slug和参数的名称必须匹配)。 如果{name}没有值(即URL是/app.php/demo),那么它将默认值“world”传递给handle方法。

您可以看到,slugs提供了一种强大的方法来通过URL参数与控制器进行交互。 您必须为方法中的每个必需参数指定一个小数块。 Routing定义中不必提供可选参数,在这种情况下,它们将取代方法定义中给出的默认值。

您还可以指定slugs的正则表达式,以更严格地控制传递给该方法的数据类型。 例如,如果我们要确保该名称是一个整数,我们将附加以下代码到我们的路由定义:

requirements:

name: \d+

项目 描述

路由 路由名称是唯一的名称,必须以供应商和扩展名为前缀。 只能使用小写字母和下划线。

路径 URL组件的路径,包括以大括号括起来的slug。 如果路径与任何路由不匹配,则返回404错误。

defaults 控制器的服务名称和调用方法的名称,以冒号分隔。 可选地,可以定义s条的默认值。

要求 用于使特定路线仅在特定条件下匹配。

route.yml可以为多个URL保存多个路由定义,根据扩展的需要可能需要。 路由按照它们在routing.yml文件中声明的顺序进行比较,这在定义路由时非常重要。 例如:

acme_blog_home:path:/blogdefaults:{_controller:acme.blog.controller:handle }acme_blog_entry:path:/blog/{id}defaults:{_controller:acme.blog.controller:handle }requirements:id:\d+acme_blog_edit:path:/blog/{id}/editdefaults:{_controller:acme.blog.controller:handle }requirements:id:\d+

生成到路由的链接

现在我们可以从URL访问我们面向用户的页面,我们需要将该URL添加到我们之前使用模板侦听器创建的导航栏链接。

回想一下,我们的模板侦听器有一个U_DEMO_PAGE变量。 我们现在将重新访问我们的PHP事件侦听器并更新它,以生成一个路由的URL并将其分配给U_DEMO_PAGE。

首先我们将使用core.page_header事件。 当您生成phpBB页面的头部时,当您想要操作代码时,这是一个理想的事件。 我们必须在事件/ main_listener.php中更新getSubscribedEvents()方法,如下所示:

static public function getSubscribedEvents() { return array( core.user_setup => load_language_on_setup, core.page_header => add_page_header_link, ); }

接下来,我们将为事件监听器添加一个新方法,该方法创建我们的链接并将其分配给我们的模板变量:

/** * Add a page header nav bar link * * @param \phpbb\event\data $event The event object */ public function add_page_header_link($event) { $this->template->assign_vars(array( U_DEMO_PAGE => $this->helper->route(acme_demo_route, array(name => world)), )); }

在这种新方法中,我们使用Controller Helper对象的route()方法创建到我们的控制器的链接。 请注意,它需要两个参数:

路由的名称,如route.yml中定义的。 在这种情况下,acme_demo_route。

可选的参数数组。 在这种情况下,我们将value world传递给name参数作为默认值。

注意

生成的网址将看起来像./app.php/demo/world这样相当于./app.php/demo?name=world。

请注意,我们的新方法add_page_header_link()需要来自phpBB的Controller Helper和Template对象。 因此,为了注入这些依赖关系,我们还必须向事件侦听器添加一个新的构造函数。 把所有东西放在一起,整个事件听众应该看起来像:

namespace acme\demo\event; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class main_listener implements EventSubscriberInterface { /* @var \phpbb\controller\helper */ protected $helper; /* @var \phpbb\template\template */ protected $template; /** * Constructor * * @param \phpbb\controller\helper $helper * @param \phpbb\template\template $template */ public function __construct(\phpbb\controller\helper $helper, \phpbb\template\template $template) { $this->helper = $helper; $this->template = $template; } /** * Load the Acme Demo language file * acme/demo/language/en/demo.php * * @param \phpbb\event\data $event The event object */ public function load_language_on_setup($event) { $lang_set_ext = $event[lang_set_ext]; $lang_set_ext[] = array( ext_name => acme/demo, lang_set => demo, ); $event[lang_set_ext] = $lang_set_ext; } /** * Add a page header nav bar link * * @param \phpbb\event\data $event The event object */ public function add_page_header_link($event) { $this->template->assign_vars(array( U_DEMO_PAGE => $this->helper->route(acme_demo_route, array(name => world)), )); } }

记住还要使用新的依赖关系更新config / services.yml中的事件侦听器的服务定义:

acme.demo.listener:class:acme\demo\event\main_listenerarguments:- @controller.helper- @templatetags:- {name:event.listener }

注意

每次更改* .yml文件中的某些内容时,请记住清除缓存。

现在,我们在导航栏中的链接应该打开一个新的面向用户的页面,它说“Hello world!”如果我们暂时用其他字符串替换“world”,例如“foo”,页面应该是“Hello foo!”。 如果我们使用“bertie”,那么我们应该显示一个403错误页面。

我们已经完成了面向用户的控制器页面。 继续阅读下一节,了解如何将ACP模块添加到扩展中,以便我们给出一些配置设置。

在线咨询

点击这里给我发消息售前咨询专员

点击这里给我发消息售后服务专员

在线咨询

免费通话

24h咨询:400-888-8888


如您有问题,可以咨询我们的24H咨询电话!

免费通话

微信扫一扫

微信联系
返回顶部