Skip to content

Instantly share code, notes, and snippets.

@MontealegreLuis
Last active August 5, 2021 12:44
Show Gist options
  • Save MontealegreLuis/9255171 to your computer and use it in GitHub Desktop.
Save MontealegreLuis/9255171 to your computer and use it in GitHub Desktop.
Pagination and DDD
<?php
namespace Doctrine1\TableGateway;
use \Doctrine_Record as Record;
use \Doctrine_Query as Query;
use \Doctrine1\QuerySpecifications\Specification;
abstract class DoctrineTable
{
protected $record;
protected $specification;
/**
* @param Doctrine_Record $record
*/
public function __construct(Record $record)
{
$this->record = $record;
}
/**
* @param Specification $specification
*/
public function addSpecification(Specification $specification)
{
$this->specification = $specification;
}
// ...
/**
* @param string $alias = ''
* @return \Doctrine_Query
*/
public function createQuery($alias = '')
{
return $this->record->getTable()->createQuery($alias);
}
/**
* @param Query $query
*/
protected function match(Query $query)
{
$this->specification->match($query);
}
}
<?php
namespace ProductCatalog;
use ProductCatalog\Products\ProductRepository;
class GetAllProducts
{
protected $repository;
/**
* @param ProductRepository $repository
*/
public function __construct(ProductRepository $repository)
{
$this->repository = $repository;
}
/**
* @return \ProductCatalog\Products\Product[]
*/
public function getAllProducts()
{
return $this->repository->allProducts();
}
}
<?php
use \ProductCatalog\GetAllProducts;
use \CatalogModule\Controllers\ListProductsController;
use \Application\ProductCatalog\Products\ProductTable;
use \Application\ProductCatalog\Products\ProductRecord;
use \ZendApplication\Paginator\PaginatorFactory;
use \ZendApplication\Paginator\Events\PaginationEventFactory;
// Initialize $request and $response ...
$paginatorFactory = new PaginatorFactory(require 'config/pagination.php');
$repository = new ProductTable(new ProductRecord());
$repository->addSpecification(new OnlyPage(
$request->param('page', 1), $paginatorFactory->getItemCountPerPage()
); // This sets limit and offset for the query
$listProductsController = new ListProductsController($request, $response);
$listProductsController->setUseCase(new GetAllProducts($repository));
$listProductsController->setPaginatorFactory($paginatorFactory);
$listProductsController->setPaginationEventFactory(new PaginationEventFactory($repository));
$listProductsController->getEventManager()->attach(
'onGetAllProducts', [$listProductsController, 'onGetAllProducts']
);
$listController->listAction();
<?php
namespace CatalogModule\Controllers;
use \ZendApplication\Controller\Action\ControllerAction;
use \ZendApplication\Paginator\PaginatorFactory;
use \ZendApplication\Paginator\Events\PaginationEventFactory;
use \ZendApplication\Paginator\Events\PaginationEvent;
use \ProductCatalog\GetAllProducts;
class ListProductsController extends ControllerAction
{
protected $paginatorFactory;
protected $paginationEventFactory
protected $useCase;
/**
* @param PaginatorFactory $paginatorFactory
*/
public function setPaginatorFactory(PaginatorFactory $paginatorFactory)
{
$this->paginatorFactory = $paginatorFactory;
}
/**
* @param GetAllProducts $getAllProducts
*/
public function setUseCase(GetAllProducts $getAllProducts)
{
$this->useCase = $getAllProducts;
}
public function listAction()
{
$this->view->products = $this->useCase->getAllProducts();
$this->getEventManager()->trigger($this->paginationEventFactory->create());
}
/**
* @param PaginationEvent $event
*/
public function onGetAllProducts(PaginationEvent $event)
{
$this->view->paginator = $this->paginatorFactory->fromArray(
$this->view->products,
$event->getTable()->count(), // Get the count of products (infrastructure layer, not domain)
$this->param('page', 1)
);
}
}
<?php
namespace Doctrine1\QuerySpecifications;
use \Doctrine_Query as Query;
class OnlyPage implements Specification
{
protected $itemsPerPage;
protected $page;
/**
* @param integer $page
* @param integer $itemsPerPage
*/
public function __construct($page, $itemsPerPage = 10)
{
$this->page = $page;
$this->itemsPerPage = $itemsPerPage;
}
public function match(Query $query)
{
return $query->limit($this->itemsPerPage)->offset($this->page);
}
}
<?php
namespace ZendApplication\Paginator\Events;
use \Countable;
use \Zend\EventManager\Event;
class PaginationEvent extends Event
{
/**
* @var Countable
*/
protected $table;
/**
* @param Countable $table
*/
public function setTable(Countable $table)
{
$this->table = $table;
}
/**
* @return Countable
*/
public function getTable()
{
return $this->table;
}
}
<?php
namespace Application\ProductCatalog\Products;
use \Doctrine_Core as Doctrine;
use \Doctrine1\TableGateway\DoctrineTable;
use \ProductCatalog\Products\ProductRepository;
use \ProductCatalog\Products\Product;
use \Countable;
class ProductTable extends DoctrineTable implements ProductRepository, Countable
{
/**
* @return Product
*/
public function allProducts()
{
$query = $this->createQuery('p');
$query->innerJoin('p.Category c');
$this->match($query); //Products get paginated here...
return $query->fetchArray();
}
/**
* @return integer
*/
public function count()
{
$query = $this->createQuery('p');
$query->select('COUNT(p.id)');
return $query->fetchOne([], Doctrine::HYDRATE_SINGLE_SCALAR);
}
}
<?php
namespace Doctrine1\QuerySpecifications;
use \Doctrine_Query as Query;
interface Specification
{
/**
* @param Query $query
*/
public function match(Query $query);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment