Many-To-Many relationship Doctrine - php

I have had quite a few problems with my current entities mapping, so I wanted an opinion on what is the issue with it.
Let's say with have the following tables example with Doctrine, but also keep in mind that a Group can have many Users, and a User can be part of many Groups
User
--
id
name
Group
--
id
title
User Groups
--
id
user_id
group_id
And this is my current approach:
/**
* User
*
* #ORM\Table(name="user")
* #ORM\Entity(repositoryClass="SomeBundle\Entity\Repository\UserRepository")
*/
class User
{
/**
* #var integer
* #ORM\Id
* #ORM\Column(name="user_id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $user_id;
// some other fields and functions here
}
Group
/**
* Group
*
* #ORM\Table(name="group", indexes={#ORM\Index(name="group_parent", columns={"parent_id"})})
* #ORM\Entity(repositoryClass="SomeBundle\Entity\Repository\GroupRepository")
*/
class Group
{
/**
* #var integer
*
* #ORM\Column(name="category_id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $categoryId;
// some other functions and variables here
}
...and user_groups
/**
* User_Groups
*
* #ORM\Table(name="user_groups",
* indexes={
* #ORM\Index(name="user_group_user", columns={"user_id"}),
* #ORM\Index(name="user_group_group", columns={"group_id"})
* }
* )
* #ORM\Entity(repositoryClass="SomeBundle\Entity\Repository\UserGroupRepository")
*/
class UserGroup
{
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(name="user_group_id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $userGroupId;
/**
* #var \SomeBundle\Entity\User
* #ORM\Column(name="user_id")
*
* #ORM\ManyToMany(targetEntity="SomeBundle\Entity\User", inversedBy="userGroups")
* #ORM\JoinTable(name="users",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="userId")})
*/
private $user;
/**
* #var SomeBundle\Entity\Category
*
* #ORM\ManyToOne(targetEntity="SomeBundle\Entity\Group", inversedBy="groups")
* #ORM\JoinColumn(name="group_id", referencedColumnName="group_id")
*
*/
private $group;
/// etc
}
Any help would be appreciated!

/** #Entity **/
class User
{
// ...
/**
* #ManyToMany(targetEntity="Group", inversedBy="users")
* #JoinTable(name="users_groups")
**/
private $groups;
public function __construct() {
$this->groups = new \Doctrine\Common\Collections\ArrayCollection();
}
// ...
}
/** #Entity **/
class Group
{
// ...
/**
* #ManyToMany(targetEntity="User", mappedBy="groups")
**/
private $users;
public function __construct() {
$this->users = new \Doctrine\Common\Collections\ArrayCollection();
}
// ...
}
Your case is Many-to-Many, Bidirectional Association
Doctrine association mapping

In this example, I have a product and a mesureUnit they relate many to many.
In your case you only need user and group. The UserGroups is generated automatically.
Many to many relationship are done as follows:
<?php
namespace TeamERP\StoresBundle\Entity;
use Doctrine\ORM\Mapping AS ORM;
/**
* #ORM\Entity
*/
class MesureUnit
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=100, nullable=true)
*/
private $name;
/**
* #ORM\Column(type="string", length=10, nullable=true)
*/
private $abreviation;
/**
* #ORM\OneToMany(targetEntity="TeamERP\StoresBundle\Entity\ProductActivity", mappedBy="mesureUnit")
*/
private $pproductActivity;
/**
* #ORM\ManyToMany(targetEntity="TeamERP\StoresBundle\Entity\Product", mappedBy="mesureUnit")
*/
private $product;
/**
* Constructor
*/
public function __construct()
{
$this->pproductActivity = new \Doctrine\Common\Collections\ArrayCollection();
$this->product = new \Doctrine\Common\Collections\ArrayCollection();
}
Then the produc class could be like:
<?php
namespace TeamERP\StoresBundle\Entity;
use Doctrine\ORM\Mapping AS ORM;
/**
* #ORM\Entity
*/
class Product
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=50, nullable=true)
*/
private $code;
/**
* #ORM\Column(type="string", length=250, nullable=true)
*/
private $description;
/**
* #ORM\Column(type="datetime", nullable=true)
*/
private $date_received;
/**
* #ORM\OneToMany(targetEntity="TeamERP\StoresBundle\Entity\ProductActivity", mappedBy="product")
*/
private $pproductActivity;
/**
* #ORM\ManyToOne(targetEntity="TeamERP\StoresBundle\Entity\Category", inversedBy="product")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
private $category;
/**
* #ORM\ManyToOne(targetEntity="TeamERP\StoresBundle\Entity\AJob", inversedBy="product")
* #ORM\JoinColumn(name="job_id", referencedColumnName="id")
*/
private $aJob;
/**
* #ORM\ManyToMany(targetEntity="TeamERP\StoresBundle\Entity\MesureUnit", inversedBy="product")
* #ORM\JoinTable(
* name="MesureUnit2Product",
* joinColumns={#ORM\JoinColumn(name="product_id", referencedColumnName="id", nullable=false)},
* inverseJoinColumns={#ORM\JoinColumn(name="mesure_unit_id", referencedColumnName="id", nullable=false)}
* )
*/
private $mesureUnit;
/**
* Constructor
*/
public function __construct()
{
$this->pproductActivity = new \Doctrine\Common\Collections\ArrayCollection();
$this->mesureUnit = new \Doctrine\Common\Collections\ArrayCollection();
}
Yo do not need to create the table manually. It is generated by Doctrine.
Hope it helps

Related

Symfony ManyToOne Form add, delete in DB

I have entity developer and comment and relationship Many comment to One developer. And I need form when I see all comment for developer and edit - add, delete in DB . What are the solutions to this problem
entity Comment:
class Comments
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Developer", inversedBy="comments")
* #ORM\JoinColumn(name="talent_id", nullable = true, referencedColumnName="id")
* */
protected $talent;
/**
* #var string
*
* #ORM\Column(name="added_by", type="string", length=10, nullable=true)
*/
private $added_by;
/**
* #var string
*
* #ORM\Column(name="comment", type="string", length=10, nullable=true)
*/
private $comment;
entity Developer:
class Developer extends CustomUser
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/////
/**
* #ORM\OneToMany(targetEntity="Comments", mappedBy="talent", cascade={"persist", "remove"})
*/
protected $comments;
Maybe need form in form but how to do this?
You are looking for field type collection.
Example usage of collection type
class Comments
{
....
/**
*
*#ORM\ManyToOne(targetEntity="Developer", inversedBy="developer_to_comments")
* #ORM\JoinColumn(name="developer_to_comments_id", referencedColumnName="id", nullable=false)
*
*/
private $comments_to_developer;
...
}
And class Developer
class Developer extends CustomUser
{
....
/**
*
* #var ArrayCollection
* #ORM\OneToMany(targetEntity="Comments", mappedBy="comments_to_developer", cascade={"remove"})
*/
private $developer_to_comments;
public function __construct()
{
$this->developer_to_comments = new ArrayCollection();
}
....
}
And don't forget use Doctrine\Common\Collections\ArrayCollection

Doctrine ORM Bind Product to Multiple Entities

I have businesses, categories and products. Categories are assigned to businesses and products are assigned to categories and businesses.
Reason being, one product can be assigned to different categories in different businesses.
Business and Category entities are working fine, but I am not sure how to write a Product entity to achieve what I need...
Business Entity:
namespace Raiel\AFMage\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
* #ORM\Table(name="businesses")
*/
class Business {
/**
* #ORM\Id()
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer", name="id")
*/
private $id;
/**
* #ORM\Column(name="name", type="string", length=64)
*/
private $name;
/**
*
* #ORM\ManyToMany(targetEntity="Category", inversedBy="businesses")
* #ORM\JoinTable(
* name="business_categories",
* joinColumns={
* #ORM\JoinColumn(name="business_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
* }
* )
*/
private $categories;
/**
* Default constructor, initializes collections
*/
public function __construct() {
$this->categories = new ArrayCollection();
}
}
Category Entity:
<?php
namespace Raiel\AFMage\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* #Gedmo\Tree(type="nested")
* #ORM\Table(name="categories")
* #ORM\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\NestedTreeRepository")
*/
class Category {
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue
*/
private $id;
/**
*
* #ORM\ManyToMany(targetEntity="Business", mappedBy="categories")
*/
private $businesses;
/**
* #Gedmo\TreePath
* #ORM\Column(name="path", type="string", length=3000, nullable=true)
*/
private $path;
/**
* #ORM\Column(name="title", type="string", length=64)
*/
private $title;
/**
* #Gedmo\TreeLevel
* #ORM\Column(name="lvl", type="integer")
*/
private $lvl;
/**
* #Gedmo\TreeLeft
* #ORM\Column(name="lft", type="integer")
*/
private $lft;
/**
* #Gedmo\TreeRight
* #ORM\Column(name="rgt", type="integer")
*/
private $rgt;
/**
* #Gedmo\TreeRoot
* #ORM\Column(name="root", type="integer", nullable=true)
*/
private $root;
/**
* #Gedmo\TreeParent
* #ORM\ManyToOne(targetEntity="Category", inversedBy="children")
* #ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="CASCADE")
*/
private $parent;
/**
* #ORM\OneToMany(targetEntity="Category", mappedBy="parent")
* #ORM\OrderBy({"lft" = "ASC"})
*/
private $children;
/**
* Constructor
*/
public function __construct() {
$this->children = new ArrayCollection();
$this->businesses = new ArrayCollection();
}
}
Also, $business->addCategory works fine but $category->addBusiness doesn't save to DB.
Your product entity will probably look something like:
namespace Raiel\AFMage\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
* #ORM\Table(name="products")
*/
class Product {
/**
* #ORM\Id()
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer", name="id")
*/
private $id;
/**
* #ORM\Column(name="name", type="string", length=64)
*/
private $name;
/**
*
* #ORM\ManyToMany(targetEntity="Category", inversedBy="products")
* #ORM\JoinTable(
* name="product_categories",
* joinColumns={
* #ORM\JoinColumn(name="product_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
* }
* )
*/
private $categories;
/**
*
* #ORM\ManyToMany(targetEntity="Business", inversedBy="products")
* #ORM\JoinTable(
* name="product_businesses",
* joinColumns={
* #ORM\JoinColumn(name="product_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="business_id", referencedColumnName="id")
* }
* )
*/
private $businesses;
}
So more or less what you have for your Business entity but with the ManyToMany relation using a different join table.
And to make $category->addBusiness() work then you'll probably want to add a cascade option to category, thusly:
/**
*
* #ORM\ManyToMany(targetEntity="Business", mappedBy="categories", cascade="persist")
*/
private $businesses;
This informs Doctrine that anything new added to the $businesses array collection should be persisted, take a look at the documentation for details.

Zend Framework 2 Doctrine2 leftJoin creating a separate SELECT query

Does anyone know why the Doctrine query below creates a separate join for the StandardDedescribed entity?
As you can see below this query pulls the information from the master entity 'EquipmentUK' and two related tables: 'SchemaInfo' and 'StandardDescribed'. It works well for the SchemaInfo, but creates another query for StandardDescribed. The relations in the Entities seem to be coded extactly the same, so I don't understand why it behaves differently for StandardDescribed?
$qb->select('e')
->from('\Lookup\Entity\Fullhistory\EquipmentUK', 'e')
->leftJoin(
'\Lookup\Entity\Fullhistory\SchemaInfo',
'si',
Expr\Join::WITH,
'e.schema_id = si.schema_id AND si.parent_schema_id != si.schema_id'
)
->leftJoin(
'\Lookup\Entity\Intelligence\StandardDescribedUK',
'sd',
Expr\Join::WITH,
'e.schema_id = sd.schema_id'
)
->where($qb->expr()->eq('e.vehicle_id', '?1'))
->setParameter(1, $jatoid);
Here are the Entities:
EquipmentUK:
namespace Lookup\Entity\Fullhistory;
use Doctrine\ORM\Mapping as ORM;
/**
* EquipmentUK
*
* #ORM\Table(name="equipment",
* uniqueConstraints={
* #ORM\UniqueConstraint(name="search_idx", columns={"vehicle_id", "option_id", "record_id", "schema_id"})
* }
* )
* #ORM\Entity
*/
class EquipmentUK
{
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(type="integer")
*/
private $vehicle_id;
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(type="integer")
*/
private $schema_id;
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(type="integer")
*/
private $option_id;
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(type="integer")
*/
private $record_id;
/**
* #var string
*
* #ORM\Column(type="string")
*/
private $location;
/**
* #ORM\ManyToOne(targetEntity="Lookup\Entity\Fullhistory\SchemaInfo", cascade={"all"}, fetch="EAGER")
* #ORM\JoinColumn(name="schema_id", referencedColumnName="schema_id")
*/
private $schemaInfo;
/**
* #ORM\ManyToOne(targetEntity="Lookup\Entity\Intelligence\StandardDescribedUK", cascade={"all"}, fetch="EAGER")
* #ORM\JoinColumn(name="schema_id", referencedColumnName="schema_id")
*/
private $standardDescribed;
/**
* #var string
*
* #ORM\Column(type="string")
*/
private $data_value;
public function getVehicleId()
{
return $this->vehicle_id;
}
public function getSchemaId()
{
return $this->schema_id;
}
public function getOptionId()
{
return $this->option_id;
}
public function getRecordId()
{
return $this->record_id;
}
public function getLocation()
{
return $this->location;
}
public function getSchemaInfo()
{
return $this->schemaInfo;
}
public function getStandardDescribed()
{
return $this->standardDescribed;
}
public function getDataValue()
{
return $this->data_value;
}
}
SchemaInfo:
namespace Lookup\Entity\Fullhistory;
use Doctrine\ORM\Mapping as ORM;
/**
* SchemaInfo
*
* #ORM\Table(name="schema_info")
* #ORM\Entity
*/
class SchemaInfo
{
/**
* #var integer
*
* #ORM\Column(name="schema_id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $schema_id;
/**
* #var integer
*
* #ORM\Column(name="parent_schema_id", type="integer", nullable=true)
*/
private $parent_schema_id;
/**
* #var integer
*
* #ORM\Column(name="location_schema_id", type="integer", nullable=true)
*/
private $locationSchemaId;
/**
* #var integer
*
* #ORM\Column(name="scale_of_data", type="smallint", nullable=true)
*/
private $scaleOfData;
/**
* #var integer
*
* #ORM\Column(name="data_type", type="smallint", nullable=true)
*/
private $dataType;
public function getSchemaId()
{
return $this->schema_id;
}
public function getParentSchemaId()
{
return $this->parent_schema_id;
}
}
StandardDescribedUK
namespace Lookup\Entity\Intelligence;
use Doctrine\ORM\Mapping as ORM;
/**
* StandardDescribedUK
*
* #ORM\Table(name="jato_uk_intelligence.standard_described")
* #ORM\Entity
*/
class StandardDescribedUK
{
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $schema_id;
/**
* #var string
*
* #ORM\Column(name="category", type="string", nullable=true)
*/
private $category;
public function getCategory()
{
return $this->category;
}
}
Your joins should use Doctrine's own relational schema: your EquipmentUK has declared its relation with SchemaInfo via the property $schemaInfo, and it has also declared its relation with StandardDescribedUK via $standardDescribed. So:
$qb->select('e')
->from('\Lookup\Entity\Fullhistory\EquipmentUK', 'e')
->leftJoin(
'e.schemaInfo',
'si'
//we don't need that third param as the relation is already known
)
->leftJoin(
'e.standardDescribed',
'sd'
//same here, no need for explicit relation
)
->where($qb->expr()->eq('e.vehicle_id', ':vehicle'))
//this here is a restriction, should be in WHERE instead of ON
->andWhere($qb->expr()->neq('si.parent_schema_id', 'si.schema_id'))
->setParameter('vehicle', $jatoid);
Hope this helps!

ManyToOne relation Symfony2

I have a many to one relation between my entities.
An application can have activities
<?php
namespace AppAcademic\ApplicationBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Activity
*
* #ORM\Table()
* #ORM\Entity
*/
class Activity
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="AppAcademic\ApplicationBundle\Entity\Application", inversedBy="activity")
* #ORM\JoinColumn(name="application_id", referencedColumnName="id", onDelete="CASCADE")
*/
private $application;
/**
* #var string
*
* #ORM\Column(name="title", type="string", length=255)
*/
private $title;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
public function setApplication($application)
{
$this->application = $application;
return $this;
}
public function getApplication()
{
return $this->application;
}
/**
* Set title
*
* #param string $title
* #return Activity
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* #return string
*/
public function getTitle()
{
return $this->title;
}
}
And the application
/**
* Application
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="AppAcademic\ApplicationBundle\Entity\ApplicationRepository")
*/
class Application
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="AppAcademic\ApplicationBundle\Entity\Activity", mappedBy="application")
*/
protected $activities;
...
}
I have this in the profiler:
AppAcademic\ApplicationBundle\Entity\Application
The mappings AppAcademic\ApplicationBundle\Entity\Application#activities and AppAcademic\ApplicationBundle\Entity\Activity#application are inconsistent with each other.
AppAcademic\ApplicationBundle\Entity\Application
The mappings AppAcademic\ApplicationBundle\Entity\Application#activities and AppAcademic\ApplicationBundle\Entity\Activity#application are inconsistent with each other.
AppAcademic\ApplicationBundle\Entity\Activity
The association AppAcademic\ApplicationBundle\Entity\Activity#application refers to the inverse side field AppAcademic\ApplicationBundle\Entity\Application#activity which does not exist.
For the mapping annotation ManyToOne on the Activity::$application property, the attribute
inversedBy="activity"
This should be
inversedBy="activities"

