Get access through another Entity in Doctrine2 - doctrine-orm

I have the problem with Association in Doctrine2.
My Entity mapping is:
Brand:
/**
* #ORM\Entity
*/
class Brand
{
/**
* #ORM\Id
*/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $name;
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\Model", mappedBy="brand")
*/
protected $models;
/**
* #ORM\Column(type="boolean")
*/
protected $isPopular;
}
Model:
/**
* #ORM\Entity
*/
class Model
{
/**
* #ORM\Id
*/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $name;
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\VehicleType", inversedBy="models")
* #ORM\JoinColumn(name="vehicle_type_id", referencedColumnName="id")
*/
protected $vehicleType;
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Brand", inversedBy="models")
* #ORM\JoinColumn(name="brand_id", referencedColumnName="id")
*/
protected $brand;
}
VehicleType:
/**
* #ORM\Entity
*/
class VehicleType
{
/**
* #ORM\Id
*/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $name;
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\Model", mappedBy="vehicleType")
*/
protected $models;
}
How I can get in Entity VehicleType array of popular Brands (brand.isPopular = true)?
Мay be my mapping is wrong?

I can do like this
$vehicleTypes = $this->getEm()->getRepository('AppBundle:VehicleType')->findAll();
foreach ($vehicleTypes as $vehicleType) {
print ('<p>'.$vehicleType->getName().'</p>');
$brands = $this->getQb()
->select('brand')
->from('AppBundle:Brand', 'brand')
->join('brand.models', 'models')
->where('brand.isPopular = true')
->andWhere('models.vehicleType = :vehicleType')
->setParameter('vehicleType', $vehicleType)
->getQuery()
->getResult()
;
foreach ($brands as $brand) {
print('<p> - '.$brand->getNameEng().'</p>');
}
}
But I have n+1 querys to DB, where n size of VehicleType. Posible decrise DB querys?

Related

Doctrine association persist

I have a problem with doctrine. I have two entities.
FriendRequest
class FriendRequest
{
/** #ORM\Id #ORM\Column(type="integer") #ORM\GeneratedValue **/
protected $id;
/**
* First person from friendship
*
* #ORM\OneToOne(targetEntity="User")
* #ORM\JoinColumn(name="id", referencedColumnName="id")
*/
protected $from;
/**
* Second person from friendship
*
* #ORM\OneToOne(targetEntity="User")
* #ORM\JoinColumn(name="id", referencedColumnName="id")
*/
protected $to;
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #return mixed
*/
public function getFrom()
{
return $this->from;
}
/**
* #param mixed $from
*/
public function setFrom($from)
{
$this->from = $from;
}
/**
* #return mixed
*/
public function getTo()
{
return $this->to;
}
/**
* #param mixed $to
*/
public function setTo($to)
{
$this->to = $to;
}
}
And User
/**
* #ORM\Entity #ORM\Table(name="users")
*/
class User
{
/** #ORM\Id #ORM\Column(type="integer") #ORM\GeneratedValue **/
protected $id;
/** #ORM\Column(type="string") **/
protected $email;
/** #ORM\Column(type="string") **/
protected $password;
/** #ORM\Column(type="string") **/
protected $name;
/** #ORM\Column(type="string") **/
protected $surname;
/** #ORM\Column(type="date") **/
protected $date;
/** #ORM\Column(type="string") **/
protected $sex;
/**
* #return mixed
*/
public function getSex()
{
return $this->sex;
}
/**
* #param mixed $sex
*/
public function setSex($sex)
{
$this->sex = $sex;
}
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #param mixed $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* #return mixed
*/
public function getEmail()
{
return $this->email;
}
/**
* #param mixed $email
*/
public function setEmail($email)
{
$this->email = $email;
}
/**
* #return mixed
*/
public function getPassword()
{
return $this->password;
}
/**
* #param mixed $password
*/
public function setPassword($password)
{
$this->password = $password;
}
/**
* #return mixed
*/
public function getName()
{
return $this->name;
}
/**
* #param mixed $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* #return mixed
*/
public function getSurname()
{
return $this->surname;
}
/**
* #param mixed $surname
*/
public function setSurname($surname)
{
$this->surname = $surname;
}
/**
* #return mixed
*/
public function getDate()
{
return $this->date;
}
/**
* #param mixed $date
*/
public function setDate($date)
{
$this->date = $date;
}
}
I tried to create the new friendship request.
$from = $this->entity_manager->getRepository(User::class)->findOneBy(
["id" => $my_id]
);
$to = $this->entity_manager->getRepository(User::class)->findOneBy(
["id" => $target_user_id]
);
/** #var FriendRequest $friend_request */
$friend_request = new FriendRequest();
$friend_request->setFrom($from);
$friend_request->setTo($to);
$this->entity_manager->persist($friend_request);
$this->entity_manager->flush();
But it does not work. Doctrine shows me error:
An exception occurred while executing 'INSERT INTO friendRequest (id) VALUES (?)' with params [186]:
SQLSTATE[HY000]: General error: 1364 Field 'from' doesn't have a default value.
I tried to print $from ad $to, but they are correct. Is there someone who know what does it mean? I spent a lot of time with it, but I dont know...
I think your issue comes from the declaration of the $from and $to attributes in the FriendRequest entity class, if you try to update your database model you are going to get an error like this:
[Doctrine\ORM\Mapping\MappingException]
Duplicate definition of column 'id' on entity 'FriendRequest' in a field or discriminator column mapping.
Since you have assigned the same name 'id' for two different attributes. Probably you have in your database two columns From and To, but they are not mapping with your model, that's why you get an error saying from doesn't have a default value. Since the column name in the database are not sync with the name of the attributes in your entity.
Assuming you already have a FriendRequest table and you are using 'from' and 'to' as the column names this should be the update of the FriendRequest entity class.
class FriendRequest
{
/** #ORM\Id #ORM\Column(type="integer") #ORM\GeneratedValue **/
protected $id;
/**
* First person from friendship
*
* #ORM\OneToOne(targetEntity="User")
* #ORM\JoinColumn(name="from", referencedColumnName="id")
*/
protected $from;
/**
* Second person from friendship
*
* #ORM\OneToOne(targetEntity="User")
* #ORM\JoinColumn(name="to", referencedColumnName="id")
*/
protected $to;
...
}

