데이터베이스와 교리 ORM


모든 애플리케이션에서 가장 일반적이고 어려운 작업 중 하나는 데이터베이스에서 데이터 정보를 읽고 유지하는 것입니다. Symfony 프레임워크는 데이터베이스 사용이 필요한 구성 요소를 통합하지 않지만 Doctrine이라는 타사 클래스 라이브러리와 긴밀하게 통합됩니다. Doctrine의 주요 목표는 데이터베이스 상호 작용을 보다 쉽고 유연하게 만드는 강력한 도구를 제공하는 것입니다.

이 장에서는 Symfony 프로젝트에서 풍부한 데이터베이스 상호 작용을 제공하기 위해 교리를 사용하는 방법을 배우게 됩니다.

교리와 심포니는 완전히 분리되어 있으며, 사용 여부는 선택 사항입니다. 이 장은 개체를 관계형 데이터베이스(예: MySQL, PostgreSQL 및 Microsoft SQL)에 매핑하는 것을 목표로 하는 Doctrine ORM에 관한 것입니다. 데이터베이스의 원시 쿼리를 사용하려는 경우 매우 간단합니다. Doctrine DBAL 사용 방법 문서를 참조하세요.

Doctrine ODM 라이브러리를 사용하여 MongoDB에 데이터를 유지할 수도 있습니다. 자세한 내용은 DoctrineMongoDBBundle을 참조하세요.

간단한 예: 제품

Doctrine의 작동 방식을 이해하기 위한 가장 쉬운 방법은 실제 적용을 살펴보는 것입니다. 이 섹션에서는 데이터베이스를 구성하고 Product 개체를 생성하고 이를 데이터베이스에 유지한 다음 검색해야 합니다. Product 对象,把它持久化到数据库,再取回它。

配置数据库 

真正开始之前,你需要配置你的数据库连接信息。按照惯例,这部分信息通常配置在 app/config/parameters.yml 文件中:

# app/config/parameters.ymlparameters:
    database_host:      localhost
    database_name:      test_project
    database_user:      root
    database_password:  password
 # ...


🎜 parameters.yml<을 통해 구성을 정의합니다. /code> , 단지 관례입니다. Doctrine을 구성할 때 해당 파일에 정의된 매개변수는 기본 구성 파일에서 참조됩니다. 🎜
<!-- app/config/config.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services"           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"           xmlns:doctrine="http://symfony.com/schema/dic/doctrine"           xsi:schemaLocation="http://symfony.com/schema/dic/services        http://symfony.com/schema/dic/services/services-1.0.xsd        http://symfony.com/schema/dic/doctrine        http://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd">     <doctrine:config>
        <doctrine:dbal                driver="pdo_mysql"                host="%database_host%"                dbname="%database_name%"                user="%database_user%"                password="%database_password%" />
    </doctrine:config></container>
// app/config/config.php$configuration->loadFromExtension('doctrine', array(
    'dbal' => array(
        'driver'   => 'pdo_mysql',
        'host'     => '%database_host%',
        'dbname'   => '%database_name%',
        'user'     => '%database_user%',
        'password' => '%database_password%',
    ),));
$  php bin/console doctrine:database:create
🎜 데이터베이스 정보를 별도의 파일로 분리하면 각 서버에 대해 서로 다른 버전을 쉽게 저장할 수 있습니다. 예를 들어 Apache의 구성 정보처럼 프로젝트 외부에 데이터베이스 구성(또는 민감한 정보)을 쉽게 저장할 수도 있습니다. 자세한 내용은 🎜서비스 컨테이너의 외부 매개변수 설정 방법🎜을 참조하세요. 🎜🎜

이제 Doctrine은 데이터베이스에 연결할 수 있으며, 다음 명령은 자동으로 빈 test_project 데이터베이스를 생성할 수 있습니다: test_project 数据库:

$  php bin/console doctrine:database:drop --force
$  php bin/console doctrine:database:create

设置数据库为UTF8

Symfony项目开始后,老练的程序员也会犯的一个错误是,忘了设置他们的数据库默认字符集和校对规则(charset and collation),最终变成latin类型,也就是多数数据库默认的。他们也许在第一次操作时会记得,但在后面的开发中敲打两行相关的常用命令之后就完全忘掉了:

[mysqld]#Version 5.5.3 introduced "utf8mb4", which is recommendedcollation-server     = utf8mb4_general_ci # Replaces utf8_general_cicharacter-set-server = utf8mb4            # Replaces utf8

设置UTF8为MySQL的默认字符集简单到只要在配置文件(一般是my.cnf文件)中加几行代码就可以了:

# app/config/config.ymldoctrine:
    dbal:
        charset: utf8mb4
        default_table_options:
            charset: utf8mb4
            collate: utf8mb4_unicode_ci

你还可以改变Doctrine的默认字符集,以便生成的SQL使用设置正确的字符集。

<!-- app/config/config.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services"           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"           xmlns:doctrine="http://symfony.com/schema/dic/doctrine"           xsi:schemaLocation="http://symfony.com/schema/dic/services        http://symfony.com/schema/dic/services/services-1.0.xsd        http://symfony.com/schema/dic/doctrine        http://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd">     <doctrine:config>
        <doctrine:dbal                charset="utf8mb4">
            <doctrine:default-table-option name="charset">utf8mb4</doctrine:default-table-option>
            <doctrine:default-table-option name="collate">utf8mb4_unicode_ci</doctrine:default-table-option>
        </doctrine:dbal>
    </doctrine:config></container>
