介绍 Zend\Db\Sql 和 Zend\Stdlib\Hydrator

2年前 阅读 134 评论 0 赞 0

介绍 Zend\Db\Sql 和 Zend\Stdlib\Hydrator

在上一个章节中我们介绍了映射层并且创建了 PostMapperInterface。现在是时候将这个接口进行实现了,以便让我们能再次使用 PostService。作为一个指导性示例,我们会使用 Zend\Db\Sql 类。

准备数据库

在我们能开始使用数据库之前,我们应该先准备一个数据库。在这个示例中我们会使用一个 MySQL 数据库,名称为 blog,并且可以在 localhost 上被访问。这个数据库会拥有一个叫做 posts 的表,表拥有三个属性 idtitletext,其中 id 是主键。为了演示需要,请使用这个数据库 dump:

  1. CREATE TABLE posts (
  2. id int(11) NOT NULL auto_increment,
  3. title varchar(100) NOT NULL,
  4. text TEXT NOT NULL,
  5. PRIMARY KEY (id)
  6. );
  7. INSERT INTO posts (title, text)
  8. VALUES ('Blog #1', 'Welcome to my first blog post');
  9. INSERT INTO posts (title, text)
  10. VALUES ('Blog #2', 'Welcome to my second blog post');
  11. INSERT INTO posts (title, text)
  12. VALUES ('Blog #3', 'Welcome to my third blog post');
  13. INSERT INTO posts (title, text)
  14. VALUES ('Blog #4', 'Welcome to my fourth blog post');
  15. INSERT INTO posts (title, text)
  16. VALUES ('Blog #5', 'Welcome to my fifth blog post');

Zend\Db\Sql 的一些小知识

要使用 Zend\Db\Sql 来查询一个数据库,你需要拥有一个可用的数据库连接。这个链接使用过任何实现 Zend\Db\Adapter\AdapterInterface 接口的类创建的。最方便的创建这种类的方法是通过使用(监听配置键 db 的) Zend\Db\Adapter\AdapterServiceFactory。让我们从创建所需配置条目开始,修改你的 module.config.php 文件,添加一个顶级键 db

  1. <?php
  2. // 文件名: /module/Blog/config/module.config.php
  3. return array(
  4. 'db' => array(
  5. 'driver' => 'Pdo',
  6. 'username' => 'SECRET_USERNAME', //edit this
  7. 'password' => 'SECRET_PASSWORD', //edit this
  8. 'dsn' => 'mysql:dbname=blog;host=localhost',
  9. 'driver_options' => array(
  10. \PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
  11. )
  12. ),
  13. 'service_manager' => array( /** ServiceManager Config */ ),
  14. 'view_manager' => array( /** ViewManager Config */ ),
  15. 'controllers' => array( /** ControllerManager Config */ ),
  16. 'router' => array( /** Router Config */ )
  17. );

如您所见我们已经添加了 db 键,并且在里面我们添加了必要的参数来创建一个驱动示例。

注意:一个需要注意的重要事情是,通常你不会希望你的凭证存放在一个普通的配置文件中,而是希望存放在本地配置文件中,例如 /config/autoload/db.local.php。在使用 zend 骨架 .gitignore 文件标记时,存放在本地的文件不会被推送到服务器。当您共享您的代码时请务必注意这点。参考下例代码:

  1. <?php
  2. // 文件名: /config/autoload/db.local.php
  3. return array(
  4. 'db' => array(
  5. 'driver' => 'Pdo',
  6. 'username' => 'SECRET_USERNAME', //edit this
  7. 'password' => 'SECRET_PASSWORD', //edit this
  8. 'dsn' => 'mysql:dbname=blog;host=localhost',
  9. 'driver_options' => array(
  10. \PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
  11. )
  12. ),
  13. );

接下来我们要做的事情就是利用 AdapterServiceFactory。这是一个 ServiceManager 条目,看上去像下面这样:

  1. <?php
  2. // 文件名: /module/Blog/config/module.config.php
  3. return array(
  4. 'db' => array(
  5. 'driver' => 'Pdo',
  6. 'username' => 'SECRET_USERNAME', //edit this
  7. 'password' => 'SECRET_PASSWORD', //edit this
  8. 'dsn' => 'mysql:dbname=blog;host=localhost',
  9. 'driver_options' => array(
  10. \PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
  11. )
  12. ),
  13. 'service_manager' => array(
  14. 'factories' => array(
  15. 'Blog\Service\PostServiceInterface' => 'Blog\Service\Factory\PostServiceFactory',
  16. 'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory'
  17. )
  18. ),
  19. 'view_manager' => array( /** ViewManager Config */ ),
  20. 'controllers' => array( /** ControllerManager Config */ ),
  21. 'router' => array( /** Router Config */ )
  22. );