Symfony 3.3 and doctrine 2

I have two entities Article and Image related by a ManytoMany relations using a third entity called ArticlesHaveImages.
I don't use classical ManytoMany relation of Doctrine because I have a third field in ArticlesHaveImages called sequence.
class Article
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
...
...
/**
* One Article has Many articleHaveImage.
* #ORM\OneToMany(targetEntity="ArticlesHaveImages", mappedBy="article")
*/
private $images;
class Image
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
...
...
/**
* One Image has Many articleHaveImage.
* #ORM\OneToMany(targetEntity="ArticlesHaveImages", mappedBy="image")
*/
private $articles;
public function __construct() {
$this->articles = new ArrayCollection();
}
class ArticlesHaveImages
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* Many ArticlesHaveImages have One Article.
* #ORM\ManyToOne(targetEntity="Article", inversedBy="images")
* #ORM\JoinColumn(name="article_id", referencedColumnName="id")
*/
private $article;
/**
* Many ArticlesHaveImages have One Image.
* #ORM\ManyToOne(targetEntity="Image", inversedBy="articles")
* #ORM\JoinColumn(name="image_id", referencedColumnName="id")
*/
private $image;
/**
* #var int
*
* #ORM\Column(name="sequence", type="integer")
*/
private $sequence;
How do I create a form out of this ?
I want a multiple select option which all images name.
I tried :
class ArticleType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$images = $options['images'];
$builder
->add('translations', CollectionType::class, array(
'entry_type' => ArticleTranslationType::class,
'entry_options' => array('label' => false)))
->add('images', ChoiceType::class, array(
"required" => false,
"choices" => $images,
'multiple' => true,
But I get :
Could not determine access type for property "images" in class
"AppBundle\Entity\Article".
BIG THANKS !

ManyToMany does not work with inheritance

I'm building an app that deals with givers and companies, that own givers. Both inherit a super-class called "Organization".
I want to add an unidirectional ManyToMany relationship between them, but when I ask doctrine to implement the database, and hydrate it with fixtures, I can't retrieve the givers owned by a company.
Doctrine hasn't even created a giver_company table whatsoever which could contain the relationship information as it is supposed to do.
Here is my code:
Organization
<?php
// src/Entity/Chain/Organization.php
namespace App\Entity\Chain;
use App\Entity\User;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\InheritanceType("SINGLE_TABLE")
* #ORM\DiscriminatorColumn(name="type", type="string")
* #ORM\DiscriminatorMap({"association" = "Association", "super_association" = "SuperAssociation", "company" = "Company", "giver" = "Giver"})
*/
abstract class Organization
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
* #Assert\NotBlank()
*/
private $name;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $address;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $city;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $zipcode;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $SIREN;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $phone;
/**
* #ORM\OneToOne(targetEntity="App\Entity\Photo")
*/
private $photo;
/**
* #ORM\OneToMany(targetEntity="App\Entity\User", mappedBy="memberOf")
*/
private $members ;
/**
* Organization constructor.
*/
public function __construct()
{
$this->members = new ArrayCollection();
}
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;
}
/**
* #param mixed $name
*/
public function setName($name): void
{
$this->name = $name;
}
public function getAddress()
{
return $this->address;
}
/**
* #param mixed $address
*/
public function setAddress($address): void
{
$this->address = $address;
}
public function getCity()
{
return $this->city;
}
/**
* #param mixed $city
*/
public function setCity($city): void
{
$this->city = $city;
}
public function getZipcode()
{
return $this->zipcode;
}
/**
* #param mixed $zipcode
*/
public function setZipcode($zipcode): void
{
$this->zipcode = $zipcode;
}
public function getSIREN()
{
return $this->SIREN;
}
/**
* #param mixed $SIREN
*/
public function setSIREN($SIREN): void
{
$this->SIREN = $SIREN;
}
public function getPhone()
{
return $this->phone;
}
/**
* #param mixed $phone
*/
public function setPhone($phone): void
{
$this->phone = $phone;
}
public function getPhoto()
{
return $this->photo;
}
/**
* #param mixed $photo
*/
public function setPhoto($photo): void
{
$this->photo = $photo;
}
public function getMembers()
{
return $this->members;
}
public function addMember(User $member)
{
if (!$this->members->contains($member)) {
$this->members->add($member);
}
}
public function removeMember(User $member){
$this->members->remove($member);
}
}
Giver
<?php
// src/Entity/Chain/Giver.php
namespace App\Entity\Chain;
use App\Entity\Photo;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
*/
class Giver extends Organization
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $status ;
/**
* Giver constructor.
*/
public function __construct()
{
parent::__construct();
}
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #return mixed
*/
public function getStatus()
{
return $this->status;
}
/**
* #param mixed $status
*/
public function setStatus($status): void
{
$this->status = $status;
}
}
Company
<?php
// src/Entity/Chain/Company.php
namespace App\Entity\Chain;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
*/
class Company extends Organization
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255, name="company_type")
*/
private $type ;
/*
* #ORM\ManyToMany(targetEntity="App\Entity\Chain\Giver")
*/
private $givers ;
/**
* Company constructor.
*/
public function __construct()
{
parent::__construct();
$this->givers = new ArrayCollection();
}
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #return mixed
*/
public function getType()
{
return $this->type;
}
/**
* #param mixed $type
*/
public function setType($type): void
{
$this->type = $type;
}
public function getGivers()
{
return $this->givers;
}
public function addGiver(Giver $opening)
{
if (!$this->givers->contains($opening)) {
$this->givers->add($opening);
}
}
public function removeGiver(Giver $opening){
$this->givers->remove($opening);
}
}
Your DocBlock for givers in Company is missing an "*" at the beginning. PHPDoc
Change:
/*
* #ORM\ManyToMany(targetEntity="App\Entity\Chain\Giver")
*/
private $givers ;
to
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Chain\Giver")
*/
private $givers ;

