Experimental resource repository

This commit is contained in:
Paweł Jędrzejewski 2012-11-05 01:32:33 +01:00
parent 4293e37e26
commit df19162347
10 changed files with 373 additions and 176 deletions

View file

@ -26,22 +26,31 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* *
* @author Paweł Jędrzejewski <pjedrzejewski@sylius.pl> * @author Paweł Jędrzejewski <pjedrzejewski@sylius.pl>
*/ */
abstract class ResourceController extends Controller implements ResourceControllerInterface class ResourceController extends Controller implements ResourceControllerInterface
{ {
/** protected $bundlePrefix;
* Get one resource. protected $resourceName;
* protected $templateNamespace;
* @param Request $request
* public function __construct($bundlePrefix, $resourceName, $templateNamespace)
* @return Response
*/
public function getAction(Request $request)
{ {
$identifier = $this->getIdentifierValue($request); $this->bundlePrefix = $bundlePrefix;
$resource = $this->findResourceOr404($identifier); $this->resourceName = $resourceName;
$this->templateNamespace = $templateNamespace;
}
/**
* Get single resource.
*/
public function getAction()
{
$criteria = $this->getCriteria();
$criteria[$this->getIdentifierName()] = $this->getIdentifierValue();
$resource = $this->findResourceOr404($criteria);
$view = View::create() $view = View::create()
->setTemplate($this->getFullTemplateName('show')) ->setTemplate($this->getFullTemplateName('show.html'))
->setTemplateVar($this->getResourceName()) ->setTemplateVar($this->getResourceName())
->setData($resource) ->setData($resource)
; ;
@ -50,23 +59,37 @@ abstract class ResourceController extends Controller implements ResourceControll
} }
/** /**
* Get all paginated resourcees. * Get collection (paginated by default) of resources.
*
* @param Request $request
*
* @return Response
*/ */
public function getCollectionAction(Request $request) public function getCollectionAction(Request $request)
{ {
$paginator = $this->getManager()->createPaginator(); $criteria = $this->getCriteria();
$paginator->setCurrentPage($request->query->get('page', 1), true, true); $sorting = $this->getSorting();
if ($this->isPaginated()) {
$paginator = $this
->getRepository()
->paginate($criteria, $sorting)
;
$paginator->setCurrentPage($request->query->get('page', 1), true, true);
$resources = $paginator->getCurrentPageResults(); $resources = $paginator->getCurrentPageResults();
$data = $this->isHtmlRequest() ? array(Pluralization::pluralize($this->getResourceName()) => $resources, 'paginator' => $paginator) : $resourcees; $pluralName = Pluralization::pluralize($this->getResourceName());
$data = $this->isHtmlRequest() ? array(
$pluralName => $resources,
'paginator' => $paginator
) : $resources;
} else {
$data = $this
->getRepository()
->getCollection($criteria, $sorting)
;
}
$view = View::create() $view = View::create()
->setTemplate($this->getFullTemplateName('list')) ->setTemplate($this->getFullTemplateName('list.html'))
->setData($data) ->setData($data)
; ;
@ -86,13 +109,16 @@ abstract class ResourceController extends Controller implements ResourceControll
$form = $this->createResourceForm($resource); $form = $this->createResourceForm($resource);
if ($request->isMethod('POST') && $form->bind($request)->isValid()) { if ($request->isMethod('POST') && $form->bind($request)->isValid()) {
$this->getManipulator()->create($resource); $this->getManager()->persist($resource);
$this->setFlash('success', sprintf("%s has been created", ucfirst($this->getResourceName())));
return $this->redirectToResource($resource); return $this->redirectToResource($resource);
} }
$htmlView = View::create() if (!$this->isHtmlRequest()) {
return $this->handleView(View::create($form));
}
$view = View::create()
->setTemplate($this->getFullTemplateName('create.html')) ->setTemplate($this->getFullTemplateName('create.html'))
->setData(array( ->setData(array(
$this->getResourceName() => $resource, $this->getResourceName() => $resource,
@ -100,8 +126,6 @@ abstract class ResourceController extends Controller implements ResourceControll
)) ))
; ;
$view = $this->isHtmlRequest() ? $htmlView : View::create($form);
return $this->handleView($view); return $this->handleView($view);
} }
@ -124,16 +148,18 @@ abstract class ResourceController extends Controller implements ResourceControll
return $this->redirectToResource($resource); return $this->redirectToResource($resource);
} }
$htmlView = View::create() if (!$this->isHtmlRequest()) {
->setTemplate($this->getFullTemplateName('update.html')) return $this->handleView(View::create($form));
}
$view = View::create()
->setTemplate($this->getFullTemplateName('create.html'))
->setData(array( ->setData(array(
$this->getResourceName() => $resource, $this->getResourceName() => $resource,
'form' => $form->createView() 'form' => $form->createView()
)) ))
; ;
$view = $this->isHtmlRequest() ? $htmlView : View::create($form);
return $this->handleView($view); return $this->handleView($view);
} }
@ -226,13 +252,23 @@ abstract class ResourceController extends Controller implements ResourceControll
/** /**
* Get resource manager. * Get resource manager.
* *
* @return ManagerInterface * @return ResourceManagerInterface
*/ */
protected function getManager() protected function getManager()
{ {
return $this->get($this->getServiceName('manager')); return $this->get($this->getServiceName('manager'));
} }
/**
* Get resource repository.
*
* @return ResourceRepositoryInterface
*/
protected function getRepository()
{
return $this->get($this->getServiceName('repository'));
}
protected function getServiceName($name) protected function getServiceName($name)
{ {
return sprintf('%s.%s.%s', $this->getBundlePrefix(), $name, $this->getResourceName()); return sprintf('%s.%s.%s', $this->getBundlePrefix(), $name, $this->getResourceName());
@ -242,17 +278,15 @@ abstract class ResourceController extends Controller implements ResourceControll
* Tries to find resource with given id. * Tries to find resource with given id.
* Throws special 404 exception when unsuccessful. * Throws special 404 exception when unsuccessful.
* *
* @param mixed $id The resource identifier * @param array $criteria Criteria
* *
* @return ResourceInterface * @return ResourceInterface
* *
* @throws NotFoundHttpException * @throws NotFoundHttpException
*/ */
protected function findResourceOr404($identifier) protected function findResourceOr404(array $criteria)
{ {
$criteria = array($this->getIdentifierName() => $this->getIdentifierValue()); if (!$resource = $this->getRepository()->get($criteria)) {
if (!$resource = $this->getManager()->findOneBy($criteria)) {
throw new NotFoundHttpException('Requested resource does not exist'); throw new NotFoundHttpException('Requested resource does not exist');
} }
@ -266,25 +300,33 @@ abstract class ResourceController extends Controller implements ResourceControll
protected function getIdentifierValue() protected function getIdentifierValue()
{ {
if (!$identifier = $this->getRequest()->get($this->getIdentifierName())) { if (null === $identifier = $this->getRequest()->get($this->getIdentifierName())) {
throw new NotFoundHttpException('No resource identifier supplied'); throw new NotFoundHttpException('No resource identifier supplied');
} }
return $identifier; return $identifier;
} }
protected function isPaginated()
{
return (Boolean) $this->getRequest()->attributes->get('_sylius.paginate', true);
}
protected function getCriteria()
{
return $this->getRequest()->get('_sylius.criteria', array());
}
protected function getSorting()
{
return $this->getRequest()->get('_sylius.sorting', array());
}
protected function renderResponse($templateName, array $parameters = array()) protected function renderResponse($templateName, array $parameters = array())
{ {
return $this->render($this->getFullTemplateName($templateName), $parameters); return $this->render($this->getFullTemplateName($templateName), $parameters);
} }
/**
* Get full template name.
*
* @param string
*
* @return string
*/
protected function getFullTemplateName($name) protected function getFullTemplateName($name)
{ {
$template = $this->getRequest()->attributes->get('_sylius.template'); $template = $this->getRequest()->attributes->get('_sylius.template');
@ -300,53 +342,38 @@ abstract class ResourceController extends Controller implements ResourceControll
); );
} }
/**
* Get engine.
*
* @return string
*/
protected function getEngine() protected function getEngine()
{ {
return $this->container->getParameter(sprintf('%s.engine', $this->getBundlePrefix())); return $this->container->getParameter(sprintf('%s.engine', $this->getBundlePrefix()));
} }
/**
* Check if request accepts html format.
*
* @return Boolean
*/
protected function isHtmlRequest() protected function isHtmlRequest()
{ {
return 'html' === $this->getRequest()->getRequestFormat(); return 'html' === $this->getRequest()->getRequestFormat();
} }
/**
* Convert view to a response object.
*
* @param View $view
*
* @return Response
*/
protected function handleView(View $view) protected function handleView(View $view)
{ {
return $this->get('fos_rest.view_handler')->handle($view); return $this->get('fos_rest.view_handler')->handle($view);
} }
/**
* Get name of the form type to use.
*
* @return string
*/
protected function getResourceFormType() protected function getResourceFormType()
{ {
return sprintf('%s_%s', $this->getBundlePrefix(), $this->getResourceName()); return sprintf('%s_%s', $this->getBundlePrefix(), $this->getResourceName());
} }
/** protected function getTemplateNamespace()
* Get templates namespace. {
* return $this->templateNamespace;
* @return string }
*/
abstract protected function getTemplateNamespace(); protected function getBundlePrefix()
abstract protected function getBundlePrefix(); {
return $this->bundlePrefix;
}
protected function getResourceName()
{
return $this->resourceName;
}
} }

