跳转到内容

事件管理器


概览

此组件的目的是通过创建拦截点来截获框架中组件的执行。拦截点。这些拦截点允许开发人员获取状态信息、操作数据,或在组件执行过程中改变执行流程。该组件由一个Phalcon\Events\Manager管理事件传播和事件执行的Phalcon\Events\Event对象,其中包含每个拦截点/事件的信息。

<?php

use Phalcon\Events\Event;
use Phalcon\Events\Manager as EventsManager;
use Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter;

$eventsManager = new EventsManager();

$eventsManager->attach(
    'db:afterQuery',
    function (Event $event, $connection) {
        echo $connection->getSQLStatement();
    }
);

$connection = new DbAdapter(
    [
        'host'     => 'localhost',
        'username' => 'root',
        'password' => 'secret',
        'dbname'   => 'invo',
    ]
);

$connection->setEventsManager($eventsManager);
$connection->query(
    'SELECT * FROM products p WHERE p.status = 1'
);

命名约定

Phalcon 的事件使用命名空间以避免命名冲突。Phalcon 中的每个组件都占据不同的事件命名空间,您可以根据需要自由创建自己的命名空间。事件名称格式为component:event。例如,Phalcon\Db占据了db命名空间,其afterQuery事件全名为db:afterQuery.

在将事件监听器附加到事件管理器时,可以使用component来捕获来自该组件的所有事件(例如db来捕获所有Phalcon\Db事件),或者component:event来定位特定事件(例如db:afterQuery)。

管理器

The Phalcon\Events\Manager是一个负责处理 Phalcon 中所有事件的主要组件。其他框架中的不同实现可能将此组件称为处理器。不管名称如何,功能和目的都是相同的。

该组件使用SplPriorityQueue内部封装了一个对象队列。它以一定优先级(默认100)注册这些对象,然后在适当时机执行它们。

管理器暴露的方法包括:

public function attach(
    string $eventType, 
    mixed $handler, 
    int $priority = self::DEFAULT_PRIORITY
)
将监听器附加到事件管理器。其中handler是一个对象或callable.

public function arePrioritiesEnabled(): bool
返回优先级是否启用

public function collectResponses(bool $collect)
告知事件管理器是否需要收集所有已注册监听器在单次fire调用中返回的响应

public function detach(string $eventType, mixed $handler)
从事件管理器中分离监听器

public function detachAll(string $type = null)
从EventsManager中移除所有事件

public function enablePriorities(bool $enablePriorities)
设置事件管理器是否启用优先级(默认false)。

public function fire(string $eventType, mixed $source, mixed $data = null, bool $cancelable = true)
在事件管理器中触发事件,导致活跃的监听器接收到该通知

final public function fireQueue(SplPriorityQueue $queue, EventInterface $event): mixed
 ```
Internal handler to call a queue of events

```php
public function getListeners(string $type): array
返回所有特定类型已附加的监听器

public function getResponses(): array
返回最后一次fire执行

public function hasListeners(string $type): bool
检查某类事件是否有监听器

public function isCollecting(): bool
检查事件管理器是否正在收集所有已注册监听器在单次fire

public function isValidHandler(object | callable handler): bool
检查处理器是对象还是可调用函数

使用

如果你使用的是Phalcon\Di\FactoryDefaultDI 容器,即Phalcon\Events\Manager已经为您以名称eventsManager。这是一个全局事件管理器。不过,您并不局限于只使用这一个管理器。您可以始终创建一个单独的管理器来处理任意所需组件的事件。

下面的示例展示了如何使用全局事件管理器来创建查询日志机制:

<?php

use Phalcon\Di\FactoryDefault;
use Phalcon\Events\Event;
use Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter;

$container     = Di::getDefault();
$eventsManager = $container->get('eventsManager');

$eventsManager->attach(
    'db:afterQuery',
    function (Event $event, $connection) {
        echo $connection->getSQLStatement();
    }
);

$connection = new DbAdapter(
    [
        'host'     => 'localhost',
        'username' => 'root',
        'password' => 'secret',
        'dbname'   => 'invo',
    ]
);

$connection->setEventsManager($eventsManager);
$connection->query(
    'SELECT * FROM products p WHERE p.status = 1'
);

或者如果您想要一个独立的事件管理器:

<?php

use Phalcon\Events\Event;
use Phalcon\Events\Manager as EventsManager;
use Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter;

