如何在Zend Framework 2中实现搜索模块的分页?

时间:2013-04-16 18:10:10

标签: pagination zend-framework2 zend-paginator

我的ZF2应用程序中有一个模块Search。用户填写搜索表单并获取课程列表。

现在我将分页添加到模块中。分页器基本上工作:我可以通过它检索数据并正确显示分页(70页找到的课程的页面链接1-7,dafault设置每页10项)。

但它仍然无法使用。单击页面链接时,表单POST数据将丢失。我知道 - 它无法正常工作,我是如何实现的(参见下面的代码)。但我不知道,如何正确地做到这一点,以便检查表单数据,但仍然可以使用分页。

那是我的代码:

表类Search \ Model \ CourseTable

class CourseTable {

    ...

    // without pagination
    // public function findAllByCriteria(CourseSearchInput $input) {
    // with pagination
    public function findAllByCriteria(CourseSearchInput $input, $pageNumber) {
        ...
        $select = new Select();
        $where = new Where();
        $having = new Having();
        ...
        // without pagination
        // $resultSet = $this->tableGateway->selectWith($select);
        // return $resultSet;
        // with pagination
        $adapter = new \MyNamespqce\Paginator\Adapter\DbSelect($select, $this->tableGateway->getAdapter());
        $paginator = new \Zend\Paginator\Paginator($adapter);
        $paginator->setCurrentPageNumber($pageNumber);
        return $paginator;
    }

    ... 

}

搜索\控制器\ SearchController

class SearchController extends AbstractActionController {

    public function searchCoursesAction() {
        $form = $this->getServiceLocator()->get('Search\Form\CourseSearchForm');
        $request = $this->getRequest();
        if ($request->isPost()) {
            $courseSearchInput = new CourseSearchInput();
            $form->setInputFilter($courseSearchInput->getInputFilter());
            $form->setData($request->getPost());
            if ($form->isValid()) {
                $courseSearchInput->exchangeArray($form->getData());
                // without pagination
                // $courses = $this->getCourseTable()->findAllByCriteria($courseSearchInput);
                // with pagination
                $page = $this->params()->fromRoute('page');
                $paginator = $this->getCourseTable()->findAllByCriteria($courseSearchInput, $page);
            } else {
                $paginator = null;
            }
        } else {
            $paginator = null;
        }
        return new ViewModel(array(
            'form' => $form,
            // without pagination
            // 'courses' => $courses,
            // with pagination
            'paginator' => $paginator,
            'cities' => ...
        ));
    }

    ...

}

如何让它运作?

2 个答案:

答案 0 :(得分:1)

我也有同样的问题,我已经解决了。但这不是好方法。可能是这个想法会对你有帮助。

我解决了它如下:(搜索Zend教程相册模块的分页)

我在控制器中构建了两个名为“search”和“index”的动作。

每当提交搜索表单时,它始终将值发布到搜索操作。搜索操作使用搜索参数构建URL,并重定向到索引以显示搜索结果。

点击分页链接后,发布的值会通过网址传递。因此,每当索引操作请求搜索参数时,它总是以相同的格式获取值。

我将路线定义如下:

'album' => array(
    'type'    => 'segment',
    'options' => array(
        'route'    => '/album[/:action][/:id][/page/:page][/order_by/:order_by][/:order][/search_by/:search_by]',
        'constraints' => array(
            'action'    => '(?!\bpage\b)(?!\border_by\b)(?!\bsearch_by\b)[a-zA-Z][a-zA-Z0-9_-]*',
            'id'     => '[0-9]+',
            'page' => '[0-9]+',
            'order_by' => '[a-zA-Z][a-zA-Z0-9_-]*',
            'order' => 'ASC|DESC',
        ),
        'defaults' => array(
            'controller' => 'Album\Controller\Album',
            'action'     => 'index',
        ),
    ),
),

有一个名为“search_by”的参数,它将所有搜索参数保存为json字符串。这是重点,我知道这不好,但还没有找到任何其他方法。