请注意名为 Zend\Db\Adapter\Adapter 的新 Service。现在调用这个 Service 终会得到一个正在运行的,实现 Zend\Db\Adapter\AdapterInterface 接口的一个示例,这取决于我们指定的驱动。

当 Adapter 就位时,我们现在可以对数据库进行查询了。查询的构造最好通过 Zend\Db\Sql 的 “QueryBuilder” 功能完成,若要进行 select 查询则使用 Zend\Db\Sql\Sql;若要进行 insert 查询则使用 Zend\Db\Sql\Insert;若要进行 update 或者 delete 查询则分别使用 Zend\Db\Sql\UpdateZend\Db\Sql\Delete。这些组件的基本工作流是:

  1. 建立一个使用 SqlInsertUpdateDelete的查询
  2. Sql 对象创建一个 SQL 语句
  3. 执行查询
  4. 对结果做点什么

知道这些之后我们现在可以编写 PostMapperInterface 接口的实现了。

编写映射器的实现

我们的映射器实现会存放在和它的接口同样的名称空间内。现在开始创建一个类,称之为 ZendDbSqlMapper 然后 implements PostMapperInterface

现在回想我们之前学到的东西。为了让 Zend\Db\Sql 能工作我们需要一个可用的 AdapterInterface 接口的实现。这是一个要求,所以会通过构造器注入进行注入。创建一个 __construct() 函数来接收 AdapterInterface 作为参数,并且将其存放在类中:

  1. <?php
  2. // 文件名: /module/Blog/src/Blog/Mapper/ZendDbSqlMapper.php
  3. namespace Blog\Mapper;
  4. use Blog\Model\PostInterface;
  5. use Zend\Db\Adapter\AdapterInterface;
  6. class ZendDbSqlMapper implements PostMapperInterface
  7. {
  8. /**
  9. * @var \Zend\Db\Adapter\AdapterInterface
  10. */
  11. protected $dbAdapter;
  12. /**
  13. * @param AdapterInterface $dbAdapter
  14. */
  15. public function __construct(AdapterInterface $dbAdapter)
  16. {
  17. $this->dbAdapter = $dbAdapter;
  18. }
  19. /**
  20. * @param int|string $id
  21. *
  22. * @return PostInterface
  23. * @throws \InvalidArgumentException
  24. */
  25. public function find($id)
  26. {
  27. }
  28. /**
  29. * @return array|PostInterface[]
  30. */
  31. public function findAll()
  32. {
  33. }
  34. }

如您从以往的课程学到的内容,每当我们被要求参数,就要为这个类编写 factory。所以现在去为我们的映射器实现创建一个 factory 吧。

现在我们可以将映射器实现注册成一个 Service 了。如果你能回想起以往的章节,或者你有去查看一下当前的错误信息,你就会注意到我们通过调用 Blog\Mapper\PostMapperInterface Service 来获取映射器的实现。修改配置文件,以便让这个键能调用我们刚调用的 factory 类。

  1. <?php
  2. // 文件名: /module/Blog/config/module.config.php
  3. return array(
  4. 'db' => array( /** Db Config */ ),
  5. 'service_manager' => array(
  6. 'factories' => array(
  7. 'Blog\Mapper\PostMapperInterface' => 'Blog\Factory\ZendDbSqlMapperFactory',
  8. 'Blog\Service\PostServiceInterface' => 'Blog\Service\Factory\PostServiceFactory',
  9. 'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory'
  10. )
  11. ),
  12. 'view_manager' => array( /** ViewManager Config */ ),
  13. 'controllers' => array( /** ControllerManager Config */ ),
  14. 'router' => array( /** Router Config */ )
  15. );

当 adapter 就绪之后,你就能刷新博客站点 localhost:8080/blog,然后发现 ServiceNotFoundException 异常已经消失,取而代之的是一个 PHP 警告信息:

  1. Warning: Invalid argument supplied for foreach() in /module/Blog/view/blog/list/index.phtml on line 13
  2. ID Text Title