View file

@ -20,15 +20,13 @@ use Sylius\Bundle\ResourceBundle\Model\ResourceInterface;
* *
* @author Paweł Jędrzejewski <pjedrzejewski@diweb.pl> * @author Paweł Jędrzejewski <pjedrzejewski@diweb.pl>
*/ */
abstract class DoctrineResourceManager extends ResourceManager implements DoctrineResourceManagerInterface class DoctrineResourceManager extends ResourceManager implements DoctrineResourceManagerInterface
{ {
protected $objectManager; protected $objectManager;
protected $objectRepository;
public function __construct(ObjectManager $objectManager, $class) public function __construct(ObjectManager $objectManager, $class)
{ {
$this->objectManager = $objectManager; $this->objectManager = $objectManager;
$this->objectRepository = $objectManager->getRepository($class);
parent::__construct($class); parent::__construct($class);
} }
@ -57,33 +55,8 @@ abstract class DoctrineResourceManager extends ResourceManager implements Doctri
} }
} }
public function find($id)
{
return $this->objectRepository->find($id);
}
public function findOneBy(array $criteria)
{
return $this->objectRepository->findOneBy($criteria);
}
public function findAll()
{
return $this->objectRepository->findAll();
}
public function findBy(array $criteria)
{
return $this->objectRepository->findBy($criteria);
}
public function getObjectManager() public function getObjectManager()
{ {
return $this->objectManager; return $this->objectManager;
} }
public function getObjectRepository()
{
return $this->objectRepository;
}
} }