“搜索”操作将此字符串构建为 -

public function searchAction()
{

    $request = $this->getRequest();

    $url = 'index';

    if ($request->isPost()) {
        $formdata    = (array) $request->getPost();
        $search_data = array();
        foreach ($formdata as $key => $value) {
            if ($key != 'submit') {
                if (!empty($value)) {
                    $search_data[$key] = $value;
                }
            }
        }
        if (!empty($search_data)) {
            $search_by = json_encode($search_data);
            $url .= '/search_by/' . $search_by;
        }
    }
    $this->redirect()->toUrl($url);
}

下一个索引操作解码字符串,执行必要的操作,并发送json字符串进行查看。

public function indexAction() {
    $searchform = new AlbumSearchForm();
    $searchform->get('submit')->setValue('Search');

    $select = new Select();

    $order_by = $this->params()->fromRoute('order_by') ?
            $this->params()->fromRoute('order_by') : 'id';
    $order = $this->params()->fromRoute('order') ?
            $this->params()->fromRoute('order') : Select::ORDER_ASCENDING;
    $page = $this->params()->fromRoute('page') ? (int) $this->params()->fromRoute('page') : 1;
    $select->order($order_by . ' ' . $order);
    $search_by = $this->params()->fromRoute('search_by') ?
            $this->params()->fromRoute('search_by') : '';


    $where    = new \Zend\Db\Sql\Where();
    $formdata = array();
    if (!empty($search_by)) {
        $formdata = (array) json_decode($search_by);
        if (!empty($formdata['artist'])) {
            $where->addPredicate(
                    new \Zend\Db\Sql\Predicate\Like('artist', '%' . $formdata['artist'] . '%')
            );
        }
        if (!empty($formdata['title'])) {
            $where->addPredicate(
                    new \Zend\Db\Sql\Predicate\Like('title', '%' . $formdata['title'] . '%')
            );
        }

    }
    if (!empty($where)) {
        $select->where($where);
    }


    $album = $this->getAlbumTable()->fetchAll($select);
    $totalRecord  = $album->count();
    $itemsPerPage = 2;

    $album->current();
    $paginator = new Paginator(new paginatorIterator($album));
    $paginator->setCurrentPageNumber($page)
            ->setItemCountPerPage($itemsPerPage)
            ->setPageRange(7);

    $searchform->setData($formdata);

    return new ViewModel(array(
        'search_by'  => $search_by,
        'order_by'   => $order_by,
        'order'      => $order,
        'page'       => $page,
        'paginator'  => $paginator,
        'pageAction' => 'album',
        'form'       => $searchform,
        'totalRecord' => $totalRecord
    ));


}

所有排序和分页网址都包含该字符串。

如果你之前知道所有的搜索参数,那么你可以在路由中定义它,并且在没有json字符串的情况下以相同的方式传递。由于我必须构建一个通用搜索,我已经构建了一个字符串。

“相册搜索”的源代码可在https://github.com/tahmina8765/zf2_search_with_pagination_example的git hub中找到。

现场演示:http://zf2pagination.lifencolor.com/public/album

答案 1 :(得分:1)

@Sam& @automatix在问题评论中都是对的。我的建议(虽然我正在寻找一个更简单的替代方案)是构建一个段路由,它涵盖了您可能需要的所有选项,并以标准表单POST请求开始。

然后,在验证请求后,将表单数据传递给paginationControl助手,如下所示:

$resultsView = new ViewModel(array(
  'paginator' => $paginator,
  'routeParams' => array_filter($form->getData())
));

然后,在视图模板中,在paginationControl视图助手中设置路由参数:

<?php echo $this->paginationControl($paginator, 'Sliding', 'paginator/default',
    array('routeParams' => $routeParams)
) ?>

我在这里使用了array_filter,因为它是从表单数据中删除任何元素的一种非常简单的方法,即空,空等等。这样你就不会传递你不需要的额外数据。