// app/config/config.php$configuration->loadFromExtension('doctrine', array(
    'dbal' => array(
        'charset' => 'utf8mb4',
        'default_table_options' => array(
            'charset' => 'utf8mb4'
            'collate' => 'utf8mb4_unicode_ci'
        )
    ),));
# app/config/config.ymldoctrine:
    dbal:
        driver: pdo_sqlite
        path: "%kernel.root_dir%/sqlite.db"
        charset: UTF8

我们推荐避免使用Mysql的 uft8 字符集,因为它并不兼容4-byte unicode字符,如果字符串中有这种字符会被清空。不过这种情况被修复了,参考 新型utf8mb4字符集

如果你要用SQLite作为数据库,在path选项中设置你的数据库路径:

<!-- app/config/config.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services"           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"           xmlns:doctrine="http://symfony.com/schema/dic/doctrine"           xsi:schemaLocation="http://symfony.com/schema/dic/services        http://symfony.com/schema/dic/services/services-1.0.xsd        http://symfony.com/schema/dic/doctrine        http://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd">     <doctrine:config>
        <doctrine:dbal                driver="pdo_sqlite"                path="%kernel.root_dir%/sqlite.db"                charset="UTF-8" />
    </doctrine:config></container>
// app/config/config.php$container->loadFromExtension('doctrine', array(
    'dbal' => array(
        'driver'  => 'pdo_sqlite',
        'path'    => '%kernel.root_dir%/sqlite.db',
        'charset' => 'UTF-8',
    ),));
// src/AppBundle/Entity/Product.phpnamespace AppBundle\Entity; class Product{
    private $name;
    private $price;
    private $description;}

创建一个Entity类 

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

$  php bin/console doctrine:generate:entity

데이터베이스를 UTF8로 설정

Symfony 프로젝트가 시작된 후 숙련된 프로그래머가 저지르는 실수는 데이터베이스의 기본 문자 집합과 데이터 정렬(문자 집합 및 데이터 정렬)을 설정하는 것을 잊어버리고 결국 대부분의 데이터베이스 기본값인 라틴어 유형이 되는 것입니다. 처음 작동할 때는 기억할 수도 있지만 후속 개발에서 관련된 공통 명령 두 줄을 입력한 후에는 완전히 잊어버립니다.
// src/AppBundle/Entity/Product.phpnamespace 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;

UTF8을 MySQL의 기본 문자 집합으로 설정하는 것은 구성 파일에서 설정하는 것만큼 간단합니다. (보통 my.cnf 파일):

# src/AppBundle/Resources/config/doctrine/Product.orm.ymlAppBundle\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
생성된 SQL이 올바른 문자 세트를 사용하도록 Doctrine의 기본 문자 세트를 변경할 수도 있습니다.
<!-- src/AppBundle/Resources/config/doctrine/Product.orm.xml --><?xml version="1.0" encoding="UTF-8" ?><doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"                  xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping        http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">     <entity name="AppBundle\Entity\Product" table="product">        <id name="id" type="integer">            <generator strategy="AUTO" />        </id>        <field name="name" type="string" length="100" />        <field name="price" type="decimal" scale="2" />        <field name="description" type="text" />    </entity></doctrine-mapping>
/**
 * @IgnoreAnnotation("fn")
 */class Product// ...
$  php bin/console doctrine:schema:validate

Mysql의 uft8 문자 집합은 4바이트 유니코드 문자와 호환되지 않고 문자열에 해당 문자가 있으면 지워지기 때문에 사용하지 않는 것이 좋습니다. 하지만 이 상황은 수정되었습니다. 새로운 utf8mb4 문자를 참조하세요. 을 설정하세요.

🎜SQLite를 데이터베이스로 사용하려면 경로 옵션에서 데이터베이스 경로를 설정하세요. 🎜
$  php bin/console doctrine:generate:entities AppBundle/Entity/Product
# generates all entities in the AppBundle# 生成AppBundle下的全部entities$  php bin/console doctrine:generate:entities AppBundle
# generates all entities of bundles in the Acme namespace
# 生成Acme命名空间下的bundles的全部entities
$  php bin/console doctrine:generate:entities Acme
$  php bin/console doctrine:schema:update --force
🎜🎜

엔티티 클래스 만들기

🎜 일부 제품을 표시해야 하는 프로그램을 구축한다고 가정해 보겠습니다. Doctrine이나 데이터베이스에 대해 생각하지 않더라도 이러한 제품을 나타내려면 Product 개체가 필요하다는 것을 이미 알고 있습니다. AppBundle의 Entity 디렉토리에 이 클래스를 생성합니다. 🎜
// src/AppBundle/Controller/DefaultController.php // ...use AppBundle\Entity\Product;use Symfony\Component\HttpFoundation\Response; // ...public function createAction(){
    $product = new Product();
    $product->setName('Keyboard');
    $product->setPrice(19.99);
    $product->setDescription('Ergonomic and stylish!');     $em = $this->getDoctrine()->getManager();     // tells Doctrine you want to (eventually) save the Product (no queries yet)
    // 告诉Doctrine你希望(最终)存储Product对象(还没有语句执行)
    $em->persist($product);     // actually executes the queries (i.e. the INSERT query)
    // 真正执行语句(如,INSERT 查询)
    $em->flush();     return new Response('Saved new product with id '.$product->getId());}
