Serializing objects with relationships to ZF3 MVC Response JSON - php

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?

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

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;
}

Related

Doctrine 2 persist only save header object why?

I want save purchase order header with purchase order details.This my PurchaseOrder Entity Class=>
namespace AppBundle\Entity;
use AppBundle\Entity\PurchaseInvoiceDetail;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* PurchaseOrder
*
* #ORM\Table(name="purchase_order", indexes={#ORM\Index(name="fk_purchase_order_supplier1_idx", columns={"supplier_id"})})
* #ORM\Entity
*/
class PurchaseOrder
{
/**
* #var PurchaseOrderDetails
*
* #ORM\OneToMany(targetEntity="AppBundle\Entity\PurchaseOrderDetails", mappedBy="purchaseOrder",cascade={"cascade"})
* #JMS\Type("ArrayCollection<FinanceBundle\Entity\AutoAllocation>")
*/
private $purchaseOrderDetails;
public function __construct()
{
$this->purchaseOrderDetails = new ArrayCollection();
}
public function addPurchaseOrderDetail(PurchaseOrderDetails $purchaseOrderDetails)
{
$this->purchaseOrderDetails->add($purchaseOrderDetails);
}
/**
* #return PurchaseOrderDetails
*/
public function getPurchaseOrderDetails()
{
return $this->purchaseOrderDetails;
}
/**
* #param PurchaseOrderDetails $purchaseOrderDetails
*/
public function setPurchaseOrderDetails($purchaseOrderDetails)
{
$this->purchaseOrderDetails = $purchaseOrderDetails;
}
}
and PurchaseOrderDetail class as this =>
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* PurchaseOrderDetails
*
* #ORM\Table(name="purchase_order_details", indexes={#ORM\Index(name="fk_purchase_order_details_purchase_order1_idx", columns={"purchase_order_id"}), #ORM\Index(name="fk_purchase_order_details_invt_item1_idx", columns={"id_item"})})
* #ORM\Entity
*/
class PurchaseOrderDetails
{
/**
* #var \AppBundle\Entity\PurchaseOrder
*
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\PurchaseOrder",inversedBy="purchaseOrderDetails")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="purchase_order_id", referencedColumnName="id")
* })
*/
private $purchaseOrder;
/**
* Set purchaseOrder
*
* #param \AppBundle\Entity\PurchaseOrder $purchaseOrder
*
* #return PurchaseOrderDetails
*/
public function setPurchaseOrder(\AppBundle\Entity\PurchaseOrder $purchaseOrder = null)
{
$this->purchaseOrder = $purchaseOrder;
return $this;
}
/**
* Get purchaseOrder
*
* #return \AppBundle\Entity\PurchaseOrder
*/
public function getPurchaseOrder()
{
return $this->purchaseOrder;
}
}
my php code in symfony 3.1 as follows=>
$em = $this->getDoctrine()->getManager();
$purchaseOrder = new PurchaseOrder();
$puchaseOrderDetail = new PurchaseOrderDetails();
$puchaseOrderDetail->setPrice(100);
$purchaseOrder->setPurchaseOrderDetails($puchaseOrderDetail);
$puchaseOrderDetail->setPurchaseOrder($purchaseOrder);
$em->persist($purchaseOrder);
$em->flush();
no errors occurred and just only purchase order have persisted and purchase order detail doesn't
You are not persisting the detail object. Either persist it manually with
$em->persist($purchaseOrderDetail);
or fix
cascade={"persist"}
in the #ORM\OneToMany annotation of PurchaseOrder::$purchaseOrderDetails (cascade={"cascade"} is probably a typo).
You need to persist PurchaseOrderDetails as well.
The below code should save both of your entities.
$em = $this->getDoctrine()->getManager();
$purchaseOrder = new PurchaseOrder();
$puchaseOrderDetail = new PurchaseOrderDetails();
$puchaseOrderDetail->setPrice(100);
$purchaseOrder->setPurchaseOrderDetails($puchaseOrderDetail);
$puchaseOrderDetail->setPurchaseOrder($purchaseOrder);
$em->persist($purchaseOrder);
$em->persist($puchaseOrderDetail);
$em->flush();
As #Finwe has mentioned, If your business logic requires, and you don't want to persist separately PurchaseOrderDetails entity while creating a new PurchaseOrder. You might consider configuring cascade_persist. which will persist automatically associated entity.
To do so, add cascade option to your association config :
#ORM\OneToMany(targetEntity="AppBundle\Entity\PurchaseOrderDetails", mappedBy="purchaseOrder",cascade={"persist"})

