I am trying to link a one to many entity together using Doctrine in Apigility. The relationship is 1 slide has many bullets points. So I want the return json to show each slide and all its related nested bullets. But as you can see from the output below the bullets always return empty:
{
"_links": {
"self": {
"href": "http://0.0.0.0:8888/slide"
}
},
"_embedded": {
"slide": [
{
"id": "2",
"title": "Title",
"previous": "Previous",
"next": "Next",
"bullets": {},
"_links": {
"self": {
"href": "http://0.0.0.0:8888/slide/2"
}
}
},
{
"id": "3",
"title": "Title",
"previous": "Previous",
"next": "Next",
"bullets": {},
"_links": {
"self": {
"href": "http://0.0.0.0:8888/slide/3"
}
}
},
{
"id": "4",
"title": "Title",
"previous": "Previous",
"next": "Next",
"bullets": {},
"_links": {
"self": {
"href": "http://0.0.0.0:8888/slide/4"
}
}
},
{
"id": "5",
"title": "Title",
"previous": "Previous",
"next": "Next",
"bullets": {},
"_links": {
"self": {
"href": "http://0.0.0.0:8888/slide/5"
}
}
},
{
"id": "6",
"title": "Title",
"previous": "Previous",
"next": "Next",
"bullets": {},
"_links": {
"self": {
"href": "http://0.0.0.0:8888/slide/6"
}
}
}
]
},
"total_items": 5
}
The slide entity for both the bullet and the slide
namespace demo\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Sentence
*
* @ORM\Table(name="slide")
* @ORM\Entity(repositoryClass="demo\Repository\SlideRepository")
*/
class Slide
{
/**
* @var integer
*
* @ORM\Column(name="id", type="bigint", nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var string
*
* @ORM\Column(type="string", length=45, nullable=true)
*/
private $title;
/**
* @var string
*
* @ORM\Column(type="string", length=45, nullable=true)
*/
private $previous;
/**
* @var string
*
* @ORM\Column(type="string", length=45, nullable=true)
*/
private $next;
/**
* @ORM\OneToMany(targetEntity="Bullet", mappedBy="slide")
*/
private $bullets;
public function __construct()
{
$this->bullets = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* @param string $title
*/
public function setTitle($title)
{
$this->title = $title;
}
/**
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* @param string $previous
*/
public function setPrevious($previous)
{
$this->previous = $previous;
}
/**
* @return string
*/
public function getPrevious()
{
return $this->previous;
}
/**
* @param int $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* @param string $next
*/
public function setNext($next)
{
$this->next = $next;
}
/**
* @return string
*/
public function getNext()
{
return $this->next;
}
/**
* Add bullets
*
* @param Bullet $bullets
* @return Slide
*/
public function addBullet(Bullet $bullets)
{
$this->bullets[] = $bullets;
return $this;
}
/**
* Remove bullets
*
* @param Bullet $bullets
*/
public function removeBullet(Bullet $bullets)
{
$this->bullets->removeElement($bullets);
}
/**
* Get bullets
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getBullets()
{
return $this->bullets;
}
}
namespace demo\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Sentence
*
* @ORM\Table(name="bullets")
* @ORM\Entity(repositoryClass="demo\Repository\BulletsRepository")
*/
class Bullet
{
/**
* @var integer
*
* @ORM\Column(name="id", type="bigint", nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="bullet", type="string", length=45, nullable=true)
*/
private $bullet;
/**
* @ORM\ManyToOne(targetEntity="Slide", inversedBy="bullets")
* @ORM\JoinColumn(name="slide_id", referencedColumnName="id")
*/
protected $slide;
public function __construct()
{
var_dump('TEST!!');
exit();
}
/**
* @param int $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* @param string $bullet
*/
public function setBullet($bullet)
{
$this->bullet = $bullet;
}
/**
* @return string
*/
public function getBullet()
{
return $this->bullet;
}
/**
* @return string
*/
public function getSlide()
{
return $this->slide;
}
/**
* @param string $slide
*/
public function setSlide(Slide $slide = null)
{
$this->slide = $slide;
return $this;
}
}
The database entries
+----+-------+----------+------+
| id | title | previous | next |
+----+-------+----------+------+
| 2 | Title | Previous | Next |
| 3 | Title | Previous | Next |
| 4 | Title | Previous | Next |
| 5 | Title | Previous | Next |
| 6 | Title | Previous | Next |
+----+-------+----------+------+
+----+----------+---------------+
| id | slide_id | bullet |
+----+----------+---------------+
| 1 | 2 | Test Bullet |
| 2 | 3 | Test Bullet |
| 3 | 4 | Array |
| 4 | 5 | test Bullet 2 |
| 5 | 6 | test Bullet 2 |
+----+----------+---------------+
Any help would be gratefully appreciated.
I've also added the application.config.php:
/**
* Configuration file generated by ZF Apigility Admin
*
* The previous config file has been stored in application.config.old
*/
return array(
'modules' => array(
'ZF\\DevelopmentMode',
'ZF\\Apigility',
'ZF\\Apigility\\Provider',
'ZF\\Apigility\\Documentation',
'AssetManager',
'ZF\\ApiProblem',
'ZF\\Configuration',
'ZF\\MvcAuth',
'ZF\\OAuth2',
'ZF\\Hal',
'ZF\\ContentNegotiation',
'ZF\\ContentValidation',
'ZF\\Rest',
'ZF\\Rpc',
'ZF\\Versioning',
'apiexample',
'DoctrineModule',
'DoctrineORMModule'
),
'module_listener_options' => array(
'module_paths' => array(
'./module',
'./vendor'
),
'config_glob_paths' => array(
'config/autoload/{,*.}{global,local}.php'
)
)
);
module/apiexample/config/module.config.php
return array(
'controllers' => array(
'factories' => array(
'apiexample\\V1\\Rpc\\Ping\\Controller' => 'apiexample\\V1\\Rpc\\Ping\\PingControllerFactory',
),
),
'router' => array(
'routes' => array(
'apiexample.rpc.ping' => array(
'type' => 'Segment',
'options' => array(
'route' => '/ping',
'defaults' => array(
'controller' => 'apiexample\\V1\\Rpc\\Ping\\Controller',
'action' => 'ping',
),
),
),
'apiexample.rest.user' => array(
'type' => 'Segment',
'options' => array(
'route' => '/user[/:user_id]',
'defaults' => array(
'controller' => 'apiexample\\V1\\Rest\\User\\Controller',
),
),
),
),
),
'zf-versioning' => array(
'uri' => array(
0 => 'apiexample.rpc.ping',
1 => 'apiexample.rest.user',
),
),
'zf-rpc' => array(
'apiexample\\V1\\Rpc\\Ping\\Controller' => array(
'service_name' => 'Ping',
'http_methods' => array(
0 => 'GET',
),
'route_name' => 'apiexample.rpc.ping',
),
),
'zf-content-negotiation' => array(
'controllers' => array(
'apiexample\\V1\\Rpc\\Ping\\Controller' => 'Json',
'apiexample\\V1\\Rest\\User\\Controller' => 'HalJson',
),
'accept_whitelist' => array(
'apiexample\\V1\\Rpc\\Ping\\Controller' => array(
0 => 'application/vnd.apiexample.v1+json',
1 => 'application/json',
2 => 'application/*+json',
),
'apiexample\\V1\\Rest\\User\\Controller' => array(
0 => 'application/vnd.apiexample.v1+json',
1 => 'application/hal+json',
2 => 'application/json',
),
),
'content_type_whitelist' => array(
'apiexample\\V1\\Rpc\\Ping\\Controller' => array(
0 => 'application/vnd.apiexample.v1+json',
1 => 'application/json',
),
'apiexample\\V1\\Rest\\User\\Controller' => array(
0 => 'application/vnd.apiexample.v1+json',
1 => 'application/json',
),
),
),
'zf-content-validation' => array(
'apiexample\\V1\\Rpc\\Ping\\Controller' => array(
'input_filter' => 'apiexample\\V1\\Rpc\\Ping\\Validator',
),
),
'input_filter_specs' => array(
'apiexample\\V1\\Rpc\\Ping\\Validator' => array(
0 => array(
'name' => 'ack',
'required' => true,
'filters' => array(),
'validators' => array(),
'description' => 'Acknowledge the request with a timestamp.',
),
),
),
'service_manager' => array(
'factories' => array(
'apiexample\\V1\\Rest\\User\\UserResource' => 'apiexample\\V1\\Rest\\User\\UserResourceFactory',
),
),
'zf-rest' => array(
'apiexample\\V1\\Rest\\User\\Controller' => array(
'listener' => 'apiexample\\V1\\Rest\\User\\UserResource',
'route_name' => 'apiexample.rest.user',
'route_identifier_name' => 'user_id',
'collection_name' => 'user',
'entity_http_methods' => array(
0 => 'GET',
1 => 'PATCH',
2 => 'PUT',
3 => 'DELETE',
4 => 'POST',
),
'collection_http_methods' => array(
0 => 'GET',
1 => 'POST',
),
'collection_query_whitelist' => array(),
'page_size' => '2',
'page_size_param' => null,
'entity_class' => 'apiexample\\Entity\\User',
'collection_class' => 'apiexample\\V1\\Rest\\User\\UserCollection',
'service_name' => 'user',
),
),
'zf-hal' => array(
'metadata_map' => array(
'apiexample\\V1\\Rest\\User\\UserEntity' => array(
'entity_identifier_name' => 'id',
'route_name' => 'apiexample.rest.user',
'route_identifier_name' => 'user_id',
'hydrator' => 'Zend\\Stdlib\\Hydrator\\ObjectProperty',
),
'apiexample\\V1\\Rest\\User\\UserCollection' => array(
'entity_identifier_name' => 'id',
'route_name' => 'apiexample.rest.user',
'route_identifier_name' => 'user_id',
'is_collection' => true,
),
'apiexample\\Entity\\User' => array(
'entity_identifier_name' => 'id',
'route_name' => 'apiexample.rest.user',
'route_identifier_name' => 'user_id',
'hydrator' => 'apiexample\\Hydrator\\UserHydrator',
),
),
),
'doctrine' => array(
'driver' => array(
'lanekeep_driver' => array(
'class' => 'Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver',
'cache' => 'array',
'paths' => array(
0 => __DIR__ . '/../src/apiexample/Entity',
),
),
'orm_default' => array(
'drivers' => array(
'apiexample\\Entity' => 'lanekeep_driver',
),
),
),
),
'view_manager' => array(
'display_not_found_reason' => true,
'display_exceptions' => true,
'doctype' => 'HTML5',
'not_found_template' => 'error/404',
'exception_template' => 'error/index',
'template_map' => array(
'layout/layout' => __DIR__ . '/../view/layout/layout.phtml',
'error/404' => __DIR__ . '/../view/error/404.phtml',
'error/index' => __DIR__ . '/../view/error/index.phtml',
),
'template_path_stack' => array(
0 => __DIR__ . '/../view',
),
),
);