View file

@ -21,5 +21,4 @@ use Sylius\Bundle\ResourceBundle\Manager\ResourceManagerInterface;
interface DoctrineResourceManagerInterface extends ResourceManagerInterface interface DoctrineResourceManagerInterface extends ResourceManagerInterface
{ {
function getObjectManager(); function getObjectManager();
function getObjectRepository();
} }

View file

@ -1,30 +0,0 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\ResourceBundle\Manager\Doctrine\ORM;
use Doctrine\ORM\EntityManager;
use Pagerfanta\Adapter\DoctrineORMAdapter;
use Pagerfanta\Pagerfanta;
use Sylius\Bundle\ResourceBundle\Manager\Doctrine\DoctrineResourceManager;
/**
* Doctrine ORM driver resource manager.
*
* @author Paweł Jędrzejewski <pjedrzejewski@diweb.pl>
*/
class ResourceManager extends DoctrineResourceManager
{
public function createPaginator()
{
return new Pagerfanta(new DoctrineORMAdapter($this->objectRepository->createQueryBuilder('r')));
}
}

View file

@ -27,13 +27,6 @@ interface ResourceManagerInterface
*/ */
function create(); function create();
/**
* Creates a new Pagerfanta instance to paginate the resources.
*
* @return PagerfantaInterface
*/
function createPaginator();
/** /**
* Persist. * Persist.
* *
@ -50,40 +43,6 @@ interface ResourceManagerInterface
*/ */
function remove(ResourceInterface $resource, $commit = true); function remove(ResourceInterface $resource, $commit = true);
/**
* Finds resource by id.
*
* @param mixed Identifier
*
* @return ResourceInterface
*/
function find($id);
/**
* Finds resource by criteria.
*
* @param array $criteria
*
* @return ResourceInterface
*/
function findOneBy(array $criteria);
/**
* Find all.
*
* @return Collection
*/
function findAll();
/**
* Finds resources by criteria.
*
* @param array $criteria
*
* @return array
*/
function findBy(array $criteria);
/** /**
* Get resource class name. * Get resource class name.
* *

View file

@ -0,0 +1,37 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\ResourceBundle\Repository\Doctrine;
use Doctrine\Common\Persistence\ObjectRepository;
use Sylius\Bundle\ResourceBundle\Repository\ResourceRepository;
/**
* Base Doctrine resource manager class.
*
* @author Paweł Jędrzejewski <pjedrzejewski@diweb.pl>
*/
abstract class DoctrineResourceRepository extends ResourceRepository implements DoctrineResourceRepositoryInterface
{
protected $objectRepository;
public function __construct(ObjectRepository $objectRepository, $class)
{
$this->objectRepository = $objectRepository;
parent::__construct($class);
}
public function getObjectRepository()
{
return $this->objectRepository;
}
}