Doctrine2 - Trigger event on property change (PropertyChangeListener)

I am not writing "what did I try" or "what is not working" since I can think of many ways to implement something like this. But I cannot believe that no one did something similar before and that is why I would like to ask the question to see what kind of Doctrine2 best practices show up.
What I want is to trigger an event on a property change. So let's say I have an entity with an $active property and I want a EntityBecameActive event to fire for each entity when the property changes from false to true.
Other libraries often have a PropertyChanged event but there is no such thing available in Doctrine2.
So I have some entity like this:
<?php
namespace Application\Entity;
class Entity
{
/**
* #var int
* #ORM\Id
* #ORM\Column(type="integer");
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var boolean
* #ORM\Column(type="boolean", nullable=false)
*/
protected $active = false;
/**
* Get active.
*
* #return string
*/
public function getActive()
{
return $this->active;
}
/**
* Is active.
*
* #return string
*/
public function isActive()
{
return $this->active;
}
/**
* Set active.
*
* #param bool $active
* #return self
*/
public function setActive($active)
{
$this->active = $active;
return $this;
}
}
Maybe ChangeTracking Policy is what you want, maybe it is not!
The NOTIFY policy is based on the assumption that the entities notify
interested listeners of changes to their properties. For that purpose,
a class that wants to use this policy needs to implement the
NotifyPropertyChanged interface from the Doctrine\Common namespace.
Check full example in link above.
class MyEntity extends DomainObject
{
private $data;
// ... other fields as usual
public function setData($data) {
if ($data != $this->data) { // check: is it actually modified?
$this->onPropertyChanged('data', $this->data, $data);
$this->data = $data;
}
}
}
UPDATE
This is a full example but silly one so you can work on it as you wish. It just demonstrates how you do it, so don't take it too serious!
entity
namespace Football\TeamBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="country")
*/
class Country extends DomainObject
{
/**
* #var int
*
* #ORM\Id
* #ORM\Column(type="smallint")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(type="string", length=2, unique=true)
*/
protected $code;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set code
*
* #param string $code
* #return Country
*/
public function setCode($code)
{
if ($code != $this->code) {
$this->onPropertyChanged('code', $this->code, $code);
$this->code = $code;
}
return $this;
}
/**
* Get code
*
* #return string
*/
public function getCode()
{
return $this->code;
}
}
domainobject
namespace Football\TeamBundle\Entity;
use Doctrine\Common\NotifyPropertyChanged;
use Doctrine\Common\PropertyChangedListener;
abstract class DomainObject implements NotifyPropertyChanged
{
private $listeners = array();
public function addPropertyChangedListener(PropertyChangedListener $listener)
{
$this->listeners[] = $listener;
}
protected function onPropertyChanged($propName, $oldValue, $newValue)
{
$filename = '../src/Football/TeamBundle/Entity/log.txt';
$content = file_get_contents($filename);
if ($this->listeners) {
foreach ($this->listeners as $listener) {
$listener->propertyChanged($this, $propName, $oldValue, $newValue);
file_put_contents($filename, $content . "\n" . time());
}
}
}
}
controller
namespace Football\TeamBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Football\TeamBundle\Entity\Country;
class DefaultController extends Controller
{
public function indexAction()
{
// First run this to create or just manually punt in DB
$this->createAction('AB');
// Run this to update it
$this->updateAction('AB');
return $this->render('FootballTeamBundle:Default:index.html.twig', array('name' => 'inanzzz'));
}
public function createAction($code)
{
$em = $this->getDoctrine()->getManager();
$country = new Country();
$country->setCode($code);
$em->persist($country);
$em->flush();
}
public function updateAction($code)
{
$repo = $this->getDoctrine()->getRepository('FootballTeamBundle:Country');
$country = $repo->findOneBy(array('code' => $code));
$country->setCode('BB');
$em = $this->getDoctrine()->getManager();
$em->flush();
}
}
And have this file with 777 permissions (again, this is test) to it: src/Football/TeamBundle/Entity/log.txt
When you run the code, your log file will have timestamp stored in it, just for demonstration purposes.

