您的位置:澳门402永利com > 编程应用 > 数据库和Doctrine,Doctrine2基本选取

数据库和Doctrine,Doctrine2基本选取

发布时间:2019-09-23 20:45编辑:编程应用浏览(187)

    CodeIgniter Doctrine2基本使用

    以前写了一篇小说叫作《CodeIgniter 3.0整合Doctrine2》里面介绍了一些轻松的Doctrine2的用法,当然笔者也曾经把它利用到项目上去了。上边作者就写一些Doctrine2在CodeIgniter框架上的一部分使用及感受吧...

    在品种上行使了一段时间后开掘,好像代码比格变高了呃,连同事都说你这种写法好像极高级的样纸呃,並且代码特别雅观。即使以后接纳的广度还不是非常的大,但稳步的笔者会把它给移动到独具模块上去,现新职能或新模块都应用了Doctrine ORM结构。新的结构确实能够少写过多代码,尽管运转的频率并不怎么高,可是总会有艺术化解的。上边作者将对部分自个儿用过或未来正值用的一部分东西举行局地简练的讲街,自身文采烂,本领轻松看不知情也请谅解谅解...

      对于其余应用程序来说最棒常见最具挑衅性的任务,正是从数据库中 读取和悠久化数据消息。固然symfony完整的框架未有暗中同意集成ORM,可是symfony规范版,集成了成都百货上千程序,还自带集成了Doctrine那样 多个库,首要的指标是给开垦者三个强劲的工具,让你职业起来更为便于。在本章,你会学会doctrine的主干思想何况可以领会怎么轻便使用数据库。

    Doctrine2 轻巧的用法

      Doctrine能够完全脱离symfony使用,何况在symfony中是不是选拔也是可选的。本章首要掌握Doctrine的ORM,其指标是让您的对 象映射到数据库中(如MySQL, PostgreSQL和Microsoft SQL)。假若您欣赏使用原本的数据库查询,那很轻易,能够领悟cookbook 中的”How to Use Doctrine DBAL“。
    你也足以行使Doctrine ODM库将数据漫长化到MongoDB。更加多音讯请参阅”DoctrineMongoDBBundle“。

    创制三个实体 Entity

    举个例子大家以后亟需三个水渠channel的数据表,表里面有成都百货上千字段那我在model/Entity目录创设叁个Channel.php的文件

    // Channel.php 部分代码namespace Entity;use EntityRepositoryChannelRepository;/** * Channel * * @Table(name="channel", options={"collate"="utf8_general_ci","charset"="utf8"}, uniqueConstraints={@UniqueConstraint(name="channel_code", columns={"channel_code"})}) * @Entity(repositoryClass="EntityRepositoryChannelRepository") */ class Channel {  /**     * @var integer     *     * @Column(name="channel_id", type="integer", nullable=false, options={"comment": "渠道id"})     * @Id     * @GeneratedValue(strategy="NONE")     */    private $channelId;    /**     * @var integer     *     * @Column(name="channel_tag", type="integer", nullable=false, options={"comment": "渠道标识"})     * @Id     * @GeneratedValue(strategy="NONE")     */    private $channelTag;    /**     * @var string     *     * @Column(name="channel_name", type="string", length=128, nullable=false, options={"comment": "渠道名称"})     */    private $channelName;        /**     * @var string     *     * @Column(name="channel_time", type="datetime", nullable=false, options={"comment": "渠道创建时间"})     */    private $channelTime;        public function __construct()    {    $this->channelTime = new DateTime;    } }
    

    OK 先写四个字段吧,然后大家进来./app目录推行php doctrine命令会突显一些doctrine能够行使的一部分指令,然后大家未来要创立每种字段的 getter 和 setter 方法,所以大家实行命令

    php doctrine orm:generate:entities ./models/ --update-entities="true" --generate-methods="true"

    当然能够实行php doctrine orm:generate:entities --help查看 orm:generate:entities 的用法;--update-entities="true"表示供给立异实体--generate-methods="true"表示更新或更动每一种成员属性的 getter 和 setter 方法(作者猜的,因为以前不生成方法时自己找了好长期才掌握是怎么回事),对了这里还写了贰个构造函数,缺省设置了二个日子,当 new Channnel()的时候就不再须求set这几个日子字断了

    改变效率后Channel那些实体应该会多出7个主意:

    /**     * Get channelId     *     * @return integer     */    public function getChannelId()    {        return $this->channelId;    }    /**     * Set channelTag     *     * @param integer $channelTag     *     * @return Channel     */    public function setChannelTag($channelTag)    {        $this->channelTag = $channelTag;        return $this;    }    /**     * Get channelTag     *     * @return integer     */    public function getChannelTag()    {        return $this->channelTag;    }    /**     * Set channelName     *     * @param string $channelName     *     * @return Channel     */    public function setChannelName($channelName)    {        $this->channelName = $channelName;        return $this;    }    /**     * Get channelName     *     * @return string     */    public function getChannelName()    {        return $this->channelName;    }/**     * Set channelTime     *     * @param DateTime $channelTime     *     * @return Detail     */    public function setCreateTime($channelTime)    {        $this->channelTime = $channelTime;        return $this;    }    /**     * Get channelTime     *     * @return DateTime     */    public function getChannelTime()    {        return $this->channelTime;    }
    

    getter 是收获这一个字段的值,setter 是安装该字段的值,大家回到地点的积极分子属性看举个例子:

    /**     * @var string     *     * @Column(name="channel_name", type="string", length=128, nullable=false, options={"comment": "渠道名称"})     */    private $channelName;
    

    表明里有@var string本条象征它回到的会是哪些,这不主要,重要的看下边那一个@Column以此很注重,是必得设置的;括号里边正是对那几个成员属性的有关安装也便是这些字段的习性。

    • name: 表字段名
    • type: 表字段类型(string,integer,datetime,text,bigint等等)
    • length: 表字段长度
    • nullable: 是不是为空(true or false)
    • unique: 是或不是独一(true or false)
    • precision: (临时不明了是干啥的只设置过0)
    • scale: (与上个字段同样为0啊)
    • options: 这里能够设置过多事物,我好像只设置过 commint 跟 default 那五个参数

    OK精晓下面的东西后大家就生成SQL语句吧试行命令php doctrine orm:schema-tool:create --dump-sql生成建表语句,固然想间接创造表的话把前边的参数--dump-sql去掉就行了;php doctrine orm:schema-tool:update --dump-sql那条命令与地点生成SQL语句的指令一样那是打字与印刷出有更新的字段假使不想打字与印刷把前边的参数--dump-sql去掉就一贯更新数据库表了;

    如此那般我们表就建好了;

    多少个轻巧的例子:一个成品
    摸底Doctrine是怎么办事的最简便易行的主意正是看三个实际的行使。在本章,你须要布署你的数据库,创制贰个Product对象,长久化它到数据库并且把它抓取回来。

    Repository

    在最上面包车型客车Channel类的笺注里有未有开掘@Entity(repositoryClass="EntityRepositoryChannelRepository")那样一段参数; 这一个便是足以友善增加的库,也就一定于本身在CI框架里写的MODEL类,假若我们要动用它的话供给执行一条创制对它实行创办:

    php doctrine orm:generate:repositories ./model

    实施上边命令后会把./model上边包车型地铁富有实体假如设置了@Entity的实例全体创办贰个Repository 类库;

    // ./app/model/Entity/Repository/ChannelRepository.phpnamespace EntityRepository;use DoctrineORMEntityRepository;//use DoctrineORMQueryExprJoin;/** * ChannelRepository * * This class was generated by the Doctrine ORM. Add your own custom * repository methods below. */class ChannelRepository extends EntityRepository{}
    

    下一场我们再回来 Channel 实体把刚刚创设的 ChannelRepository 库给援用进来并接二连三它;

    use EntityRepositoryChannelRepository;class Channel extends ChannelRepository{}
    

    那样的话,当大家加载贰个实体后就足以兑现那几个实体里本人写的强大方法了,非常方便呢,前面小编会讲;

    OK成立实体宗旨的主意差不离即是上在这么些,如有不明白的地点请我们在上边辩论区留言。。。

    配置数据库

    加载实体

    既然大家实体及实体库已经创办好了,那要怎么样运用它吧?

    首先先把要求用的那么些实体给加载进来,大家得以应用:$this->em->getRepository措施,当然前提是你必须先加载Doctrine这几个类库小说《CodeIgniter 3.0整合Doctrine2》好像有讲,能够去探访,不想看的话小编下边再写一下

    末尾写的 $this->em 的缘由
    平日大家在CI创立二个调控器时索要持续三个父调控器一般在 ./app/core/MY_Controller.php 不要问笔者干什么要这么写,不明了的回到把CodeIgniter框架抄写一次
    下一场大家在 MY_Controller 控制器的 __function() 方法载入 Doctrine 扩充类能够参见下边代码

    // ./app/core/MY_Controller.phpclass MY_Controller extends Controller {protected $em;function __construct(){parent::__construct();$this->load->library('doctrine');        /** @var  $em DoctrineORMEntityManager */        $em = $this->doctrine->em;        $this->em = $em;}}
    

    下一场我们就足以动用$em那几个成员了;

    要怎么着选取啊?

    诸如大家创设叁个调整器就叫 channel.php 好了

    class Channel extends MY_Controller{function __construct(){parent::__construct();}public function index(){/** @var  $channelRepository EntityChannel */$channelRepository = $this->em->getRepository('EntityChannel');$channelRepository->findAll();}}
    

    为什么要加/** @var $channelRepository EntityChannel */那般一个讲明呢?

    世家可别小看这种注释,很有用的,不信的话你按住command+鼠标左键点一下试跳(在差不离IDE上都是永葆的,Sublime Text也能够运用)

    好了,加载实体基本上便是是讲完了。

    在你实在起始以前,你需求安顿你的数据库链接音信。根据惯例,那么些音信平日配置在app/config/parameters.yml文件中:

    操作实体

    地点大家曾经把实体给加载进来了,现在我们要对数据库过行相关操作;其实呢大家操作实体就一定于是在操作数据库表,每贰个实体就一定于是一张表,它于表是一种炫人眼目关系。

    # app/config/parameters.yml
    parameters:
        database_driver:    pdo_mysql
        database_host:      localhost
        database_name:      test_project
        database_user:      root
        database_password:  password
    
    # ...
    
    插入一条数据

    持入一条数据首先须要把那些实体实例化,也正是new一下那几个实体大家技能运用它,举个例子以下代码:

    /** @var  $channel EntityChannel */$channel = new EntityChannel();$channel->setChannelTag()->setChannelName();$this->em->persist( $channel );$this->em->flush();
    

    OK笔者来大约的教学一下方面包车型地铁代码,这里大家须求呢。大家清楚那张表一共有两个字段分别是

    • channelId
    • channelTag
    • channelName
    • channelTime

    然后大家必要各自对那个字段设置有些值,那大家就必要运用EntityChannel以此实体里恰恰生成的setter方法了。 那为啥本身只set了两直字段呢?

    1. channel_id 是二个主键大家不必要对它实行操作,能够看到主建是未有setter方法的之所以没有须要安装那么些字段的值,推行前它是空的只要成功拷入数据后那几个字段就能够是刚刚插入后归来的ID
    2. channel_time 下面已经讲到了 大家在EntityChannel以此实体的构造函数里早就对它实行赋值了,所以它是有内容的,不信的话你var_dump其一实体看它的成员的值

    安装完后大家供给调用$this->em->persist那人方法把设置好的EntityChannel那一个实体塞进去,注意:此时并不曾实行SQL语句步入数据。大家要求调用一下$this->em->flush()那么些方法实行SQL语句,借使想看它生成的是何许的SQL的话能够进去数据库输入以下命令:

    • show variables like '%gene%';
    Variable_name Value
    general_log OFF
    general_log_file /opt/rh/mysql55/root/var/lib/mysql/default.log

    我们能够观察后天具有的数据库操作日志状态是OFF大家须求所它设置成ON,实行以下命令

    • set global general_log = ON;

    /opt/rh/mysql55/root/var/lib/mysql/default.log以此就是操作日志,大家得以tail -f一转眼它然后能够可知到后头大家地数据库的具备操作了。

     将安顿消息定义到parameters.yml仅仅是多个惯例。定义在该文件中的配置新闻将会被主配置文件在设置Doctrine时援引。

    询问操作

    原作链接:

    # app/config/config.yml
    doctrine:
        dbal:
            driver:   "%database_driver%"
            host:     "%database_host%"
            dbname:   "%database_name%"
            user:     "%database_user%"
            password: "%database_password%"
    

    由此把数据库音讯分别到叁个一定的文书中,你能够很轻巧的为每一个服务器保存差别的版本。你也足以在品种外轻便存款和储蓄数据库配置(一些聪明才智新闻),就疑似apache配置同样。更加的多消息请参阅How to Set external Parameters in the 瑟维斯 Container.
    现行反革命Doctrine知道你的数据库配置了,你能够用它来创制贰个数据库了。

    $ php app/console doctrine:database:create
    

    设置数据库为UTF8
    不畏对于经验丰硕的程序猿来讲,三个常犯的错误是,在Symfony项目始于后,忘记设置他们的数额库默许字符集和核查法则,仅把一大1/4据库给出的latin类型的查对作为私下认可。他们唯恐在首先次操作时会记得,但到了前面敲打两行有关的健康命令之后,就完全忘记了。

    $ php app/console doctrine:database:drop --force
    $ php app/console doctrine:database:create
    在Doctrine里一直指派默许字符集是不容许的,因为doctrine会依据条件安排,尽恐怕多地去适应各样“不可见”情况。消除办法之一,是去安插“服务器品级”的暗中认可音讯。
    安装UTF8为MySql的默许字符集是极其轻巧的,只要在数据库配置文件中加几行代码就足以了(一般是my.cnf文件)

    [mysqld]
    # Version 5.5.3 introduced "utf8mb4", which is recommended
    collation-server     = utf8mb4_general_ci # Replaces utf8_general_ci
    character-set-server = utf8mb4            # Replaces utf8
    大家推荐防止选择Mysql的uft8字符集,因为它并不协作4-byte unicode字符,假使字符串中有这种字符会被清空。不过这种情景被修复了,仿照效法《新型utf8mb4字符集》

    ---------------------------------------------新建数据库这段还不比直接在mysql里面操作更利于-----------------------------------------------

    若是您想要使用SQLite作为数据库,你需求安装path为您的数据库路径

    # app/config/config.yml
    doctrine:
        dbal:
            driver: pdo_sqlite
            path: "%kernel.root_dir%/sqlite.db"
            charset: UTF8
    

    成立三个实体类

    比如你创建二个应用程序,在这之中多少产品需求呈现。即时不思索Doctrine可能数据库,你也理应明白您供给八个Product对象来突显那么些制品。在您的AppBundle的Entity目录下创建一个类。

    // src/AppBundle/Entity/Product.php
    namespace AppBundleEntity;
    
    class Product
    {
        protected $name;
        protected $price;
        protected $description;
    }
    

    如此那般的类通常被称得上“Entity”,意味着三个基础类保存数据。它们简单来满意你应用程序的工作必要。不过现在它还不能够被封存到数据库中,因为昨天它只可是依然个轻松的PHP类。

    假定您读书了Doctrine背后的定义,你能够让Doctrine来为您创制实体类。他会问你某些标题来成立entity:

    $ php app/console doctrine:generate:entity
    

     加多映射音讯

    Doctrine允许你采纳一种更有趣的点子对数据库实行操作,实际不是只是得到基于列表的行到数组中。Doctrine允许你保存整个对象到数据库可能把对象从数据库中抽出。那些都以由此映射PHP类到贰个数码库表,PHP类的属性对应数据库表的列来完毕的。

    图片 1

    因为Doctrine能够做那一个,所以你仅仅只必要创制多少个meatdata,或许配置告诉Doctrine的Product类和它的属性应该什么映射到数据库。那几个metadata能够被定义成各样格式,包罗YAML,XML或许经过注脚直接定义到Product类中。

    annotations:
    
    
    // src/AppBundle/Entity/Product.php
    namespace AppBundleEntity;
    
    use DoctrineORMMapping as ORM;
    
    /**
     * @ORMEntity
     * @ORMTable(name="product")
     */
    class Product
    {
        /**
         * @ORMColumn(type="integer")
         * @ORMId
         * @ORMGeneratedValue(strategy="AUTO")
         */
        protected $id;
    
        /**
         * @ORMColumn(type="string", length=100)
         */
        protected $name;
    
        /**
         * @ORMColumn(type="decimal", scale=2)
         */
        protected $price;
    
        /**
         * @ORMColumn(type="text")
         */
        protected $description;
    }
    

    贰个bundle只还行一种metadata定义格式。比方,不能把YAML定义的metadata和评释PHP实体类一同混用。
    表名是可选的,假设简单,将基于entity类的名目自动显明。
    Doctrine允许你去挑选各类区别的字段类型,每一种字段都有温馨的布署。有关字段类型新闻,请看Doctrine Field Types Reference。

    你也得以查看Doctrine官方文书档案Basic Mapping Documentation关于映射消息的有所细节。假若你选取annotations,你供给持有的注释都有ORM(举个例子ORMColumn()),那么些doctrine模板并不曾。你还亟需去引进use DoctrineORMMapping as ORM;注脚,它是用来推举ORM注册前缀的。
    小心您的类名和本性很也许就被映射到三个受保证的SQL字段(如group和user)。比如,假设您的entity类名叫Group,那么,在默许景况下,你的表名字为group,在有的斯特林发动机中或者导致SQL错误。请查看 Reserved SQL keywords documentation,他会报告你怎么科学的躲避那么些名称。别的,你能够轻便轻巧的照射到分裂的表名和字段名,来摘取你的数据库纲要。请查看 Doctrine的Persistent classes和Property Mapping文书档案。
    当使用其余的库或许程序(比如Doxygen)它们选用了讲明,你应有把@IgnoreAnnotation注释增加到该类上来告诉Symfony忽略它们。
    举例大家要堵住@fn 表明抛出十二分,能够那样:

    /**
     * @IgnoreAnnotation("fn")
     */
    class Product
    // ...
    

    生产Getters和Setters
    即使Doctrine今后精晓了怎么样长久化Product对象到数据库,但是类本身是还是不是有用啊。因为Product仅仅是贰个正经的PHP类,你供给创立getter和setter方法(譬喻getName(),setName())来访谈它的习性(因为它的性格是protected),幸运的是 Doctrine可以为大家做那么些:

    $ php app/console doctrine:generate:entities AppBundle/Entity/Product
    

    该命令能够保障Product类全体的getter和setter都被转移。那是贰个平安的命令行,你能够反复运作它,它只会扭转那一个不设有的getters和setters,而不会交替已有的。

    请牢记doctrine entity引擎生产轻便的getters/setters。你应当检查生成的实体,调解getter/setter逻辑为和谐想要的。

    关于doctrine:generate:entities命令
    用它你能够生成getters和setters。
    用它在配备@ORMEntity(repositoryClass=”…”)申明的图景下,生成repository类。
    用它可以为1:n或然n:m生成适宜的构造器。
    该命令会保存八个原本Product.php文件的备份Product.php~。 某些时候可也能够会促成“没办法再一次注明类”错误,你能够放心的删减它,来解除错误。您还足以应用–no-backup选项,来制止产生那个安排文件。
    自然你不必要借助于该命令行,Doctrine不依赖于代码生成,像正规的PHP类,你只须求确定保障它的protected/private属性具有getter和setter方法就能够。首要出于用命令行去制造是,一种常见事。
    你也得感到四个bundle只怕全体实体命名空间内的具备已知实体(任何带有Doctrine映射评释的PHP类)来生成getter和setter:

    # generates all entities in the AppBundle
    $ php app/console doctrine:generate:entities AppBundle
    
    # generates all entities of bundles in the Acme namespace
    $ php app/console doctrine:generate:entities Acme
    

    Doctrine不关切你的性质是protected还是private,也许那么些属性是不是有getter或setter。之所以生成这几个getter恐怕setter完全部是因为您供给跟你的PHP对象开展沟通须要它们。  

    成立数量库表和情势
    今昔我们有了叁个可用的Product类和它的投射消息,所以Doctrine知道如何悠久化它。当然,以往Product还从未对应的product数据库表在数据库中。幸运的是,Doctrine能够活动创制全部的数额库表。

    $ php app/console doctrine:schema:update --force
    

     说真的,那条命令是异样的强有力。它会依据你的entities的照耀音讯,来相比未来的数据库,并生成所须求的新数据库的革新SQl语句。换句话说,若是你想增加三个新的性质映射元数据到Product并运维该职责,它将生成一个alert table 语句来增加新的列到已经存在的product表中。
    贰个越来越好的发挥这一优势的成效是透过migrations,它同意你生成那么些SQL语句。并积累到一个迁移类,并能有集体的运作在您的生产情状中,系统为了安全可靠地追踪和迁移数据库。
    明日你的数据库中有了多个专职能的product表,它的各样列都会被映射到您内定的元数据。

    长久化对象到数据库
    现行反革命我们有了一个Product实体和与之映射的product数据库表。你能够把数量长久化到数据库里。在Controller内,它特别简单。增多底下的措施到bundle的DefaultController中。

     

    // src/AppBundle/Controller/DefaultController.php
    
    // ...
    use AppBundleEntityProduct;
    use SymfonyComponentHttpFoundationResponse;
    
    // ...
    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());
    }
    

    若是你想演示那么些案例,你需求去创建叁个路由指向那几个action,让她职业。
    正文显示了在调控器中动用Doctrine的getDoctrine()方法。这几个方式是赢得doctrine服务最便捷的措施。你能在劳务中的任何其余地点使用doctrine注入该服务。越多关于普及自个儿的劳动音讯,请参阅ServiceContainer。
    在会见前边例子的详细情形:

    在本节10-13行,你实例化$product对象,就好像其余任何一般的php对象同样。

    15行得到doctrine实体管理对象,那是承受管理数据库漫长化进程和读取对象的。

    16行persist()方法告诉Doctrine去“管理”这么些$product对象。还并未在数据库中动用过语句。

    17行党那些flush()方法被调用,Doctrine会查看它管理的有所目的,是不是须要被长久化到数据库。在本例子中,这几个$product对象还从未长久化,所以那些entity管理就能举行一个insert语句並且会在product表中开创一行数据。

    其实,Doctrine明白你全体的被管制的实体,当你调用flush()方法时,它会计算出全数的成形,并施行最管用的查询恐怕。 他利用筹算好的缓存略微进步质量。举个例子,你要悠久化总是为100的成品对象,然后调用flush()方法。Doctrine会成立贰个唯一的准备语句不分畛域复使用它插入。
    在开立和翻新指标时,职业流是一律的。在下一节中,如若记录已经存在数据库中,您将见到Doctrine如汪峥嵘明的自行发出叁个Update语句。

    Doctrine提供了贰个类库允许你通过编程,加载测量检验数据到您的花色。该类库为 DoctrineFixturesBundle()

    从数据库中赢得对象

    从数据库中得到对象更便于,比如,倘令你安插了多少个路由来,用它的ID显示特定的product。

    public function showAction($id)
    {
        $product = $this->getDoctrine()
            ->getRepository('AppBundle:Product')
            ->find($id);
    
        if (!$product) {
            throw $this->createNotFoundException(
                'No product found for id '.$id
            );
        }
    
        // ... do something, like pass the $product object into a template
    }
    

    您能够选取@ParamConverter注释不用编写任何代码就足以兑现均等的效果。越多音讯请查看FrameworkExtraBundle文书档案。
    当您询问某些特定的产品时,你总是须求动用它的”respository”。你能够感觉Respository是多个PHP类,它的当世无双工作正是帮扶您从某些特定类哪儿获得实体。你可以为三个实体对象访谈三个repository对象,如下:

    $repository = $this->getDoctrine()
        ->getRepository('AppBundle:Product');
    

    内部appBundle:Product是简单写法,你能够在Doctrine中大肆使用它来代替实体类的全限定称号(比方AppBundleEntityProduct)。只要你的entity在您的bundle的Entity命名空间下它就能够做事。你只要有了Repository,你就能够访问其抱有分类的支持方法了。

    // query by the primary key (usually "id")
    $product = $repository->find($id);
    
    // dynamic method names to find based on a column value
    $product = $repository->findOneById($id);
    $product = $repository->findOneByName('foo');
    
    // find *all* products
    $products = $repository->findAll();
    
    // find a group of products based on an arbitrary column value
    $products = $repository->findByPrice(19.99);
    

     当然,你也能够行使复杂的询问,想询问越来越多请阅读Querying for Objects 。
    您也能够有效行使findBy和findOneBy方法的优势,很轻易的遵照四个标准来拿到对象。

    // query for one product matching by name and price
    $product = $repository->findOneBy(
        array('name' => 'foo', 'price' => 19.99)
    );
    
    // query for all products matching the name, ordered by price
    $products = $repository->findBy(
        array('name' => 'foo'),
        array('price' => 'ASC')
    );
    

    当您去渲染页面,你能够在网页调节和测验工具的右下角看到十分多的询问。
    doctrine_web_debug_toolbar
    假诺您单机该Logo,分析页面将展开,突显你的确切查询。
    即便您的页面查询抢先了四十七个它会成为暗黑。那只怕申明你的前后相继有标题。

    创新指标
    设若你从Doctrine中赢得了二个目的,那么更新它就变得很轻易了。假如你有叁个路由映射贰个出品id到一个controller的updateaction。

    public function updateAction($id)
    {
        $em = $this->getDoctrine()->getManager();
        $product = $em->getRepository('AppBundle:Product')->find($id);
    
        if (!$product) {
            throw $this->createNotFoundException(
                'No product found for id '.$id
            );
        }
    
        $product->setName('New product name!');
        $em->flush();
    
        return $this->redirectToRoute('homepage');
    }
    

    创新贰个对象包涵三步:

    1.从Doctrine收取对象
    2.改动对象
    3.在实业管理者上调用flush()方法

    留神调用 $em->persist($product) 在那边无需。大家想起一下,调用该方法的目标重若是报告Doctrine来治本照旧“观望”$product对象。在此地,因为你已经取到了$product对象了,表明已经被管理了。

    剔除对象

    删去两个目的,须要从实体管理者这里调用remove()方法。

    $em->remove($product);
    $em->flush();
    

    正如您想的那么,remove()方法告诉Doctrine你想从数据库中移除内定的实体。真正的删减查询未有被真正的推行,直到flush()方法被调用。

    询问对象

    您早已见到了repository对象允许你实施一些大旨的询问而不必要你做任何的干活。

    $repository->find($id);
    
    $repository->findOneByName('Foo');
    

    本来,Doctrine 也允许你利用Doctrine Query Language(DQL)写一些繁杂的询问,DQL类似于SQL,只是它用于查询一个依旧多少个实体类的靶子,而SQL则是询问二个数据库表中的行。

    在Doctrinez中询问时,你有三种选拔:写纯Doctrine查询 恐怕使用Doctrine的询问成立器。

     

    选择Doctrine’s Query Builder查询对象
    只要你想询问产品,需求重返价格当先19.99的制品,况且供给按价格从低到高排列。你能够应用Doctrine的QueryBuilder:

    $repository = $this->getDoctrine()
        ->getRepository('AppBundle:Product');
    
    $query = $repository->createQueryBuilder('p')
        ->where('p.price > :price')
        ->setParameter('price', '19.99')
        ->orderBy('p.price', 'ASC')
        ->getQuery();
    
    $products = $query->getResult();
    

    QueryBuilder对象包蕴了成立查询的具有必得的方法。通过调用getQuery()方法,查询创立器将回来一个正规的Query对象。它跟我们一向写查询对象效果一样。

    切记setParameter()方法。当Doctrine工作时,外界的值,会由此“占位符”(上边例子的:price)传入,来防御SQL注入攻击。
    该getResult()方法再次回到三个结出数组。想要得到四个结实,你能够运用getSingleResult()(这几个措施在平素不结果时会抛出几个极度)只怕getOneOrNullResult():

    $product = $query->getOneOrNullResult();
    

    越来越多Doctrine’s Query Builder的音讯请阅读Query Builder。  

    利用DQL查询对象

    不爱动用QueryBuilder,你还足以一向动用DQL查询:

    $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();
    

    假若你习贯了写SQL,那么对于DQL也应该不会感到到素不相识。它们中间最大的不等正是你供给思索对象,并非数据库表行。正因为这么,所以您从AppBundle:Product选拔并给它定义外号p。(你看和上边完毕的结果一致)。

    该DQL语法变得强大到令人质疑,允许你轻松地在里头步向实体(稍后会介绍关系)、组等。越来越多音信请参阅Doctrine Query Language文书档案。

    自定义Repository类

    在地点你曾经起来在controller中制造和使用负担的询问了。为了隔开,测量检验和选定那个查询,贰个好的章程是为你的实体成立多个自定义的repository类并累加相关逻辑查询办法。

    要定义repository类,首先要求在您的映照定义中增添repository类的扬言:

    // src/AppBundle/Entity/Product.php
    namespace AppBundleEntity;
    
    use DoctrineORMMapping as ORM;
    
    /**
     * @ORMEntity(repositoryClass="AppBundleEntityProductRepository")
     */
    class Product
    {
        //...
    }
    

    下一场经过运行跟从前生成错失的getter和setter方法同样的命令行,Doctrine会为您自动生成repository类。

    $ php app/console doctrine:generate:entities AppBundle
    

    上边,增添多个新格局findAllOrderedByName() 到新生成的repository类。该情势将查询全体的Product实体,并依照字符顺序排序。

    // src/AppBundle/Entity/ProductRepository.php
    namespace AppBundleEntity;
    
    use DoctrineORMEntityRepository;
    
    class ProductRepository extends EntityRepository
    {
        public function findAllOrderedByName()
        {
            return $this->getEntityManager()
                ->createQuery(
                    'SELECT p FROM AppBundle:Product p ORDER BY p.name ASC'
                )
                ->getResult();
        }
    }
    

     在Repository类中得以由此$this->getEntityManager()方法类获取entity管理。
    您就足以像使用默许的法子同样使用这几个新定义的艺术了:

    $em = $this->getDoctrine()->getManager();
    $products = $em->getRepository('AppBundle:Product')
        ->findAllOrderedByName();
    

    当使用一个自定义的repository类时,你照样能够访谈原本的暗中认可查找方法,譬喻find() 和findAll()等。

    实业的涉嫌/关联
    如若你应用程序中的产品属于一分明的归类。那时你需求四个分拣目的和一种把Product和Category对象关系在协同的点子。首先我们创立Category实体,我们最终要因而Doctrine来对其实行悠久化,所以大家那边让Doctrine来帮大家创立那一个类。

    $ php app/console doctrine:generate:entity 
        --entity="AppBundle:Category" 
        --fields="name:string(255)"
    

    该命令行为您生成二个Category实体,包罗id字段和name字段以及有关的getter和setter方法。

    波及映射

    论及Category和Product七个实体,首先在Category类中创造二个products属性:

    // src/AppBundle/Entity/Category.php
    
    // ...
    use DoctrineCommonCollectionsArrayCollection;
    
    class Category
    {
        // ...
    
        /**
         * @ORMOneToMany(targetEntity="Product", mappedBy="category")
         */
        protected $products;
    
        public function __construct()
        {
            $this->products = new ArrayCollection();
        }
    }
    

    率先,由于三个Category对象将波及到三个Product对象,二个products数组属性被加多到Category类保存那几个Product对象。其次,那不是因为Doctrine需求它,而是因为在应用程序中为每一个Category来保存四个Product数组特别实用。

    代码中__construct()方法十三分关键,因为Doctrine需求$products属性成为三个ArrayCollection对象,它跟数组极其周围,但会灵活一些。借使那让你倍感不舒适,不用忧郁。试想他是二个数组,你会欣然接受它。
    下边注释所用的targetEntity 的值可以应用合法的命名空间引用任何实体,而不仅是概念在同三个类中的实体。 假使要提到三个定义在差别的类依然bundle中的实体则必要输入完全的命名空间作为指标实体。
    接下去,因为各样Product类可以提到一个Category对象,全体加多三个$category属性到Product类:

    // src/AppBundle/Entity/Product.php
    
    // ...
    class Product
    {
        // ...
    
        /**
         * @ORMManyToOne(targetEntity="Category", inversedBy="products")
         * @ORMJoinColumn(name="category_id", referencedColumnName="id")
         */
        protected $category;
    }
    

    到明日甘休,大家增添了四个新个性到Category和Product类。今后报告Doctrine来为它们生成getter和setter方法。

    $ php app/console doctrine:generate:entities AppBundle
    

    我们先不看Doctrine的元数据,你今后有八个类Category和Product,并且具备七个一对多的关系。该Category类满含二个数组Product对象,Product满含二个Category对象。换句话说,你曾经创立了你所急需的类了。事实上把那些须要的多少长久化到数据库上 是协助的。

    今日,让大家来寻访在Product类中为$category配置的元数据。它报告Doctrine关系类是Category何况它需求保留 category的id到product表的category_id字段。换句话说,相关的分类目的将会被封存到$category属性中,不过在底 层,Doctrine会通过存款和储蓄category的id值到product表的category_id列长久化它们的涉嫌。

    图片 2

    Category类中$product属性的元数据配置不是特意重大,它可是是报告Doctrine去寻觅Product.category属性来测算出涉嫌映射是怎么着。

    在继续从前,必要求告知Doctrine加多二个新的category表和product.category_id列以及新的外键。

    $ php app/console doctrine:schema:update --force
    

    封存相关实业

    这两天让我们来拜候Controller内的代码怎样管理:

     

    // ...
    
    use AppBundleEntityCategory;
    use AppBundleEntityProduct;
    use SymfonyComponentHttpFoundationResponse;
    
    class DefaultController extends Controller
    {
        public function createProductAction()
        {
            $category = new Category();
            $category->setName('Main Products');
    
            $product = new Product();
            $product->setName('Foo');
            $product->setPrice(19.99);
            $product->setDescription('Lorem ipsum dolor');
            // 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()
            );
        }
    }
    

    现行反革命,二个独自的行被加多到category和product表中。新产品的product.categroy_id列被安装为新category表中的id的值。Doctrine会为你管理这一个悠久化关系。

    收获有关对象

    当您要求获得相关的目的时,你的做事流跟在此以前一样。首先取得$product对象,然后访谈它的连锁Category

    public function showAction($id)
    {
        $product = $this->getDoctrine()
            ->getRepository('AppBundle:Product')
            ->find($id);
    
        $categoryName = $product->getCategory()->getName();
    
        // ...
    }
    

    在这一个事例中,你首先遵照产品id查询多个Product对象。他单独查询产品数据并把多少给$product对象。接下来,当您调 用$product->getCategory()->getName() 时,Doctrine默默的为您实施了第三遍查询,查找一个与该产品有关的category,它生成二个$category对象回来给您。

    图片 3

    主要的是您很轻巧的拜望到了product的有关category对象。不过category的数码并不会被抽取来而甘休你央求category的时候。这正是延迟加载。

    您也能够从别的方向实行询问:

    public function showProductsAction($id)
    {
        $category = $this->getDoctrine()
            ->getRepository('AppBundle:Category')
            ->find($id);
    
        $products = $category->getProducts();
    
        // ...
    }
    

    在这种景色下,同样的事体发生了。你首先查看二个category对象,然后Doctrine创建了第二遍查询来赢得与之相关联的有着Product对 象。唯有在你调用->getProducts()时才会实施叁回。 $products变量是二个通过它的category_id的值跟给定的category对象相关联的有所Product对象的集合。

    论及和代理类

    “延迟加载”成为大概,是因为Doctrine再次来到贰个代理对象来替代真正的对象:

    $product = $this->getDoctrine()
        ->getRepository('AppBundle:Product')
        ->find($id);
    
    $category = $product->getCategory();
    
    // prints "ProxiesAppBundleEntityCategoryProxy"
    echo get_class($category);
    

    该代理对象承继了Category对象,从外表到作为都不行像category对象。所例外的是,通过那些代理对象,Doctrine能够顺延查询真正的Category对象数据,直到真正必要它时(调用$category->getName())。
    Doctrine生成了代理对象并把它存款和储蓄到cache目录中,就算你恐怕根本未有察觉过它。记住它这点很珍视。
    大家能够经过join连接来二回性抽出product和category数据。那时Doctrine将会回到真正的Category对象,因为不供给延期加载。

    join相关记录
    在从前的我们的查询中,会产生四次询问操作,一次是获取原对象,叁回是获得涉及对象。

    请记住,你可以由此网页调节和测验工具查看伏乞的持有查询。
    当然,假使您想叁次访问多个对象,你能够经过一个join连接来防止三遍查询。把上面包车型大巴点子加多到ProductRepository类中:

    // src/AppBundle/Entity/ProductRepository.php
    public function findOneByIdJoinedToCategory($id)
    {
        $query = $this->getEntityManager()
            ->createQuery(
                'SELECT p, c FROM AppBundle:Product p
                JOIN p.category c
                WHERE p.id = :id'
            )->setParameter('id', $id);
    
        try {
            return $query->getSingleResult();
        } catch (DoctrineORMNoResultException $e) {
            return null;
        }
    }
    

    今后您就足以在您的controller中壹次性查询三个产品对象和它涉及的category对象音信了。

    public function showAction($id)
    {
        $product = $this->getDoctrine()
            ->getRepository('AppBundle:Product')
            ->findOneByIdJoinedToCategory($id);
    
        $category = $product->getCategory();
    
        // ...
    }
    

    更加多涉及音讯
    本节中早就介绍了三个日常的实体关联,一对多关系。对于更加高等的涉及和什么运用另外的关系(举个例子一对一,多对一),请参见 doctrine 的Association Mapping Documentation.

    借使您使用注释,你须要事先在拥有注释加ORM(如ORMOneToMany),这几个在doctrine官方文书档案里未有。你还须求注解use DoctrineORMMapping as ORM;技术应用annotations的ORM。

    配置
    Doctrine是莫大可配备的,不过你大概永久不要关怀他们。要想打听越来越多关于Doctrine的安插新闻,请查看config reference。

    生命周期回调
    不经常你也许需求在壹个实体被创立,更新也许去除的上下推行一些操作。这几个操作方法处在二个实体不一样的生命周期阶段,所以这个作为被喻为”生命周期回调“。

    假令你用annotations情势,开启二个生命周期回调,须求如下设置:(即使您不希罕你也得以使用yaml和xml方式)

    /**
     * @ORMEntity()
     * @ORMHasLifecycleCallbacks()
     */
    class Product
    {
        // ...
    }
    

    当今您能够告诉Doctrine在其它可用的生命周期事件上来施行贰个主意了。比如,假诺你想在一个新的实体第一遍被创建时设置创立日期列(created)为前段时间些天期。

    // src/AppBundle/Entity/Product.php
    
    /**
     * @ORMPrePersist
     */
    public function setCreatedAtValue()
    {
        $this->createdAt = new DateTime();
    }
    

    地方的例证要是你早就创立了createdAt属性(为在这里彰显)。
    后天在实业第二回被封存时,Doctrine会自动调用那一个格局使created日期自动安装为目今日期。

    再有部分其余的生命周期事件,你能够采取它。越来越多生命周期事件和生命周期回调,请查看Doctrine的Lifecycle Events documentation。

    生命周期回调护治疗事件监听
    专一到setCreatedValue()方法无需抽出任何参数。那是生命周期回调常常的做法和常规:生命周期回调应该是粗略方法,更关怀于实体内部传输数据。比如设置一个成立/更新字段,生成一个定量值等。
    假若您要求部分不小的一坐一起活动,像奉行日志恐怕发送邮件,你应该登记二个扩大类作为事件监听器或接收器给它赋予访谈所需能源的义务。想打听越多,请参阅How to Register Event Listeners and Subscribers.  

    Doctrine字段类型参照他事他说加以考察
    Doctrine配备了汪洋可用的字段类型。它们每两个都能映射PHP数据类型到一定的列类型,无论你使用什么数据库。对于每二个字段类型,Column 都足以被进一步安顿,能够安装length, nullable行为,name只怕另外布署。想查看更加的多消息请参阅Doctrine的Mapping Types documentation。

     

    总结

    有了Doctrine,你能够集中精力到你的靶子以及哪些把它使用于您的应用程序中,而不要忧郁数据库长久化。因为Doctrine允许你利用别的的PHP对象保存你的数量并依据映射元数据消息来维系一个目的到特定的数额库表。

    即使Doctrine围绕着叁个粗略的概念发展而来,不过它不敢相信 无法相信的强硬。允许你创建复杂的查询和订阅事件,通过订阅事件你能够在任何漫长化进程中推行一些不等的一言一动。

    本文由澳门402永利com发布于编程应用,转载请注明出处:数据库和Doctrine,Doctrine2基本选取

    关键词:

上一篇:没有了

下一篇:MVC学习笔记1