Symfony2 / Doctrine2 - Get rows not present in other side of relation - php

I've got 2 entites, with its setters and getters:
/**
* #ORM\Entity
* #ORM\Table(name="users")
*/
class User
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="SRC\PurchaseBundle\Entity\Purchase", inversedBy="users")
* #ORM\JoinTable(name="user_purchases",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="purchase_id", referencedColumnName="id")}
* )
*/
protected $purchases;
...
}
/**
* #ORM\Entity
* #ORM\Table(name="purchases")
*/
class Purchase
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #var users
*
* #ORM\ManyToMany(targetEntity="SRC\UserBundle\Entity\User", mappedBy="purchases")
*/
protected $users;
...
}
I'd need to select all missing purchases for the user.
I've already achieved this by getting all existing purchases and checking, one by one, they doesn't exist in $user->getPurchases().
Does exist a better way to get this results?
Is there a way so I could create a method inside USER entity called getMissingPurchases()?

Yes, you are missing
#ORM\JoinColumn(name="{name_of_column}", referencedColumnName="{name_of_fk_column}")

Related

ORM Annotations in Symfony 6.0 - Add Multiple Constraints for Entity field

Using ORM Annotations in Symfony 6.0, I am trying to add the correct annotations to my entities so that I can output this SQL in a migration.
I am not sure how I am able to have both the group_id and the vendor_id match the id and vendor_id only using annotations.
ALTER TABLE `product_option_group_items`
ADD CONSTRAINT `FK123456` FOREIGN KEY (`group_id`, `vendor_id`)
REFERENCES `product_option_groups`(`id`, `vendor_id`)
ON DELETE RESTRICT ON UPDATE RESTRICT;
Up until now, I have manually modified the database to add the constraints, but would much prefer to have this added only using Symfony.
I have supplied the entities below.
I will add further business logic using #Constraints to the php code to validate if the groups vendor_id is that of the options vendor_id. I also want to know that this bug could not be inserted into the database in the event that a new migration file is created knocking out the constraints in the database that I manually updated after the fact.
I also do not want to have to add custom code to the migrations files, I would prefer to rely on doctrine:migrations:diff to assist me here.
Thanks in advance.
/**
* #ORM\Table(name="product_option_group_items")
*/
class ProductOptionGroupItemEntity
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private int $id;
/**
* #ORM\ManyToOne(
* targetEntity=ProductOptionGroupEntity::class
* )
* #ORM\JoinColumn(nullable=false)
*
*/
private ProductOptionGroupEntity $group;
/**
* #ORM\ManyToOne(
* targetEntity=ProductOptionEntity::class
* )
* #ORM\JoinColumn(nullable=false)
*/
private ProductOptionEntity $option;
/**
* #ORM\ManyToOne(
* targetEntity=VendorEntity::class
* )
* #ORM\JoinColumn(nullable=false)
*/
private VendorEntity $vendor;
}
/**
* #ORM\Entity(repositoryClass=VendorEntityRepository::class)
* #ORM\Table(name="vendors")
*/
class VendorEntity
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private int $id;
/**
* #ORM\ManyToOne(targetEntity=VendorTypeEntity::class)
* #ORM\JoinColumn(nullable=false)
*/
private VendorTypeEntity $type;
}
/**
* #ORM\Entity(repositoryClass=ProductOptionGroupEntityRepository::class)
* #ORM\Table(name="product_option_groups",
* indexes={
* #ORM\Index(name="Vendor_GroupId", columns={"id", "vendor_id"})
* })
*/
class ProductOptionGroupEntity
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private int $id;
/**
* #ORM\ManyToOne(
* targetEntity=VendorEntity::class,
* inversedBy="productOptionGroups"
* )
* #ORM\JoinColumn(nullable=false)
*/
private VendorEntity $vendor;
}
/**
* #ORM\Entity(repositoryClass=ProductOptionEntityRepository::class)
* #ORM\Table(name="product_options",
* indexes={
* #ORM\Index(columns={"id", "vendor_id"})
* })
*/
class ProductOptionEntity
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private int $id;
/**
* #ORM\ManyToOne(targetEntity=VendorEntity::class)
* #ORM\JoinColumn(nullable=false)
*/
private VendorEntity $vendor;
}