Is there a better way to handle the Doctrine proxy object

I have two classes linked with a one-to-one relation.
class Client {
...
/**
* #ORM\OneToOne(targetEntity="ClientInfo")
* #ORM\JoinColumn(name="id", referencedColumnName="client_id")
*/
private $info;
...
public function doSomething() {
if (!$this->getInfo() instanceof ClientInfo) {
return false;
}
return $this->getInfo()->doSomething();
}
...
}
class ClientInfo {
...
/**
* #ORM\Id
* #ORM\OneToOne(targetEntity="Client")
* #ORM\JoinColumn(name="client_id", referencedColumnName="id")
*/
private $client;
...
public function doSomething() {
return 'something';
}
...
}
Those classes are loaded with database content with Doctrine. It is working perfectly when there is data in the database. But if there is not ClientInfo data, I have a \Doctrine\ORM\EntityNotFoundException raised.
So I changed the doSomething() method to take this into account.
public function doSomething() {
if (!$this->getInfo() instanceof ClientInfo) {
return false;
}
try {
return $this->getInfo()->doSomething();
} catch (\Doctrine\ORM\EntityNotFoundException $e) {
return false;
}
}
But it does not feel right to me since it is tied with Doctrine. I am trying to modify my unit tests to add a mock of the proxy object but it does not feel right either.
Is there a better way of doing that?
EDIT 1
I followed Nico Kaag suggestion but it does not change anything.
My constructor in my Client class look like this:
public function __construct() {
$this->info = new ClientInfo();
}
If I do a var_dump of $this->info after retrieving my object with Doctrine, this is what I get.
object(Proxies\__CG__\MyBundle\Entity\ClientInfo)[444]
public '__initializer__' =>
object(Closure)[461]
public '__cloner__' =>
object(Closure)[462]
public '__isInitialized__' => boolean false
private 'client' (MyBundle\Entity\ClientInfo) => string '21055' (length=5)
...
EDIT 2
I finally changed what I have done. I removed the try..catch block and change the query to retrieve objects from database. Now I force the query to retrieve the ClientInfo object at the same time as the Client object.
This way, I can trust my test and if I forget to query both objects simultaneously, I will have an exception to remind it to me.
See I have made classes for you.
use Doctrine\ORM\Mapping AS ORM;
/**
* #ORM\Entity
*/
class client
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="Entities\client_info", inversedBy="client")
* #ORM\JoinColumn(name="client_info_id", referencedColumnName="id", unique=true)
*/
private $clientInfo;
}
use Doctrine\ORM\Mapping AS ORM;
/**
* #ORM\Entity
*/
class client_info
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="Entities\client", mappedBy="clientInfo")
*/
private $client;
}
Try this, you will not get such issue.
Also I have used bi-directional relation with cardinality one-to-one, parent connection 0:1*- (parent optional), please see the diagram.
Suggetion : Use ORM designer tool for designing and extracting entity classes.

Doctrine 2 Index Inheritance

