How to save additional entity while persisting another in Doctrine? - symfony

I've got a Place entity and a Distance one, like so:
class Place
{
/** #ORM\Id #ORM\Column(type="integer") #ORM\GeneratedValue(strategy="AUTO") */
private $id;
/** #ORM\Column(type="string", length=62, nullable=false) */
private $name;
/** #ORM\OneToMany(targetEntity="Distance", mappedBy="origin") */
protected $distancesTo;
/** #ORM\OneToMany(targetEntity="Distance", mappedBy="destination") */
protected $distancesFrom;
}
class Distance
{
/** #ORM\Id #ORM\Column(type="integer") #ORM\GeneratedValue(strategy="AUTO") */
private $id;
/** #ORM\ManyToOne(targetEntity="Place", inversedBy="distancesTo") */
protected $origin;
/** #ORM\ManyToOne(targetEntity="Place", inversedBy="distancesFrom") */
protected $destination;
/** #ORM\Column(type="integer") */
private $miles;
}
I want that every time a new Distance (from Place_A to Place_B) is saved, the reverse distance (from Place_B to Place_A) gets inserted too in the DB. How can I do that?

You need to create listener and listen for persisting on Distance entity. While it persists you can create new Distance with reverse route.

Related

Doctrine relation from MappedSuperClass to Entity

I want to ultimately have an abstract base class that defines a relationship to another entity for all inheriting Entity-classes. So have this test-setup that was created with symfony's make:entity-command.
The only thing I changed was switching the MappedSuperClass's property-visibility from private to protected to make them visible to the extenders.
This is the MappedSuperClass:
[...]
/**
* Class TestMappedSuperclass
*
* #package App\Entity
* #ORM\MappedSuperclass()
*/
class TestMappedSuperclass
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity=TestTarget::class, mappedBy="testMappedSuperclass")
*/
protected $targets;
public function __construct()
{
$this->targets = new ArrayCollection();
}
//..getters/setters,add/remove...
}
This my target-entity for the mapping:
[...]
/**
* #ORM\Entity(repositoryClass=TestTargetRepository::class)
*/
class TestTarget
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity=TestMappedSuperclass::class, inversedBy="targets")
*/
private $testMappedSuperclass;
// ..getters,setters..
}
This is the extending entity class:
[...]
/**
* #ORM\Entity(repositoryClass=TestEntityRepository::class)
*/
class TestEntity extends TestMappedSuperclass
{
}
So when I try to do a make:migration it produces the following error:
Column name `id` referenced for relation from App\Entity\TestTarget towards
App\Entity\TestMappedSuperclass does not exist.
Using: Symfony 5.1, Doctrine 2.7
AFAIK you need to have repeat id as protected in TestEntity :
/**
* #ORM\Entity(repositoryClass=TestEntityRepository::class)
*/
class TestEntity extends TestMappedSuperclass
{
/**
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
}
I took this from a project where i´m using mappedSuperClass like this, i´m not relate entities in it though

Symfony + Doctrine - Set property default value equal to ID

I have a Question entity with a property called code. I want to set the value of code equal to id on default with Doctrine annotations.
This is how I tried but I'm getting an error:
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="integer")
*/
private $code = $id;
Or:
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="integer", options = {"default": $id})
*/
private $code;
Thanks.
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html
I don't know what is your need but maybe postPersist event is what you want :
postPersist - The postPersist event occurs for an entity after the
entity has been made persistent. It will be invoked after the database
insert operations. Generated primary key values are available in the
postPersist event.
Then in your entity :
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="integer")
*/
private $code;
/** #PostPersist */
public function doStuffOnPostPersist()
{
$this->code = $this->id;
}
It is important to understand that your doctrine entity will have an ID only after having been persisted, thus after the post persist event.

Entity inheritance in Doctrine doesn't include OneToOne-relationships

