Symfony ManyToMany relation add constraint without entity - doctrine

I have ManyToMany relation, without entity and I want add constraint for ManyToMany table, example for uniq fields, how it's done ?
My constrait example for entity
* #ORM\Table(name="courses",
* uniqueConstraints={
* #UniqueConstraint(name="unique",
* columns={"courses_id", "courses_of_study_id"})
* }
* )
*/
class Courses
But this is approcah for entity/ In my case I don't need create entity, just relation ManyToMany in both side. This relation create table in database with courses_courses_of_study with courses_id and courses_of_study_id and I want add to it uniqueConstraints
may entity
class Courses
{
use TraitTimestampable;
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var ArrayCollection|CoursesOfStudy[]
*
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\CoursesOfStudy", inversedBy="courses", cascade={"persist", "remove"})
*/
private $coursesOfStudy;
class CoursesOfStudy
{
use TraitTimestampable;
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var ArrayCollection|Courses[]
*
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Courses", mappedBy="coursesOfStudy", cascade={"persist"})
*/
private $courses;
I try added this uniqueConstraints to entity Courses, but after migration diff I have error
[Doctrine\DBAL\Schema\SchemaException]
There is no column with name 'courses_id' on table 'courses'.
when I try
* #ORM\Table(name="courses")
* #ORM\Table(name="courses_courses_of_study",
* uniqueConstraints={
* #UniqueConstraint(name="unique",
* columns={"courses_id", "courses_of_study_id"})
* }
* )
*/
class Courses
have error
[Doctrine\DBAL\Schema\SchemaException]
The table with name 'project.courses_courses_of_study' already exists.

Related

Symfony 5 - Doctrine - Index not created in custom ManyToOne relation

I've created two Entity, and i try to create a custom relation between them, without using the default syntax.
See :
/**
* #ORM\Entity(repositoryClass=LandRepository::class)
* #ORM\HasLifecycleCallbacks()
*/
class Land
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $libelle;
/**
* #ORM\Column(type="integer")
*/
private $uid;
/**
* #ORM\OneToMany(targetEntity=Ride::class, mappedBy="uidparent")
*/
private $rides;
}
/**
* #ORM\Entity(repositoryClass=RideRepository::class)
* #ORM\HasLifecycleCallbacks()
*/
class Ride
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $libelle;
/**
* #ORM\ManyToOne(targetEntity=Land::class, inversedBy="rides")
* #ORM\JoinColumn(name="uidparent", referencedColumnName="uid")
*/
private $uidparent;
}
Tables are correctly created, but the last instruction have an error.
In MySQL, i made some test, and i need to create an index on "uid" column in "land" table.
So, i changed the header of my class "Land" to force the index
/**
* #ORM\Entity(repositoryClass=LandRepository::class)
* #ORM\Table(name="land",indexes={#ORM\Index(columns={"uid"})})
* #ORM\HasLifecycleCallbacks()
*/
class Land
{
/ ... /
}
I don't understand why i need to specify this index creation.
I hope to have something like this :
(PS : I know i can use the classic syntax (using in my entity Ride a column auto named "land_id") but I want to understand and master this alternative syntax to manage future complex entities and associations)
Thanks !
Need to manually specify in Entity header annotation :
#ORM\Table(name="land",indexes={#ORM\Index(columns={"uid"})})

DQL join two joined tables from different tables

I know the title isn't very clear, but I will try to better explain my problem here.
I have 3 Doctrine entities : A, B and C
class A { class B { class C {
$id; $id; $id;
ManyToMany ManyToMany }
$C; $C;
} }
I'm trying to know if an object A and an object B have at least one same C.
The many to many relations gives me table like :
table AC { table BC {
A_id; B_id;
C_id; C_id;
} }
I know that I can't use these tables in DQL but what I want to do can be done in SQL. It would give :
SELECT COUNT(A.id) FROM AC INNER JOIN BC
ON AC.C_id = BC.C_id
WHERE BC.B_id=1217 AND AC.A_id=185
You will need to make the many to many accosiation bidirectional, so entities will look like this:
<?php
namespace App\Model;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class A
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
* #var integer
*/
private $id;
/**
* #var ArrayCollection|C[]
* #ORM\ManyToMany(targetEntity="C", inversedBy="as")
*/
private $cs;
}
/**
* #ORM\Entity
*/
class B
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
* #var integer
*/
private $id;
/**
* #var ArrayCollection|C[]
* #ORM\ManyToMany(targetEntity="C", inversedBy="bs")
*/
private $cs;
}
/**
* #ORM\Entity
*/
class C
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
* #var integer
*/
private $id;
/**
* #var ArrayCollection|A[]
* #ORM\ManyToMany(targetEntity="A", mappedBy="cs")
*/
private $as;
/**
* #var ArrayCollection|A[]
* #ORM\ManyToMany(targetEntity="B", mappedBy="cs")
*/
private $bs;
}
And then you can query the C class with conditional join on A and B entities, by this DQL query:
$query = $this->entityManager->createQuery("SELECT count(c.id) FROM C::class c INNER JOIN c.as a WITH a.id = :a_id INNER JOIN c.bs b WITH b.id = :b_id")
->setParameter('a_id', 185)
->setParameter('b_id', 1217);
$result = $query->getSingleScalarResult();

