symfony 连接mysql_symfony2  数据库操作

1.创建一个bundle

$php app/console generate:bundle --namespace=Acme/StoreBundle

2.创建数据库

$php app/console doctrine:database:create

3.创建实体类

$php app/console doctrine:generate:entity --entity="AcmeStoreBundle:Product" --fields="name:string(255) price:float description:text"

4.生成Getters和Setters

$php app/console doctrine:generate:entities Acme/StoreBundle/Entity/Product

5.所有已知实体生成getter和setter

$php app/console doctrine:generate:entities AcmeStoreBundle$php app/console doctrine:generate:entities Acme

6.根据entities创建数据表

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

持久化对象到数据库

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

// src/Acme/StoreBundle/Controller/DefaultController.php

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

$em->persist($product);

$em->flush();

return new Response('Created product id '.$product->getId());

}

事实上,Doctrine了解你所有的被管理的实体,当你调用flush()方法时,它会计算出所有的变化,并执行最有效的查询可能。

比如,你要持久化总是为100的产品对象,然后调用flush()方法。Doctrine会创建一个唯一的预备语句并重复使用它插入。

这种模式成为Unit of work。

在创建和更新对象是,工作流是相同的。Doctrine提供了一个类库允许你通过编程加载测试数据到你的项目。该类库为

DoctrineFixturesBundle(http://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html)

从数据库中读取对象

从数据库中获取对象更容易,举个例子,加入你配置了一个路由来基于它的ID显示特定的product。

复制代码

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,想把$product对象传递给一个template等。

}

复制代码

当你查询某个特定的产品是,你总是需要使用它的"respository"。你可以认为Respository是一个PHP类,它的唯一工作就是帮助你从某个特定类哪里获取实体。你可以为一个实体对象访问一个repository对象,如下:

$repository = $this->getDoctrine()

->getRepository('AcmeStoreBundle:Product');

其中AcmeStoreBundle:Product是简洁写法,你可以在Doctrine中任意使用它来替代实体类的全限定名称。

Acme\StoreBung\Entity\Product

你一旦有了Repository,你就可以访问其所有分类的帮助方法了。

复制代码

//通过主键查询(一般为"id")

$product=$repository->find($id);

//动态方法名基于列值查找

$product=$repository->findOneById($id);

$product=$repository->findOneByName('foo');

//查询所有产品

$products=$repository->findAall();

//基于任意列值查找一组产品

$products = $repository->findByPrice(19.99);

复制代码

你也可以发挥findBy和findOneBy方法的优势很容易的基于多个条件来获取对象。

复制代码

//按照名字和价格来获取一个匹配的对象

$product=$repository->findOneBy(array('name'=>'foo','price'=>19.99));

//查询匹配名字的所有产品并按照价格排序

$products = $repository->findBy(

array('name'=> 'foo'),

array('price'=>'ASC')

);

更新对象

一旦你从Doctrine中获取了一个对象,那么更新它就变得很容易了。假设你有一个路由映射一个产品id到一个controller的更新行为。

a4c26d1e5885305701be709a3d33442f.png

public function updateAction($id)

{$em = $this->getDoctrine()->getEntityManager();$product = $em->getRepository('AcmeStoreBundle:Product')->find($id);if (!$product) {throw $this->createNotFoundException('No product found for id '.$id);

}$product->setName('New product name!');$em->flush();return $this->redirect($this->generateUrl('homepage'));

}

更新一个对象包括三步:

1.从Doctrine取出对象

2.修改对象

3.在实体管理者上调用flush()方法

注意调用 $em->persist($product)

在这里没有必要。我们回想一下,调用该方法的目的主要是告诉Doctrine来管理或者“watch"$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的查询创建器。

用DQL查询对象:

假设你想查询产品,需要返回价格高于19.99的产品,并且要求按价格从低到高排列。我们可以在相应的Controller里进行如下操作:

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

如果你习惯了写SQL,那么对于DQL也应该不会感到陌生。它们之间最大的不同就是你需要思考对象,而不是数据库表行。正因为如此,所以你从

AcmeStoreBundle:Product选择并给它定义别名p。getResult()方法返回一个结果数组。如果你只需要一个对象,你可以使用

getSingleResult()方法。

$product = $query->getSingleResult();

如果没有符合要求的结果,getSingleResult()方法会抛出一个

Doctrine\ORM\NoResultException 异常和如果不只有一个结果返回那么就会

抛出一个Doctrine\ORM\NonUniqueResultException异常。所以,如果你要使用该方法的话,需要把它包裹在一个try-catch块内,以确保只有

一个结果被返回。

$query = $em->createQuery('SELECT ....')->setMaxResults(1);try{$product = $query->getSingleResult();

}catch (\Doctrine\Orm\NoResultException $e) {$product = null;

}//...

DQL的语法难以置信的强大,允许你很容易的俩和多个实体,分组等进行查询。

设置参数:

注意setParameter()方法,在使用Doctrine时,把任何的外部值设置成占位符是一个非常好的做法。

比如上例中 ...WHERE p.price>:price ...

这样你可以通过调用setParameter()方法为price占位符设置具体值。

->setParameter('price', '19.99')

