4.phpBB Extension Controllers and Routes
介绍
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对象。
依赖
现在让我们看看控制器的构造函数,然后再看看handle()方法中的实际控制器代码。
我们的控制器有几个依赖phpBB对象。 我们必须告诉phpBB关于我们的控制器,它的依赖是通过在我们的config / services.yml文件中定义一个服务,这是在“教程:事件和监听器”中介绍的。 完整的services.yml文件应如下所示:
警告
请记住,参数的顺序必须与构造函数方法定义中的参数顺序相匹配。
请求处理
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页眉和页脚:
注意
这个简单的模板文件可以存储在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文件应如下所示:
上面的路由定义说,当用户转到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文件中声明的顺序进行比较,这在定义路由时非常重要。 例如:
生成到路由的链接
现在我们可以从URL访问我们面向用户的页面,我们需要将该URL添加到我们之前使用模板侦听器创建的导航栏链接。
回想一下,我们的模板侦听器有一个U_DEMO_PAGE变量。 我们现在将重新访问我们的PHP事件侦听器并更新它,以生成一个路由的URL并将其分配给U_DEMO_PAGE。
首先我们将使用core.page_header事件。 当您生成phpBB页面的头部时,当您想要操作代码时,这是一个理想的事件。 我们必须在事件/ main_listener.php中更新getSubscribedEvents()方法,如下所示:
接下来,我们将为事件监听器添加一个新方法,该方法创建我们的链接并将其分配给我们的模板变量:
在这种新方法中,我们使用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对象。 因此,为了注入这些依赖关系,我们还必须向事件侦听器添加一个新的构造函数。 把所有东西放在一起,整个事件听众应该看起来像:
记住还要使用新的依赖关系更新config / services.yml中的事件侦听器的服务定义:
注意
每次更改* .yml文件中的某些内容时,请记住清除缓存。
现在,我们在导航栏中的链接应该打开一个新的面向用户的页面,它说“Hello world!”如果我们暂时用其他字符串替换“world”,例如“foo”,页面应该是“Hello foo!”。 如果我们使用“bertie”,那么我们应该显示一个403错误页面。
我们已经完成了面向用户的控制器页面。 继续阅读下一节,了解如何将ACP模块添加到扩展中,以便我们给出一些配置设置。