symfony2 how to get mapping table id?

how to get mapping table id from mappipng table?
i have user and group table mapped together
and i want to get group id at login time but i am not getting it.
i have three table
user, group, user_groupname
->first table
user
id,name
->second table
group
id,name
->third table
groupname
user_id,group_id
first entity is as follows
/Entity/groupname.php
class groupname
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255, nullable=false)
*/
private $name;
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="role", inversedBy="groupname")
* #ORM\JoinTable(name="groupname_role",
* joinColumns={
* #ORM\JoinColumn(name="groupname_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="role_id", referencedColumnName="id")
* }
* )
*/
private $role;
/**
* #ORM\ManyToMany(targetEntity="\Dashboard\SecurityBundle\Entity\User", mappedBy="groupname")
*/
private $users;
}
second entity is as follows
/Entity/User.php
<?php
namespace Dashboard\SecurityBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Dashboard\SecurityBundle\Entity\User
*
* #ORM\Table(name="users")
* #ORM\Entity(repositoryClass="Dashboard\SecurityBundle\Repository\UserRepository")
* #ORM\HasLifecycleCallbacks()
*/
class User implements UserInterface, \Serializable, AdvancedUserInterface
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=25, unique=true)
*/
protected $username;
*/
/**
* #ORM\ManyToMany(targetEntity="\Dashboard\AdminManageUserBundle\Entity\groupname", inversedBy="users")
*
*/
public $groupname;
/**
* #var Dashboard\SecurityBundle\Entity\UserPhoto UserPhoto
*
*/
private $userPhoto;
public function __construct()
{
$this->groupname = new ArrayCollection();
}
/**
* Add groupname
*
* #param \Dashboard\AdminManageUserBundle\Entity\groupname $groupname
* #return User
*/
public function addGroupname(\Dashboard\AdminManageUserBundle\Entity\groupname $groupname)
{
$this->groupname[] = $groupname;
return $this;
}
/**
* Remove groupname
*
* #param \Dashboard\AdminManageUserBundle\Entity\groupname $groupname
*/
public function removeGroupname(\Dashboard\AdminManageUserBundle\Entity\groupname $groupname)
{
$this->groupname->removeElement($groupname);
}
/**
* Get groupname
*
* #return \Doctrine\Common\Collections\ArrayCollection
*/
public function getGroupname()
{
return $this->groupname;
}
}
and i have following code right in Controller file
$userEntity = $this->getDoctrine()->getRepository('DashboardSecurityBundle:User')->findOneBy(array('username' =>$usernames));
and i have print_R($userEntity) pc got hanged
$userEntiry is a object of UserEntity
So, your pc got hanged.
please try this.
print_r($userEntity->getUsername());

Categories