使用参数而不是直接把具体在插入到查询字符串中是为了放置SQL注入攻击,所以必须始终这么做。如果你使用了多个参数,你可以使用setParameters()方法一次性设置他们的值。

->setParameters(array('price'=>'19.99',

'name' =>'foo',))

使用Doctrine的查询创建器

除了直接编写查询以外,你可以使用Doctrine的QueryBuilder来做相同的工作。面前对象接口。如果你使用IDE,你还可以获取自动编译检查的好处。

复制代码

$repository = $this->getDoctrine()

->getRepository('AcmeStoreBundle:Product');

$query = $repository->createQueryBuilder('p')

->where('p.price > :price')

->setParameter('price', '19.99')

->orderBy('p.price', 'ASC')

->getQuery();

$products = $query->getResult();

复制代码

QueryBuilder对象包含了创建查询的所有必须的方法。通过调用getQuery()方法,查询创建器将返回一个标准的Query对象。它跟我们直接写查询对象效果相同。

自定义Repository类

在上面你已经开始在controller中创建和使用负责的查询了。为了隔离,比阿育测试和重用这些查询,一个好的办法是为你的实体创建一个自定义的repository类并添加相关逻辑查询方法。要定义repository类,首先需要在你的映射定义中添加repository类的声明:

在实体类中声明方式:

复制代码

// src/Acme/StoreBundle/Entity/Product.php

namespace Acme\StoreBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

class Product

{

//...

}

复制代码

YAML格式:

# src/Acme/StoreBundle/Resources/config/doctrine/Product.orm.yml

Acme\StoreBundle\Entity\Product:

type: entity

repositoryClass: Acme\StoreBundle\Repository\ProductRepository

# ...

XML格式:

复制代码

repository-class="Acme\StoreBundle\Repository\ProductRepository">

复制代码

然后通过运行跟之前生成丢失的getter和setter方法同样的命令行,Doctrine会为你自动生成repository类。

$php app/console doctrine:generate:entities Acme

接下来,添加一个新方法findAllOrderedByName() 到新生成的repository类。该方法将查询所有的Product实体,并按照字符顺序排列。

复制代码

// src/Acme/StoreBundle/Repository/ProductRepository.php

namespace Acme\StoreBundle\Repository;

use Doctrine\ORM\EntityRepository;

class ProductRepository extends EntityRepository

{

public function findAllOrderedByName()

{

return $this->getEntityManager()

->createQuery('SELECT p FROM AcmeStoreBundle:Product p ORDER BY p.name ASC')

->getResult();

}

}

复制代码

注意在Repository类中可以通过$this->getEntityManager()方法类获取实体管理者。如此一来你就可以像使用默认的方法一样使用这个新定义的方法了:

$em = $this->getDoctrine()->getEntityManager();

$products = $em->getRepository('AcmeStoreBundle:Product')

->findAllOrderedByName();

在使用自定义的repository类时,你依然可以访问原有的默认查找方法,比如find() 和findAll()等。

实体关系/关联

假设你应用程序中的产品属于一确定的分类。这时你需要一个分类对象和一种把Product和Category对象联系在一起的方式。首先我们创建Category实体,我们最终要通过Doctrine来对其进行持久化,所以我们这里让Doctrine来帮我们创建这个类。

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

该命令行为你生成一个Category实体,包含id字段和name字段以及相关的getter和setter方法。

关系映射元数据:

联系Category和Product两个实体,首先在Category类中创建一个products属性:

Category类中声明格式:

复制代码

// src/Acme/StoreBundle/Entity/Category.php

// ...

use Doctrine\Common\Collections\ArrayCollection;

class Category

{

// ...

protected $products;

public function __construct()

{

$this->products = new ArrayCollection();

}

}

复制代码

YAML定义格式:

复制代码

# src/Acme/StoreBundle/Resources/config/doctrine/Category.orm.yml

Acme\StoreBundle\Entity\Category:

type: entity

# ...

oneToMany:

products:

targetEntity: Product

mappedBy: category

# 不要忘记在实体的 __construct() 方法中初始化集合

复制代码

首先,因为一个Category对象将关系到多个Product对象,一个products数组属性被添加到Category类保存Product对象。

其次,这里没有被做因为Doctrine需要它,但在应用程序中为每一个Category来保存一个Product数组非常有用。

代码中__construct()方法非常重要,因为Doctrine需要$products熟悉成为一个ArrayCollection对象,它跟数组非常类似。targetEntity 的值可以使用合法的命名空间引用任何实体,而不仅仅是定义在同一个类中的实体。 如果要关系一个定义在不同的类或者bundle中的实体则需要输入完全的命名空间作为目标实体。

接下来,因为每个Product类可以关联一个Category对象,所有添加一个$category属性到Product类:

在Product类声明中定义:

复制代码

// src/Acme/StoreBundle/Entity/Product.php

// ...

class Product

{

// ...

protected $category;

}

复制代码

YAML定义格式:

复制代码

# src/Acme/StoreBundle/Resources/config/doctrine/Product.orm.yml

Acme\StoreBundle\Entity\Product:

type: entity

# ...

manyToOne:

category:

targetEntity: Category

inversedBy: products

joinColumn:

name: category_id

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值