03.06 仓库

Repository(代码仓库)是SF中的另一个重要概念。

顾名思义,代码仓库就是存放(通常是通用的)代码的地方。在SF中,一般用来堆放进行数据库操作的代码。

SF为什么要增加这么一个额外的层?有两个原因:

  • 虽然一个实体提供了一些基本的数据库操作,如findOneBy之类的,但是肯定不能满足我们定制搜索的需要;
  • 如上的这个要求既不应该是Model的任务,更不应该是Controller的任务(不符合DRY和代码重用原则)。
    所以,我们有必要加入一个新的层,形成这样的一个关系图:

3.6. Repository/仓库  - 图1

  • Controller只提出我要什么数据;
  • Repository只负责选择数据;
  • Model存放真正的数据。
    现在要马上透彻理解这里的关系和区别还是比较困难的。我们会在后续文章中更深入地讨论这些。

我们来看一个典型的仓库的代码:

  1. <?php
  2. namespace AppBundle\Repository;
  3. use Doctrine\ORM\EntityRepository;
  4. use Symfony\VarDumper;
  5. /**
  6. * StatusRepo
  7. *
  8. * This class was generated by the Doctrine ORM. Add your own custom
  9. * repository methods below.
  10. */
  11. class StatusRepo extends EntityRepository
  12. {
  13. public function getStatusIn($start, $end, $count = 4)
  14. {
  15. $inter_s = new \DateInterval($start);
  16. $inter_e = new \DateInterval($end);
  17. $cts = new \DateTime();
  18. $cts->sub($inter_s);
  19. $cte = new \DateTime();
  20. $cte->sub($inter_e);
  21. $em = $this->getEntityManager();
  22. $repo = $em->getRepository('AppBundle:Status');
  23. $q = $repo->createQueryBuilder('s')
  24. ->leftJoin('AppBundle:User', 'u', 'with', 'u=s.author')
  25. ->where('s.created>=:e')
  26. ->setParameter('e', $cte)
  27. ->andWhere('s.created<=:s')
  28. ->setParameter('s', $cts)
  29. ->setMaxResults($count)
  30. ->orderBy('s.created', 'desc')
  31. ->addOrderBy('s.id', 'desc')
  32. ->getQuery()
  33. ;
  34. $status = $q->getResult();
  35. return $status;
  36. }
  37. }

getStatusIn方法会提供在开始和结束期间的数据,缺省是提供4个。显然,这个数据的提供(搜索)不是简单地由findBy之类的实体方法可以完成的。

上面我们看到的构建SQL的方法是两种可用方法中的一种,即通过链接各个函数调用,在查询构造中中加入joinwhereorder by等限定而得到我们需要的一个select语句。

对其的调用在Controller中一般这样进行:

  1. public function indexAction()
  2. {
  3. $em = $this->getDoctrine()->getManager();
  4. $repo = $em->getRepository('AppBundle:Status');
  5. $day = $repo->getStatusIn('P0D', 'P1D', 5);
  6. $week = $repo->getStatusIn('P1D', 'P7D');
  7. $month = $repo->getStatusIn('P7D', 'P1M', 5);
  8. ... ...

这几乎是一个标准的调用模式。

重要更新:如今的一种开发方式将我们从这样的重度耦合中解放了出来。因此不再需要Repository,而直接改用远程RESTful API的调用。详细的讨论可以参见03.01 MVC