Warpsale Doctrine integration with Apigility
Installation (with composer):
- Install Apigility;
- Install Doctrine;
- Install doctrine/doctrine-orm-module;
- Install warpsale/ws-apigility-doctrine.
Setup:
- Copy the "_utils/module/Base" folder to the "/module" folder of Apigility;
- Add the "Base" module to the "/config/modules.config.php" Apigility file;
- Append to the "/config/autoload/local.php" Apigility file:
'doctrine' => array(
'connection' => array(
'orm_default' => array(
'driverClass' => 'Doctrine\\DBAL\\Driver\\PDOPgSql\\Driver',
'params' => array(
'host' => 'hostname',
'port' => '5432',
'user' => 'username',
'password' => 'password',
'dbname' => 'database',
),
),
),
'hydrators' => [
'initializers' => [
'Base\V1\Model\BaseHydratorInitializer',
],
],
- Create a new API (Geo, for example).
- Create a new REST Service (Region, for example)
- Create the folder "Model" inside the "/module/Geo/src/Geo/V1" Apigility folder and Copy your Doctrine Entity Files. Region.php example:
<?php
namespace Geo\V1\Model;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Base\V1\Model\BaseReadEntity;
/**
* @ORM\Entity(readOnly=true)
* @ORM\Table(name="region",
* uniqueConstraints={@ORM\UniqueConstraint(name="geo__region__unm49__key", columns={"unm49"})},
* indexes={@ORM\Index(name="geo__region__level__idx", columns={"level"})},
* schema="geo"
* )
*/
class Region extends BaseReadEntity
{
/**
* @ORM\Id @ORM\Column(type="smallint", options={"comment":"custom shorted hierarchical code"})
* @var int
*/
private $id;
/**
* @ORM\Column(type="string", length=3, options={"comment":"united nations UN M.49 code"})
* @var string
*/
private $unm49;
/**
* @ORM\ManyToOne(targetEntity="Region", inversedBy="children")
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="RESTRICT")
* @var int
*/
private $parent;
/**
* @ORM\OneToMany(targetEntity="Region", mappedBy="parent")
* @ORM\OrderBy({"id"="ASC"})
* @var array
*/
private $children;
/**
* @ORM\OneToMany(targetEntity="Country", mappedBy="region")
* @ORM\OrderBy({"id"="ASC"})
* @var array
*/
private $countries;
/**
* @ORM\Column(type="smallint")
* @var int
*/
private $level;
/**
* @ORM\Column(type="string", length=32)
* @var string
*/
private $name;
/**
* @return the $id
*/
public function getId()
{
return $this->id;
}
/**
* @return the $unm49
*/
public function getUnm49()
{
return $this->unm49;
}
/**
* @return the $parent
*/
public function getParent()
{
return $this->parent;
}
/**
* @return the $children
*/
public function getChildren()
{
return $this->children;
}
/**
* @return the $countries
*/
public function getCountries()
{
return $this->countries;
}
/**
* @return the $level
*/
public function getLevel()
{
return $this->level;
}
/**
* @return the $name
*/
public function getName()
{
return $this->name;
}
public function __construct()
{
$this->children = new ArrayCollection();
$this->countries = new ArrayCollection();
}
}
- append to the "/module/Geo/config/module.config.php" file:
'doctrine' => array(
'driver' => array(
'geo_model' => array(
'class' => 'Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver',
'cache' => 'array',
'paths' => array(
0 => __DIR__ . '/../src/Geo/V1/Model',
),
),
'orm_default' => array(
'drivers' => array(
'Geo\\V1\\Model' => 'geo_model',
),
),
),
),
- Apply the "DoctrineModule\Stdlib\Hydrator\DoctrineObject" to the "Hydrator Service Name"
- Add "page", "query" and "sort" words to the "Collection Query String Whitelist";
- Change the "Entity Class" to "Geo\V1\Model\Region" and, after the service created, delete the file "/module/Geo/src/Geo/V1/Rest/Region/RegionEntity.php" of Apigility;
- This is a readonly example, so in sections "HTTP Entity Methods" and "HTTP Collection Methods", select the "GET" options;
- In "Page Size Parameter", write "results";
- Save;
- Create the file "RegionMapper.php" inside the "/module/Geo/src/Geo/V1/Rest/Region" Apigility folder;
- Write the following code:
<?php
namespace Geo\V1\Rest\Region;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Pagination\Paginator;
use DoctrineORMModule\Paginator\Adapter\DoctrinePaginator;
use WSApigilityDoctrine\DoctrineFilter;
use WSApigilityDoctrine\DoctrineSort;
use WSApigilityDoctrine\ReadMapperInterface;
use Geo\V1\Model\Region as RegionEntity;
class RegionMapper implements ReadMapperInterface
{
protected $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function fetch($id)
{
$qb = $this->em->createQueryBuilder();
$qb->select('e')
->from(RegionEntity::class, 'e')
->where('e.id = :id');
$qb->setParameters(array(
'id' => $id
));
return $qb->getQuery()->getOneOrNullResult();
}
public function fetchAll($params = array())
{
$qb = $this->em->createQueryBuilder();
$qb->select('e')
->from(RegionEntity::class, 'e')
->leftJoin('e.parent', 'p')
->add('orderBy', 'e.level ASC, e.id ASC');
// QUERY (RQL) AND SORT
DoctrineFilter::filter($qb, $params);
DoctrineSort::sort($qb, $params);
// PAGINATE RESULTS
$paginator = new Paginator($qb, $fetchJoinCollection = true);
$adapter = new DoctrinePaginator($paginator);
return new RegionCollection($adapter);
}
}
- edit the "/module/Geo/src/Geo/V1/Rest/Region/RegionResource.php" Apigility file and:
- create the "mapper" protected propety:
protected $mapper;
* create a constructor:
public function __construct(RegionMapper $mapper)
{
$this->mapper = $mapper;
}
* change the "GET" methods:
/**
* Fetch a resource
*
* @param mixed $id
* @return ApiProblem|mixed
*/
public function fetch($id)
{
return $this->mapper->fetch($id);
}
/**
* Fetch all or a subset of resources
*
* @param array $params
* @return ApiProblem|mixed
*/
public function fetchAll($params = array())
{
return $this->mapper->fetchAll($params);
}
- edit the "/module/Geo/src/Geo/V1/Rest/Region/RegionResourceFactory.php" Apigility file:
<?php
namespace Geo\V1\Rest\Region;
use Doctrine\ORM\EntityManager;
use Geo\V1\Rest\Region\RegionMapper;
use Geo\V1\Rest\Region\RegionResource;
class RegionResourceFactory
{
public function __invoke($services)
{
$em = $services->get(EntityManager::class);
$mapper = new RegionMapper($em);
return new RegionResource($mapper);
}
}