Nested jointable joincolumns in symfony 2 with doctrine 2

So given the entity Comment, what is the cleanest way to get the CommentPerson to find out if the CommentPerson isModerator()?
Without getting your fingers dirty using a repository.
/**
* #ORM\Entity(repositoryClass="MyApp\MyBundle\Repository\CommentRepository")
* #ORM\Table(name="comment")
*/
class Comment
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="integer")
*/
protected $user_id; //id of entity User
/**
* #ORM\ManyToOne(targetEntity="User")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
**/
protected $user; //a user can have many comments
/**
* #ORM\Column(type="text")
*/
protected $commentText;
}
/**
* #ORM\Entity(repositoryClass="MyApp\MyBundle\Repository\UserRepository")
* #ORM\Table(name="user")
*/
class User //this is the web user
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="integer")
*/
protected $person_id; //id of entity Person
/**
* #ORM\ManyToOne(targetEntity="Person")
* #ORM\JoinColumn(name="person_id", referencedColumnName="id")
**/
protected $person; //many web users can map to one actual person
public function getPerson()
{
return $this->person;
}
}
/**
* #ORM\Entity(repositoryClass="MyApp\MyBundle\Repository\PersonRepository")
* #ORM\Table(name="person")
*/
class Person
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="text")
*/
protected $email;
/**
* #ORM\OneToMany(targetEntity="CommentPerson", mappedBy="person")
* #ORM\JoinColumn(name="id", referencedColumnName="person_id")
*/
private $commentPersons; //one person can have many commentPersons (since one person can be part in many different comment sections, not shown in code here, but take it as a fact)
}
/**
* #ORM\Entity(repositoryClass="MyApp\MyBundle\Repository\CommentPersonRepository")
* #ORM\Table(name="comment_Person")
*/
class CommentPerson
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="integer")
*/
protected $person_id; //this is the id of the entity Person
/**
* #ORM\Column(type="boolean")
*/
protected $isModerator;
}

Doctrine2 cascade delete doesn't work with Abstract Class

In my web application, which is built with Symfony2, contains the following entities:
/**
* #ORM\Entity
* #ORM\Table
*/
class Entity
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(name="id", type="integer")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="MappedSuperclass", mappedBy="entity", cascade={"persist", "remove"})
*/
private $mappedSuperclasses;
}
/**
* #ORM\MappedSuperclass
*/
abstract class MappedSuperclass
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(name="id", type="integer")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Entity", inversedBy="mappedSuperclasses")
* #ORM\JoinColumn(name="entity_id", referencedColumnName="id", nullable=false)
*/
protected $entity;
}
/**
* #ORM\Entity
* #ORM\Table(name="table_1")
*/
class Subclass1 extends MappedSuperclass
{
/**
* #ORM\Column(name="unique_member", type="string")
*/
private $uniqueMember;
}
/**
* #ORM\Entity
* #ORM\Table(name="table_2")
*/
class Subclass2 extends MappedSuperclass
{
/**
* #ORM\Column(name="unique_member", type="string")
*/
private $uniqueMember; // This is different from Subclass1
}
I'll explain this a bit. An Entity has a collection of MappedSuperclass. MappedSuperclass is an abstract class which contains some common variables for its subclasses. Subclass1 and Subclass2 are subclasses of MappedSuperclass. When an Entity is removed from database, the items in $mappedSuperclasses should be removed together, that's why the cascade={"persist", "remove"} is set.
However, when I try to delete an Entity, I got the following error:
ContextErrorException: Notice: Undefined index: entity in C:\project\vendor\doctrine\orm\lib\Doctrine\ORM\Persisters\BasicEntityPersister.php line 1753
If I change the targetEntity of Entity::$mappedSuperclasses to Subclass1 or Subclass2, it will work. Is my set up impossible to achieve ON DELETE CASCADE? What am I missing?
I solved this problem by setting the ON DELETE action to database level:
/**
* #ORM\Entity
* #ORM\Table
*/
class Entity
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(name="id", type="integer")
*/
private $id;
}
/**
* #ORM\MappedSuperclass
*/
abstract class MappedSuperclass
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(name="id", type="integer")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Entity")
* #ORM\JoinColumn(name="entity_id", referencedColumnName="id", nullable=false, onDelete="CASCADE")
*/
protected $entity;
}
Sources: [1] [2]
Im answering year after the issue was resolved but I had the same problem. Error occurs when I tried to empty count arrayCollection.
So the solution was to check if $this->entity is array and then return its length.