View file

@ -0,0 +1,24 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\ResourceBundle\Repository\Doctrine;
use Sylius\Bundle\ResourceBundle\Repository\ResourceRepositoryInterface;
/**
* Doctrine resource manager interface.
*
* @author Paweł Jędrzejewski <pjedrzejewski@diweb.pl>
*/
interface DoctrineResourceRepositoryInterface extends ResourceRepositoryInterface
{
function getObjectRepository();
}

View file

@ -0,0 +1,122 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\ResourceBundle\Repository\Doctrine\ORM;
use Doctrine\ORM\QueryBuilder;
use Pagerfanta\Adapter\DoctrineORMAdapter;
use Pagerfanta\Pagerfanta;
use Sylius\Bundle\ResourceBundle\Repository\Doctrine\DoctrineResourceRepository;
/**
* Doctrine ORM driver resource manager.
*
* @author Paweł Jędrzejewski <pjedrzejewski@diweb.pl>
*/
class ResourceRepository extends DoctrineResourceRepository
{
/**
* {@inheritdoc}
*/
public function get(array $criteria)
{
return $this
->getQueryBuilder($criteria, array())
->getQuery()
->getOneOrNullResult()
;
}
/**
* {@inheritdoc}
*/
public function getCollection(array $criteria = array(), array $sorting = array(), $limit = null)
{
$queryBuilder = $this->getQueryBuilder($criteria, $sorting);
if (null !== $limit) {
$queryBuilder->setMaxResults($limit);
}
return $queryBuilder
->getQuery()
->execute()
;
}
/**
* {@inheritdoc}
*/
public function paginate(array $criteria = array(), array $sorting = array())
{
return new Pagerfanta(new DoctrineORMAdapter($this->getQueryBuilder($criteria, $sorting)));
}
protected function getQueryBuilder(array $criteria, array $sorting)
{
$queryBuilder = $this->getBasicQueryBuilder();
$this->filter($queryBuilder, $criteria);
$this->sort($queryBuilder, $sorting);
return $queryBuilder;
}
protected function filter(QueryBuilder $queryBuilder, array $criteria)
{
$reflectionClass = new \ReflectionClass($this->getClass());
$properties = array_keys($reflectionClass->getDefaultProperties());
$i = 0;
foreach ($criteria as $property => $condition) {
if (!is_array($condition)) {
$condition = array('=', $condition);
}
list($comparison, $value) = $condition;
if (in_array($property, $properties) && in_array($comparison, array('=', '!=', '>', '<', '>=', '<='))) {
$formula = sprintf("%s.%s %s :PARAM%d", $this->getAlias(), $property, $comparison, $i);
$queryBuilder
->andWhere($formula)
->setParameter('PARAM'.$i, $value)
;
$i++;
}
}
}
protected function sort(QueryBuilder $queryBuilder, array $sorting)
{
$acceptedOrders = array('asc', 'desc');
foreach ($sorting as $property => $order) {
if (in_array(strtolower($order), $acceptedOrders)) {
$queryBuilder->orderBy($this->getAlias().'.'.$property, $order);
}
}
}
protected function getBasicQueryBuilder()
{
return $this
->getObjectRepository()
->createQueryBuilder($this->getAlias())
;
}
protected function getAlias()
{
return 'r';
}
}

View file

@ -0,0 +1,32 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\ResourceBundle\Repository;
/**
* Base resource repository class.
*
* @author Paweł Jędrzejewski <pjedrzejewski@diweb.pl>
*/
abstract class ResourceRepository implements ResourceRepositoryInterface
{
protected $class;
public function __construct($class)
{
$this->class = $class;
}
public function getClass()
{
return $this->class;
}
}

View file

@ -0,0 +1,54 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\ResourceBundle\Repository;
use Sylius\Bundle\ResourceBundle\Model\ResourceInterface;
/**
* Resource repository interface.
*
* @author Paweł Jędrzejewski <pjedrzejewski@diweb.pl>
*/
interface ResourceRepositoryInterface
{
/**
* Finds resource by identifier.
*
* @param array $criteria
*
* @return ResourceInterface
*/
function get(array $criteria);
/**
* Finds resource by criteria.
*
* @param array $criteria
*
* @return ResourceInterface
*/
function getCollection(array $criteria = array(), array $sorting = array(), $limit = null);
/**
* Creates a new Pagerfanta instance to paginate the resources.
*
* @return PagerfantaInterface
*/
function paginate(array $criteria = array(), array $sorting = array());
/**
* Get resource class name.
*
* @return string
*/
function getClass();
}