is possible use setId() for id in doctrine entity? - symfony

I want to set id manual I write this code in my Test entity:
can I use setId() for entities like my code?
My code is here:
/**
* Test
* #ORM\Table(name="test")
*/
class Test
{
/**
* #var int
* #ORM\Column(name="id", type="integer")
*/
private $id;
/**
* #var string
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* Set id
* #param integer $id
* #return Test
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* Get id
* #return integer
*/
public function getId()
{
return $this->id;
}
// other methods
}
is this correct way to set id?
if not what is the correct and standard way?

You can use your own primary key, telling to Doctrine not to generate value ...
https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/annotations-reference.html#annref_generatedvalue
/**
* Test
* #ORM\Table(name="test")
*/
class Test
{
/**
* #var int
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
* #ORM\Column(name="id", type="integer")
*/
private $id;
/**
* Set id
* #param integer $id
* #return Test
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
Don't forget setId before persist!

Doctrine expects the primary key of your entity to be immutable (non-changeable) after the entity is persisted/flushed to the database (or fetched from DB).
The code you wrote is perfectly correct in terms of PHP but will most likely break doctrine functionality if you ever use setId().
If you are interested in the internals, look up "Doctrine identity maps"

Related

Symfony2 and Doctrine: The table with name 'blog.post' already exists.

i working with Symfony2 and Doctrine ORM using MySql.
When i try uo use:
php app/console doctrine:migration:diff
i have this error:
[Doctrine\DBAL\Schema\SchemaException]
The table with name 'blog.post' already exists.
My code in Post.php (i use annotation) is:
namespace Blog\ModelBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Post
*
* #ORM\Table()
* #ORM\Entity
*/
class Post extends Timestampable
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="title", type="string", length=150)
* #Assert\NotBlank
*/
private $title;
/**
* #var string
*
* #ORM\Column(name="body", type="text")
* #Assert\NotBlank
*/
private $body;
/**
* #var Author
* #ORM\ManyToOne (targetEntity="Author", inversedBy="posts")
* #ORM\JoinColumn (name="author_id", referencedColumnName="id", nullable=false)
* #Assert\NotBlank
*/
private $author;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set title
*
* #param string $title
* #return Post
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set body
*
* #param string $body
* #return Post
*/
public function setBody($body)
{
$this->body = $body;
return $this;
}
/**
* Get body
*
* #return string
*/
public function getBody()
{
return $this->body;
}
/**
* Set author
*
* #param \Blog\ModelBundle\Entity\Author $author
* #return Post
*/
public function setAuthor(Author $author)
{
$this->author = $author;
return $this;
}
/**
* Get author
*
* #return \Blog\ModelBundle\Entity\Author
*/
public function getAuthor()
{
return $this->author;
}
}
I try to define * #ORM\Table(name="Post").
Can you help me with this type of error.
Sorry for my bad english.
Your mapping looks incorrect. The ManyToOne declaration does not need an inversedBy attribute if you're not using a join table. You also do not need to specify the #var since it already knows it's using the entity. Try this:
/**
* #ORM\ManyToOne(targetEntity="Author")
* #ORM\JoinColumn(name="author_id", referencedColumnName="id")
**/
private $author;
One other thing to do is to check that you're not trying to declare the same entity in another bundle, this will also cause the "table already exists" error.
Also, to avoid using full path entity references in the getter and setter, just include the entity in the use statemnets at the top of the class, then you only need write the entity name:
/**
* set Author
*
* #param Author $author
*
* #return Post
/**

Can't save the relation in a self-referencing entity

Im tying to add communication parts to a rootCommunication in my data-fixture, there is no error, but only just NULL in the database field 'root_communication_id'. Why?
Parts of my Model 'Communication'
/**
* Communication
*
* #ORM\Table(name="communication")
* #ORM\Entity(repositoryClass="Mother\BaseBundle\Entity\Repository\CommunicationRepository")
*/
class Communication
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="message", type="text", nullable=true)
*/
private $message;
/**
* #ORM\ManyToOne(targetEntity="Communication", inversedBy="childrenCommunication", cascade={"persist"})
* #ORM\JoinColumn(name="root_communication_id", referencedColumnName="id", nullable=true)
*
*/
private $rootCommunication;
/**
* #ORM\OneToMany(targetEntity="Communication", mappedBy="rootCommunication")
*
*/
private $childrenCommunication;
}
In a first data-fixture i added three communications to the database, in this secound fixture i add the childrenCommunication to the rootCommunication.
/**
* {#inheritDoc}
*/
public function load( ObjectManager $manager ){
$contentRepo = $this->container->get('doctrine')->getManager()->getRepository('MotherBaseBundle:Communication');
$communication1 = $contentRepo->find( $this->getReference('communication1')->getId() );
$communication1->addChildrenCommunication( $this->getReference('communication2') );
$communication1->addChildrenCommunication( $this->getReference('communication3') );
$manager->persist( $communication1 );
$manager->flush();
}
I assume you are not setting the rootCommunication when you are adding the child.
You should add an auto setter to the add method, like..
public function addChildrenCommunication(CommunicationInterface $communication)
{
if (!$this->childrenCommunication->contains($communication)) {
$this->childrenCommunication->add($communication);
$communication->setRootCommunication($this);
}
return $this;
}
.. and the same for the remove..

