1

创建第一个 Symfony 页面

创建一个新的页面,不管是HTML页面还是JSON数据,都只包含下面两个简单的步骤

  1. 创建一个路由:路由就是你页面的URL(例如 /about),并且指向一个控制器

  2. 创建一个控制器:控制器是你用来搭建页面而编写的一个方法。你接收传入的请求信息,并使用它来创建一个Symfony的 Response 对象,该对象可以包含HTML内容,JSON字符串或者别的东西。

就像在web页面中,每个交互都已经被HTTP请求初始化了。你要做的非常简单纯粹:理解请求,返回响应。

这里是视频教程。http://knpuniversity.com/screencast/symf...

创建一个页面:路由和控制器

在继续之前,请确保你已经读过了 安装 教程,并且可以在浏览器中打开Symfony应用。

假如你想要创建一个页面 /lucky/number 用来生成一个幸(sui)运(ji)数并打印出来。要做到这点,我们可以创建一个类和一个成员方法,当访问 /lucky/number 时,该成员方法将被执行。

// 文件位置 src/AppBundle/Controller/LuckyController.php
namespace AppBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;

class LuckyController
{
    /**
     * @Route("/lucky/number")
     */
    public function numberAction()
    {
        $number = rand(0, 100);

        return new Response(
            '<html><body>Lucky number: '.$number.'</body></html>'
        );
    }
}

在深入研究之前,先看看测试结果。

http://localhost:8000/luck/number

如果你在页面中看见一个幸运数字,恭喜!但是在你跑出去买彩票之前,先看看这是如何完成的。

注释里的 @route 定义了URL格式。你也可以在YAML文件或者其他配置文件中书写路由(参考 路由 章节)。

注释下面的 numberAction 方法叫做 控制器,你就是在那里搭建页面的。这里唯一的规则就是控制器 必须 返回一个Symfony Response 对象(当然,你最终会学会改变这个规则)。

创建一个JSON响应

你所返回的 Response 对象可以包含HTML,JSON甚至是一个图像或PDF的二进制码。你可以轻松地设置HTTP头信息或者状态码。

假如你想要以JSON形式返回幸运数字,只需要在 LuckyController 中添加另一个方法:

// 文件位置 src/AppBundle/Controller/LuckyController.php

// ...
class LuckyController
{
    // ...

    /**
     * @Route("/api/lucky/number")
     */
    public function apiNumberAction()
    {
        $data = array(
            'lucky_number' => rand(0, 100),
        );

        return new Response(
            json_encode($data),
            200,
            array('Content-Type' => 'application/json')
        );
    }
}

在浏览器中走一个:

http://localhost:8000/api/lucky/number

你也可以使用 JsonResponse 对象来简化书写:

// 文件位置 src/AppBundle/Controller/LuckyController.php

// ...
// --> 别忘了使用 use 来引入 JsonResponse
use Symfony\Component\HttpFoundation\JsonResponse;

class LuckyController
{
    // ...

    /**
     * @Route("/api/lucky/number")
     */
    public function apiNumberAction()
    {
        $data = array(
            'lucky_number' => rand(0, 100),
        );

        // calls json_encode and sets the Content-Type header
        return new JsonResponse($data);
    }
}

华丽分割线!下面的路由,我们换一种写法!将路由定义在 app/config/routing.yml 配置文件中!


动态URL格式:/lucky/number/{count}

哇哈哈,上面的路由碉堡了!但是Symfony的路由还可以做更多事情。假如你想要用户访问 /lucky/number/5 来一次性生成 5 个幸运数。更新你的路由,将 {花括号} 加在末尾:

# app/config/routing.yml
lucky_number:
    path:     /lucky/number/{count}
    defaults: { _controller: AppBundle:Lucky:number }

由于在路由中添加了 {count} 占位符,现在该页面的URL变得不同了:路由会匹配 /luck/number/* 形式的URL,比如 /lucky/number/5 。最棒的地方在于你可以获取到这个值 并且在控制器中使用:

// src/AppBundle/Controller/LuckyController.php
// ...

class LuckyController
{

    /**
     * 这个路由已经在 app/config/routing.yml 文件中定义了
     */
    public function numberAction($count)
    {
        $numbers = array();
        for ($i = 0; $i < $count; $i++) {
            $numbers[] = rand(0, 100);
        }
        $numbersList = implode(', ', $numbers);

        return new Response(
            '<html><body>Lucky numbers: '.$numbersList.'</body></html>'
        );
    }

    // ...
}

通过访问 /lucky/number/xx (将xx用 任何 数字替换)来试试看。

http://localhost:8000/lucky/number/7

你应该会看见 7 个幸运数字从页面输出!通过在控制器中加入 $placeholder 参数,你可以获取 {placeholder} 中的值。只是需要确保他们有相同的命名。

路由系统还可以做 更多事情 ,比如支持多个占位符(e.g. /blog/{category}/{page} )、可选型占位符,以及让占位符去匹配正则表达式。

查找关于路由的一切,成为路由专家,请看 路由 章节

渲染模板(用 Service Container)

如果你从控制器中要返回HTML,你也许希望渲染一个模板。幸运的是,Symfony搭载了Twig:一个简单强大,事实上很有趣的模板语言。

目前为止, LuckyController 没有继承任何基类。使用Twig或者许多其他Symfony工具最简单的方法是--继承Symfony的基类:

// src/AppBundle/Controller/LuckyController.php

// ...
// --> 别忘了用 use 语句来引入 Controller
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class LuckyController extends Controller
{
    // ...
}

使用模板服务

这不会发生任何改变,但它 的确 让你得到了Symfony的 container :一个数组形式的对象,让系统中的 每一个 有用的对象变得触手可得。这些有用的对象叫做 服务(Service) ,Symfony便搭载着这些可以渲染Twig模板,可以记录日志,还有其他更多功能的服务。