$eventsManager = new EventsManager();
$eventsManager->attach(
    'db:afterQuery',
    function (Event $event, $connection) {
        echo $connection->getSQLStatement();
    }
);

$connection = new DbAdapter(
    [
        'host'     => 'localhost',
        'username' => 'root',
        'password' => 'secret',
        'dbname'   => 'invo',
    ]
);

$connection->setEventsManager($eventsManager);
$connection->query(
    'SELECT * FROM products p WHERE p.status = 1'
);

在上面的例子中,我们使用事件管理器监听由afterQuery服务产生的db事件,在本例中为 MySQL。我们使用attach方法将我们的事件附加到管理器并监听db:afterQuery事件。我们添加了一个匿名函数作为该事件的处理程序,它接受一个Phalcon\Events\Event作为第一个参数。这个对象包含了该事件触发时的上下文信息。数据库连接对象作为第二个参数。通过连接变量我们可以打印出 SQL 语句。您还可以随时传递第三个参数,携带与事件相关的任意数据,甚至可以在匿名函数中传入一个日志记录器对象,以便将您的查询记录到单独的日志文件中。

注意

您必须使用setEventsManager()方法显式地将事件管理器设置给某个组件,这样该组件才能触发事件。您可以为每个组件创建一个新的事件管理器实例,也可以将同一个事件管理器设置给多个组件,因为命名约定会避免冲突。

处理程序

事件管理器将一个处理器绑定到一个事件。当事件触发时,处理器是一段用来执行某些操作的代码。如上例所示,您可以使用匿名函数作为您的处理器:

<?php

use Phalcon\Events\Event;
use Phalcon\Events\Manager as EventsManager;
use Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter;

$eventsManager = new EventsManager();
$eventsManager->attach(
    'db:afterQuery',
    function (Event $event, $connection) {
        echo $connection->getSQLStatement();
    }
);

$connection = new DbAdapter(
    [
        'host'     => 'localhost',
        'username' => 'root',
        'password' => 'secret',
        'dbname'   => 'invo',
    ]
);

$connection->setEventsManager($eventsManager);
$connection->query(
    'SELECT * FROM products p WHERE p.status = 1'
);

您还可以创建一个监听器类,这种形式提供了更多灵活性。在一个监听器中,您可以监听多个事件,甚至可以继承 [Phalcon\Di\Injectable][di-injectable],从而获得对 DI 容器中服务的完整访问权限。可以通过实现下面的监听器来增强上面的例子:

<?php

namespace MyApp\Listeners;

use Phalcon\Logger;
use Phalcon\Config;
use Phalcon\Db\AdapterInterface;
use Phalcon\Di\Injectable;
use Phalcon\Events\Event;

/**
 * Class QueryListener
 *
 * @property Config $config
 * @property Logger $logger
 */
class QueryListener extends Injectable
{
    public function beforeQuery(Event $event, AdapterInterface $connection)
    {
        if ($this->config->path('app.logLevel') > 1) {
            $this->logger->info(
                sprintf(
                    '%s - [%s]',
                    $connection->getSQLStatement(),
                    json_encode($connection->getSQLVariables())
                )
            );
        }
    }

    public function rollbackTransaction(Event $event)
    {
        if ($this->config->path('app.logLevel') > 1) {
            $this->logger->warning($event->getType());
        }
    }
}

将监听器附加到我们的事件管理器非常简单:

<?php

$eventsManager->attach(
    'db',
    new QueryListener()
);

最终的行为将是,如果app.logLevel配置变量被设为大于1(表示我们处于开发模式),则所有查询及其实际绑定参数都将被记录。此外,每次事务回滚时也将进行日志记录。

另一个有用的监听器是404监听器:

<?php

namespace MyApp\Listeners\Dispatcher;

use Phalcon\Logger;
use Phalcon\Di\Injectable;
use Phalcon\Events\Event;
use Phalcon\Mvc\Dispatcher;
use MyApp\Auth\Adapters\AbstractAdapter;

/**
 * Class NotFoundListener
 *
 * @property AbstractAdapter $auth
 * @property Logger          $logger
 */
