I have a bit of an issue. i am modeling a DB structure using Doctrine 2 entities and I got stuck with one relation.
What I need to represent in the database is a matrix like table:
| |A|B|C|D|
|A| x
|B|x x
|C| x x
|D| x
What the table shows is what offers are available with other offers (x=true, empty = false).
What I tried to do is a Many to Many relationship with doctrine, hoping that this will generate a mapping table, but Doctrine does not do that.
Here is my entity:
/**
* #ORM\Entity #ORM\HasLifecycleCallbacks
* #ORM\Entity(repositoryClass="Core\Repository\Main")
* #ORM\Table(name="offer_availability")
*/
class OfferAvailability implements JsonSerializable
{
/**
* #var int
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
protected $id;
/**
* #var String
* #ORM\Column(type="string")
*/
protected $name;
/**
* #var \Doctrine\Common\Collections\Collection
* #ORM\ManyToMany(targetEntity="Core\Entity\Offers\OfferAvailability", mappedBy="availableWith", inversedBy="availableWith", fetch="EXTRA_LAZY")
*/
protected $availableWith;
I know I can create the mapping table entity manually and Use One to Many relations. But what I am wondering if there is a more clever way of approaching this.
Never mind, i have found the issue. Creating mappings in this case only confuses Doctrine. Removing mapping and inversion compleely solved the problem:
/**
* #var \Doctrine\Common\Collections\Collection
* #ORM\ManyToMany(targetEntity="Core\Entity\Offers\OfferAvailability", fetch="EXTRA_LAZY")
*/
protected $availableWith;
This generated a mapping table:
------------------------------------
|offeravailablity_offeravailability|
------------------------------------
|offeravailability_source |
|offeravailability_target |
------------------------------------
Related
Can the discriminator mapping strings of a Doctrine entity be fetched from a database foreign table field? If not, how to handle inheritance type mapping in such a situation?
Considering a Doctrine 2.7.2 abstract entity Person with concrete entities A and B like:
/**
* #MappedSuperclass
* #Table(name="PERSON")
*/
abstract class Person {
/**
* #Id
* #GeneratedValue
*/
protected $id;
/**
* #Column(name="name",type="string")
*/
protected $name;
/**
* #OneToOne(targetEntity="PersonType")
* #JoinColumn(name="type", referencedColumnName="id")
*/
protected $type;
}
/**
* #Entity
* #Table(name="PERSON")
*/
class A extends Person {}
/**
* #Entity
* #Table(name="PERSON")
*/
class B extends Person {}
A Person has a type bound to a PersonType entity like:
/**
* #Entity
* #Table(name="PERSON_TYPE")
*/
class PersonType {
/**
* #Id
* #GeneratedValue
*/
protected $id;
/**
* #Column(name="code",type="string")
*/
protected $code;
/**
* #Column(name="name",type="string")
*/
protected $name;
}
How to get the right class instantiated by repository query methods like find(), findBy(), findById(), etc?
Database set:
SELECT * FROM PERSON:
id name type
1 John 1
2 Tom 2
SELECT * FROM PERSON_TYPE:
id code name
1 A Type A
2 B Type B
Expected results:
$entityManager->getRepository("A")->findOneById(2); // null
$entityManager->getRepository("B")->findOneById(2); // B object (Tom)
$entityManager->getRepository("A")->findOneById(1); // A object (John)
I can't find how to specify this using a discriminator.
Alternatively I have a working solution implementing a SQLFilter with the inconvenience to have to enable or disable filter.
An alternative solution may be to populate $discr?
(I can of course use the Person::findByType() method but it would be nice to have this feature directly managed by the respective repositories).
Let's say I have a simple entity EstablishmentEntity, with a ManyToOne relationship on $employee that looks like this :
namespace Msm\CeopBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Msm\CeopBundle\Entity\Establishment;
/**
* Establishment
*
* #ORM\Table(name="establishment")
* #ORM\Entity()
*/
class School
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
*
* #ORM\ManyToOne(targetEntity="Professionnal", cascade={"persist"})
* #ORM\JoinColumn(name="teacher_id", referencedColumnName="id", nullable=true)
*/
private $employee;
My problem : that entity is used for different kinds of establishments and has a lot more useful attributes in my code (I kept it simple for my question). One kind of establishement won't have any employees. Is it possible to tell Doctrine/symfony NOT to cascade persist the employee in that perticular case after class instanciation for example ?
So far it automatically persists an empty employee entity when creating an establishment, which is ok for most establishments but not all...
I have the following property in my User entity to track followers and following. Basically a user can follow other user as well. I have a join column called app_user_follow_user, however I also wanted to add a timestamp of whenever someone follows another user, when did it happen. How can I specify a created timestamp via this ORM?
/**
* #ORM\ManyToMany(targetEntity="User", mappedBy="following")
*/
protected $followers;
/**
* #ORM\ManyToMany(targetEntity="User", inversedBy="followers")
* #ORM\JoinTable(name="app_user_follow_user",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="follow_user_id", referencedColumnName="id")}
* )
*/
protected $following;
Doctrine ManyToMany relationships are used when your join table has two columns. If you need to add another column you have to convert the relationship to OneToMany on both sides and ManyToOne on the joined entity.
This is entirely untested but it will hopefully give you the gist.
User Entity
/**
* #ORM\OneToMany(targetEntity="AppUserFollowUser", mappedBy="appUser")
*/
protected $followers;
/**
* #ORM\OneToMany(targetEntity="AppUserFollowUser", mappedBy="followUser")
*/
protected $following;
AppUserFollowUser Entity
/**
* #ORM\Table(name = "app_user_follow_user")
*/
class AppUserFollowUser
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="User", inversedBy="followers")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
* })
*/
private $appUser;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="User", inversedBy="following")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="follow_user_id", referencedColumnName="id")
* })
*/
private $followUser;
/**
* #ORM\Column(name="created_date", type="datetime", nullable=false)
*/
private $createdDate;
}
I think that you will have to create a link entity manually (entiy1 onetomany linkEntity manytoone entity2.
Because, the usual link entity are automated and should be as simple and (data less) as possible, so doctrine can take all the controle over it,
imagine you need to get the timestamp, how can you do it on an (none hard coded) entity, you will need a getter, and the annotations are not supposed to contains code.
I'm new to Symfony and Doctrine and I'm trying to join two tables so I can then access the associated values from Twig template easily.
Here is my db scheme:
+--------------------------------------+--------------------+
|Messages | User |
|id user text user_id | id name |
|1 testuser something 1 | 1 John |
+--------------------------------------+--------------------+
This is my Message entity:
/**
* #ORM\Entity
* #ORM\Table(name="Messages")
*/
class Message {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
protected $user_id;
/**
* #ORM\Column(name="text", type="text")
*/
protected $text;
/**
* #ORM\ManyToOne(targetEntity="User")
* */
private $user;
}
And this is my User entity:
/**
* #ORM\Entity
* #ORM\Table(name="Users")
*/
class User {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(name="name", type="string", length=255)
*/
protected $name;
}
Then in controller I send $messages variable to Twig template:
$messages = $this->getDoctrine()->getEntityManager()->getRepository('MeMyBundle:Message')->findAll()
And the question is: Is the joing made properly? How can I access name property through message in Twig? Thanks.
Because of your many to one relationship, the variable $user in the Message class should be an object of type User. Because your variables $user and $name are private or protected, you should make getters and setter for them or make Doctrine generate them for you. After that $messages[i]->getUser()-getName() should work. (Generating getters and setters)
For more info about accessing attributes in relationships, take a deeper look at Fetching Related Objects section of the documentation.
From the same symfony documentation page "Of course, if you know up front that you'll need to access both objects, you can avoid the second query by issuing a join in the original query."
If you want a true JOIN instead of a lazily loaded query you can write your own sql query following the documentation.
I have an Author entity, which is a Class Table Inheritance containing an AuthorUser and an AuthorGroup.
/**
* Author
*
* #ORM\Table
* #ORM\Entity
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="type", type="string")
* #ORM\DiscriminatorMap({"user" = "AuthorUser", "group" = "AuthorGroup"})
*/
class Author {
// ...
}
AuthorUser relates to my User entity and AuthorGroup to my Group entity.
class AuthorUser extends Author
{
/**
* #var User
*
* #ORM\ManyToOne(targetEntity="User", inversedBy="?????")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user;
}
class AuthorGroup extends Author
{
/**
* #var Group
*
* #ORM\ManyToOne(targetEntity="Group", inversedBy="?????")
* #ORM\JoinColumn(name="group_id", referencedColumnName="id")
*/
protected $user;
}
I have no idea how to inverse this. Anyway, the problem is that i have to add this CTI to my Article entity field. How can i relate using ManyToOne to this Article entity field?
class Article
{
/**
* #var Author
*
* #ORM\ManyToOne(targetEntity="Author", inversedBy="?????????")
* #ORM\JoinColumn(name="author_id", referencedColumnName="id")
*/
protected $author;
}
I'm not sure how to make this as transparent as possible. When i create a new Article, i need to provide either an User or Group object to the author field. I followed this behavior, but it doesn't seem to help. It gets even more complicated.
One solution could be to always have AuthorGroups, even when there's only one Author.
Otherwise, take a look at https://github.com/FabienPennequin/DoctrineExtensions-Rateable
You might be able to use that code to provide a similar Authored interface that can discriminate between the AuthorUser and AuthorGroup.