One to Many Relation In Doctrine

I have 2 Tables
Users
Messages
And the Structure of Tables:
Users:
Messages:
Now see there are number of users in Users Table and their messages are stored in Messages table identifying by fk_user_Id.
How can I make One-To-Many Relationship between these two tables or create this SQL Schema using Doctrine/Annotations?
This is a common case and i think you can easily find such examples if you would have searched.
You may refer this example
Your two entity files User.php and Message.php will look something like this
/**
* #ORM\Entity
* #ORM\Table(name="users")
*/
class User
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $username;
/**
* #ORM\OneToMany(targetEntity="Message", mappedBy="user")
*/
protected $messages;
}
Message entity will look like this
/**
* #ORM\Entity
* #ORM\Table(name="messages")
*/
class Message
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $messageDescription;
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="messages")
* #ORM\JoinColumn(name="fk_user_id", referencedColumnName="id")
*/
protected $user;
}

OneToOne relationship in Doctrine2 ORM and Symfony

I have two entity called PictureTag and Tag, here's the relationship:
/**
* #ORM\Entity
* #ORM\Table(name="picture_tag")
* #ORM\HasLifecycleCallbacks()
*/
class PictureTag
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
*
* #ORM\OneToOne(targetEntity="App\MainBundle\Entity\Tag", inversedBy="id")
* #ORM\JoinColumn(name="tag_id", referencedColumnName="id", nullable=false)
*/
private $tag;
}
/**
* #ORM\Entity
* #ORM\Table(name="tag")
* #ORM\HasLifecycleCallbacks()
*/
class Tag
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\ManyToOne(targetEntity="App\MainBundle\Entity\PictureTag", inversedBy="tag")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
* #ORM\Column(name="tag", type="string", nullable=true)
*/
private $tag;
}
Basically I wanted the tag table to contain all the unique tags, so there are no duplicate in the tag. And i wanted picturetag to have a joincolumn that points to the id of the tag. So here's my code in the controller:
foreach ($image->tags as $tag) {
$existingTag = $em->getRepository('AppMainBundle:InstagramTag')->findOneByTag($tag);
$instaPictureTag = new PictureTag();
if ($existingTag) {
$instaPictureTag->setTag($existingTag);
} else {
$instagramTag = new Tag();
$instagramTag->setTag($tag);
$em->persist($instagramTag);
$instaPictureTag->setTag($instagramTag);
}
$instaPictureTag->setPicture($instaShopPicture);
$em->persist($instaPictureTag);
}
So the relationship is basically:
One picture is going to have many tags. And one tag will belong to many pictures.
Picture tag here is the intermediary table.
Basically I am doing a check if the tag already exists in the tag table, if it is then I set the picturetag to be associated with this tag, if not then create one. However doing so generates the following error:
Fatal error: Call to a member function setValue() on a non-object in /Users/MyName/Sites/App/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php on line 2625
Any idea why this is?
As I understand, you want implement OneToMany bidirectional relation between PictureTag and Tag.
Please try:
/**
* #ORM\Entity
* #ORM\Table(name="picture_tag")
* #ORM\HasLifecycleCallbacks()
*/
class PictureTag
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="DynamicSolutions\Bundle\ProsAndConsBundle\Entity\Tag", inversedBy="pictureTags")
* #ORM\JoinColumn(name="tag_id", referencedColumnName="id", nullable=false)
*/
private $tag;
}
/**
* #ORM\Entity
* #ORM\Table(name="tag")
* #ORM\HasLifecycleCallbacks()
*/
class Tag
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="PictureTag", mappedBy="tag")
*/
private $pictureTags;
/**
* #var string
* #ORM\Column(name="tag", type="string", nullable=true)
*/
private $tag;
}

Categories