Skip to content

控制器基础#

从基本层面来看,控制器是当您访问XF中的页面时执行的代码。控制器通常负责处理用户输入并将该用户输入传递到适当的位置,通常是为了执行某种数据库操作(模型)或加载视觉内容(视图)。

当用户点击链接时,请求的URL会被路由到特定的控制器和控制器操作。请参见路由基础。例如,在XF中,如果您点击像index.php?conversations/add这样的URL,您将被路由到XF\Pub\Controller\Conversation控制器并执行add操作。

如果您在文件系统中查看此类(请参见自动加载器了解类和文件路径如何相互映射),您会注意到有许多以action为前缀的方法。所有这些方法都表示特定的控制器操作。因此,要查看上面提到的conversations/add页面时涉及的代码,请在此文件中查找public function actionAdd()

XF控制器负责返回一个回复对象,通常由以下类型之一组成:

视图回复#

这是您在XF开发过程中最常处理的回复之一。返回视图回复的控制器通常需要传入最多三个参数。一个视图类(稍后会详细介绍),一个模板名称,以及一个$viewParams数组,这是模板中可用的数据。

以下是一个典型的返回视图回复的控制器操作示例:

PHP
public function actionExample()
{
    $hello = 'Hello';
    $world = 'world!';

    $viewParams = [
        'hello' => $hello,
        'world' => $world
    ];
    return $this->view('Demo:Example', 'demo_example', $viewParams);
}

第一个参数是特定视图类的短类名。此类可能存在也可能不存在(通常不需要存在,稍后我们会详细介绍视图类),但它应该为控制器和操作提供一个大致唯一的名称。与其他短类名一样,上面的特定短类名将解析为Demo\Pub\View\Example。同样,Pub是从控制器类型自动推断的。

第二个参数是模板名称。在这种情况下,我们正在寻找名为demo_example的模板。

第三个参数是应可供视图使用的模板参数/变量的数组。此数组通常应为key => value对。上面的示例向模板传递了两个模板参数。数组的key部分表示模板中可用的变量名称。数组的value部分表示值。

因此,如果我们在demo_example模板中有以下内容:

HTML
{$hello} {$world}

模板将输出以下内容:

HTML
Hello world!

重定向回复#

当您希望用户在完成某种操作后重定向到不同的URL时,返回此回复。

这里的一个常见用例是,在用户通过表单提交数据后,您可能希望将他们重定向到不同的页面,例如将用户返回到项目列表。

以下是一个执行重定向的典型控制器操作示例:

PHP
public function actionRedirect()
{
    return $this->redirect($this->buildLink('demo/example'), 'This is a redirect message.', 'permanent');
}

第一个参数是要重定向到的URL。此示例将用户重定向到index.php?demo/example URL。

第二个参数仅在表单通过AJAX请求提交并选择阻止重定向时显示。结果将是从屏幕顶部出现的“闪存消息”,其中包含您选择的消息。您不必提供自己的消息。如果未提供,它将默认为“您的更改已保存”。

第三个参数默认为temporary,但您也可以选择将其设置为permanent,如示例所示。这里的唯一区别是服务器提供的HTTP响应代码类型。temporary在大多数情况下是理想的,这将响应303代码。permanent将发出301响应代码。

虽然您可以以这种方式触发永久重定向,但实际上有一个特定的方法可以用于此目的,如下所示。它还接受一个“消息”参数,但如上所述,它是可选的。

PHP
public function actionRedirect()
{
    return $this->redirectPermanently($this->buildLink('demo/example'));
}

错误回复#

顾名思义,此回复是您需要在向用户显示错误时返回的回复。它有点简单,以下是一个示例:

PHP
public function actionError()
{
    return $this->error('Unfortunately the thing you are looking for could not be found.', 404);
}

这里只支持两个参数。第一个是您要显示的错误消息,第二个是您希望服务器发送的HTTP响应代码。404表示未找到某些内容时的适当响应。

消息回复#

此回复与错误回复非常相似,并支持相同的参数。主要区别在于,在外观上,显示的消息不是作为错误呈现的。

异常回复#

有时需要中断控制器代码的正常流程,并返回异常。异常回复不一定代表错误;例如,它们可以用于强制控制器执行重定向。然而,通常情况下,它们通常用于停止控制器的流程以显示错误,如下例所示:

PHP
public function actionException()
{
    throw $this->exception($this->error('An unexpected error occurred'));
}

异常回复只接受一个参数,实际上该参数必须是其他形式的回复对象,例如错误回复。此特定示例抛出异常,此时整个控制器代码将停止,并显示标准错误。

请注意,异常回复必须使用throw抛出,而不是使用return返回。

重新路由回复#

在某些条件下,有必要将用户重新路由到同一控制器中的完全不同的控制器或操作,而无需执行完全重定向,无需更改用户登陆的URL,也无需复制目标操作的代码。

这看起来有点像这样:

PHP
public function actionReroute()
{
    return $this->rerouteController(__CLASS__, 'error');
}

public function actionError()
{
    return $this->error('Oops! Something went wrong!');
}

在此特定示例中,如果用户导航到index.php?demo/reroute URL,他们将看到来自actionError()方法的错误回复。他们不会被重定向,浏览器中的URL也不会改变;他们只会收到错误操作的回复。

重新路由回复还支持第三个参数,该参数允许将各种参数从一个控制器操作传递到另一个控制器操作。这可以是数组或ParameterBag对象(稍后会详细介绍)。

正确修改控制器操作回复#

扩展类部分,我们已经看到了扩展类是多么简单,但在扩展已经存在的控制器操作时需要格外小心。

除非您有特定的需要完全覆盖现有操作并用新的操作替换它(通常不推荐),否则您应该修改父类的现有回复。这很简单,例如让我们修改上面视图回复示例中的视图回复。

PHP
public function actionExample()
{
    $reply = parent::actionExample();

    return $reply;
}

假设上述内容添加到扩展控制器中,其中actionExample()方法已经存在,上面的代码实际上除了返回原始视图回复外什么也不做。现在让我们将现有的hello参数更改为显示“Bonjour”而不是“Hello”。

PHP
public function actionExample()
{
    $reply = parent::actionExample();

    if ($reply instanceof \XF\Mvc\Reply\View)
    {
        $reply->setParam('hello', 'Bonjour');
    }

    return $reply;
}

因为控制器回复实际上可以代表具有不同行为和方法的多个不同对象,所以我们必须确保仅尝试扩展正确的回复类型。我们在上面的示例中通过检查父$reply对象是否实际上是View类型来做到这一点。如果我们不这样做,我们扩展此操作并且控制器操作回复重定向,那么很可能会出现错误。

在扩展此操作之前,访问此页面将显示“Hello world!”。扩展后,视图现在将显示“Bonjour world!”。