这是因为实际上我们的映射器还不会返回任何东西。让我们来修改一下 findAll() 函数来从数据库表中返回所有博客帖子。

  1. <?php
  2. // 文件名: /module/Blog/src/Blog/Mapper/ZendDbSqlMapper.php
  3. namespace Blog\Mapper;
  4. use Zend\Db\Adapter\AdapterInterface;
  5. class ZendDbSqlMapper implements PostMapperInterface
  6. {
  7. /**
  8. * @var \Zend\Db\Adapter\AdapterInterface
  9. */
  10. protected $dbAdapter;
  11. /**
  12. * @param AdapterInterface $dbAdapter
  13. */
  14. public function __construct(AdapterInterface $dbAdapter)
  15. {
  16. $this->dbAdapter = $dbAdapter;
  17. }
  18. /**
  19. * @param int|string $id
  20. *
  21. * @return \Blog\Entity\PostInterface
  22. * @throws \InvalidArgumentException
  23. */
  24. public function find($id)
  25. {
  26. }
  27. /**
  28. * @return array|\Blog\Entity\PostInterface[]
  29. */
  30. public function findAll()
  31. {
  32. $sql = new Sql($this->dbAdapter);
  33. $select = $sql->select('posts');
  34. $stmt = $sql->prepareStatementForSqlObject($select);
  35. $result = $stmt->execute();
  36. return $result;
  37. }
  38. }

上述代码应该看上去十分直接。可惜的是,再次刷新页面会发现另外一个错误信息。

让我们暂时先不要返回 $result 变量,然后生成一个 dump 来看看到底这里发生了什么。更改 findAll() 函数来做一个 $result 变量的数据 dump:

  1. <?php
  2. // 文件名: /module/Blog/src/Blog/Mapper/ZendDbSqlMapper.php
  3. namespace Blog\Mapper;
  4. use Blog\Model\PostInterface;
  5. use Zend\Db\Adapter\AdapterInterface;
  6. use Zend\Db\Sql\Sql;
  7. class ZendDbSqlMapper implements PostMapperInterface
  8. {
  9. /**
  10. * @var \Zend\Db\Adapter\AdapterInterface
  11. */
  12. protected $dbAdapter;
  13. /**
  14. * @param AdapterInterface $dbAdapter
  15. */
  16. public function __construct(AdapterInterface $dbAdapter)
  17. {
  18. $this->dbAdapter = $dbAdapter;
  19. }
  20. /**
  21. * @param int|string $id
  22. *
  23. * @return PostInterface
  24. * @throws \InvalidArgumentException
  25. */
  26. public function find($id)
  27. {
  28. }
  29. /**
  30. * @return array|PostInterface[]
  31. */
  32. public function findAll()
  33. {
  34. $sql = new Sql($this->dbAdapter);
  35. $select = $sql->select('posts');
  36. $stmt = $sql->prepareStatementForSqlObject($select);
  37. $result = $stmt->execute();
  38. \Zend\Debug\Debug::dump($result);die();
  39. }
  40. }

刷新应用程序后你应该能看见以下输出:

  1. object(Zend\Db\Adapter\Driver\Pdo\Result)#303 (8) {
  2. ["statementMode":protected] => string(7) "forward"
  3. ["resource":protected] => object(PDOStatement)#296 (1) {
  4. ["queryString"] => string(29) "SELECT `posts`.* FROM `posts`"
  5. }
  6. ["options":protected] => NULL
  7. ["currentComplete":protected] => bool(false)
  8. ["currentData":protected] => NULL
  9. ["position":protected] => int(-1)
  10. ["generatedValue":protected] => string(1) "0"
  11. ["rowCount":protected] => NULL
  12. }