A new entity was found through the relationship - error

I try to establish a simple association of two tables. But I always geht the following error:
A new entity was found through the relationship 'Shopware\CustomModels\JoeKaffeeAbo\Client#abos' that was not configured to cascade persist operations for entity: Shopware\CustomModels\JoeKaffeeAbo\Abo#00000000211b173900000000cf7658ac
Here are my Models:
<?php
namespace Shopware\CustomModels\JoeKaffeeAbo;
use Symfony\Component\Validator\Constraints as Assert,
Doctrine\Common\Collections\ArrayCollection,
Shopware\Components\Model\ModelEntity,
Doctrine\ORM\Mapping AS ORM;
/**
* #ORM\Entity
* #ORM\Table(name="joe_kaffee_abo_abos")
*/
class Abo extends ModelEntity
{
public function __construct() {
$client = new ArrayCollection();
}
/**
* Unique identifier
*
* #var integer
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="Shopware\CustomModels\JoeKaffeeAbo\Client", inversedBy="abos", cascade={"persist", "remove"})
**/
protected $clients;
/**
* #var string
* #ORM\Column(name="name", type="string", length=255, nullable=true)
*/
protected $name = '';
/**
* #var string
* #ORM\Column(name="desc", type="string", length=255, nullable=true)
*/
protected $desc = '';
/**
* #var string
* #ORM\Column(name="name_en", type="string", length=255, nullable=true)
*/
protected $name_en = '';
/**
* #var string
* #ORM\Column(name="desc_en", type="string", length=255, nullable=true)
*/
protected $desc_en = '';
//getter and setters...
}
?>
Client Model:
<?php
namespace Shopware\CustomModels\JoeKaffeeAbo;
use Symfony\Component\Validator\Constraints as Assert,
Doctrine\Common\Collections\ArrayCollection,
Shopware\Components\Model\ModelEntity,
Doctrine\ORM\Mapping AS ORM;
/**
* #ORM\Entity
* #ORM\Table(name="joe_kaffee_abo_client")
*/
class Client extends ModelEntity
{
public function __construct() {
$this->abos = new ArrayCollection();
}
/**
* Unique identifier
*
* #var integer
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="Shopware\CustomModels\JoeKaffeeAbo\Abo", mappedBy="clients", cascade={"persist", "remove"})
**/
protected $abos = null;
public function addAbo($abo)
{
$abo->addClient($this);
$this->abos[] = $abo;
}
/**
* #var integer
* #ORM\Column(name="customerid", type="integer", nullable=true)
*/
protected $customerid;
/**
* #var integer
* #ORM\Column(name="customernumber", type="integer", nullable=true)
*/
protected $customernumber;
/**
* #var boolean
* #ORM\Column(name="is_active", type="boolean", nullable=true)
*/
protected $is_active;
//Getters and Setters
}
?>
The error occurs after I executed the following statements:
$client = new Client();
$client->setCustomerid(12);
$client->setCustomernumber(12);
$client->setIs_active(true);
Shopware()->Models()->persist($client);
$abo = new Abo();
$abo->setName("name");
$abo->setDesc("desc");
$abo->setName_en("name");
$abo->setDesc_en("desc");
$client->addAbo($abo);
//$abo->addClient($client);
//$client->addAbo($abo);
Shopware()->Models()->persist($client);
//Shopware()->Models()->persist($abo);
Shopware()->Models()->flush();
What this is telling you is that you need to save the Abo Entity before saving the client.
$abo = new Abo();
$abo->setName("name");
$abo->setDesc("desc");
$abo->setName_en("name");
$abo->setDesc_en("desc");
Shopware()->Models()->persist($abo); //Persist the Abo before assigning it to the client
$client->addAbo($abo);
//$abo->addClient($client);
//$client->addAbo($abo);
Shopware()->Models()->persist($client);
//Shopware()->Models()->persist($abo);
Shopware()->Models()->flush();