Many-to-Many Relations using non-"id" Primary Key in Doctrine

So I'd like to create two entities and make a many-to-many reference. I would love to make this association using a string primary key on one table. This seems to be really hard, at least it took me pretty much time trying without any results yet.
This is my approach:
First entity:
namespace Project\AdminBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="User")
*/
class User
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $Id;
/**
* #ORM\ManyToMany(targetEntity="Role", inversedBy="Users")
* #ORM\JoinTable(name="role_user",
* joinColumns={#ORM\JoinColumn(name="User_Id", referencedColumnName="Id")},
* inverseJoinColumns={#ORM\JoinColumn(name="Role_Name", referencedColumnName="Name")}
* )
*/
private $Roles;
}
And the second:
namespace Project\AdminBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="Role")
*/
class Role
{
/**
* #ORM\Id
* #ORM\Column(type="string", length=256)
*/
private $Name;
/**
* #ORM\ManyToMany(targetEntity="User", mappedBy="Roles")
* #ORM\JoinTable(name="role_user",
* joinColumns={#ORM\JoinColumn(name="Role_Name", referencedColumnName="Name")},
* inverseJoinColumns={#ORM\JoinColumn(name="User_Id", referencedColumnName="Id")}
* )
*/
private $Users;
}
Output of ./app/console doctrine:schema:validate:
[Mapping] FAIL - The entity-class 'Project\AdminBundle\Entity\User' mapping is invalid:
* The referenced column name 'Id' has to be a primary key column on the target entity class 'Project\AdminBundle\Entity\User'.
* The referenced column name 'Id' has to be a primary key column on the target entity class 'Project\AdminBundle\Entity\Role'.
What do I miss?
Attention upper/lowercase! Doctrine generates its columns as lowercase per default. This solves the issue:
* joinColumns={#ORM\JoinColumn(name="User_Id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="Role_Name", referencedColumnName="name")}
This it over-complicated; it's enough to put this into the Role entity:
/**
* #ORM\ManyToMany(targetEntity="User", mappedBy="Roles")
* #ORM\JoinColumn(name="role_user", referencedColumnName="name")
*/
private $Users;
I only thought about this when writing the question.. what a good method to think about the problem again from scratch.
Cheers

Create a createQueryBuilder with UniqueConstraint on 2 keys

i'm trying to retrive data from several tables to make a json, but i'm stuck for the table having UniqueConstraint on 2 keys.
Here's my QueryBuilder sofar :
$qb = $this->_em->createQueryBuilder()
->select('partial s.{id, activity}, partial a.{id, title}, partial p.{id, evaluationType}')
->from('Innova\PathBundle\Entity\Step', 's')
->leftJoin('s.activity', 'a') //join on Activity entity
->leftJoin('a.parameters', 'p') // join on ActivityParameters entity
->andWhere('s.path = 2')
;
but i want to also join on Evaluation entity, which is :
/**
* #ORM\Table(
* name="claro_activity_evaluation",
* uniqueConstraints={
* #ORM\UniqueConstraint(
* name="user_activity_unique_evaluation",
* columns={"user_id", "activity_parameters_id"}
* )
* }
* )
*/
class Evaluation
{
/**
* #ORM\ManyToOne(targetEntity="Claroline\CoreBundle\Entity\User")
* #ORM\JoinColumn(onDelete="CASCADE", nullable=false)
*/
protected $user;
/**
* #ORM\ManyToOne(targetEntity="Claroline\CoreBundle\Entity\Activity\ActivityParameters")
* #ORM\JoinColumn(name="activity_parameters_id", onDelete="CASCADE", nullable=false)
*/
protected $activityParameters;
/**
* #ORM\Column(name="attempts_count", type="integer", nullable=true)
*/
protected $attemptsCount;
}
the User entity :
/**
* #ORM\Table(name="claro_user")
* #ORM\Entity(repositoryClass="Claroline\CoreBundle\Repository\UserRepository")
*/
class User
{
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="first_name", length=50)
* #Assert\NotBlank()
*/
protected $firstName;
}
The ActivityParameters entity
/**
* #ORM\Entity
* #ORM\Table(name="claro_activity_parameters")
*/
class ActivityParameters
{
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var \Claroline\CoreBundle\Entity\Resource\Activity
*
* #ORM\OneToOne(
* targetEntity="Claroline\CoreBundle\Entity\Resource\Activity",
* mappedBy="parameters"
* )
* #ORM\JoinColumn(name="activity_id", onDelete="CASCADE", nullable=true)
*/
protected $activity;
/**
* #var string
*
* #ORM\Column(name="evaluation_type", nullable=true)
*/
protected $evaluationType;
/**
* #return string
*/
public function getEvaluationType()
{
return $this->evaluationType;
}
}
the Activity entity
/**
* #ORM\Table(name="claro_activity")
*/
class Activity
{
/**
* #var string
* #ORM\Column(length=255, nullable=true)
*/
protected $title;
/**
* #ORM\OneToOne(
* targetEntity="Claroline\CoreBundle\Entity\Activity\ActivityParameters",
* inversedBy="activity",
* cascade={"persist"}
* )
* #ORM\JoinColumn(name="parameters_id", onDelete="cascade", nullable=true)
*/
protected $parameters;
/**
* #return string
*/
public function getTitle()
{
return $this->title;
}
}
I have no clue how to modify this querybuilder to retrieve also hte data from Evaluation entity. I want something like :
$qb = $this->_em->createQueryBuilder()
->select('partial s.{id, activity}, partial a.{id, title}, partial p.{id, evaluationType}, e')
->from('Innova\PathBundle\Entity\Step', 's')
->leftJoin('s.activity', 'a') //join on Activity entity
->leftJoin('a.parameters', 'p') // join on ActivityParameters entity
->andWhere('s.path = 2')
->leftJoin('?i dont know what?', 'e') // join on Evaluation entity
->andWhere('e.user = 3') //data for a specific user
;
Thank you for any help
I "seem" to have found a nearly working solution, reading this topic : i had to make a subquery :
$qb->select('e, partial p.{id, evaluationType}, partial a.{id, title}')
->from('Claroline\CoreBundle\Entity\Activity\Evaluation', 'e')
->leftJoin('e.activityParameters', 'p')
->leftJoin('p.activity', 'a')
->where(
$qb->expr()->in( //needs a subquery
'a.id',
$subq->select('a2.id')
->from('Innova\PathBundle\Entity\Step', 's')
->leftJoin(
's.activity',
'a2',
\Doctrine\ORM\Query\Expr\Join::WITH,
$subq->expr()->eq('s.path', '?1') //can't do a andWhere('s.path = :path'))
)
->getDQL() //needs a dql, not a querybuilder for the main query
)
)
->andWhere($qb->expr()->eq('e.user', '?2')) //can't do a andWhere('e.user = :user'))
->setParameter(1, $pid)
->setParameter(2, $uid)
;
I just would also like to retrieve the Step entity data (id, ...) in the query result. I can't add 's' to the main select : i have Error: 's' is used outside the scope of its declaration.

FOSElasticaBundle to filter out entity with certain property

I have setup FOSElasticaBundle that indexes InstagramShopPictures, which has the following property:
class InstagramShopPicture
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #Exclude()
* #ORM\OneToMany(targetEntity="MyApp\MainBundle\Entity\InstagramPictureCategory", mappedBy="picture", cascade={"persist","remove"})
*/
protected $category;
}
How do I specify in elasticsearch (or FOSElasticaBundle) that I want to filter out the results such that only the one that has category of A, where A is a InstagramPictureCategory that the user specifies. Is this possible to filter this out in elastica?

Resources