class NotFoundListener extends Injectable
{
    public function beforeException(
        Event $event, 
        Dispatcher $dispatcher, 
        \Exception $ex
    ) {
        switch ($ex->getCode()) {
            case Dispatcher::EXCEPTION_HANDLER_NOT_FOUND:
            case Dispatcher::EXCEPTION_ACTION_NOT_FOUND:
                $dispatcher->setModuleName('main');
                $params = [
                    'namespace'  => 'MyApp\Controllers',
                    'controller' => 'session',
                    'action'     => 'fourohfour',
                ];

                /**
                 * 404 not logged in
                 */
                if (true !== $this->auth->isLoggedIn()) {
                    $params['action'] = 'login';
                }

                $dispatcher->forward($params);

                return false;
            default:
                $this->logger->error($ex->getMessage());
                $this->logger->error($ex->getTraceAsString());

                return false;
        }
    }
}

并将其附加到事件管理器:

<?php

$eventsManager->attach(
    'dispatch:beforeException',
    new NotFoundListener(),
    200
);

首先,我们将监听器附加到dispatcher组件和beforeException事件。这意味着事件管理器仅在该事件触发时调用我们的监听器。我们也可以将钩子点更改为dispatcher,以便将来可以在同一监听器中添加更多的调度器事件。

The beforeException函数接受$event作为第一个参数,$dispatcher作为第二个参数,$ex从调度器组件抛出的异常。利用这些信息,我们可以确定是否找不到处理器(或控制器)或动作。如果是这种情况,我们就将用户转发到特定的模块、控制器和动作。如果用户未登录,则发送他们到登录页面。或者,我们只是将异常信息记录到日志器中。

该示例清楚地展示了事件管理器的功能,以及如何使用监听器改变应用程序的流程。

事件:触发

您可以在应用程序中创建向事件管理器触发事件的组件。当事件被触发时,附加到这些事件的监听器将被调用。为了创建一个可以触发事件的组件,我们需要实现以下接口:Phalcon\Events\EventsAwareInterface.

自定义组件

考虑以下示例:

<?php

namespace MyApp\Components;

use Phalcon\Di\Injectable;
use Phalcon\Events\EventsAwareInterface;
use Phalcon\Events\ManagerInterface;

/**
 * @property ManagerInterface $eventsManager
 * @property Logger           $logger
 */
class NotificationsAware extends Injectable implements EventsAwareInterface
{
    protected $eventsManager;

    public function getEventsManager()
    {
        return $this->eventsManager;
    }

    public function setEventsManager(ManagerInterface $eventsManager)
    {
        $this->eventsManager = $eventsManager;
    }


    public function process()
    {
        $this->eventsManager->fire('notifications:beforeSend', $this);

        $this->logger->info('Processing.... ');

        $this->eventsManager->fire('notifications:afterSend', $this);
    }
}

上述组件实现了Phalcon\Events\EventsAwareInterface接口,并且因此使用了getEventsManagersetEventsManager。最后一个方法是执行工作的部分。在这个示例中,我们想向用户发送一些通知,并希望在通知发送前后触发事件。

我们选择将组件命名为notification,事件被命名为beforeSendafterSend。在process方法中,你可以在调用触发相关事件之间添加所需的任何代码。此外,你可以在此组件中注入更多有助于实现和处理通知的数据。

自定义监听器

现在我们需要为此组件创建一个监听器:

<?php

namespace MyApp\Listeners;

use Phalcon\Events\Event;
use Phalcon\Logger;

/**
 * @property Logger $logger
 */
class MotificationsListener
{
    /**
     * @var Logger
     */
    private $logger;

    public function __construct(Logger $logger)
    {
        $this->logger = $logger;
    }

    public function afterSend(
        Event $event, 
        NotificationsAware $component
    ) {
        $this->logger->info('After Notification');
    }

    public function beforeSend(
        Event $event, 
        NotificationsAware $component
    ) {
        $this->logger->info('Before Notification');
    }
}

将所有内容整合在一起

<?php

use MyApp\Components\NotificationAware;
use MyApp\Listeners\MotificationsListener;
use Phalcon\Events\Manager as EventsManager;

$eventsManager = new EventsManager();
$component     = new NotificationAware();

$component->setEventsManager($eventsManager);

$eventsManager->attach(
    'notifications',
    new NotificationsListener()
);

$component->process();

process被执行时,监听器中的两个方法将被执行。你的日志将包含以下条目:

[2019-12-25 01:02:03][INFO] Before Notification
[2019-12-25 01:02:03][INFO] Processing...
[2019-12-25 01:02:03][INFO] After Notification

