symfony文档
控制器
一个简单的控制器示例
// src/AppBundle/Controller/LuckyController.php
namespace AppBundle\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class LuckyController
{
/**
* @Route("/lucky/number/{max}")
*/
public function numberAction($max)
{
$number = random_int(0, $max);
return new Response(
'<html><body>Lucky number: '.$number.'</body></html>'
);
}
}
注释路由
/**
* @Route("/lucky/number/{max}")
*/
浏览器访问路由地址:http:// localhost:8000/lucky/number/100
生成URL
$url = $this->generateUrl('blog_show', ['slug' => 'slug-value']);
重定向
如果要将用户重定向到另一个页面,请使用redirectToRoute() 和redirect()方法:
public function indexAction()
{
// redirects to the "homepage" route
return $this->redirectToRoute('homepage');
// does a permanent - 301 redirect
return $this->redirectToRoute('homepage', [], 301);
// redirects to a route with parameters
return $this->redirectToRoute('blog_show', ['slug' => 'my-page']);
// redirects to a route and maintains the original query string parameters
return $this->redirectToRoute('blog_show', $request->query->all());
// redirects externally
return $this->redirect('http://symfony.com/doc');
}
渲染模板
如果要提供HTML,则需要呈现一个模板。该render() 方法呈现一个模板,并将该内容放入Response 您的对象中:
// renders app/Resources/views/lucky/number.html.twig
return $this->render('lucky/number.html.twig', ['number' => $number]);
模板也可以存在于更深的子目录中。只是尝试避免创建不必要的深层结构:
// renders app/Resources/views/lottery/lucky/number.html.twig
return $this->render('lottery/lucky/number.html.twig', [
'number' => $number,
]);
获取服务作为控制器参数
Symfony 3.3中引入了提示控制器参数以接收服务的功能。
如果您需要控制器中的服务,则只需键入一个带有其类(或接口)名称的参数即可。Symfony会自动为您提供所需的服务:
use Psr\Log\LoggerInterface;
// ...
/**
* @Route("/lucky/number/{max}")
*/
public function numberAction($max, LoggerInterface $logger)
{
$logger->info('We are logging!');
// ...
}
直接访问服务
如果扩展基Controller类,则可以通过get() 方法访问任何Symfony服务。以下是您可能需要的几种常见服务:
$templating = $this->get('templating');
$router = $this->get('router');
$mailer = $this->get('mailer');
// you can also fetch parameters
$someParameter = $this->getParameter('some_parameter');
管理错误和404页面
如果找不到任何内容,则应该使用HTTP协议,并返回404响应。为此,您将抛出一种特殊类型的异常。如果要扩展Controller基AbstractController 类或基类,请执行以下操作:
public function indexAction()
{
// retrieve the object from database
$product = ...;
if (!$product) {
throw $this->createNotFoundException('The product does not exist');
}
return $this->render(...);
}
自定义错误页面
https://symfony.com/doc/3.4/controller/error_pages.html
会话:session的设置和获取
use Symfony\Component\HttpFoundation\Session\SessionInterface;
public function indexAction(SessionInterface $session)
{
// stores an attribute for reuse during a later user request
$session->set('foo', 'bar');
// gets the attribute set by another controller in another request
$foobar = $session->get('foobar');
// uses a default value if the attribute doesn't exist
$filters = $session->get('filters', []);
}
请求
use Symfony\Component\HttpFoundation\Request;
public function indexAction(Request $request)
{
$request->isXmlHttpRequest(); // is it an Ajax request?
$request->getPreferredLanguage(['en', 'fr']);
// retrieves GET and POST variables respectively
$request->query->get('page');
$request->request->get('page');
// retrieves SERVER variables
$request->server->get('HTTP_HOST');
// retrieves an instance of UploadedFile identified by foo
$request->files->get('foo');
// retrieves a COOKIE value
$request->cookies->get('PHPSESSID');
// retrieves an HTTP request header, with normalized, lowercase keys
$request->headers->get('host');
$request->headers->get('content-type');
}
Flash消息
您还可以在用户的会话中存储特殊消息,称为“即时消息”。按照设计,即时消息应仅使用一次:一旦您检索它们,它们就会自动从会话中消失。此功能使“刷新”消息特别适合存储用户通知。
例如,假设您正在处理 表单内容 提交:
处理完请求后,控制器在会话中设置一条Flash消息,然后进行重定向。
use Symfony\Component\HttpFoundation\Request;
public function updateAction(Request $request)
{
// ...
if ($form->isSubmitted() && $form->isValid()) {
// do some sort of processing
$this->addFlash(
'notice',
'Your changes were saved!'
);
// $this->addFlash() is equivalent to $request->getSession()->getFlashBag()->add()
return $this->redirectToRoute(...);
}
return $this->render(...);
}
然后,在模板中(或者甚至更好的是,在您的基本布局模板中),使用app.flashes() 命令从会话中读取所有Flash消息:
3.3版的新功能:该app.flashes()枝条函数,Symfony的3.3推出。在此之前,您必须使用app.session.flashBag()。
{# app/Resources/views/base.html.twig #}
{# read and display just one flash message type #}
{% for message in app.flashes('notice') %}
<div class="flash-notice">
{{ message }}
</div>
{% endfor %}
{# read and display several types of flash messages #}
{% for label, messages in app.flashes(['success', 'warning']) %}
{% for message in messages %}
<div class="flash-{{ label }}">
{{ message }}
</div>
{% endfor %}
{% endfor %}
{# read and display all flash messages #}
{% for label, messages in app.flashes %}
{% for message in messages %}
<div class="flash-{{ label }}">
{{ message }}
</div>
{% endfor %}
{% endfor %}
JSON助手
要从控制器返回JSON,请json()在基本控制器上使用helper方法。这将返回一个特殊的JsonResponse对象,该对象会自动对数据进行编码:
// ...
public function indexAction()
{
// returns '{"username":"jane.doe"}' and sets the proper Content-Type header
return $this->json(['username' => 'jane.doe']);
// the shortcut defines three optional arguments
// return $this->json($data, $status = 200, $headers = [], $context = []);
}
文件助手
可以使用file() 帮助程序从控制器内部提供文件:
public function fileAction()
{
// send the file contents and force the browser to download it
return $this->file('/path/to/some_file.pdf');
}
该file()助手提供一些参数来配置它的行为:
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
public function fileAction()
{
// load the file from the filesystem
$file = new File('/path/to/some_file.pdf');
return $this->file($file);
// rename the downloaded file
return $this->file($file, 'custom_name.pdf');
// display the file contents in the browser instead of downloading it
return $this->file('invoice_3241.pdf', 'my_invoice.pdf', ResponseHeaderBag::DISPOSITION_INLINE);
}
模板
layout布局:模板继承和布局
链接到页面
要链接到该页面,只需使用path()Twig功能并参考以下路线:
<a href="{{ path('welcome') }}">Home</a>
链接资源(js,css,image等静态资源)
<img src="{{ asset('images/logo.png') }}" alt="Symfony!"/>
<link href="{{ asset('css/blog.css') }}" rel="stylesheet"/>
如果您需要资源的绝对URL,请absolute_url()按以下方式使用Twig函数:
<img src="{{ absolute_url(asset('images/logo.png')) }}" alt="Symfony!"/>
链接css和js
通过app变量访问Twig中的用户,请求,会话等
应用场景: 可以用来实现在模板中判断用户是否登录的状态
表单
数据库 ORM
配置数据库
在真正开始之前,您需要配置数据库连接信息。按照约定,此信息通常在app/config/parameters.yml文件中配置 :
# app/config/parameters.yml
parameters:
database_host: localhost
database_name: test_project
database_user: root
database_password: password
# ...
您还可以更改Doctrine的默认值,以便生成的SQL使用正确的字符集。
# app/config/config.yml
doctrine:
dbal:
charset: utf8mb4
default_table_options:
charset: utf8mb4
collate: utf8mb4_unicode_ci
创建实体类
假设您正在构建一个需要显示产品的应用程序。甚至不用考虑Doctrine或数据库,您就已经知道需要一个Product对象来表示那些产品。在Entity您的AppBundle目录中创建此类:
// src/AppBundle/Entity/Product.php
namespace AppBundle\Entity;
/**
* @IgnoreAnnotation("fn")
*/
class Product
{
private $id;
private $name;
private $price;
private $description;
}
添加映射信息
使用Doctrine,您可以以比将标量数据的行读取到数组中更有趣的方式使用数据库。取而代之的是,Doctrine允许您从数据库中提取整个对象,并将整个对象持久化到数据库中。为了使Doctrine能够做到这一点,您必须将数据库表映射到特定的PHP类,并且这些表上的列必须映射到其相应的PHP类上的特定属性。
以以多种不同的格式(包括YAML,XML)或Product通过DocBlock批注直接在类内部指定此元数据:
# src/AppBundle/Resources/config/doctrine/Product.orm.yml
AppBundle\Entity\Product:
type: entity
table: product
id:
id:
type: integer
generator: { strategy: AUTO }
fields:
name:
type: string
length: 100
price:
type: decimal
scale: 2
description:
type: text
验证映射命令: 根据错误提示进行修改配置
php bin/console doctrine:schema:validate
实体类生成数据表
php bin/console doctrine:schema:update --force
将对象持久化到数据库中
既然您已将Product实体映射到其对应的product 表,就可以将Product对象持久保存到数据库了。从控制器内部,这非常容易。将以下方法添加到 DefaultController包的中:
// src/AppBundle/Controller/DefaultController.php
// ...
use AppBundle\Entity\Product;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Response;
public function createAction()
{
// you can fetch the EntityManager via $this->getDoctrine()
// or you can add an argument to your action: createAction(EntityManagerInterface $entityManager)
$entityManager = $this->getDoctrine()->getManager();
$product = new Product();
$product->setName('Keyboard');
$product->setPrice(19.99);
$product->setDescription('Ergonomic and stylish!');
// tells Doctrine you want to (eventually) save the Product (no queries yet)
$entityManager->persist($product);
// actually executes the queries (i.e. the INSERT query)
$entityManager->flush();
return new Response('Saved new product with id '.$product->getId());
}
// if you have multiple entity managers, use the registry to fetch them
public function editAction()
{
$doctrine = $this->getDoctrine();
$entityManager = $doctrine->getManager();
$otherEntityManager = $doctrine->getManager('other_connection');
}
该 t h i s − > g e t D o c t r i n e ( ) − > g e t M a n a g e r ( ) 方 法 获 取 D o c t r i n e 的 实 体 管 理 器 对 象 , 这 是 D o c t r i n e 中 最 重 要 的 对 象 。 它 负 责 将 对 象 保 存 到 数 据 库 并 从 数 据 库 中 获 取 对 象 。 您 将 this->getDoctrine()->getManager()方法获取Doctrine的 实体管理器对象,这是Doctrine中最重要的对象。它负责将对象保存到数据库并从数据库中获取对象。 您将 this−>getDoctrine()−>getManager()方法获取Doctrine的实体管理器对象,这是Doctrine中最重要的对象。它负责将对象保存到数据库并从数据库中获取对象。您将product 像其他任何普通的PHP对象一样实例化并使用该对象。
该persist( p r o d u c t ) 调 用 告 诉 D o c t r i n e 对 product)调用告诉Doctrine对 product)调用告诉Doctrine对product对象进行“管理” 。这并不会导致查询到数据库中进行。
flush()调用该方法时,Doctrine会浏览它正在管理的所有对象,以查看是否需要将它们持久化到数据库中。在此示例中,$product对象的数据在数据库中不存在,因此实体管理器执行INSERT查询,并在product表中创建新行。
事务和并发
从数据库中获取对象
从数据库中取回对象更加容易。例如,假设您已经配置了一条路由,以Product根据其id值显示特定的路由:
public function showAction($productId)
{
$product = $this->getDoctrine()
->getRepository(Product::class)
->find($productId);
if (!$product) {
throw $this->createNotFoundException(
'No product found for id '.$productId
);
}
// ... do something, like pass the $product object into a template
}
一旦有了存储库对象,就可以访问各种有用的方法:
$repository = $this->getDoctrine()->getRepository(Product::class);
// looks for a single product by its primary key (usually "id")
$product = $repository->find($productId);
// dynamic method names to find a single product based on a column value
$product = $repository->findOneById($productId);
$product = $repository->findOneByName('Keyboard');
// dynamic method names to find a group of products based on a column value
$products = $repository->findByPrice(19.99);
// finds *all* products
$products = $repository->findAll();
使用 findBy()和findOneBy() 方法 多条件获取对象
$repository = $this->getDoctrine()->getRepository(Product::class);
// looks for a single product matching the given name and price
//查找与给定名称和价格匹配的单个产品
$product = $repository->findOneBy([
'name' => 'Keyboard',
'price' => 19.99
]);
// looks for multiple products matching the given name, ordered by price
//按价格查找与给定名称匹配的多个产品
$products = $repository->findBy(
['name' => 'Keyboard'],
['price' => 'ASC']
);
更新对象
从Doctrine获取对象后,对其进行更新就很容易。假设您有一条将产品ID映射到控制器中的更新操作的路由:
use AppBundle\Entity\Product;
// ...
public function updateAction($productId)
{
$entityManager = $this->getDoctrine()->getManager();
$product = $entityManager->getRepository(Product::class)->find($productId);
if (!$product) {
throw $this->createNotFoundException(
'No product found for id '.$productId
);
}
$product->setName('New product name!');
$entityManager->flush();
return $this->redirectToRoute('homepage');
}
删除对象
删除对象非常相似,但是需要调用remove() 实体管理器的方法:
$entityManager->remove($product);
$entityManager->flush();
如您所料,该remove()方法通知Doctrine您要从数据库中删除给定的对象。DELETE但是,直到flush()调用该方法后,才实际执行实际查询。
查询对象
您已经了解了存储库对象如何使您无需任何工作即可运行基本查询:
$repository = $this->getDoctrine()->getRepository(Product::class);
$product = $repository->find($productId);
$product = $repository->findOneByName('Keyboard');
使用Doctrine,您还可以使用Doctrine查询语言(DQL)编写更复杂的查询。DQL与SQL相似,不同之处在于,您应该想象自己正在查询实体类的一个或多个对象(例如Product),而不是查询表中的行(例如product)。
在Doctrine中进行查询时,您有两个主要选择:编写纯DQL查询或使用Doctrine的查询生成器。
用DQL查询对象
假设您要查询价格超过的产品(价格19.99从最低到最贵)。您可以使用Doctl(Doctrine的类似SQL的本地语言)来为这种情况构造查询:
$query = $entityManager->createQuery(
'SELECT p
FROM AppBundle:Product p
WHERE p.price > :price
ORDER BY p.price ASC'
)->setParameter('price', 19.99);
$products = $query->getResult();
SQL和DQL的区别: 最大的区别是您需要考虑选择PHP对象而不是数据库中的行。
出于这个原因,你选择从该
AppBundle:Product 实体(为一个可选的快捷方式 AppBundle\Entity\Product类),然后别名它p。
setParameter() 方法使用Doctrine时,最好将任何外部值设置为“占位符”(:price在上面的示例中),因为它可以防止SQL注入攻击
getResult() 方法返回结果数组。要仅获得一个结果,可以使用getOneOrNullResult():
$product = $query->setMaxResults(1)->getOneOrNullResult();
更多 官方的 Doctrine Query Language文档
查询使用Doctrine的查询生成器对象
除了编写DQL字符串,您可以使用一个名为的有用对象 QueryBuilder为您构建该字符串。当实际查询取决于动态条件时,这很有用,因为随着您开始连接字符串,您的代码很快将变得难以用DQL读取:
$repository = $this->getDoctrine()
->getRepository(Product::class);
// createQueryBuilder() automatically selects FROM AppBundle:Product
// and aliases it to "p"
$query = $repository->createQueryBuilder('p')
->where('p.price > :price')
->setParameter('price', '19.99')
->orderBy('p.price', 'ASC')
->getQuery();
$products = $query->getResult();
// to get just one result:
// $product = $query->setMaxResults(1)->getOneOrNullResult();
该QueryBuilder对象包含构建查询所需的所有方法。通过调用该getQuery()方法,查询构建器将返回一个普通Query对象,该对象可用于获取查询结果。
有关Doctrine的查询生成器的更多信息,请查阅Doctrine的 查询生成器文档。
Doctrine的 查询生成器文档
如何创建自定义存储库类
该篇博客主要参考symfony3.4版本的官方文档