Symfony2/Doctrine2 Inheritance

I'm attempting to accomplish BASIC inheritance in Doctrine 2, but I'm running into several major issues. Such a task should not be so complicated. Let's get down to business...
I have three classes, BaseFoodType, Drink, and Snack. My BaseFoodType has the following class definition:
/** #ORM\MappedSuperclass */
class BaseFoodType {
/**
* #ORM\Column(type="integer", length=7)
*/
public $budget = 0;
}
Which follows the instructions for inheritance on the doctrine website: http://docs.doctrine-project.org/en/2.0.x/reference/inheritance-mapping.html
Here is what the sub-classes look like prior to generating my entities:
namespace MySite\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* MySite\MainBundle\Entity\EventDrink
*
* #ORM\Table(name="drink")
* #ORM\Entity
*/
class Drink extends BaseFoodType {
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="integer", length=5, nullable=true)
*/
public $people_count;
}
Both Drink, and Snack inherit from this base class but I'm running into numerous issues when attempting to build my entities using the doctrine:generate:entities command. First, Symfony inserts a private "budget" property into each subclass, along with getters and setters (THIS DEFEATS THE PURPOSE INHERITANCE)
/**
* #var integer
*/
private $budget;
/**
* Set budget
*
* #param integer $budget
*/
public function setBudget($budget)
{
$this->budget = $budget;
return $this;
}
/**
* Get budget
*
* #return integer
*/
public function getBudget()
{
return $this->budget;
}
Second, I'm getting a fatal error:
Fatal error: Access level to MySite\MainBundle\Entity\Drink::$budget
must be public (as in class MySite\MainBundle\Entity\BaseFoodType) in
C:\xampp\htdocs\MySite\src\MySite\MainBundle\Entity\Drink.php on line
197
I could probably make the generated properties public and be on my way, but again, that defeats the purpose of inheritance!
Thanks in advance for any insight.
Doctrine provides the means to specify the visibility of generated fields. Either protected or private. The default is private.
The problem is that the Symfony command that invokes Doctrine offers no way to change this.
Creating your own subclass of the standard Symfony command will allow you more control over the generation process. This might help you along.
namespace Foo\Bundle\FooBundle\Command;
use Doctrine\Bundle\DoctrineBundle\Command as DC;
use Doctrine\ORM\Tools\EntityGenerator;
class GenerateEntitiesDoctrineCommand extends DC\GenerateEntitiesDoctrineCommand
{
protected function configure()
{
parent::configure();
$this->setName('foo:generate:entities');
}
/**
* get a doctrine entity generator
*
* #return EntityGenerator
*/
protected function getEntityGenerator()
{
$entityGenerator = new EntityGenerator();
$entityGenerator->setGenerateAnnotations(true);
$entityGenerator->setGenerateStubMethods(true);
$entityGenerator->setRegenerateEntityIfExists(false);
$entityGenerator->setUpdateEntityIfExists(true);
$entityGenerator->setNumSpaces(4);
$entityGenerator->setAnnotationPrefix('ORM\\');
$entityGenerator->setFieldVisibility($entityGenerator::FIELD_VISIBLE_PROTECTED);
return $entityGenerator;
}
}
This does two things. It sets the property visibility to protected. This prevents php errors.
$entityGenerator->setFieldVisibility($entityGenerator::FIELD_VISIBLE_PROTECTED);
It also copies the annotations from mapped super class into the entity class.
$entityGenerator->setGenerateAnnotations(true);
Here's some example code where properties are inherited from a base class and their visibility and annotations copy correctly into the inheriting class
/** #ORM\MappedSuperclass */
class DataSuper {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Campaign", inversedBy="data")
* #ORM\JoinColumn(name="campaign_id", referencedColumnName="id")
* #Exclude
*/
protected $campaign;
/**
* #ORM\Column(type="text", nullable=true, name="data")
*/
protected $data;
/**
* #ORM\Column(type="datetime")
*/
protected $createdDate;
}
/**
* #ORM\Entity(repositoryClass="Foo\Bundle\FooBundle\Entity\DataRepository")
* #ORM\Table(name="data")
* #ExclusionPolicy("none")
*/
class Data extends DataSuper
{
}
After generation the Data class looks like:
class Data extends DataSuper
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", precision=0, scale=0, nullable=false, unique=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="data", type="text", precision=0, scale=0, nullable=true, unique=false)
*/
protected $data;
/**
* #var \DateTime
*
* #ORM\Column(name="createdDate", type="datetime", precision=0, scale=0, nullable=false, unique=false)
*/
protected $createdDate;
/**
* #var \Foo\Bundle\FooBundle\Entity\Campaign
*
* #ORM\ManyToOne(targetEntity="Foo\Bundle\FooBundle\Entity\Campaign", inversedBy="data")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="campaign_id", referencedColumnName="id", nullable=true)
* })
*/
protected $campaign;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set data
*
* #param string $data
* #return Data
*/
public function setData($data)
{
$this->data = $data;
return $this;
}
/**
* Get data
*
* #return string
*/
public function getData()
{
return $this->data;
}
/**
* Set createdDate
*
* #param \DateTime $createdDate
* #return Data
*/
public function setCreatedDate($createdDate)
{
$this->createdDate = $createdDate;
return $this;
}
/**
* Get createdDate
*
* #return \DateTime
*/
public function getCreatedDate()
{
return $this->createdDate;
}
/**
* Set campaign
*
* #param \Foo\Bundle\FooBundle\Entity\Campaign $campaign
* #return Data
*/
public function setCampaign(\Foo\Bundle\FooBundle\Entity\Campaign $campaign = null)
{
$this->campaign = $campaign;
return $this;
}
/**
* Get campaign
*
* #return \Foo\Bundle\FooBundle\Entity\Campaign
*/
public function getCampaign()
{
return $this->campaign;
}
}
And the table structure is correct once you do:
php app/console doctrine:schema:update --force
The exception is being thrown because BaseFoodType::budget is a public property and doctrine:generate:entities created a private property in your Drink / Snack classes extending BaseFoodType ( which is not correct but the way the command works by now ).
Property visibility in a subclass can only be the same level or more liberate ( private -> protected -> public ) but never more restrictive.
doctrine:generate:entities did not take superclass's public property into account when generating the getters/setters as the implementation with a public property is non-standard.
Therefore you will have to adjust the generated class manually.
I recommend using private/protected properties combined with getters & setters.