自定义数据

在使用fire():

<?php

$data = [
    'name'     => 'Darth Vader',
    'password' => '12345',
];

$eventsManager->fire('notifications:afterSend', $this, $data);

在监听器中,第三个参数也会接收到数据:

<?php

use Phalcon\Events\Event;

$data = [
    'name'     => 'Darth Vader',
    'password' => '12345',
];

$eventsManager->attach(
    'notifications',
    function (Event $event, $component, $data) {
        print_r($data);
    }
);

$eventsManager->attach(
    'notifications',
    function (Event $event, $component) {
        print_r($event->getData());
    }
);

传播

一个事件管理器可以有多个附加到它的监听器。一旦事件触发,所有能接收到该特定事件的通知的监听器都会被通知到。这是默认行为,但在需要时可以通过提前停止传播来更改:

<?php

use Phalcon\Events\Event;

$eventsManager->attach(
    'db',
    function (Event $event, $connection) {
        if ('2019-01-01' < date('Y-m-d')) {
            $event->stop();
        }
    }
);

在上述简单示例中,如果今天早于2019-01-01.

取消

默认情况下,所有事件都可以取消。但是,您可能希望将某个特定事件设置为不可取消,使得该特定事件将在所有实现它的可用监听器上执行。

<?php

use Phalcon\Events\Event;

$eventsManager->attach(
    'db',
    function (Event $event, $connection) {
        if ($event->isCancelable()) {
            $event->stop();
        }
    }
);

在上面的例子中,如果事件是可以取消的,我们将停止传播。你可以通过使用使用fire():

<?php

$eventsManager->fire('notifications:afterSend', $this, $data, false);

The afterSend事件将不再可取消,并将在所有实现它的监听器上执行。

注意

您可以通过在事件中返回false来停止执行(但不是总是如此)。例如,如果您将事件附加到dispatch:beforeDispatchLoop并且您的监听器返回false分派过程将停止。只有当您只有一个监听器正在监听dispatch:beforeDispatchLoop事件并返回false的情况下才成立。如果有两个监听器附加到该事件,而执行的第二个监听器返回true那么进程将继续执行。如果您希望阻止后续事件触发,则必须在您的监听器中对Event对象发出stop() in your listener on the Event object.

优先级

添加监听器时,可以设置特定的优先级。在将监听器附加到事件管理器时设置优先级定义了它们被调用的顺序:

<?php

use Phalcon\Events\Manager as EventsManager;

$eventsManager = new EventsManager();

$eventsManager->enablePriorities(true);

$eventsManager->attach(
    'db', 
    new QueryListener(), 
    150
);
$eventsManager->attach(
    'db', 
    new QueryListener(), 
    100
);
$eventsManager->attach(
    'db', 
    new QueryListener(), 
    50
); 

注意

为了让优先级生效,enablePriorities()必须与true一起调用以启用它们。优先级默认是禁用的。

注意

高优先级数字意味着该监听器将在低优先级监听器之前被处理。

响应

事件管理器还可以收集每个事件返回的响应,并使用getResponses()方法将它们返回。该方法返回一个包含响应的数组:

<?php

use Phalcon\Events\Manager as EventsManager;

$eventsManager = new EventsManager();

$eventsManager->collectResponses(true);

$eventsManager->attach(
    'custom:custom',
    function () {
        return 'first response';
    }
);

$eventsManager->attach(
    'custom:custom',
    function () {
        return 'second response';
    }
);

$eventsManager->fire('custom:custom', $eventsManager, null);

print_r($eventsManager->getResponses());

上面的示例输出如下:

[
    0 => 'first response',
    1 => 'second response',
]

注意

为了让优先级生效,collectResponses()必须与true一起调用以启用收集。

异常

Paginator 组件中抛出的任何异常都将属于类型Phalcon\Events\Exception。你可以使用此异常选择性地捕获仅从此组件抛出的异常。

<?php

use Phalcon\Events\EventsManager;
use Phalcon\Events\Exception;

try {

    $eventsManager = new EventsManager();

    $eventsManager->attach('custom:custom', true);
} catch (Exception $ex) {
    echo $ex->getMessage();
}

控制器

控制器本身已经作为监听器注册在事件管理器中。因此,您只需要创建一个与已注册事件同名的方法,它就会被触发。

例如,如果我们想将未登录的用户引导至/login页面,我们可以在主控制器中添加以下代码:

