質問

What is considered the correct place for my pagination to live when using a service/datamapper/domain object trio?

Example:

  • Fetch ports with a few given criteria
  • Paginate the results
  • Know what page we are on, number of pages in total, number of results etc.. from the view class

The below is just something I wrote here and now, but it is similar to my application.

class PostController extends Controller
{
    function viewPosts()
    {
        return $this->serviceFactory
            ->build('post')
            ->getPosts($aCriteria, $this->request->_get('page'), 10);
    }
}

I am currently both calculating and storing pagination parameters in each service. Note that I am not pushing any data to the view from my controller.

class PostService extends AbstractService
{
    public $posts;

    public $iTotalPages; // This does not belong here does it?

    function getPosts($aCriteria, $iPage, $iItemsPerPage)
    {
        $mapper = $this->dataMapperFactory->build('post');

        // I do not know where to put the below
        // (The parameters and the code itself)
        $iCount = $mapper->count($aCriteria);
        $iOffset = $iItemsPerPage * $iPage;
        $this->iTotalPages = $iCount / $iItemsPerPage;

        $this->posts = $mapper->find($aCriteria, $iOffset, $iOffset + $iItemsPerPage);

        return $this->posts;
    }
}

My views have access to the same instance of the Model layer as my controller, so I could call $service->iTotalPages from the view, but that feels wrong.

class PostsView extends AbstractView
{
    function viewPosts()
    {
        $service = $this->serviceFactory->build('post');

        if(count($service->posts)>0) {
            $this->template->assign_var('TOTAL_PAGES', $service->iTotalPages);
            $this->template->assign_vars('POSTS', $service->posts);        
        }
    }
}

Solutions?

1) Create a service for pagination and have the controller exchange data with the post service as required?

2) Create a helper class for pagination that each service can include? (How would such a class look like?)

3) Add generic pagination to the AbstractService?

4) Add some sort of pagination support to my Repos?

役に立ちましたか?

解決

You answer is pretty good, though I have a few suggestions.

Layer location:

The pagination infrastructure should live in the data access layer, this is so that you have low level control on how the data are retrieved.

Highest invocation

The pagination's interface should be abstracted and exposed in the UI through the service, since its a front-end concern. (I think you already have this covered in your answer)

The Abstraction:

What the UI should know are the page index, number of pages, number of items per page, and total items. Not the Offset nor the limit, these are infrastructure terms that should be encapsulated.

Input: (part of your fitlers)

  1. Search filters
  2. Sorting filters (if necessary)
  3. Page index.
  4. Number of items per page. (if the UI has control, if not then this should be encapsulated)

Output:

  1. Filtered collection
  2. Number of pages (for navigation)
  3. Number of total items (if necessary in the UI)

他のヒント

Due to lack of answers to this question I am posting the solution I came up with. Appreciate comments/additions to it if it can be improved.

// Controller method
public function viewPosts()
{
    // Create service objects
    $postService = $this->serviceFactory->build('post', true);
    $searchService = $this->serviceFactory->build('search');

    // Set the search/filter parameters
    $searchService->addFilter('author_id', $this->visitor->user_id);
    $searchService->setOffset($this->request->_get('offset'));
    $searchService->setLimit($this->request->_get('limit'));

    // Search service will call the 'find' method on $articleService
    $searchService->setServiceObject($articleService, 'find');

    // Search service will return a filtered collection
    return $searchService->search();
}

Doing it this way I am not leaking business logic into my controller (I think), and I have a single class to do all my filtering and analysis of the returned sql data, while still keeping each specific service in control of their specific find() method and datamappers.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top