I am trying to insert a new object/row in a database. The object is created like so:
$nodeaccess = new Nodeaccess(); // A by doctrine2 generated entity
$nodeaccess->setAccesslevel(0);
$nodeaccess->setDraw(0);
$nodeaccess->setUserid($userid);
$nodeaccess->setNodename($this->getUser()->getUsername() . ' Node');
$nodeaccess->setMac($node);
All columns of the table are set. When I print $nodeaccess->getUserid()
and $nodeaccess->getMac()
the desired results are printed. And they are both not null.
But when the object is persisted like so:
$em = $this->getDoctrine()->getManager();
$em->persist($nodeaccess);
$em->flush();
the following error happens:
An exception occurred while executing 'INSERT INTO nodeaccess (mac, userID, accessLevel, nodeName, draw) VALUES (?, ?, ?, ?, ?)' with params {"1":null,"2":null,"3":0,"4":"Example Node","5":0}:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'mac' cannot be null
The mac and userID combined is the primary key and they are both foreign keys aswell. They are setup in the model like this:
/**
* @var integer
*
* @ORM\Column(name="mac", type="bigint", nullable=false)
* @ORM\Id
*/
private $mac;
/**
* @var integer
*
* @ORM\Column(name="userID", type="integer", nullable=false)
* @ORM\Id
**/
private $userid;
Public accessors are implemented and I have tried changing the fields to public but it did not help.
Update The accessors:
public function getMac()
{
return $this->mac;
}
public function setMac($mac)
{
$this->mac = $mac;
}
public function getUserid()
{
return $this->userid;
}
public function setUserid($userid)
{
$this->userid = $userid;
}
Update 2 I have changed the table, now only the mac
field is NULL. The new model:
/**
* @var integer
*
* @ORM\Column(name="id", type="integer", nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var integer
*
* @ORM\Column(name="mac", type="bigint", nullable=false)
*/
private $mac;
/**
* @var integer
*
* @ORM\Column(name="userID", type="integer", nullable=false)
**/
private $userid;
UPDATE The controller action:
public function inviteAction() {
$repository = $this->getDoctrine()
->getRepository('GeninnoEDSBundle:Nodeaccess');
$options = $repository->createQueryBuilder('na')
.......
->getQuery()
->getResult();
$form = $this->createFormBuilder()
->add('user', 'text', array(
'attr' => array(
'placeholder' => '+ Gebruiker'
)
))
->add('node', 'hidden')
->getForm();
if ($this->getRequest()->isMethod('POST')) {
$form->bind($this->getRequest());
if ($form->isValid()) {
$data = $form->getData();
$user_repository = $this->getDoctrine()
->getRepository('GeninnoEDSBundle:User');
$user = $user_repository->findOneBy(array('username' => $data['user']));
$node_repository = $this->getDoctrine()
->getRepository('GeninnoEDSBundle:Node');
$node = $node_repository->find($data['node']);
$nodeaccess = new Nodeaccess();
$nodeaccess->setAccesslevel(0);
$nodeaccess->setDraw(0);
$nodeaccess->setUserid($user);
$nodeaccess->setNodename($this->getUser()->getUsername() . ' Node');
$nodeaccess->setMac($node);
$em = $this->getDoctrine()->getManager();
$em->persist($nodeaccess);
$em->flush();
}
}
return array('options' => $options, 'form' => $form->createView());
}
The problem has been fixed by regenerating this particular entity (oh oh). The fields have changed to:
/**
* @var \User
*
* @ORM\ManyToOne(targetEntity="User")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="userID", referencedColumnName="id")
* })
*/
private $userid;
/**
* @var \Node
*
* @ORM\ManyToOne(targetEntity="Node")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="mac", referencedColumnName="mac")
* })
*/
private $mac;
UPDATE
That might not have been the fix I thought it was. Had the problem again after adding some fields back to the class. I found out that by removing the following code the user was no longer assigned to null while persisting.
/**
* @var \Doctrine\Common\Collections\Collection
*
* @ORM\ManyToOne(targetEntity="User", inversedBy="accessNodes")
* @ORM\JoinColumn(name="userID", referencedColumnName="id")
**/
private $accessUsers;
Short Answer: Your hidden form field for node uses the __toString() value, which is not an id and therefore will not be found by your repository call, and hence is null at persist time.
Long Answer: Use a transformer:
In your Controller:
use GeninnoEDSBundle\Transformer\NodeTransformer;
And modify the form builder:
$transformer = new NodeTransformer( $em );
$form = $this->createFormBuilder()
->add('user', 'text', array(
'attr' => array(
'placeholder' => '+ Gebruiker'
)
))
->add($builder->create( 'node', 'hidden')
->addModelTransformer( $transformer )
)
->getForm();
Your transformer ( new file: GeninnoEDSBundle\Transformer\NodeTransformer.php ):
<?php
namespace GeninnoEDSBundle\Transformer;
use Doctrine\Common\Persistence\ObjectManager;
use GeninnoEDSBundle\Entity\Node;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
class NodeTransformer implements DataTransformerInterface
{
/**
* @var ObjectManager
*/
private $em;
// If selector is multiple (Many2One or Many2Many)
private $multi;
/**
* @param ObjectManager $em
*/
public function __construct(ObjectManager $em, $multi=false)
{
$this->em = $em;
$this->multi=$multi;
}
/**
* Transforms an object (node) to a string (id).
*
* @param Issue|null $node
* @return string
*/
public function transform($node)
{
if (null === $node) {return "";}
if (is_object($node) && method_exists($node, "toArray")){
$node=$node->map(function ($ob){return $ob->getId();});
return implode(",",$node->toArray());
}
if ('array' == gettype($node)) {
return implode(','
, array_map(function($element){
return $element->getId();
}
,$node));
}
// var_dump($node);
return $node->getId();
}
/**
* Transforms a string (id) to an object (node).
*
* @param string $id
* @return Issue|null
* @throws TransformationFailedException if object (node) is not found.
*/
public function reverseTransform($id)
{
if (!$id) {
if($this->multi) {return array();}
return null;
}
if (strpos($id,',') !== false) {
$id=explode(',',$id);
}
$qb=$this->em
->getRepository('GeninnoEDSBundle:Node')
->createQueryBuilder('r');
$qb->andWhere($qb->expr()->in('r.id', $id));
if (is_array($id) || $this->multi){
$node=$qb->getQuery()
->getResult();
} else {
$node=$qb->getQuery()
->getSingleResult();
}
if (null === $node) {
throw new TransformationFailedException(sprintf(
'An node with id "%s" does not exist!',
$id
));
}
return $node;
}
}
Please note: I've added my transformer, but you may need to fiddle with the logic for your application.
More on transformers: http://symfony.com/doc/current/cookbook/form/data_transformers.html