Trying to utilize inheritance, I've created the following entities:
/**
* #ORM\Table(name="persons")
* #ORM\Entity()
*/
class Person
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
protected $name;
/**
* #ORM\OneToOne(targetEntity="Image", cascade={"persist"})
* #ORM\JoinColumn(name="image_id", referencedColumnName="id")
*/
protected $image;
}
/**
* #ORM\Table(name="actors")
* #ORM\Entity()
*/
class Actor extends Person
{
/**
* #ORM\Column(name="character", type="string", length=255)
*/
private $character;
}
/**
* #ORM\Table(name="images")
* #ORM\Entity()
*/
class Image
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="path", type="string", length=255)
*/
private $path;
}
Which almost works perfectly. The generated actors-table contains all the persons-fields, except for the image-relation. I've tried to change the relation to a ManyToOne, which didn't help.
How to make the Actor-entity also inherit all joined fields? I'm open to other solutions, if the above isn't ideal.
You need a parent construct in your Actor class:
public function __construct()
{
parent::__construct();
// your own logic
}
It is advised that you add an ID aswell.

Removing related entity Symfony2

I have related entities. Many to Many relation and the annotation exists on only one entity:
/**
* #ORM\ManyToMany(targetEntity="Event")
* #ORM\JoinTable(name="viewed_events",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="event_id", referencedColumnName="id")}
* )
**/
protected $viewedEvents;
The problem is when I try to delete Event entity I get Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails error. How do I solve this? I tried adding orphanRemoval=true like that: #ORM\ManyToMany(targetEntity="Event", orphanRemoval=true) and also tried adding cascade="delete" and cascade="all" instead with no success.
I give you one simple example so that you can work out what you need to add/change in your application.
Assume that there is a M-N relationship between Student and Course entities.
STUDENT
class Student
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="StudentCourse", mappedBy="studentInverse", cascade={"persist", "remove"})
*/
protected $studentInverse;
public function __construct()
{
$this->studentInverse = new \Doctrine\Common\Collections\ArrayCollection();
}
}
COURSE
class Course
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="StudentCourse", mappedBy="courseMap", cascade={"persist", "remove"})
*/
protected $courseInverse;
public function __construct()
{
$this->courseInverse = new \Doctrine\Common\Collections\ArrayCollection();
}
}
STUDENTCOURSE (this the one you're more interested in)
class StudentCourse
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Course", inversedBy="courseInverse")
* #ORM\JoinColumn(name="course", referencedColumnName="id", nullable=false, onDelete="CASCADE")
*/
protected $courseMap;
/**
* #ORM\ManyToOne(targetEntity="Student", inversedBy="studentInverse")
* #ORM\JoinColumn(name="student", referencedColumnName="id", nullable=false, onDelete="CASCADE")
*/
protected $studentMap;
}
onDelete="CASCADE"
On Yours JoinColumn.

Symfony2 and Doctrine ManyToMany realtionship

I am heaving some headache about this and I don't find the solution.
I have 2 entities: Movie.php and Category.php
I want one Movie to have multiple Categories and vice versa. That's why I chose a ManyToMany relationship.
Now I am wondering... What happens on the database site? Is there a "in-between" table that maps movie_ids to category_ids? But that's not what happened. Actually my first try was to make a MovieCategory entity - I mapped one movie to multiple categories with OneToMany and in the MovieCategory entity I made a OneToOne connection to get the category name from my Category entity. But I guess that's not how it should work, am I right?
Now here's my code of how i think it should work, I really appreciate any help I can get on this:
Movie.php
<?php
/**
* #ORM\Table(name="movies")
* #ORM\HasLifecycleCallbacks()
*/
class Movie
{
public function __construct()
{
$this->categories = new ArrayCollection();
}
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/** #ORM\Column(type="string") */
protected $moviename;
/**
* #ORM\ManyToMany(targetEntity="Category", mappedBy="movie")
*/
protected $categories;
}
Category.php
<?php
/**
* #ORM\Table(name="categories")
* #ORM\HasLifecycleCallbacks()
*/
class Category
{
public function __construct()
{
$this->movies = new ArrayCollection();
}
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $name;
// ...
/**
* #ORM\ManyToMany(targetEntity="Movie", mappedBy="movie", cascade={"persist"})
*/
protected $movies;
}
According to Doctrine docs it should look this way:
// Movie.php
/**
* #ORM\ManyToMany(targetEntity="Category", inversedBy="movies")
* #ORM\JoinTable(name="movies_categories")
*/
protected $categories;
// ...
// Category.php
/**
* #ORM\ManyToMany(targetEntity="Movie", mappedBy="categories")
*/
protected $movies;
You're using the same value for mappedBy in both declarations. Plus, the value you use is singular, it should be plural. This cannot work.

Resources