<?php

namespace MyApp\Controller;

use Phalcon\Logger;
use Phalcon\Dispatcher;
use Phalcon\Http\Response;
use Phalcon\Mvc\Controller;
use MyApp\Auth\Adapters\AbstractAdapter;

/**
 * Class BaseController
 *
 * @property AbstractAdapter $auth
 * @property Logger          $logger
 * @property Response        $response
 */
class BaseController extends Controller
{
    public function beforeExecuteRoute(Dispatcher $dispatcher)
    {
        /**
         * Send them to the login page if no identity exists
         */
        if (true !== $this->auth->isLoggedIn()) {
            $this->response->redirect(
                '/login',
                true
            );

            return false;
        }

        return true;
    }
}
在路由器之前执行代码,以便我们可以确定用户是否已登录。如果没有,请将其转发到登录页面。

模型

类似于控制器,模型也已经作为监听器注册在事件管理器中。因此,您只需要创建一个与已注册事件同名的方法,它就会被触发。

在下面的示例中,我们使用beforeCreate事件来自动生成发票号码:

<?php

namespace MyApp\Models;

use Phalcon\Mvc\Model;

use function str_pad;

/**
 * Class Invoices
 *
 * @property string $inv_created_at
 * @property int    $inv_cst_id
 * @property int    $inv_id
 * @property string $inv_number
 * @property string $inv_title
 * @property float  $inv_total
 */
class Invoices extends Model
{
    /**
     * @var int
     */
    public $inv_cst_id;

    /**
     * @var string
     */
    public $inv_created_at;

    /**
     * @var int
     */
    public $inv_id;

    /**
     * @var string
     */
    public $inv_number;

    /**
     * @var string
     */
    public $inv_title;

    /**
     * @var float
     */
    public $inv_total;

    public function beforeCreate()
    {
        $date     = date('YmdHis');
        $customer = substr(
            str_pad(
                $this->inv_cst_id, 6, '0', STR_PAD_LEFT
            ),
            -6
        );

        $this->inv_number = 'INV-' . $customer . '-' . $date;
    }
}

自定义

The Phalcon\Events\ManagerInterface接口必须被实现,以创建自己的事件管理器替换Phalcon提供的事件管理器。

<?php

namespace MyApp\Events;

use Phalcon\Events\ManagerInterface;

class EventsManager implements ManagerInterface
{
    /**
     * @param string          $eventType
     * @param object|callable $handler
     */
    public function attach(string $eventType, $handler);

    /**
     * @param string          $eventType
     * @param object|callable $handler
     */
    public function detach(string $eventType, $handler);

    /**
     * @param string $type
     */
    public function detachAll(string $type = null);

    /**
     * @param string $eventType
     * @param object $source
     * @param mixed  $data
     * @param mixed  $cancelable
     * 
     * @return mixed
     */
    public function fire(
        string $eventType, 
        $source, 
        $data = null, 
        bool $cancelable = false
    );

    /**
     * @param string $type
     *
     * @return array
     */
    public function getListeners(string $type): array;

    /**
     * @param string $type
     *
     * @return bool
     */
    public function hasListeners(string $type): bool;
}

事件列表

Phalcon中可用的事件包括:

组件 事件 参数
ACL acl:afterCheckAccess Acl
ACL acl:beforeCheckAccess Acl
应用程序 application:afterHandleRequest 应用程序、控制器
应用程序 application:afterStartModule 应用程序、模块
应用程序 application:beforeHandleRequest 应用程序、调度器
应用程序 application:beforeSendResponse 应用程序、响应
应用程序 application:beforeStartModule 应用程序、模块
应用程序 application:boot 应用程序
应用程序 application:viewRender 应用程序、视图
缓存 cache:afterSet 缓存
缓存 cache:afterGet 缓存
缓存 cache:afterHas 缓存
缓存 cache:afterIncrement 缓存
缓存 cache:afterDecrement 缓存
缓存 cache:afterDelete 缓存
缓存 cache:beforeSet 缓存
缓存 cache:beforeGet 缓存
缓存 cache:beforeHas 缓存
缓存 cache:beforeIncrement 缓存
缓存 cache:beforeDecrement 缓存
缓存 cache:beforeDelete 缓存
CLI dispatch:beforeException 控制台、异常
控制台 console:afterHandleTask 控制台、任务
控制台 console:afterStartModule 控制台、模块
控制台 console:beforeHandleTask 控制台、调度器
控制台 console:beforeStartModule 控制台、模块
控制台 console:boot 控制台
数据库 db:afterQuery 数据库
数据库 db:beforeQuery 数据库
数据库 db:beginTransaction 数据库
数据库 db:createSavepoint 数据库、保存点名称
数据库 db:commitTransaction 数据库
数据库 db:releaseSavepoint 数据库、保存点名称
数据库 db:rollbackTransaction 数据库
数据库 db:rollbackSavepoint 数据库、保存点名称
分派器 dispatch:afterBinding 分派器
分派器 dispatch:afterCallAction 分派器
分派器 dispatch:afterDispatch 分派器
分派器 dispatch:afterDispatchLoop 分派器
分派器 dispatch:afterExecuteRoute 分派器
分派器 dispatch:afterInitialize 分派器
分派器 dispatch:beforeDispatch 分派器
分派器 dispatch:beforeCallAction 分派器
分派器 dispatch:beforeDispatchLoop 分派器
分派器 dispatch:beforeException 调度器、异常
分派器 dispatch:beforeExecuteRoute 分派器
分派器 dispatch:beforeForward 调度器、数组(MVC调度器)
分派器 dispatch:beforeNotFoundAction 分派器
加载器 loader:afterCheckClass 加载器、类名
加载器 loader:beforeCheckClass 加载器、类名
加载器 loader:beforeCheckPath 加载器
加载器 loader:pathFound 加载器、文件路径
微型 micro:afterBinding 微型
微型 micro:afterHandleRoute 微服务、混合返回值
微型 micro:afterExecuteRoute 微型
微型 micro:beforeException 微服务、异常
微型 micro:beforeExecuteRoute 微型
微型 micro:beforeHandleRoute 微型
微型 micro:beforeNotFound 微型
模型 model:afterCreate 模型
模型 model:afterDelete 模型
模型 model:afterFetch 模型
模型 model:afterSave 模型
模型 model:afterUpdate 模型
模型 model:afterValidation 模型
模型 model:afterValidationOnCreate 模型
模型 model:afterValidationOnUpdate 模型
模型 model:beforeDelete 模型
模型 model:beforeCreate 模型
模型 model:beforeSave 模型
模型 model:beforeUpdate 模型
模型 model:beforeValidation 模型
模型 model:beforeValidationOnCreate 模型
模型 model:beforeValidationOnUpdate 模型
模型 model:notDeleted 模型
模型 model:notSaved 模型
模型 model:onValidationFails 模型
模型 model:prepareSave 模型
模型 model:validation 模型
模型管理器 modelsManager:afterInitialize 管理器、模型
请求 request:afterAuthorizationResolve 请求、['server' => Server array]
请求 request:beforeAuthorizationResolve 请求、['headers' => [Headers], 'server' => [Server]]
响应 response:afterSendHeaders 响应
响应 response:beforeSendHeaders 响应
路由器 router:afterCheckRoutes 路由器
路由器 router:beforeCheckRoutes 路由器
路由器 router:beforeCheckRoute 路由器、路由
路由器 router:beforeMount 路由器、组
路由器 router:matchedRoute 路由器、路由
路由器 router:notMatchedRoute 路由器、路由
存储 storage:afterSet 存储
存储 storage:afterGet 存储
存储 storage:afterHas 存储
存储 storage:afterIncrement 存储
存储 storage:afterDecrement 存储
存储 storage:afterDelete 存储
存储 storage:beforeSet 存储
存储 storage:beforeGet 存储
存储 storage:beforeHas 存储
存储 storage:beforeIncrement 存储
存储 storage:beforeDecrement 存储
存储 storage:beforeDelete 存储
视图 view:afterCompile Volt
视图 view:afterRender 视图
视图 view:afterRenderView 视图
视图 view:beforeCompile Volt
视图 view:beforeRender 视图
视图 view:beforeRenderView 视图、视图引擎路径
视图 view:notFoundView 视图、视图引擎路径
Volt compileFilter Volt, [name, arguments, function arguments]
Volt compileFunction Volt, [name, arguments, function arguments]
Volt compileStatement Volt, [语句]
Volt resolveExpression Volt, [表达式]
无噪 Logo
无噪文档
25 年 6 月翻译
版本号 5.9
文档源↗