i am new to Doctrine 2 am i trying to figure out how to do index inheritance with it.
What i am trying to achieve is to have a base class that defines some default columns along with necessary indexes for all entities within the application.
Example: All tables in my application will have created_on and modified_on, so i prepared one base #MappedSuperclass with those 2 columns in it.
Here is my code:
<?php
/**
* #MappedSuperclass
*/
abstract class EntityAbstract
{
/**
* #Column(type="datetime", name="created_on", nullable=false)
*/
protected $createdOn;
/**
* #Column(type="datetime", name="modified_on", nullable=true)
*/
protected $modifiedOn;
}
/**
* #Entity
* #Table(name="member", indexes={#Index(name="credential", columns={"email_address", "password"})})
*/
class Member extends EntityAbstract
{
/**
* #Column(type="string", name="full_name", length=50)
*/
protected $fullName;
/**
* #Column(type="string", name="email_address", length=50, unique=true, nullable=false)
*/
protected $emailAddress;
/**
* #Column(type="string", name="password", length=40, nullable=false)
*/
protected $password;
}
?>
I want to enforce created_on to be an index, so i put #Index annotation in the base class for this particular column. Hoping that this will result in 2 indexes for Member which is created_on and email_address+password combination. This however results in indexes of the base class being overriden by the child class, thus created_on is not an index.
/**
* #MappedSuperclass
* #Table(indexes={#Index(name="timestampcreated", columns={"created_on"})})
*/
abstract class EntityAbstract
How do i achieve this in Doctrine 2? Have looked at single table inheritance, but my understanding is that it's meant for different purpose.
Here's a full solution for the way laid out at https://github.com/doctrine/orm/issues/5928#issuecomment-273624392, thanks to https://medium.com/#alexkunin/doctrine-symfony-adding-indexes-to-fields-defined-in-traits-a8e480af66b2
namespace App\EventListener;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
use App\Entity\Member;
class MemberIndexListener
{
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
{
/** #var Doctrine\ORM\Mapping\ClassMetadata $classMetadata */
$classMetadata = $eventArgs->getClassMetadata();
if (Member::class === $classMetadata->getName())
{
$prefix = strtolower((new \ReflectionClass($classMetadata->getName()))->getShortName()); // you can omit this line and ...
$classMetadata->table['indexes'][$prefix.'_created_on'] = // ... replace `[$prefix.'_created_on']` with `[]` for automatic index naming
['columns' => ['username']
];
// For UniqueConstraints, use:
// $classMetadata->table['uniqueConstraints'][...] = ...
}
}
}
And in services.yaml:
services:
App\EventListener\MemberIndexListener:
tags:
- { name: doctrine.event_listener, event: loadClassMetadata }
I wanted to do the same thing, but #Table is not allowed in #mappedSuperclass classes. I've posted issue on doctrine2 github page https://github.com/doctrine/doctrine2/issues/5928 and the answer is:
#Table is not valid on a mappedsuperclass.
When you think about it is sounds logical, but still, it would be nice if there is such functionality, to inherit indexes and other declarations.
This is my solution for automatic index inheritance.
You can specify indexes in table annotation of mapped superclass. And all children will extend them.
The listener takes indexes of all parent mapped superclases.
#src/EventListener/InheritIndexListener.php
<?php
namespace App\EventListener;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
use Doctrine\ORM\Mapping\ClassMetadata;
final class InheritIndexListener
{
/** #var EntityManagerInterface */
private $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
{
$classMetadata = $eventArgs->getClassMetadata();
$name = $classMetadata->name;
if (!$classMetadata->isMappedSuperclass) {
foreach (class_parents($name) as $parent) {
$this->addParentIndexes($parent, $classMetadata);
}
}
}
private function addParentIndexes(string $parent, ClassMetadata $classMetadata): void
{
$parentMetadata = $this->entityManager
->getClassMetadata($parent);
foreach ($parentMetadata->table['indexes'] as $index) {
if (!$this->hasSameIndex($index, $classMetadata->table['indexes'])) {
$classMetadata->table['indexes'][] = $index;
}
}
foreach ($parentMetadata->table['uniqueConstraints'] as $uniqueConstraint) {
if (!$this->hasSameIndex($uniqueConstraint, $classMetadata->table['uniqueConstraints'])) {
$classMetadata->table['uniqueConstraints'][] = $uniqueConstraint;
}
}
}
private function hasSameIndex(array $needle, array $haystack): bool
{
foreach ($haystack as $item) {
if ($item['columns'] === $needle['columns']) {
return true;
}
}
return false;
}
}
#config/services.yaml
services:
App\EventListener\InheritIndexListener:
tags:
- { name: doctrine.event_listener, event: loadClassMetadata }
And entities.
#src/Entity/BaseResource.php
<?php
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\MappedSuperclass
* #ORM\Table(
* indexes={
* #ORM\Index(columns={"external_id"}),
* }
* )
*/
abstract class BaseResource
{
/**
* #var int|null
* #ORM\Column(type="integer")
*/
private $externalId;
//...
}
#src/Entity/BaseSlugableResource.php
<?php
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\MappedSuperclass
* #ORM\Table
* uniqueConstraints={
* #ORM\UniqueConstraint(columns={"slug"}),
* },
* )
*/
abstract class BaseSlugableResource extends BaseResource
{
/**
* #var string|null
* #ORM\Column(type="string")
*/
private $slug;
//...
}
#src/Entity/Article.php
<?php
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class Article extends BaseSlugableResource
{
//...
}
In result the Article entity will have externalId index and slug unique index.