如您所见,没有任何数据被返回,取而代之的是我们得到了一些 Result 对象的 dump,并且里面并不包含任何有用的数据。不过这是一个错误的推论,这个 Result 对象只有在当你实际试图访问的时候才会拥有信息。所以若要利用 Result 对象内的数据,最佳方案是将 Result 对象传给 ResultSet 对象,只要查询成功就可以这样做。

  1. <?php
  2. // 文件名: /module/Blog/src/Blog/Mapper/ZendDbSqlMapper.php
  3. namespace Blog\Mapper;
  4. use Blog\Model\PostInterface;
  5. use Zend\Db\Adapter\AdapterInterface;
  6. use Zend\Db\Adapter\Driver\ResultInterface;
  7. use Zend\Db\ResultSet\ResultSet;
  8. use Zend\Db\Sql\Sql;
  9. class ZendDbSqlMapper implements PostMapperInterface
  10. {
  11. /**
  12. * @var \Zend\Db\Adapter\AdapterInterface
  13. */
  14. protected $dbAdapter;
  15. /**
  16. * @param AdapterInterface $dbAdapter
  17. */
  18. public function __construct(AdapterInterface $dbAdapter)
  19. {
  20. $this->dbAdapter = $dbAdapter;
  21. }
  22. /**
  23. * @param int|string $id
  24. *
  25. * @return PostInterface
  26. * @throws \InvalidArgumentException
  27. */
  28. public function find($id)
  29. {
  30. }
  31. /**
  32. * @return array|PostInterface[]
  33. */
  34. public function findAll()
  35. {
  36. $sql = new Sql($this->dbAdapter);
  37. $select = $sql->select('posts');
  38. $stmt = $sql->prepareStatementForSqlObject($select);
  39. $result = $stmt->execute();
  40. if ($result instanceof ResultInterface && $result->isQueryResult()) {
  41. $resultSet = new ResultSet();
  42. \Zend\Debug\Debug::dump($resultSet->initialize($result));die();
  43. }
  44. die("no data");
  45. }
  46. }

再次刷新页面,你应该能看见 ResultSet 对象的 dump 现在拥有属性 ["count":protected] => int(5),这意味着我们有5列元组在我们的数据库中。

  1. object(Zend\Db\ResultSet\ResultSet)#304 (8) {
  2. ["allowedReturnTypes":protected] => array(2) {
  3. [0] => string(11) "arrayobject"
  4. [1] => string(5) "array"
  5. }
  6. ["arrayObjectPrototype":protected] => object(ArrayObject)#305 (1) {
  7. ["storage":"ArrayObject":private] => array(0) {
  8. }
  9. }
  10. ["returnType":protected] => string(11) "arrayobject"
  11. ["buffer":protected] => NULL
  12. ["count":protected] => int(2)
  13. ["dataSource":protected] => object(Zend\Db\Adapter\Driver\Pdo\Result)#303 (8) {
  14. ["statementMode":protected] => string(7) "forward"
  15. ["resource":protected] => object(PDOStatement)#296 (1) {
  16. ["queryString"] => string(29) "SELECT `posts`.* FROM `posts`"
  17. }
  18. ["options":protected] => NULL
  19. ["currentComplete":protected] => bool(false)
  20. ["currentData":protected] => NULL
  21. ["position":protected] => int(-1)
  22. ["generatedValue":protected] => string(1) "0"
  23. ["rowCount":protected] => int(2)
  24. }
  25. ["fieldCount":protected] => int(3)
  26. ["position":protected] => int(0)
  27. }

另外一个非常有趣的属性是 ["returnType":protected] => string(11) "arrayobject"。这告诉了我们所有的数据库条目都会以 ArrayObject 的形式返回。这产生了一个小问题,因为 PostMapperInterface 要求我们返回一个 PostInterface 对象数组,幸运的是这里有非常简单的办法让我们来解决它。在上面的例子中我们使用了默认的 ResultSet 对象。其实这里还有 HydratingResultSet 对象来将给出的数据充水成给出的对象。意思就是,如果我们告诉 HydratingResultSet 对象来使用数据库数据为我们生成 post 对象,那么它就能做到。让我们修改一下我们的代码:

  1. <?php
  2. // 文件名: /module/Blog/src/Blog/Mapper/ZendDbSqlMapper.php
  3. namespace Blog\Mapper;
  4. use Blog\Model\PostInterface;
  5. use Zend\Db\Adapter\AdapterInterface;
  6. use Zend\Db\Adapter\Driver\ResultInterface;
  7. use Zend\Db\ResultSet\HydratingResultSet;
  8. use Zend\Db\Sql\Sql;
  9. class ZendDbSqlMapper implements PostMapperInterface
  10. {
  11. /**
  12. * @var \Zend\Db\Adapter\AdapterInterface
  13. */
  14. protected $dbAdapter;
  15. /**
  16. * @param AdapterInterface $dbAdapter
  17. */
  18. public function __construct(AdapterInterface $dbAdapter)
  19. {
  20. $this->dbAdapter = $dbAdapter;
  21. }
  22. /**
  23. * @param int|string $id
  24. *
  25. * @return PostInterface
  26. * @throws \InvalidArgumentException
  27. */
  28. public function find($id)
  29. {
  30. }
  31. /**
  32. * @return array|PostInterface[]
  33. */
  34. public function findAll()
  35. {
  36. $sql = new Sql($this->dbAdapter);
  37. $select = $sql->select('posts');
  38. $stmt = $sql->prepareStatementForSqlObject($select);
  39. $result = $stmt->execute();
  40. if ($result instanceof ResultInterface && $result->isQueryResult()) {
  41. $resultSet = new HydratingResultSet(new \Zend\Stdlib\Hydrator\ClassMethods(), new \Blog\Model\Post());
  42. return $resultSet->initialize($result);
  43. }
  44. return array();
  45. }
  46. }

