创建项目
composer create-project symfony/framework-standard-edition
创建 bundle
php app/console generate:bundle --namespace=Acme/HelloBundle --format=yml
创建数据库
php app/console doctrine:database:create
创建模型
php app/console doctrine:generate:entity
更新数据库
php app/console doctrine:schema:create
CRUD
php app/console generate:doctrine:crud --override
php app/console generate:doctrine:crud --entity=AcmeBlogBundle:Post --format=annotation --with-write --no-interaction
Generating Getters and Setters
for class
php app/console doctrine:generate:entities Acme/StoreBundle/Entity/Product --no-backup
for bundle
php app/console doctrine:generate:entities AcmeStoreBundle
for namespace
php app/console doctrine:generate:entities Acme
一对多关系
use Doctrine\Common\Collections\ArrayCollection;
class Category
{
// ...
/**
* @ORM\OneToMany(targetEntity="Product", mappedBy="category")
*/
protected $products;
public function __construct()
{
$this->products = new ArrayCollection();
}
}
belongsTo
// src/Acme/StoreBundle/Entity/Product.php
// ...
class Product
{
// ...
/**
* @ORM\ManyToOne(targetEntity="Category", inversedBy="products")
* @ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
protected $category;
}
启动服务
php app/console server:run
如果prod环境出错,需要生成prod缓存
php app/console cache:clear --env=prod --no-debug
在console显示配置
app/console config:dump-reference FrameworkBundle
Response
public function helloAction()
{
return new Response('Hello world!');
}
根据路由生成url
$this->generateUrl('homepage’)
设置flash
$this->get('session')->getFlashBag()->add(
'notice',
'Your changes were saved!'
);
读取 flash
for flashMessage in app.session.flashbag.get('notice')
json 响应
$response = new Response(json_encode(array('name' => $name)));
$response->headers->set('Content-Type', 'application/json’);
For JSON, there is JsonResponse6. See Creating a JSON Response.
文件 响应
For files, there is BinaryFileResponse7. See Serving Files
路由中设定参数类型
blog:
path: /blog/{page}
defaults: { _controller: AcmeBlogBundle:Blog:index, page: 1 }
method: [GET] / [POST]
condition: “php code"
requirements:
culture: en|fr page: \d
查看所有路由
php app/console router:debug
查看路由详情
php app/console router:debug acme_hello_homepage
测试路由
php app/console router:match /blog/my-latest-post
Asynchronous Content with hinclude.js
编译 asset
php app/console assets:install target [—symlink]
设置数据库为UTF-8
my.cnf
collation-server = utf8_general_ci
character-set-server = utf8
查看路由详情
php app/console router:debug acme_hello_homepage
测试路由
php app/console router:match /blog/my-latest-post
定义模型
class Product
{
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(type="string", length=100)
*/
protected $name;
/**
* @ORM\Column(type="decimal", scale=2)
*/
}
create table
php app/console doctrine:schema:update --force
save to database
use Acme\StoreBundle\Entity\Product;
use Symfony\Component\HttpFoundation\Response;
public function createAction()
{
$product = new Product();
$product->setName('A Foo Bar');
$product->setPrice('19.99');
$product->setDescription('Lorem ipsum dolor');
$em = $this->getDoctrine()->getManager();
$em->persist($product);
$em->flush();
return new Response('Created product id '.$product->getId());
}
Doctrine
doctrine find
public function showAction($id)
{
$product = $this->getDoctrine()
->getRepository('AcmeStoreBundle:Product')
->find($id);
if (!$product) {
throw $this->createNotFoundException(
'No product found for id '.$id
);
}
// ... do something, like pass the $product object into a template
}
save relation
use Acme\StoreBundle\Entity\Category;
use Acme\StoreBundle\Entity\Product;
use Symfony\Component\HttpFoundation\Response;
class DefaultController extends Controller
{
public function createProductAction()
{
$category = new Category();
$category->setName('Main Products');
$product = new Product();
$product->setName('Foo');
$product->setPrice(19.99);
// relate this product to the category
$product->setCategory($category);
$em = $this->getDoctrine()->getManager();
$em->persist($category);
$em->persist($product);
$em->flush();
return new Response(
'Created product id: '.$product->getId()
.' and category id: '.$category->getId()
); }
}
get relation
public function showAction($id)
{
$product = $this->getDoctrine()
->getRepository('AcmeStoreBundle:Product')->find($id);
$categoryName = $product->getCategory()->getName();
// ...
}
joined search
public function showAction($id)
{
$product = $this->getDoctrine()
->getRepository('AcmeStoreBundle:Product')
->findOneByIdJoinedToCategory($id);
$category = $product->getCategory();
// ...
}
doctrie event
/**
* @ORM\PrePersist
*/
public function setCreatedAtValue()
{
$this->createdAt = new \DateTime();
}
添加验证规则
# src/Acme/BlogBundle/Resources/config/validation.yml
Acme\BlogBundle\Entity\Author:
properties:
name:
- NotBlank: ~
验证模型
// ...
use Symfony\Component\HttpFoundation\Response;
use Acme\BlogBundle\Entity\Author;
public function indexAction()
{
$author = new Author();
// ... do something to the $author object
$validator = $this->get('validator');
$errors = $validator->validate($author);
if (count($errors) > 0) {
/*
* Uses a __toString method on the $errors variable which is a
* ConstraintViolationList object. This gives us a nice string
* for debugging
*/
$errorsString = (string) $errors;
return new Response($errorsString);
}
return new Response('The author is valid! Yes!');
}
Basic Constraints
These are the basic constraints: use them to assert very basic things about the value of properties or the return value of methods on your object.• NotBlank • Blank
• NotNull • Null
• True • False • Type
String Constraints
• Email • Length • Url
• Regex • Ip
• Uuid
PDF brought to you by
generated on July 11, 2014
# app/config/config.yml
framework:
validation: { enable_annotations: true }
Chapter 11: Validation | 141