Doctrine turns given value into null

I've got a problem that looks kinda hard to describe, but i'm gonna try anyway.
In my MatchesResultscontroller, i've got the following code, to build up an entity:
$em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
if($this->getRequest()->isPost()) {
// get id of current match
$match_id = (int)$this->params()->fromRoute('match', 1);
// find match based on current match id
$results = $em->getRepository('Competitions\Entity\MatchesResults')->findBy(
['match_id' => $match_id]
);
$matchresults = new \Competitions\Entity\MatchesResults();
// Input
$matchresults->stek = $this->getRequest()->getPost('Res_Stek');
$matchresults->member_id = $this->getRequest()->getPost('Res_Name');
$matchresults->weight = $this->getRequest()->getPost('Res_Gewicht');
$matchresults->points = $this->getRequest()->getPost('Res_Punten');
$matchresults->match_id = $match_id;
$matchresults->amount = $this->getRequest()->getPost('Res_Aantal');
// Add
$em->persist($matchresults);
$em->flush($matchresults);
// Redirect back to the competition overview
return $this->redirect()->toRoute('admin-match');
The file MatchesResults.php looks like this
<?php
namespace Competitions\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
#ORM\Table()
#ORM\Entity
#ORM\Table(name="matches_results")
*/
class MatchesResults {
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
public $id;
/** #ORM\Column(type="integer") */
public $match_id;
/** #ORM\Column(type="integer") */
public $member_id;
/** #ORM\Column(type="integer") */
public $stek;
/** #ORM\Column(type="integer") */
public $weight;
/** #ORM\Column(type="integer") */
public $amount;
/** #ORM\Column(type="float") */
public $points;
/** #ORM\Column(type="integer") */
public $position;
public $var;
/**
* #ORM\OneToMany(targetEntity="Competitions\Entity\Matches", mappedBy="Members")
* #ORM\JoinColumn(name="match_id", referencedColumnName="id")
*/
public $result;
public function getResult() {
return $this->result;
}
/**
* #ORM\OneToOne(targetEntity="Members\Entity\Members")
* #ORM\JoinColumn(name="member_id", referencedColumnName="user_id") <----- problem here
*/
public $member;
public function getMember() {
return $this->member;
}
}
When i need to get an overview of all results of a given match, with the correct user linked to that result, it works perfectly.
However, when i need to add a new result, I get a member_id = null, since doctrine is trying to get the member_id of a non existing result.
$matchresults->stek = $this->getRequest()->getPost('Res_Stek');
$matchresults->member_id = $this->getRequest()->getPost('Res_Name');
$matchresults->weight = $this->getRequest()->getPost('Res_Gewicht');
$matchresults->points = $this->getRequest()->getPost('Res_Punten');
$matchresults->match_id = $match_id;
$matchresults->amount = $this->getRequest()->getPost('Res_Aantal');
This code does set all values correctly into the entity, but the entities member_id field is just overwritten.
How would i solve this issue?
I could make a separate file that does not contain the troubling line, but i don't think that is a very elegant solution.
Mark

Categories