我们又进行了几项更改。首先我们将普通的 ResultSet 替换成 HydratingResultSet。这个对象要求两个参数,第一个是使用的 hydrator 类型,第二个是 hydrator 目标对象。hydrator 简单来说,就是一个对象用来将任意类型的数据从一种格式转换成另一种。我们现在的输入类型是 ArrayObject,但是我们想要 Post 模型。而 ClassMethods hydrator 搞定这个转换问题,通过调用我们的 Post 模型的 getter 和 setter 函数。

比起去 dump $result 变量,我们现在直接返回初始化过的 HydratingResultSet 对象,从而得以访问里面存储的数据。如果我们得到了一些不是 ResultInterface 的实例的返回值,那么就会返回一个空数组。

刷新页面,现在你就能看见你所有的博客帖子了,很好!

重构隐藏依赖对象

在我们完成的事情中,还有一件事情并没有做到最佳实践。我们同时使用 hydrator 和一个对象在下述文件内:

  1. <?php
  2. // 文件名: /module/Blog/src/Blog/Mapper/ZendDbSqlMapper.php
  3. namespace Blog\Mapper;
  4. use Blog\Model\PostInterface;
  5. use Zend\Db\Adapter\AdapterInterface;
  6. use Zend\Db\Adapter\Driver\ResultInterface;
  7. use Zend\Db\ResultSet\HydratingResultSet;
  8. use Zend\Db\Sql\Sql;
  9. use Zend\Stdlib\Hydrator\HydratorInterface;
  10. class ZendDbSqlMapper implements PostMapperInterface
  11. {
  12. /**
  13. * @var \Zend\Db\Adapter\AdapterInterface
  14. */
  15. protected $dbAdapter;
  16. /**
  17. * @var \Zend\Stdlib\Hydrator\HydratorInterface
  18. */
  19. protected $hydrator;
  20. /**
  21. * @var \Blog\Model\PostInterface
  22. */
  23. protected $postPrototype;
  24. /**
  25. * @param AdapterInterface $dbAdapter
  26. * @param HydratorInterface $hydrator
  27. * @param PostInterface $postPrototype
  28. */
  29. public function __construct(
  30. AdapterInterface $dbAdapter,
  31. HydratorInterface $hydrator,
  32. PostInterface $postPrototype
  33. ) {
  34. $this->dbAdapter = $dbAdapter;
  35. $this->hydrator = $hydrator;
  36. $this->postPrototype = $postPrototype;
  37. }
  38. /**
  39. * @param int|string $id
  40. *
  41. * @return PostInterface
  42. * @throws \InvalidArgumentException
  43. */
  44. public function find($id)
  45. {
  46. }
  47. /**
  48. * @return array|PostInterface[]
  49. */
  50. public function findAll()
  51. {
  52. $sql = new Sql($this->dbAdapter);
  53. $select = $sql->select('posts');
  54. $stmt = $sql->prepareStatementForSqlObject($select);
  55. $result = $stmt->execute();
  56. if ($result instanceof ResultInterface && $result->isQueryResult()) {
  57. $resultSet = new HydratingResultSet($this->hydrator, $this->postPrototype);
  58. return $resultSet->initialize($result);
  59. }
  60. return array();
  61. }
  62. }

现在我们的映射器需要更多的参数来更新 ZendDbSqlMapperFactory 并且注入那些参数了。

  1. <?php
  2. // 文件名: /module/Blog/src/Blog/Factory/ZendDbSqlMapperFactory.php
  3. namespace Blog\Factory;
  4. use Blog\Mapper\ZendDbSqlMapper;
  5. use Blog\Model\Post;
  6. use Zend\ServiceManager\FactoryInterface;
  7. use Zend\ServiceManager\ServiceLocatorInterface;
  8. use Zend\Stdlib\Hydrator\ClassMethods;
  9. class ZendDbSqlMapperFactory implements FactoryInterface
  10. {
  11. /**
  12. * Create service
  13. *
  14. * @param ServiceLocatorInterface $serviceLocator
  15. *
  16. * @return mixed
  17. */
  18. public function createService(ServiceLocatorInterface $serviceLocator)
  19. {
  20. return new ZendDbSqlMapper(
  21. $serviceLocator->get('Zend\Db\Adapter\Adapter'),
  22. new ClassMethods(false),
  23. new Post()
  24. );
  25. }
  26. }