how to check whether foreign key is working or not in symfony2 with doctrine

I have followed One-to-Many relation not working and created a one to many relationship
i have a users table where i have following fields
- id(primary key)
- name
- pwd
i have attachments table where user can upload more than one file i.e one user_id contains multiple files
- id
- user_id(foreignkey)
- path
my user entity contains the following code
namespace Repair\StoreBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* users
* #ORM\Entity(repositoryClass="Repair\StoreBundle\Entity\usersRepository")
*/
class users
{
/**
* #var integer
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
--some code --
/**
* #ORM\OneToMany(targetEntity="attachments", mappedBy="user_id")
*/
private $attachments;
public function __construct()
{
$this->attachments= new ArrayCollection();
}
/**
* Add attachments
*
* #param \Repair\StoreBundle\Entity\attachments $attachments
* #return users
*/
public function addAttachment(\Repair\StoreBundle\Entity\attachments $attachments)
{
$this->attachments[] = $attachments;
return $this;
}
/**
* Remove attachments
*
* #param \Repair\StoreBundle\Entity\attachments $attachments
*/
public function removeAttachment(\Repair\StoreBundle\Entity\attachments $attachments)
{
$this->attachments->removeElement($attachments);
}
/**
* Get attachments
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getAttachments()
{
return $this->attachments;
}
this is my attachments entity
namespace Repair\StoreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* attachments
*/
class attachments
{
-- some code for id--
private $id;
/**
* #var integer
* #ORM\Column(name="user_id", type="integer", nullable=false)
* #ORM\ManyToOne(targetEntity="users", inversedBy="users")
* #ORM\JoinColumn(name="user_id", referencedColumnName="user_id")
*/
protected $userId;
public function getId()
{
return $this->id;
}
/**
* Set userId
* #param integer $userId
* #return attachments
*/
public function setUserId($userId)
{
$this->userId = $userId;
return $this;
}
/**
* Get userId
*
* #return integer
*/
public function getuserId()
{
return $this->userId;
}
--Some code for paths --
}
It is not displaying any errors
but how to know whether the foriegn key is set or not i went to phpmyadmin and checked the indexes it only shows the primary keys.please say whether i did correct or not and how to check whether foreign key is set or not
problem is in your annotations. In your attachment entity you should have annotation like this.
* #ORM\ManyToOne(targetEntity="users", inversedBy="annotations")
you don't have to have join column annotation. But if you want to have it there, it should look like this.
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
Also it shouldn't be called user_id but user, because doctrine takes it as whole entity.

Symfony2 forms - Setting several fields using one method

Let's say that I have an entity.
This entity has two field that should be changed only through one function, because of domain logic
How could I make the form framework to set the values using one method call.
What I've read about data transformers, lead me to the impression that it can not be used to this propose.
Next is form events, this are the available events
PRE_BIND
BIND
POST_BIND
PRE_SET_DATA
POST_SET_DATA
BIND_CLIENT_DATA
BIND_NORM_DATA
SET_DATA
but the documentation about this is very scarce.
This is a sample entity
<?php
namespace X3\TestBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Test
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="X3\TestBundle\Entity\TestRepository")
*/
class Test
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="firstValue", type="string", length=255)
*/
private $firstValue;
/**
* #var string
*
* #ORM\Column(name="secondValue", type="string", length=255)
*/
private $secondValue;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Test
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set firstValue
*
* #param string $firstValue
* #return Test
*/
protected function setFirstValue($firstValue)
{
$this->firstValue = $firstValue;
return $this;
}
/**
* Get firstValue
*
* #return string
*/
public function getFirstValue()
{
return $this->firstValue;
}
/**
* Set secondValue
*
* #param string $secondValue
* #return Test
*/
protected function setSecondValue($secondValue)
{
$this->secondValue = $secondValue;
return $this;
}
/**
* Get secondValue
*
* #return string
*/
public function getSecondValue()
{
return $this->secondValue;
}
//
// The objective here is that the form use this function
// to set the two values in one call
//
protected function setValues($firstValue, $secondValue)
{
$this->firstValue = $firstValue;
$this->secondValue = $secondValue;
return $this;
}
}
Do note that setFirstValue($firstValue) and setSecondValue($secondValue) are protected, the values should be set using the method setValues($firstValue, $secondValue)
Is there an event I can use, to retrieve the firstValue and secondValue and set it using setValues($firstValue, $secondValue) and avoid the form component to complain about Method "setFirstValue()" is not public in class...?
Some code or link to it, would be a bonus.
Extending the form framework would not be easy, even if using some of form events.
One possible solution would be simply create values property in the entity which isn't mapped to any database field, and its setter and getter. Then the setValues function can do whatever needed to set firstValue and secondValue.
You may want to use DataTransformer. It allows you to control the transformation of data in both directions. Anyway you need to add values field to form, that will transformed to two fields and saved as one field.

Resources