月: <span>一月 2018</span>

创建JSON响应

通过Response类,设置合适的contentheaders,即可创建任何类型的响应。一个JSON响应看起来像下面这样:

use Symfony\Component\HttpFoundation\Response;
 
$response = new Response();
$response->setContent(json_encode(array(
    'data' => 123,
)));
$response->headers->set('Content-Type', 'application/json');
框架里有一个好用的JsonResponse类,可以简化类似操作:
use Symfony\Component\HttpFoundation\JsonResponse;
 
$response = new JsonResponse();
$response->setData(array(
    'data' => 123
));

这可以把你的data数组转换成JSON,然后设置其Content-Type头为application/json

 

为了防止XSS|JSON Hijacking(JSON劫持),你应该传入一个关联数组作为JsonResponse最外层数组,而不是一个索引数组,这样一来最终结果就是一个对象:[{"object": "not inside an array"}]


Doctrine ORM 的结构与使用(基于symfony)

对于任何应用程序来说,一个最常见和最具挑战的任务,就是从数据库中读取和持久化数据信息。尽管symfony框架并未整合任何需要使用数据库的组件,但是却紧密集成了一个名为 Doctrine 的三方类库。Doctrine的主要目标是为你提供一个强有力的工具,令数据库互动更加轻松和灵活。

配置数据库

(略):各个框架集成的database_config各不相同,自己配置就好

创建一个Entity

假设你正构建一套程序,其中有些产品需要展示。即使不考虑Doctrine或者数据库,你也已经知道你需要一个Product对象来呈现这些产品。在你AppBundleEntity目录下创建这个类:

// src/AppBundle/Entity/Product.php
namespace AppBundle\Entity;
 
use Doctrine\ORM\Mapping as ORM;
 
/**
 * @ORM\Entity
 * @ORM\Table(name="product")
 */
class Product
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;
 
    /**
     * @ORM\Column(type="string", length=100)
     */
    private $name;
 
    /**
     * @ORM\Column(type="decimal", scale=2)
     */
    private $price;
 
    /**
     * @ORM\Column(type="text")
     */
    private $description;
}

即是建表一样,设置好每个字段的格式,长度。考验你SQL基础的时候

创建数据表/Schema

现在你有了一个包含映射信息的可用Product类,因此Doctrine确切地知道如何持久化它。当然,你还没有相应的Product数据表在库中。幸运的是,Doctrine可以自动创建所有的数据表。要这么做,运行以下命令:

php bin/console doctrine:schema:update --force

它会比较你的数据库 理论上应该是 什么样子的(基于你的entities的映射信息)以及 实际上 它应该是什么样,然后执行所需的SQl语句来将数据库的schema 更新到 它所应有的样子。换句话说,如果你添加了一个包含“映射元数据”(mapping metadata)的新属性到Product并运行此任务,它将执行所需的 “ALTER TABLE” 语句,向已经存在的Product表添加那个新列。


把路由参数传入控制器

我们现在已经知道路由指向AppBundle中的HelloController::indexAction()方法。还有更有趣的就是控制器方法的参数传递:

// src/AppBundle/Controller/HelloController.php
// ...
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
 
/**
 * @Route("/hello/{name}", name="hello")
 */
public function indexAction($name)
{
    // ...
}

控制器有个参数$name,对应所匹配路由的{name}参数(如果你访问/hello/ryan, 在本例中是ryan)。实际上当执行你的控制器时,Symfony在所匹配路由中匹配带参数控制器中的每个参数。所以这个{name}值被传入到$name。只需要确保占位符的名称和参数名称一样就行。

以下是更有趣的例子,这里的控制器有两个参数:

// src/AppBundle/Controller/HelloController.php
// ...
 
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
 
class HelloController
{
    /**
     * @Route("/hello/{firstName}/{lastName}", name="hello")
     */
    public function indexAction($firstName, $lastName)
    {
        // ...
    }
}

将路由参数映射到控制器参数是十分容易和灵活的。在你开发时请遵循以下思路:

1. 控制器参数的顺序无关紧要

Symfony可以根据路由参数名匹配控制器方法参数。换句话说,它可以实现last_name参数与$last_name参数的匹配。控制器可以在随意排列参数的情况下正常工作。

public function indexAction($lastName, $firstName)
{
    // ...
}

2.控制器所需参数必须匹配路由参数

下面会抛出一个运行时异常(RuntimeException),因为在路由定义中没有foo参数:

public function indexAction($firstName, $lastName, $foo)
{
    // ...
}

如果参数是可选的,那该多好。下面的例子不会抛出异常:

public function indexAction($firstName, $lastName, $foo = 'bar')
{
    // ...
}

3.不是所有的路由参数都需要在控制器上有响应参数的

如果,举个例子,last_name对你控制器不是很重要的话,你可以完全忽略掉它:

public function indexAction($firstName)
{
    // ...
}

你也可以从你的路由器传入其他的参数到你的控制器参数。请看 如何从路由向控制器传递额外的信息


将URI映射到控制器 

我们的新控制器返回一个简单的HTML页。为了能够在指定的URI中渲染该控制器,我们需要为它创建一个路由。 我们将在路由章节中讨论路由组件的细节,但现在我们为我们的控制器创建一个简单路由:

// src/AppBundle/Controller/HelloController.php
namespace AppBundle\Controller;
 
use Symfony\Component\HttpFoundation\Response;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
 
class HelloController
{
    /**
     * @Route("/hello/{name}", name="hello")
     */
    public function indexAction($name)
    {
        return new Response('<html><body>Hello '.$name.'!</body></html>');
    }
}

现在,你来到/hello/ryan(例如,如果你使用内置的web服务http://localhost:8000/hello/ryan),那么它就会执行HelloController::indexAction()控制器,并且将ryan赋给$name变量。创建这样一个页面就能够让路由跟控制器做简单的关联


控制台命令

创建一个命令

命令通过类来定义,这些类必须存放在你的bundle (如 AppBundle\Command) 的 Command 命名空间下。类名必须是 Command 后缀。

例如,一个名为 CreateUser 的命令必须遵循此结构:

// src/AppBundle/Command/CreateUserCommand.php
namespace AppBundle\Command;
 
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
 
class CreateUserCommand extends Command
{
    protected function configure()
    {
        // ...
    }
 
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        // ...
    }
}

配置命令

首先,你必须在configure()方法中配置命令的名称。然后可选地定义一个帮助信息(help message)和 输入选项及输入参数(input options and arguments):

// ...
protected function configure()
{
    $this
        // the name of the command (the part after "bin/console")
        // 命令的名字("bin/console" 后面的部分)
        ->setName('app:create-users')
 
        // the short description shown while running "php bin/console list"
        // 运行 "php bin/console list" 时的简短描述
        ->setDescription('Creates new users.')
 
        // the full command description shown when running the command with
        // the "--help" option
        // 运行命令时使用 "--help" 选项时的完整命令描述
        ->setHelp("This command allows you to create users...")
    ;
}

执行命令

配置命令之后,你就能在终端(terminal)中执行它:

php bin/console app:create-users

你可能已经预期,这个命令将什么也不做,因为你还没有写入任何逻辑。在execute()方法里添加你自己的逻辑,这个方法可以访问到input stream(如,选项和参数)和output stream(以写入信息到命令行):

// ...
protected function execute(InputInterface $input, OutputInterface $output)
{
    // outputs multiple lines to the console (adding "\n" at the end of each line)
    // 输出多行到控制台(在每一行的末尾添加 "\n")
    $output->writeln([
        'User Creator',
        '============',
        '',
    ]);
 
    // outputs a message followed by a "\n"
    $output->writeln('Whoa!');
 
    // outputs a message without adding a "\n" at the end of the line
    $output->write('You are about to ');
    $output->write('create a user.');
}

现在,尝试执行此命令:

$  php bin/console app:create-user
User Creator
============
 
Whoa!
You are about to create a user.