如何在Zend Framework 2中使用JOIN的分页?

时间:2016-09-12 10:02:48

标签: php pagination zend-framework2 zend-db zend-db-select

在一个应用程序中,我实现了一个Mapper来从数据库和ResultSet中的对象中检索数据。为了获得所有数据,我需要JOIN多个表。然后我得到一个像这样的大阵列:

[
    0 => [
        main_id => 1,
        main_title => 'lorem',
        main_desc => 'ipsum',
        foo_id => '12',
        foo_name => 'qwer',
        bar_id => '56',
        bar_name => 'asdf'
    ],
    1 => [
        main_id => 1,
        main_title => 'lorem',
        main_desc => 'ipsum',
        foo_id => '12',
        foo_name => 'qwer',
        bar_id => '67',
        bar_name => 'hjkl'
    ],
    2 => [
        main_id => 1,
        main_title => 'lorem',
        main_desc => 'ipsum',
        foo_id => '23',
        foo_name => 'uiop',
        bar_id => '67',
        bar_name => 'hjkl'
    ],
    ...
    10 => [
        main_id => 1,
        main_title => 'lorem',
        main_desc => 'ipsum',
        foo_id => '23',
        foo_name => 'uiop',
        bar_id => '91',
        bar_name => 'cvbn'
    ],
    11 => [
        main_id => 2,
        main_title => 'dolor',
        main_desc => 'sit',
        foo_id => '78',
        foo_name => 'fghj',
        bar_id => '89',
        bar_name => 'vbnm'
    ],
    ...
    12 => [
        main_id => 3,
        foo_id => '135',
        bar_id => '246',
        ...
    ],
    13 => [
        main_id => 3,
        foo_id => '135',
        bar_id => '468',
        ...
    ],
    14 => [
        main_id => 3,
        foo_id => '357',
        bar_id => '680',
        ...
    ],
    ...
    1000 => [
        ...
    ]
]

然后我遍历数组,构建对象(MainFooBar等),然后将它们组合起来,例如

$newMain = $myMainHydrator->hydrate($results[0]);
$newFoo = $myFooHydrator->hydrate($results[0]);
$newBar = $myBarHydrator->hydrate($results[0]);
$newFoo->setBar($newBar);
$newMain->setFoo($newFoo);
$resultObjects[] = $newMain;

现在我内置了Paginator并遇到了以下问题:Paginator设置了LIMIT,例如10,然后只检索10行,而我需要每个对象多个结果行(目前甚至是12行)。

我无法相信,Paginator无法处理JOIN,因此必须有办法让它发挥作用。如何使用Paginator复杂SELECTJOIN s?

1 个答案:

答案 0 :(得分:1)

可以通过LIMIT IN Paginator中的Adapter替换getItems(...)条款来解决此问题。

namespace Foo\Paginator\Adapter;

use Zend\Db\Sql\Select;
use Zend\Paginator\Adapter\DbSelect;
use Zend\Db\Sql\Sql;
use Zend\Db\Sql\Expression;

class FooPaginatorAdapter extends DbSelect
{

    public function count()
    {
        $select = new Select();
        $select->from('foo')->columns([self::ROW_COUNT_COLUMN_NAME => new Expression('COUNT(*)')]);

        $statement = $this->sql->prepareStatementForSqlObject($select);
        $result    = $statement->execute();
        $row       = $result->current();
        $this->rowCount = $row[self::ROW_COUNT_COLUMN_NAME];

        return $this->rowCount;
    }

    public function getItems($offset, $itemCountPerPage)
    {
        $select = clone $this->select;
        // replaced
        // $select->offset($offset);
        // $select->limit($itemCountPerPage);
        // by this
        $relevantIds = $this->getRelevantIds($offset, $itemCountPerPage);
        $select->where->in('foo.id', $relevantIds);

        $statement = $this->sql->prepareStatementForSqlObject($select);
        $result    = $statement->execute();

        $resultSet = clone $this->resultSetPrototype;
        $resultSet->initialize($result);

        return iterator_to_array($resultSet);
    }

    protected function getRelevantIds($offset, $itemCountPerPage)
    {
        $sql = new Sql($this->sql->getAdapter());
        $select = $sql->select('foo');
        $select->columns(['id']);
        $select->offset($offset);
        $select->limit($itemCountPerPage);

        $statement = $this->sql->prepareStatementForSqlObject($select);
        $result    = $statement->execute();

        $resultArray = iterator_to_array($result);

        $relevantIds = array_column($resultArray, 'id');

        return $relevantIds;
    }

}

正如您在本案中所看到的,首先必须使用单独的数据库请求检索ID。但无论如何 - 它有效。如果您知道更好的解决方案,请随时发布。