当这些就绪之后,你可以再次刷新应用程序,就能看见你的博客帖子再次显示出来了。我们的映射器现在拥有一个很不错的架构,并且没有更多隐含的依赖对象了。

完成映射器

在我们跨越到下一个章节之前,先快速地通过为 find() 函数编写一个实现来完成映射器。

  1. <?php
  2. // 文件名: /module/Blog/src/Blog/Mapper/ZendDbSqlMapper.php
  3. namespace Blog\Mapper;
  4. use Blog\Model\PostInterface;
  5. use Zend\Db\Adapter\AdapterInterface;
  6. use Zend\Db\Adapter\Driver\ResultInterface;
  7. use Zend\Db\ResultSet\HydratingResultSet;
  8. use Zend\Db\Sql\Sql;
  9. use Zend\Stdlib\Hydrator\HydratorInterface;
  10. class ZendDbSqlMapper implements PostMapperInterface
  11. {
  12. /**
  13. * @var \Zend\Db\Adapter\AdapterInterface
  14. */
  15. protected $dbAdapter;
  16. /**
  17. * @var \Zend\Stdlib\Hydrator\HydratorInterface
  18. */
  19. protected $hydrator;
  20. /**
  21. * @var \Blog\Model\PostInterface
  22. */
  23. protected $postPrototype;
  24. /**
  25. * @param AdapterInterface $dbAdapter
  26. * @param HydratorInterface $hydrator
  27. * @param PostInterface $postPrototype
  28. */
  29. public function __construct(
  30. AdapterInterface $dbAdapter,
  31. HydratorInterface $hydrator,
  32. PostInterface $postPrototype
  33. ) {
  34. $this->dbAdapter = $dbAdapter;
  35. $this->hydrator = $hydrator;
  36. $this->postPrototype = $postPrototype;
  37. }
  38. /**
  39. * @param int|string $id
  40. *
  41. * @return PostInterface
  42. * @throws \InvalidArgumentException
  43. */
  44. public function find($id)
  45. {
  46. $sql = new Sql($this->dbAdapter);
  47. $select = $sql->select('posts');
  48. $select->where(array('id = ?' => $id));
  49. $stmt = $sql->prepareStatementForSqlObject($select);
  50. $result = $stmt->execute();
  51. if ($result instanceof ResultInterface && $result->isQueryResult() && $result->getAffectedRows()) {
  52. return $this->hydrator->hydrate($result->current(), $this->postPrototype);
  53. }
  54. throw new \InvalidArgumentException("Blog with given ID:{$id} not found.");
  55. }
  56. /**
  57. * @return array|PostInterface[]
  58. */
  59. public function findAll()
  60. {
  61. $sql = new Sql($this->dbAdapter);
  62. $select = $sql->select('posts');
  63. $stmt = $sql->prepareStatementForSqlObject($select);
  64. $result = $stmt->execute();
  65. if ($result instanceof ResultInterface && $result->isQueryResult()) {
  66. $resultSet = new HydratingResultSet($this->hydrator, $this->postPrototype);
  67. return $resultSet->initialize($result);
  68. }
  69. return array();
  70. }
  71. }

这个 find() 函数看上去真的很像 findAll() 函数。这里只有三点简单的差别:首先我们需要为查询添加一个条件,让其只选择一行,这通过使用 Sql 对象的 where() 函数实现。然后我们也要检查 $result 变量内是否有元组在内,这通过 getAffectedRows() 函数实现。返回语句会被注入的 hydrator 变成同样被注入的原型中。

这次,但我们找不到任何元组时,会抛出一个 \InvalidArgumentException 异常,以便应用程序可以方便的处理这种状况。

总结

完成这个章节之后,你现在了解了如何通过 Zend\Db\Sql 类来查询数据,也学习了关于 ZF2 新关键组件之一的 Zend\Stdlib\Hydrator 的知识。而且你再一次证明了你可以驾驭恰当的依赖对象注入。

在下一个章节中,我们会更进一步地了解 router,这样能让我们在模组内做更多动作。

你的支持将鼓励作者继续创作

评论(0)

(无)