🎜이 클래스 - 종종 "Entity"라고 불리며, 이는 🎜데이터를 보유하는 기본 클래스🎜를 의미합니다. - 매우 간단하며 비즈니스를 충족할 수 있습니다. 프로그램에 필요한 제품의 요구 사항. 이 클래스는 아직 데이터베이스에 저장할 수 없습니다. 단순한 PHP 클래스입니다. 🎜🎜🎜🎜🎜Doctrine의 개념을 배우고 나면 Doctrine에서 엔터티 클래스를 생성하도록 할 수 있습니다. 엔터티를 만드는 데 도움이 되는 몇 가지 대화형 질문이 표시됩니다. 🎜
public function showAction($productId){
    $product = $this->getDoctrine()
        ->getRepository('AppBundle:Product')
        ->find($productId);     if (!$product) {
        throw $this->createNotFoundException(
            'No product found for id '.$productId
        );
    }     // ... do something, like pass the $product object into a template
    // ... 做一些事,比如把 $product 对象传入模板}
🎜🎜

매핑 정보 추가

Doctrine을 사용하면 단순히 스칼라 데이터 행을 배열로 가져오는 대신 데이터베이스를 더 흥미로운 방식으로 사용할 수 있습니다. Doctrine을 사용하면 데이터베이스에서 전체 객체를 검색하고 동시에 전체 객체를 데이터베이스에 유지할 수 있습니다. Doctrine이 이를 구현하려면 데이터 테이블을 특정 PHP 클래스로 매핑해야 하며 해당 테이블의 열은 해당 PHP 클래스의 특정 속성에 매핑되어야 합니다.

1466153595_56497_19601_doctrine_image_1.png

이 매핑 정보를 "meatdata" 형식으로 제공해야 합니다. 이는 Product 클래스와 해당 속성이 특정 데이터에 Product 类及其属性应该如何 映射到 一个特定的数据表。这个metadata可以通过不同的格式来指定,包括YAML,XML或者通过DocBlock注释(译注:annotations)直接定义到 Product 类中:

$repository = $this->getDoctrine()
    ->getRepository('AppBundle:Product');
$repository = $this->getDoctrine()->getRepository('AppBundle:Product');
// query for a single product by its primary key (usually "id")// 通过主键(通常是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); 
// find *all* products / 查出 *全部* 产品$products = $repository->findAll();
$repository = $this->getDoctrine()->getRepository('AppBundle:Product'); // query for a single product matching the given name and price// 查询一件产品,要匹配给定的名称和价格$product = $repository->findOneBy(
    array('name' => 'Keyboard', 'price' => 19.99)); // query for multiple products matching the given name, ordered by price// 查询多件产品,要匹配给定的名称和价格$products = $repository->findBy(
    array('name' => 'Keyboard'),
    array('price' => 'ASC'));

一个bundle只可以接受一种metadata的定义格式。比如,不能把YAML的metadata定义和添加了注释(annotation)的PHP entity类混用。

表名是可选的,如果省略,将自动取决于entity类的名称。

Doctrine允许你选择广泛的字段类型,每一种都有自己的配置。可用字段类型的信息,参考 Doctrine字段类型参考。

你也可以查看Doctrine官方文档 Basic Mapping Documentation 以了解关于映射的所有细节信息。如果你使用annotation,你需要为所有annotation加挂 ORM (例如  ORMColumn(...) ),这在Doctrine文档中并未写明。你还需要去包容 use DoctrineORMMapping as ORM; 声明,它可以 import(导入) ORM annotation前缀。

小心Entity类名(或者其属性)同时也是一个SQL保留的关键字(如 groupuser )。例如,如果你的entity类名称为 Group매핑

되어야 하는 방법을 Doctrine에 정확히 알려주는 규칙 집합입니다. 시트. 이 메타데이터는 YAML, XML 등 다양한 형식으로 지정하거나 DocBlock 주석(주석: 주석)을 통해 Product 클래스에 직접 정의할 수 있습니다.
public function updateAction($productId){
    $em = $this->getDoctrine()->getManager();
    $product = $em->getRepository('AppBundle:Product')->find($productId);     if (!$product) {
        throw $this->createNotFoundException(
            'No product found for id '.$productId
        );
    }     $product->setName('New product name!');
    $em->flush();     return $this->redirectToRoute('homepage');}
$em->remove($product);$em->flush();
$repository = $this->getDoctrine()->getRepository('AppBundle:Product'); $product = $repository->find($productId);$product = $repository->findOneByName('Keyboard');
🎜번들은 하나의 메타데이터 정의 형식만 허용할 수 있습니다. 예를 들어 주석이 추가된 YAML 메타데이터 정의와 PHP 엔터티 클래스를 혼합할 수 없습니다. 🎜🎜🎜
🎜테이블 이름은 선택 사항이며, 생략할 경우 자동으로 엔터티 클래스 이름에 따라 달라집니다. 🎜🎜🎜🎜Doctrine을 사용하면 각각 고유한 구성이 있는 다양한 분야 유형 중에서 선택할 수 있습니다. 사용 가능한 필드 유형에 대한 자세한 내용은 교리 필드 유형 참조를 참조하세요. 🎜
🎜Doctrine 공식 문서 기본 매핑 문서를 보고 매핑에 대한 모든 세부 정보를 알아볼 수도 있습니다. 주석을 사용하는 경우 Doctrine 문서에 명시되지 않은 모든 주석에 ORM(예: ORMColumn(...))을 첨부해야 합니다. 또한 ORM 주석 접두어를 🎜import🎜할 수 있는 use DoctrineORMMapping as ORM; 문을 포함해야 합니다. 🎜🎜🎜
🎜Entity 클래스 이름(또는 해당 속성)도 SQL 예약 키워드(예: 그룹사용자). 예를 들어 엔터티 클래스 이름이 Group인 경우 기본적으로 테이블 이름은 그룹이 되며 이로 인해 일부 데이터베이스 엔진에서 SQL 오류가 발생할 수 있습니다. 이러한 이름을 올바르게 우회하는 방법을 알아보려면 예약된 SQL 키워드 설명서를 참조하세요. 선택적으로 데이터베이스의 스키마를 임의로 선택하고 이를 다른 테이블 이름이나 열 이름에 쉽게 매핑할 수 있습니다. 데이터베이스 및 속성 매핑 문서에 대한 클래스 생성을 참조하세요. 🎜🎜🎜

