Reputation: 43
I have a Zend Framework 3 app. I added the ViewJsonStrategy to module.config.php. But i wants return a JSON Object with their relation objects ONE TO MANY in Array:
On my controller
public function getdirectoriojsonAction(){
$idraiz = $this->cfgGral->getIdDirectorioRaiz();
if ($idraiz <= 0) {
return $this->redirect()->toRoute('configuracion', ['action' => 'index']);
} else {
if ($this->params()->fromRoute('id') > 0) {
$idraiz = $this->params()->fromRoute('id');
}
$directorio = $this->em->find($this->rutaEntityDirectorio, $idraiz);
if ($directorio->getEstado() != 0) {
$directorio = $directorio->getPadre();
$directorio->getDirectoriosHijos();
$directorio->getArchivosHijos();
}
}
$hydrator = new Reflection;
return new JsonModel($hydrator->extract($directorio));
}
The Entity Directorio
<?php
namespace Directorios\Entity;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Zend\Form\Annotation as ZendAnnotation;
use Directorios\Model\ArchivoInterface;
use Doctrine\Common\Collections\ArrayCollection;
/**
* @ORM\Entity
* @ORM\Table (name="directorio")
*
*/
class Directorio
{
/**
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\Column(type="integer")
* @ZendAnnotation\Exclude()
* @var int|null
*/
private $id;
/**
* @ORM\Column(type="string")
* @var string
* @Required
* @ZendAnnotation\Filter({"name":"StringTrim"})
* @ZendAnnotation\Validator({"name":"StringLength", "options":{"min":1, "max":60}})
* @ZendAnnotation\Validator({"name":"Regex", "options":{"pattern":"/^[a-zA-Z][a-zA-Z0-9_-]{0,24}$/"}})
* @ZendAnnotation\Attributes({"type":"text"})
* @ZendAnnotation\Options({"label":"Nombre:"})
*/
private $nombre;
/**
* @ORM\ManyToOne(targetEntity="Directorios\Entity\Directorio", inversedBy="directoriosHijos")
* @ORM\JoinColumn(name="padre", referencedColumnName="id")
*/
private $padre;
/**
* @ORM\OneToMany(targetEntity="Directorios\Entity\Directorio", mappedBy="padre",cascade={"persist", "remove"})
*/
private $directoriosHijos;
/**
* @ORM\OneToMany(targetEntity="Directorios\Entity\Archivo", mappedBy="padre", cascade={"persist", "remove"})
*/
private $archivosHijos;
/**
* @ORM\Column(type="datetime")
* @var \DateTime
*/
private $fechaCreacion;
/**
* @ORM\Column(type="datetime")
* @var \DateTime
*/
private $fechaModificacion;
/**
* @ORM\Column(name="ruta_real")
* @ORM\Column(type="text")
*/
private $ruta_real;
/**
*
* @ORM\Column(type="integer")
*
*/
private $estado=0;
/**
*
* @ORM\Column(type="integer")
*
*/
private $tipo;
//....... methods
public function __construct(){
$this->archivosHijos=new ArrayCollection();
$this->directoriosHijos=new ArrayCollection();
}
}
The JSON response:
id 2
nombre "Nuevo directorio"
padre Object <- Returns Objects
directoriosHijos Object <- Returns Objects
archivosHijos Object <- Returns Objects
fechaCreacion
date "2017-09-09 21:23:20.000000"
timezone_type 3
timezone "Europe/Berlin"
fechaModificacion
date "2017-09-09 21:23:20.000000"
timezone_type 3
timezone "Europe/Berlin"
ruta_real "D:\\testDirectorioRaiz"
estado 0
tipo 0
The Objects relationated come like Object not like Array(). How i can do that relationated objects arrives like Json Array() too?
Upvotes: 0
Views: 512
Reputation: 43
Thanks jeger, i was search for a most simply solution, but i see that's not for this case. Just now i start investigate the doctrine hydrators, however for now i fix with a rustic recursion XD. I lets the code here bellow, maybe will be helpfull.
In my controller ...
// Method with response JSON
public function getdirectoriojsonAction(){
$idraiz = $this->cfgGral->getIdDirectorioRaiz();
if ($idraiz <= 0) {
return $this->redirect()->toRoute('configuracion', ['action' => 'index']);
} else {
if ($this->params()->fromRoute('id') > 0) {
$idraiz = $this->params()->fromRoute('id');
}
$directorio = $this->em->find($this->rutaEntityDirectorio,$idraiz);
if ($directorio->getEstado() == 0) {
$hydrator = new Reflection();
$dir = $hydrator->extract($directorio);
$dir = $this->getArrayHijosRec($dir, $hydrator);
}else{
return $this->redirect()->toRoute('directorios',['action'=>'error','id'=>2]);
}
}
return new JsonModel($dir);
}
// recursive method ... is not the best practice but works ...
private function getArrayHijosRec($directorioArray, Reflection $hydrator){
$directoriosHijos=$directorioArray['directoriosHijos'];
$archivosHijos=$directorioArray['archivosHijos'];
$padre=$directorioArray['padre'];
$directorioArray['directoriosHijos']=[];
$directorioArray['archivosHijos']=[];
$directorioArray['padre']=[];
$padre=(is_object($padre))?$hydrator->extract($padre):[];
$directorioArray['padre']=$padre;
foreach ($archivosHijos as $archHijo){
$archHijo=$hydrator->extract($archHijo);
$archHijo['padre']=$padre;
array_push($directorioArray['archivosHijos'],$archHijo);
}
foreach ($directoriosHijos as $dirHijo) {
$dirHijo=($hydrator->extract($dirHijo))
array_push($directorioArray['directoriosHijos'],($this->getArrayHijosRec($dirHijo,$hydrator)));
}
return $directorioArray;
}
Upvotes: 0
Reputation: 111
The Reflection Hydrator itself does not allow nested hydration/extraction. However Hydrator Aggregates do so, but you have to invest a bit more work into it then just simply instantiating it. If you choose this route I would invest a bit more time and injecting it into the controller in order to keep testability high
Also consider using the Doctrine Hydrator provided by the doctrine/doctrine-module composer package. The project also has a short documentation on hydration
Upvotes: 1