Number Constraints
• Range Comparison Constraints
• EqualTo
• NotEqualTo
• IdenticalTo
• NotIdenticalTo
• LessThan
• LessThanOrEqual
• GreaterThan
• GreaterThanOrEqual
Date Constraints
• Date
• DateTime • Time
Collection Constraints
• Choice
• Collection
• Count
• UniqueEntity • Language
• Locale
• Country
File Constraints
• File
• Image
Financial and other Number Constraints
• CardScheme • Currency
• Luhn
• Iban
• Isbn • Issn
Other Constraints
• Callback
• Expression
• All
• UserPassword • Valid
创建表单
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Acme\TaskBundle\Entity\Task;
use Symfony\Component\HttpFoundation\Request;
class DefaultController extends Controller
{
public function newAction(Request $request)
{
// create a task and give it some dummy data for this example
$task = new Task();
$task->setTask('Write a blog post');
$task->setDueDate(new \DateTime('tomorrow'));
$form = $this->createFormBuilder($task)
->add('task', 'text')
->add('dueDate', 'date')
->add('save', 'submit')
->getForm();
if ($form->isValid()) {
// perform some action, such as saving the task to the database
return $this->redirect($this->generateUrl('task_success'));
}
return $this->render('AcmeTaskBundle:Default:new.html.twig', array(
'form' => $form->createView(),
));
} }
禁用html5 validation
{{ form(form, {'attr': {'novalidate': 'novalidate'}}) }}
指定控件类型与label值
->add('dueDate', 'date', array(
'widget' => 'single_text',
'label' => 'Due Date',
))
生成form html
{{ form_start(form) }}
{{ form_errors(form) }}
{{ form_row(form.task) }}
{{ form_row(form.dueDate) }}
{{ form_end(form) }}
创建 form_builder
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class TaskType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('task')
->add('dueDate', null, array('widget' => 'single_text'))
->add('save', 'submit');
}
public function getName()
{
return 'task';
}
}
使用 formbuilder
// src/Acme/TaskBundle/Controller/DefaultController.php
// add this new use statement at the top of the class
use Acme\TaskBundle\Form\Type\TaskType;
public function newAction()
{
$task = ...;
$form = $this->createForm(new TaskType(), $task);
// ...
}
取得某个字段值
定义form service
# src/Acme/TaskBundle/Resources/config/services.yml
services:
acme_demo.form.type.task:
class: Acme\TaskBundle\Form\Type\TaskType
tags:
- { name: form.type, alias: task}
使用form service
public function newAction()
{
$task = ...;
$form = $this->createForm('task', $task);
}
从form 取实例
$task = $form->getData();
form type 嵌套
use Symfony\Component\Form\FormBuilderInterface;
public function buildForm(FormBuilderInterface $builder, array $options)
{
// ...
$builder->add('category', new CategoryType());
}
form type 嵌套验证
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\TaskBundle\Entity\Task',
'cascade_validation' => true,
)); }
form type 嵌套显示
<h3>Category</h3>
<div class="category">
{{ form_row(form.category.name) }}
</div>
override form_row
{ # src/Acme/TaskBundle/Resources/views/Form/fields.html.twig #}
{% block form_row %}
{% spaceless %}
<div class="form_row">
{{ form_label(form) }}
{{ form_errors(form) }}
{{ form_widget(form) }}
</div>
{% endspaceless %}
{% endblock form_row %}
使用 form_row
{# src/Acme/TaskBundle/Resources/views/Default/new.html.twig #}
{% form_theme form 'AcmeTaskBundle:Form:fields.html.twig' %}
{% form_theme form 'AcmeTaskBundle:Form:fields.html.twig'
'AcmeTaskBundle:Form:fields2.html.twig' %}
I18n
基本使用
use Symfony\Component\HttpFoundation\Response;
public function indexAction()
{
$translated = $this->get('translator')->trans('Symfony2 is great');
return new Response($translated);
}
xliff
<!-- messages.fr.xliff -->
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="en" datatype="plaintext" original="file.ext">
<body>
<trans-unit id="1">
<source>Symfony2 is great</source>
<target>J'aime Symfony2</target>
</trans-unit>
</body>
</file>
</xliff>
including javascript
{% javascripts '@AcmeFooBundle/Resources/public/js/*' %}
<script type="text/javascript" src="{{ asset_url }}"></script>
{% endjavascripts %}
{% block javascripts %}
{% javascripts '@AcmeFooBundle/Resources/public/js/*' %}
<script type="text/javascript" src="{{ asset_url }}"></script>
{% endjavascripts %}
{% endblock %}
including CSS Stylesheets
{% javascripts '@AcmeFooBundle/Resources/public/js/*' %}
<script type="text/javascript" src="{{ asset_url }}"></script>
{% endjavascripts %}
{% block javascripts %}
{% javascripts '@AcmeFooBundle/Resources/public/js/*' %}
<script type="text/javascript" src="{{ asset_url }}"></script>
{% endjavascripts %}
{% endblock %}
Including images
{% image '@AcmeFooBundle/Resources/public/images/example.jpg' %}
<img src="{{ asset_url }}" alt="Example" />
{% endimage %}
using Named Assets
app/config/config.yml
assetic:
assets:
jquery_and_ui:
inputs:
- '@AcmeFooBundle/Resources/public/js/thirdparty/jquery.js'
- '@AcmeFooBundle/Resources/public/js/thirdparty/jquery.ui.js'
{% javascripts
'@jquery_and_ui'
'@AcmeFooBundle/Resources/public/js/*' %}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
security
app/config/security.yml
security:
firewalls:
secured_area:
pattern: ^/
anonymous: ~
http_basic:
realm: "Secured Demo Area"
access_control:
- { path: ^/admin/, roles: ROLE_ADMIN }
# Include the following line to also secure the /admin path itself
# - { path: ^/admin$, roles: ROLE_ADMIN }
providers:
in_memory:
memory:
users:
ryan: { password: ryanpass, roles: 'ROLE_USER' }
admin: { password: kitten, roles: 'ROLE_ADMIN' }
encoders:
Symfony\Component\Security\Core\User\User: plaintext
CMF
create CMF
php composer.phar create-project symfony-cmf/standard-edition cmf ~1.1
php app/console doctrine:database:create
php app/console doctrine:phpcr:init:dbal
php app/console doctrine:phpcr:repository:init
php app/console doctrine:phpcr:fixtures:load