1.2 菜单

hook_menu() 和它的回调函数发生了什么?

Drupal 8 里,hook_menu() 系统被拆分为几个 YAML 文件:

YAML 文件

描述

modulename.routing.yml

包含 URL 路径和回调函数的映射关系。

modulename.links.menu.yml

包含菜单项的结构。

modulename.links.action.yml

等效 Drupal 7 的常量 MENU_LOCAL_ACTION 。

modulename.links.task.yml

等效 Drupal 7 的常量 MENU_DEFAULT_LOCAL_TASK 。

Drupal 8 中我们使用 Symfony2 components 处理路径到控制器方法的路由,进行数据显示。

  1. 在同一个目录(page_example),创建 page_example.routing.yml 文件。
  2. 添加代码,见辅助内容区。

剖析下上面定义的路由 page_example_description :

  • page_example_description: 为 Page example 模块定义一个新路由。
  • path: 路由注册的路径,等价于 Drupal 7 中  hook_menu()$items[] 数组的 key。 需要以斜线开头,详细请查看文档 structure of routes 。
  • _controller: 定义路由的路径对应 PageExampleController 控制器的 description 方法。
    _content 变为 _controller 这个比较有趣,这使 Drupal 8 与 Symfony 更同步。
  • requirements:用户能够访问这个页面所具有的权限。

想使用额外的路由选项,请查看 Structure of routes 文档页。

page_example_description:
  path: '/examples/page_example'
  defaults:
    _controller: '\Drupal\page_example\Controller\PageExampleController::description'
  requirements:
    _access: 'TRUE'

page_example_simple:
  path: '/examples/page_example/simple'
  defaults:
    _controller: '\Drupal\page_example\Controller\PageExampleController::simple'
  requirements:
    _permission: 'access simple page'

 

构建控制器

Page example 的控制器叫 PageExampleController,里面有个 description() 方法,用户请求这个页面时会被调用。

注意:

在模块里,采用了部分 PSR-4 标准,控制器和其他类被要求放在 src/ 目录。 Drupal 的其他部分使用了较长的文件路径,使用的是PSR-0 标准。 如果你看到捐献模块的代码还放在 lib/ 目录,那是 PSR-0,之前的 Drupal 8 进化版本遗留下来的产物, 应该被移动到 src/ 目录。

  1. 在模块目录创建放置控制器的目录 src/Controller。
  2. 创建控制器文件 PageExampleController.php 。
  3. 在文件内声明 PageExampleController 控制器类,见辅助内容区

PageExampleController 类里有两个函数:

  • description() 函数: 返回一个类似 Drupal 7 的可渲染数组,这里用到了 URL::fromRoute 方法。
  • simple() 函数: 返回了一个 HTML 的标记。

出于实用性,这是我们要把文本显示在目标 URL 内所需要写的最少代码。
代码中的第 8 行定义了类的名字空间,名字空间允许在其他地方使用这个类。

<?php

/**
* @file
* Contains \Drupal\page_example\Controller\PageExampleController.
*/

namespace Drupal\page_example\Controller;

use Drupal\Core\Url;

/**
* Controller routines for page example routes.
*/
class PageExampleController {
  /**
   * Constructs a page with descriptive content.
   *
   * Our router maps this method to the path 'examples/page_example'.
   */
  public function description() {
    $simple_url = Url::fromRoute('page_example_simple');
    $simple_link = \Drupal::l(t('simple page'), $simple_url);

    $arguments_url = Url::fromRoute('page_example_description', [], ['absolute' => TRUE]);
    $arguments_link = \Drupal::l(t('arguments page'), $arguments_url);

    $build = [
      '#markup' => t(
        '<p>The Page example module provides two pages, "simple" and "arguments".</p>'
          . '<p>The !simple_link just returns a renderable array for display.</p>'
          . '<p>The !arguments_link takes two arguments and displays them, as in @arguments_url</p>',
        [
          '!simple_link' => $simple_link,
          '!arguments_link' => $arguments_link,
          '@arguments_url' => $arguments_url->toString()
        ]
      ),
    ];

    return $build;
  }

  /**
   * Constructs a simple page.
   *
   * The router _controller callback, maps the path 'examples/page_example/simple'
   * to this method.
   *
   * _controller callbacks return a renderable array for the content area of the
   * page. The theme system will later render and surround the content with the
   * appropriate blocks, navigation, and styling.
   */
  public function simple() {
    return [
      '#markup' => '<p>' . t('Simple page: The quick brown fox jumps over the lazy dog.') . '</p>',
    ];
  }

}

 

声明了名字空间后,我们便可以通过 use 操作符引入这些类,以便使用它们的方法。

PHP 中的名字空间

“尽管名字空间可以包含任何有效的 PHP 代码,但名字空间只会影响以下代码类型: 类(包括 abstracts 和 traits 类),接口,函数和常量。 名字空间使用 namespace 关键字进行声明。 包含名字空间的文件必须在文件的顶部、任何其他代码(declare 关键字除外)之前进行名字空间的声明。” Defining Namespaces

怎么知道名字空间和 use 操作符的路径?

其实,名字空间就是文件所在位置的路径,之后使用这个作为 use 操作符使用的别名。

类文件类似这样:

namespace Drupal\page_example\Controller;

另一个要使用它的文件这样:

use Drupal\page_example\Controller

之后你就可以使用 Controller 目录下的文件了。

使用 use 操作符

“使用别名引用外部的一个完全限定名是名字空间的重要特征。 这类似 unix 文件系统中为文件或目录创建符号链接一样。 PHP 中别名通过 use 操作符完成。” Using namespaces: Aliasing/Importing

菜单链接

Drupal 7 中使用 hook_menu() 构建菜单链接。现在不再这么处理了,而是通过 yml 文件配置。

构建链接

我们现在在 Drupal 管理界面的 Reports 菜单下创建一个菜单链接。
首先我们需要在模块的根目录下创建 page_example.links.menu.yml 文件,在里面定义菜单的链接和位置。

  1. 在模块目录创建 page_example.links.menu.yml
  2. 追加代码到文件内,见辅助内容区

首先我们定义了菜单链接的机器名,接下来是菜单的标题和菜单使用的路由(机器名),最后是菜单的 parent(决定菜单的位置)。

parent 的值是父菜单链接机器名,确定这个需要对 *.links.menu.yml 进行些调查。管理界面菜单定义在核心 System 模块内,因此需要查看 system.links.menu.yml 文件来确定这个值。

现在清空缓存,打开 http://example.com/admin/reports 页面,你会看到添加的链接。

page_example.description:
  title: 'Page Example'
  route_name: page_example_description
  parent: system.admin_reports
page_example.simple:
  title: 'Simple - no arguments'
  route_name: page_example_simple
  parent: system.admin_reports

 

清空缓存

如果要通过命令行重建 Drupal 8 站点、清空缓存,需要使用最新版本的 drush: drush rc

本书共39小节。


评论 (2)