Doctrine: one to many relationship and cascade persistance

I mean I have these two classes (one to many relationship). As you can appreciate in both I have included cascade={"persist"}.
namespace Project\FrontendBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="task")
*/
class Task
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=255, name="description", nullable=true)
*/
protected $description;
/**
* #ORM\OneToMany(targetEntity="Tag", mappedBy="task", cascade={"persist"})
**/
protected $tags;
/*************************************/
public function __toString()
{
return $this->description;
}
/**
* Constructor
*/
public function __construct()
{
$this->tags = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set description
*
* #param string $description
* #return Task
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Add tags
*
* #param \Project\FrontendBundle\Entity\Tag $tags
* #return Task
*/
public function addTag(\Project\FrontendBundle\Entity\Tag $tags)
{
$this->tags[] = $tags;
return $this;
}
/**
* Remove tags
*
* #param \Project\FrontendBundle\Entity\Tag $tags
*/
public function removeTag(\Project\FrontendBundle\Entity\Tag $tags)
{
$this->tags->removeElement($tags);
}
/**
* Get tags
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getTags()
{
return $this->tags;
}
}
namespace Project\FrontendBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="tag")
*/
class Tag
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=255, name="name", nullable=true)
*/
protected $name;
/**
* #ORM\ManyToOne(targetEntity="Task", inversedBy="tags", cascade={"persist"})
* #ORM\JoinColumn(name="task_id", referencedColumnName="id")
**/
private $task;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Tag
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set task
*
* #param \Project\FrontendBundle\Entity\Task $task
* #return Tag
*/
public function setTask(\Project\FrontendBundle\Entity\Task $task = null)
{
$this->task = $task;
return $this;
}
/**
* Get task
*
* #return \Project\FrontendBundle\Entity\Task
*/
public function getTask()
{
return $this->task;
}
}
In my controller I have this:
$task = new Task();
$tag = new Tag();
$task->addTag($tag);
$em = $this->getDoctrine()->getManager();
$em->persist($item);
$em->flush();
but the foreign key is always NULL, why?
I think in the Task class, the addTag and removeTag should look like this:
public function addTag($tag)
{
$tag->setTask($this);
$this->tags->add($tag);
}
public function removeTag($tag)
{
$tag->setTask(null);
$this->tags->removeElement($tag);
}
Or if you want to add and remove many tags in one function call use these:
public function addTags(Collection $tags)
{
foreach ($tags as $tag) {
$tag->setTask($this);
$this->tags->add($tag);
}
}
public function removeTags(Collection $tags)
{
foreach ($tags as $tag) {
$tag->setTask(null);
$this->tags->removeElement($tag);
}
}