渲染一个Twig模板,可以使用 templating 服务:

// src/AppBundle/Controller/LuckyController.php

// ...
class LuckyController extends Controller
{
    /**
     * @Route("/lucky/number/{count}")
     */
    public function numberAction($count)
    {
        // ...
        $numbersList = implode(', ', $numbers);

        $html = $this->container->get('templating')->render(
            'lucky/number.html.twig',
            array('luckyNumberList' => $numbersList)
        );

        return new Response($html);
    }

    // ...
}

坚持读下去,你将会学习到更多重要的 service container 。目前,你只需要知道它包含了许多的对象,你可以通过 get() 方法并使用它们的别名,比如 templatinglogger , 来获取相应的服务。 templating 服务是 TwigEngine 的实例,它拥有 render() 方法。

但这甚至可以变得更简便!通过继承 Container 类,你也可以获得许多方法上的捷径,比如 render()

// src/AppBundle/Controller/LuckyController.php

// ...
/**
 * @Route("/lucky/number/{count}")
 */
public function numberAction($count)
{
    // ...

    /*
    $html = $this->container->get('templating')->render(
        'lucky/number.html.twig',
        array('luckyNumberList' => $numbersList)
    );

    return new Response($html);
    */

    // render: a shortcut that does the same as above
    return $this->render(
        'lucky/number.html.twig',
        array('luckyNumberList' => $numbersList)
    );
}

参考 Controller 章节来了解更多捷径方法和它们的用法。

创建模板

如果你现在刷新浏览器,你会看见报错:

Unable to find template "lucky/number.html.twig"

修复这个报错,可以通过创建文件 app/Resources/views/lucky/number.html.twig ,在twig文件中输入下面内容:

{# app/Resources/views/lucky/number.html.twig #}
{% extends 'base.html.twig' %}

{% block body %}
    <h1>Lucky Numbers: {{ luckyNumberList }}</h1>
{% endblock %}

欢迎使用Twig!这个简单的文件已经展示了基本的语法:比如 {{ variableName }} 语法是如何输出东西的。 luckyNumberList 是你在控制器中通过调用 render() 方法向模板传入的变量。

{% extends 'base.html.twig' %} 表示你的布局文件位于 app/Resources/views/base.html.twig ,并加载到了项目中。这 真的 很基本(一个没有样式的HTML结构),它现在已经是你的了,你可以各种自定义。 {% block body %} 这部分使用了Twig的 继承系统 来把内容添加到布局文件 base.html.twig 的中间。

马上刷新浏览器!

http://localhost:8000/lucky/number/9

如果你查看源代码,你将会看见一个基本的HTML结构,这归功于 base.html.twig

这只是在小试牛刀。当你已经准备好掌握Twig语法,数组循环,渲染其他模板以及其他酷炫技能时,读一下 Templating 章节。

探索项目

你已经创建了一个灵活的URL,利用继承完成了模板渲染,创建了JSON响应。干得漂亮!

是时候探索并揭秘项目中的文件了。你已经在两个最重要的路径下撸过代码了:

app/
    包含了配置文件和模板。基本上任何非PHP代码都在这里。
src/
    你的php代码就在住这里

99%是时间,你将会在 src/ (php文件)或者 app/(其他所有文件)路径下撸代码。随着你的了解逐渐加深,你将学习到在这些路径下能完成什么。

app/ 路径下也包含了一些其他东西,比如 app/AppKernel.php 你会用它来启用新的bundle(这是在 app/ 路径下的一个简短的php清单)。

src/ 路径下只有一个路径: src/AppBundle ,所有东西都在里面。一个bundle就像是一个"插件",你可以 查找开源bundle 并在你的项目中安装。但是哪怕是你自己写的代码,也要存放在bundle中,比如典型的 AppBundle (虽然AppBundle没有任何特别之处)。想要了解更多bundle相关信息和了解为什么你可能会创建多个bundle(提示一下:为了在项目之间共享代码),请参考 Bundles 章节。

那么项目中其他的路径呢?

web/
    这是项目的文档根目录,包含了可访问的公共文件,
    比如 CSS ,图片,和 Symfony用来执行 app (add_dev 和 app.php) 的前端控制器。
tests/
    存放应用中的自动测试文件(比如单元测试)。
bin/
    存放二进制文件。最重要的就是 console 文件,该文件通过控制台来执行Symfony命令。
var/
    存放自动生成的文件,比如缓存文件(var/cache/) 和日志(var/logs/)。
vendor/
    存放通过Composer包管理器下载的第三方类库,包和bundle。你永远都不应该更改里面的东西。

Symfony是灵活的。如果需要,你可以轻松重写默认的结构,参考 http://symfony.com/doc/current/cookbook/...

应用配置

Symfony拥有许多内置的bundle(打开你的 app/AppKernel.php 文件)而且你也许还会安装更多。bundle的主配置文件是 app/config/config.yml

# app/config/config.yml

# ...
framework:
    secret: '%secret%'
    router:
        resource: '%kernel.root_dir%/config/routing.yml'
    # ...

twig:
    debug:            '%kernel.debug%'
    strict_variables: '%kernel.debug%'

# ...

framework key 配置 框架Bundle,twig key 配置TwigBundle,以此类推。仅仅通过更改配置文件中的某个选项,便可控制Symfony的 许多 行为。想知道这是怎么玩的,参考 配置参考 部分。

下一步往哪走?

流弊!你已经开始掌握Symfony了,并且开始学习以一种全新的方式去构建一个优美、多功能、快速、可维护的应用。

好,是时候阅读下面章节来掌握基本原理了:


日期:2016-4


唐小璜
229 声望12 粉丝

引用和评论

0 条评论