"주석을 사용하는" 다른 클래스 라이브러리나 프로그램(예: Doxygen)을 사용할 때 클래스에 @IgnoreAnnotation 주석을 추가하여 지시해야 합니다. 주석을 무시해야 하는 Symfony입니다. @IgnoreAnnotation 注释添加到类中,来指示Symfony应该忽略哪个annotation。

例如,要避免 @fn annotation抛出异常,添加下列注释:

$em = $this->getDoctrine()->getManager();$query = $em->createQuery(
    'SELECT p
    FROM AppBundle:Product p
    WHERE p.price > :price
    ORDER BY p.price ASC')->setParameter('price', 19.99); $products = $query->getResult();

创建entity之后,你应该使用以下命令来验证映射(mappings):

$product = $query->setMaxResults(1)->getOneOrNullResult();

生成Getters和Setters 

尽管Doctrine现在知道了如何持久化 Product 对象到数据库,但是类本身还不具备真正用途。因为 Product 仅仅是一个带有 private 属性的常规PHP类,你需要创建 public 的getter和setter方法(比如 getName() , setName($name) )以便在程序其他部分来访问它的属性(其属性是protected)。幸运的是,下面的命令可以自动生成这些模板化的方法:

$repository = $this->getDoctrine()
    ->getRepository('AppBundle:Product'); // createQueryBuilder() automatically selects FROM AppBundle:Product// and aliases it to "p"// createQueryBuilder() 自动从 AppBundle:Product 进行 select 并赋予 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();

该命令可以确保 Product 类所有的getter和setter都被生成。这是一个安全的命令行——你可以多次运行它,它只会生成那些不存在的getters和setters(即,不会替换已有的方法)。

重要提示下面这句话极其深刻,乃是活用Doctrine的关键。大家一定照做。

记得,doctrine entity generator生成的是简单的getters/setters。你应该复审那些已生成的方法,在必要时,添加逻辑进去,以满足你的程序之需求。

关于 doctrine:generate:entities 的更多内容

使用 doctrine:generate:entities 命令你可以:

  • 在entity类中生成getters和setters;

  • 在entity类配置了 @ORMEntity(repositoryClass=”…”) annotation的情况下生成所对应的repository类;

  • 为 1:n 或 n:m 生成合适的构造器。

doctrine:generate:entities 命令会保存原始 Product.php 文件的备份并命名为 Product.php~ 。 有些时候这个文件可能会引发“Cannot redeclare class”错误。它可以被安全删除。你还可以使用 –no-backup

예를 들어 @fn 주석으로 인해 예외가 발생하지 않도록 하려면 다음 주석을 추가하세요.

rrreee#🎜🎜 #

엔티티를 생성한 후 다음 명령을 사용하여 매핑을 확인해야 합니다.
rrreee
#🎜🎜#

게터 생성 및 Setter

#🎜🎜#Doctrine은 이제 제품을 유지하는 방법을 알고 있지만 그러나 클래스 자체에는 아직 실제 목적이 없습니다. Productprivate 속성이 있는 일반 PHP 클래스이므로 public getter 및 setter 메서드(예: getName( ), setName($name)) 프로그램의 다른 부분에서 해당 속성에 액세스합니다(해당 속성은 보호됩니다). 다행히 다음 명령은 이러한 템플릿 메서드를 자동으로 생성할 수 있습니다. #🎜🎜#rrreee#🎜🎜#이 명령을 사용하면 Product 클래스의 모든 getter 및 setter가 생성됩니다. 이것은 안전한 명령줄입니다. 여러 번 실행할 수 있으며 존재하지 않는 getter 및 setter만 생성합니다(즉, 기존 메서드를 대체하지 않습니다). #🎜🎜##🎜🎜#
#🎜🎜#중요 알림다음 문장은 매우 심오함은 교리를 활용하는 열쇠입니다. 모두가 그것을 해야 합니다. #🎜🎜##🎜🎜##🎜🎜#기억하세요. 교리 엔터티 생성기는 간단한 getter/setter를 생성합니다. 생성된 메서드를 검토하고 필요한 경우 애플리케이션의 요구 사항을 충족하는 논리를 추가해야 합니다. #🎜🎜##🎜🎜##🎜🎜##🎜🎜#

#🎜🎜#교리 관련 추가 정보:generate:entities#🎜🎜## 🎜🎜#doctrine:generate:entities 명령을 사용하면 다음을 수행할 수 있습니다. #🎜🎜#
  • #🎜🎜#엔티티 클래스에서 getter 및 setter 생성 #🎜🎜#
  • #🎜🎜#엔터티 클래스가 @ORMEntity(repositoryClass="...") 주석으로 구성되면 해당 저장소 클래스를 생성합니다. #🎜🎜#
  • < li>#🎜🎜#1:n 또는 n:m에 적합한 생성자를 생성합니다. #🎜🎜#
#🎜🎜# doctrine:generate:entities 명령은 원본 Product.php 파일과 이름의 백업을 저장합니다. Product.php~입니다. 때때로 이 파일로 인해 "클래스를 다시 선언할 수 없습니다" 오류가 발생할 수 있습니다. 안전하게 제거할 수 있습니다. –no-backup 옵션을 사용하여 이러한 백업 파일이 생성되지 않도록 할 수도 있습니다. #🎜🎜##🎜🎜# 이 명령은 #🎜🎜# 필요 #🎜🎜# 필요하지 않습니다(의존). getter와 setter를 직접 작성할 수도 있습니다. 이러한 메서드를 만드는 것은 개발 중에 일반적인 작업이므로 이 옵션은 시간을 절약하기 위해서만 존재합니다. #🎜🎜##🎜🎜##🎜🎜#

또한 번들 또는 엔터티 네임스페이스(Docrine 매핑 정보가 포함된 모든 PHP 클래스)의 알려진 모든 엔터티에 대해 getter 및 setter를 생성할 수 있습니다.

rrreee

데이터 테이블/스키마 만들기

이제 사용 가능한 < 매핑 정보가 포함된 code>Product 클래스이므로 Doctrine은 이를 유지하는 방법을 정확히 알 수 있습니다. 물론 아직 라이브러리에는 해당 제품 데이터 테이블이 없습니다. 다행히 Doctrine은 모든 데이터 테이블을 자동으로 생성할 수 있습니다. 이렇게 하려면 다음 명령을 실행하세요. Product 类,因此Doctrine确切地知道如何持久化它。当然,你还没有相应的 product 数据表在库中。幸运的是,Doctrine可以自动创建所有的数据表。要这么做,运行以下命令:

rrreee

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

一个利用此功能之优势的更佳方式是通过 migrations,它允许你生成这些SQL语句,并把它们并存储到migration类中,这些类能够有序运行在你的生产环境中,进而安全可靠地更新和追踪数据库的schema改变。

不管你是否利用了数据库迁移,doctrine:schema:update 命令只适合在开发环境中使用。它不应该被用于生产环境。

现在你的数据库中有了一个全功能的product表,它的列与你指定的元数据相匹配。

持久化对象到数据库 

现在你有了一个Product实体和与之映射的product数据库表。你可以把数据持久化到数据库里。在Controller内,它非常简单。添加下面的方法到bundle的DefaultController中。

现在你已经把 Product entity 映射到与之对应的 product 表中,你已经准备好把 Product 对象持久化到数据库中。在控制器里面,这极其简单。向bundle的 DefaultControllerrrreee

정말로 이 명령은 놀라울 정도로 강력합니다. 데이터베이스가 이론상(엔티티의 매핑 정보를 기반으로 함)과 실제로 어떻게 보이는지 비교한 다음 필요한 SQL 문을 수행하여 데이터베이스 스키마를 해당 데이터베이스 스키마로 업데이트합니다. 되어야 한다. 즉, 제품에 "매핑 메타데이터"가 포함된 새 속성을 추가하고 이 작업을 실행하면 필수 "ALTER TABLE" 문이 이미 기존 <에 해당 새 열을 추가합니다. 코드>제품
테이블. 🎜 데이터베이스 마이그레이션 사용 여부에 관계없이 doctrine:schema:update 명령은 개발 환경에서만 사용하기에 적합합니다. 프로덕션 환경에서는 사용하면 안 됩니다. 🎜🎜🎜🎜이제 데이터베이스에 지정한 메타데이터와 일치하는 열이 포함된 완전한 기능을 갖춘 제품 테이블이 생겼습니다. 🎜🎜데이터베이스 ¶🎜🎜🎜에 대한 영구 개체 이제 Product 엔터티와 이에 매핑된 제품 데이터베이스 테이블이 있습니다. 데이터를 데이터베이스에 유지할 수 있습니다. 컨트롤러 내부는 매우 간단합니다. 번들의 DefaultController에 다음 메서드를 추가합니다. 🎜🎜이제 제품 엔터티를 해당 제품 테이블에 매핑했으므로 제품 개체는 데이터베이스에 유지됩니다. 컨트롤러 내부에서는 매우 간단합니다. 번들의 DefaultController에 다음 메서드를 추가합니다. 🎜rrreee🎜🎜이 예제를 따르는 경우 경로를 생성하고 이 작업이 실행되는 것을 확인하도록 지정해야 합니다. 🎜🎜

이 예에서는 컨트롤러에서 Doctrine의 getDoctrine() 메서드를 사용하는 방법을 보여줍니다. 이는 doctrine 서비스를 빠르게 꺼내는 방법입니다. 이 서비스를 귀하의 서비스에 주입하면 어디서나 교리를 사용할 수 있습니다. 서비스 생성에 대한 자세한 내용은 서비스 컨테이너doctrine 服务的快捷方法。若你在服务中注入此服务,即可在任意地方使用doctrine。参考 服务容器 以了解更多创建服务之内容。

深入分析一下前面的例子:

  • 10-13行 在此处实例化,并且像其他常规PHP对象一样去使用 $product 对象。
  • 15行 这一行取出了Doctrine的 entity manager 对象,它负责处理数据库的持久化(译注:写入)和取出对象的过程。
  • 18行 persist($product) 调用,告诉Doctrine去 "管理" $product 对象。它 没有 引发对数据库的请求。
  • 21行flush() 方法被调用时,Doctrine会遍历它管理的所有对象以确定是否需要被持久化到数据库。本例中, $product 对象的数据在库中并不存在,因此entity manager要执行 INSERT 请求,在 product 表中创建一个新行。

事实上,由于Doctrine了解你的全部被管理的实体,当你调用 flush() 方法时,它会计算出所有的变更集合(changeset),并按正确顺序执行语句。它利用准备好的缓存语句以略微提高性能。比如,你要持久化总数为100的 Product 对象,然后调用 flush() 方法,Doctrine将用一个单一的prepare语法对象,来执行100次 INSERT 请求。

如果 flush() 调用失败,一个 DoctrineORMORMException를 참조하세요.

이전 예제를 자세히 분석해 보겠습니다.
  • 10-13행 여기에서 인스턴스화하고 다른 일반 PHP 객체처럼 사용합니다.< code class= "notranslate">$product 개체.
  • 15행 이 줄은 데이터베이스 지속성(주석: 쓰기) 처리 및 객체 검색을 담당하는 Doctrine의 엔티티 관리자 객체를 가져옵니다.
  • 18행 persist($product)가 호출되어 Doctrine에 를 "관리"하라고 지시합니다. $ 제품 객체. 데이터베이스에 대한 요청을 트리거합니다.
  • 21행 flush() 메서드가 호출되면 Doctrine은 관리하는 모든 객체를 순회하여 필요한지 여부를 결정합니다. 데이터베이스에 대한 지속성을 유지합니다. 이 예에서는 $product 개체의 데이터가 라이브러리에 존재하지 않으므로 항목 관리자가 INSERT 요청, < 코드 클래스="notranslate">제품 테이블에 새 행 생성.
🎜
🎜사실 Doctrine은 관리되는 모든 엔터티를 알고 있으므로 flush() 메서드를 호출하면 모든 변경 집합(changeset)을 계산하고 올바른 순서로 명령문을 실행합니다. 성능을 약간 향상시키기 위해 준비된 캐시 문을 활용합니다. 예를 들어, 총 100개의 Product 개체를 유지하고 flush() 메서드를 호출하려는 경우 Doctrine은 단일 준비 구문 개체를 사용하여 를 실행합니다. >INSERT 요청이 100번 발생했습니다. 🎜🎜🎜🎜

flush() 호출이 실패하면 DoctrineORMORMException 예외가 발생합니다. 🎜트랜잭션 및 동시성🎜을 참조하세요. 🎜🎜🎜

객체를 생성하고 업데이트할 때의 작업 흐름은 동일합니다. 다음 섹션에서는 레코드가 데이터베이스에 이미 존재하는 경우 Doctrine이 Update 문을 자동으로 자동으로 실행하는 방법을 살펴보겠습니다. Update 语句的。

Doctrine提供了一个类库,允许你程序化地加载测试数据到你的项目中(即,"fixture data",固定的数据)。参考 DoctrineFixturesBundle 以了解更多。

从数据库中获取对象 

从数据库中取回对象就更简单了,举个例子,假如你配置了一个路由,基于产品的 id 来显示特定的 Product 对象:

rrreee

你可以使用 @ParamConverter 快捷注释,毋须编写任何代码即可实现同样的功能。参考 FrameworkExtraBundle 以了解更多。

当你要查询某个特定类型的对象时,你总是要使用它的”respository”(宝库)。你可以认为Respository是一个PHP类,它的唯一工作就是帮助你从那个特定的类中取出entity。对于一个entity类,要访问其宝库,通过:

rrreee

appBundle:Product 是快捷写法,你可以在Doctrine里随处使用,以替代entity类的FQCN类名(如 AppBundleEntityProduct )。只要你的entity存放在bundle的 Entity 命名空间下,它就会工作。

一旦有了Repository对象,你就可以访问它的全部有用的方法了。

rrreee

当然,你也可以使用复杂的查询,参考 对象查询 小节 。

你也可以有效利用 findByfindOneBy

Doctrine은 프로그래밍 방식으로 테스트 데이터를 프로젝트에 로드할 수 있는 클래스 라이브러리를 제공합니다(예: "픽스처 데이터", 고정 데이터). 자세히 알아보려면 DoctrineFixturesBundle을 참조하세요.

데이터베이스에서 개체 가져오기

1466160351_18163_67861_doctrine_web_debug_toolbar (1).png데이터베이스에서 개체 가져오기가 더 쉽습니다. 예를 들어 , 제품의 id를 기반으로 특정 Product 개체를 표시하도록 경로를 구성하는 경우:

rrreee

@ParamConverter를 사용할 수 있습니다. 빠른 댓글 , 코드를 작성하지 않고도 동일한 기능을 수행할 수 있습니다. 자세한 내용은 FrameworkExtraBundle을 참조하세요.

특정 유형의 개체를 쿼리하려면 항상 "저장소"를 사용해야 합니다. 저장소를 특정 클래스에서 엔터티를 가져오는 데 도움을 주는 유일한 작업을 수행하는 PHP 클래스로 생각할 수 있습니다. 엔터티 클래스의 경우 보물 창고에 액세스하려면 다음을 전달하세요.
rrreee
🎜appBundle:Product는 Doctrine의 어느 곳에서나 사용할 수 있는 바로가기 방법입니다. 엔터티 클래스의 FQCN 클래스 이름(예: AppBundleEntityProduct)입니다. 엔터티가 번들의 Entity 네임스페이스에 저장되어 있으면 작동합니다. 🎜🎜🎜Repository 개체가 있으면 모든 유용한 메서드에 액세스할 수 있습니다. 🎜rrreee🎜
🎜물론 복잡한 쿼리를 사용할 수도 있습니다. 객체 쿼리 섹션 . 🎜🎜🎜🎜findByfindOneBy 메서드를 효과적으로 사용하여 여러 조건에 따라 개체를 쉽게 가져올 수도 있습니다. 🎜rrreee🎜🎜🎜페이지를 렌더링할 때 웹 디버그 도구 모음의 오른쪽 하단에서 많은 쿼리를 볼 수 있습니다. 🎜🎜🎜🎜🎜아이콘을 클릭하면 생성된 정확한 쿼리를 보여주는 프로파일러가 열립니다. 🎜🎜페이지 쿼리가 50개를 초과하면 아이콘이 노란색으로 변합니다. 이는 뭔가 잘못되었음을 나타냅니다. 🎜🎜🎜

객체 업데이트

Doctrine에서 객체를 얻은 후에는 업데이트하기가 쉽습니다. 제품 ID를 컨트롤러의 업데이트 작업에 매핑하는 경로가 있다고 가정합니다.

rrreee

객체 업데이트에는 다음 세 단계가 포함됩니다.

  1. Doctrine에서 객체를 검색합니다.
  2. 객체 수정
  3. 엔티티 관리자의 <코드를 호출합니다. 클래스 ="notranslate">flush() 메서드. flush() 方法。

注意调用 $em->persist($product) 是不必要的。回想一下,这个方法只是告诉Doctrine去管理或者“观察” $product 对象。此处,因为你已经取到了 $product 对象了,它已经被管理了。

删除对象 

删除一个对象十分类似,但需要从entity manager调用 remove() 方法:

rrreee

你可能已经预期,remove() 方法通知Doctrine你想从数据库中删除指定的entity。真正的 DELETE 查询不会被真正执行,直到 flush() 方法被调用。

对象查询 

你已经看到repository对象是如何让你执行一些基本查询而毋须做任何工作了:

rrreee

当然,Doctrine 也允许你使用Doctrine Query Language(DQL)来写一些复杂的查询,DQL类似于SQL,只是它用于查询一个或者多个entity类的对象(如 product),而SQL则是查询一个数据表中的行(如 product )。

在Doctrine中查询时,你有两个主要选择:编写纯正的Doctrine查询(DQL) 或者 使用Doctrine的Query Builder。

使用DQL进行对象查询 

假设你要查询价格高于 19.99 的产品,并且按价格从低到高排列。你可以使用DQL,Doctrine中类似原生SQL的语法,来构造一个用于此场景的查询:

rrreee

如果你习惯了写SQL,那么对于DQL也会非常自然。它们之间最大的不同就是你需要就“select PHP对象”来进行思考,而不是数据表的行。正因为如此,你要 AppBundle:Product 这个 entity (可选的一个AppBundleEntityProduct 类的快捷写法)来select,然后给entity一个 p 的别名。

注意 setParameter() 方法。当使用Doctrine时,通过“占位符”来设置任意的外部值(上面例子的 :price

$em->persist($product) 호출은 불필요합니다. 이 메소드는 단순히 Doctrine에게 $product 객체를 관리하거나 "관찰"하도록 지시한다는 점을 기억하세요. 여기서는 이미 $product 객체를 획득했기 때문에 이미 관리되고 있습니다.
객체 삭제 ¶🎜🎜🎜객체 삭제는 매우 유사하지만 remove() 엔터티 관리자의 메서드 :🎜rrreee🎜 예상한 대로 remove() 메서드는 데이터베이스에서 지정된 엔터티를 제거하고 싶다고 Doctrine에 알립니다. 실제 DELETE 쿼리는 flush() 메서드가 호출될 때까지 실제로 실행되지 않습니다. 🎜🎜

객체 쿼리 ¶🎜

🎜저장소 객체를 사용하여 별도의 작업 없이 몇 가지 기본 쿼리를 수행할 수 있는 방법을 살펴보았습니다. 모든 작업 수행: 🎜rrreee🎜 물론 Doctrine에서는 DQL(Doctrine Query Language)을 사용하여 일부 복잡한 쿼리를 작성할 수도 있습니다. 단, DQL은 하나 이상의 엔터티 클래스 객체(예: 제품), SQL은 데이터 테이블(예: 제품)의 행을 쿼리합니다. 🎜🎜Doctrine에서 쿼리할 때 두 가지 주요 옵션이 있습니다. 순수 Doctrine 쿼리(DQL)를 작성하거나 Doctrine의 쿼리 빌더를 사용하는 것입니다. 🎜🎜객체 쿼리에 DQL 사용 ¶🎜🎜🎜 가격이 19.99보다 높은 제품을 쿼리한다고 가정해 보겠습니다. 프레스 가격은 가장 낮은 가격부터 가장 높은 가격 순으로 정렬됩니다. Doctrine의 기본 SQL과 유사한 구문인 DQL을 사용하여 이 시나리오에 대한 쿼리를 구성할 수 있습니다.🎜rrreee🎜SQL 작성에 익숙하다면 DQL도 매우 자연스러울 것입니다. 이들 사이의 가장 큰 차이점은 데이터 테이블의 행이 아닌 "PHP 개체 선택"의 관점에서 생각해야 한다는 것입니다. 이 때문에 AppBundle:Product(선택적으로 AppBundleEntityProduct 클래스에 대한 바로가기)에서 엔티티시작하여 선택한 다음 엔터티에 p라는 별칭을 지정합니다. 🎜🎜
🎜 setParameter() 메소드에 주목하세요. Doctrine을 사용할 때 SQL 주입 공격을 방지하려면 "자리 표시자"(위 예에서는 :price)를 통해 임의의 외부 값을 설정하는 것이 좋습니다. 🎜🎜🎜

getResult() 메서드는 결과 배열을 반환합니다. 결과를 얻으려면 getSingleResult()(결과가 없을 때 이 메서드는 예외를 발생시킵니다) 또는 getOneOrNullResult()를 사용할 수 있습니다. getResult() 方法返回一个结果数组。要得到一个结果,可以使用getSingleResult()(这个方法在没有结果时会抛出一个异常)或者 getOneOrNullResult()

rrreee

DQL语法强大到令人难以置信,允许轻松地在entity之间进行join(稍后会覆盖relations)和group等。参考 Doctrine Query Language 文档以了解更多。

使用Doctrine's Query Builder进行对象查询 

不去写DQL的大字符串,你可以使用一个非常有用的QueryBuilder对象,来构建那个字符串。当你的查询取决于动态条件时,这很有用,因为随着你的连接字符串不断增加,DQL代码会越来越难以阅读:

rrreee

QueryBuilder对象包含了创建查询时的所有必要方法。通过调用getQuery()方法,query builder将返回一个标准的Query对象,可用于取得请求的结果集。

Query Builder更多信息,参考Doctrine的 Query Builder 文档。

把自定义查询组织到Repository类中 

前面所有的查询是直接写在你的控制器中的。但对于程序的组织来说,Doctrine提供了一个专门的repository类,它允许你保存所有查询逻辑到一个中心位置。

参考 如何创建自定义Repository类 以了解更多。

配置 

Doctrine是高度可配置的,虽然你可能永远不会去关心那些选项。要了解Doctrine的配置信息,参考 config reference。

Doctrine字段类型参考 ¶

Doctrine配备了大量可用的字段类型。每一个都能把PHP数据类型映射到特定的字段类型中,无论你使用什么数据库。对于每一个字段类型, Column 都可以被进一步配置,可以设置 lengthnullable 行为,namerrreee

DQL 구문은 다음과 같습니다. 믿을 수 없을만큼 강력하며 엔터티(나중에 관계에서 다룸), 그룹 등을 쉽게 조인할 수 있습니다. 교리 쿼리 언어를 참조하세요. 자세히 알아보려면 문서를 참조하세요.

개체 쿼리에 Doctrine의 쿼리 작성기를 사용하세요

DQL의 큰 문자열을 작성하지 마세요. 매우 유용한 QueryBuilder 개체를 사용하여 해당 문자열을 작성할 수 있습니다. 이는 연결 문자열이 계속 증가함에 따라 DQL 코드를 읽기가 점점 어려워지기 때문에 쿼리가 동적 조건에 의존할 때 유용합니다.

rrreee

QueryBuilder 개체에는 쿼리를 생성할 때 필요한 모든 메서드가 포함되어 있습니다. getQuery() 메서드를 호출하면 쿼리 빌더는 요청된 결과 집합을 얻는 데 사용할 수 있는 표준 쿼리 개체를 반환합니다.
🎜🎜쿼리 빌더 자세한 내용은 Doctrine의 쿼리 빌더 문서. 🎜

사용자 정의 쿼리를 저장소 클래스

🎜모든 이전 쿼리는 컨트롤러에 직접 기록됩니다. . 그러나 프로그램 구성을 위해 Doctrine은 모든 쿼리 논리를 중앙 위치에 저장할 수 있는 전용 저장소 클래스를 제공합니다. 🎜🎜자세한 내용은 사용자 정의 저장소 클래스를 만드는 방법을 참조하세요. 🎜🎜구성 🎜🎜Doctrine은 고도로 구성 가능하지만 해당 옵션은 신경 쓰지 않을 수도 있습니다. 교리 구성 정보는 구성 참조를 확인하세요. 🎜🎜Doctrine 필드 유형 참조 ¶🎜🎜Doctrine에는 사용 가능한 필드 유형이 많이 포함되어 있습니다. 어떤 데이터베이스를 사용하든 상관없이 각각은 PHP 데이터 유형을 특정 필드 유형에 매핑합니다. 각 필드 유형에 대해 길이, null 허용 동작, 이름 또는 기타 옵션을 설정하도록 을 추가로 구성할 수 있습니다. 사용 가능한 필드 유형 목록은 매핑 유형 설명서를 참조하세요. 🎜🎜Associations and Relations ¶🎜🎜Doctrine은 데이터베이스 관계(연관이라고도 함)를 관리하는 데 필요한 모든 기능을 제공합니다. 더 많은 정보를 보려면 교리 연관/관계를 사용하는 방법을 참조하십시오. 🎜

요약 ¶

Doctrine을 사용하면 객체와 이를 애플리케이션에 적용하는 방법에 집중할 수 있으며 데이터베이스 지속성은 두 번째입니다. 이는 Doctrine을 사용하면 모든 PHP 개체를 사용하여 데이터를 저장할 수 있고 "메타데이터 매핑" 정보를 사용하여 개체의 데이터를 특정 데이터 테이블에 매핑할 수 있기 때문입니다.

Doctrine에는 관계, 복잡한 쿼리, 이벤트 모니터링 등 학습을 기다리는 많은 강력한 기능이 있습니다.