Doctrine2 OneToMany without mappedBy - symfony

I have an entity 'listing' with OneToMany to entity 'view', the key between these to is view.content_id which holds the ID of listing, however, it also relates to other entities, so by adding
/**
* #var Listing
*
* #ORM\ManyToOne(targetEntity="\Acme\Bundle\Entity\Listing", inversedBy="views")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="content_id", referencedColumnName="id")
* })
*/
private $listing;
To the view it brakes because when saving the view entity the content_id becomes null.
How can I fix it?
Relation on listing side:
/**
* #var views
*
* #ORM\OneToMany(targetEntity="\Acme\Bundle\Entity\View", mappedBy="listing")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="id", referencedColumnName="content_id")
* })
*/
private $views;
I'm making queries by joining the Listing.views and adding WITH content_type = :ContentType which discriminates some 'view' results.

I'm coming pretty late to the party, but thought I would answer in case it helps someone else.
Because of the relation you've established between the two entities, you now have to assign an object to that property rather than the FK value itself. Like so:
$listing = $em->getRepository('Acme\Bundle\Entity\Listing')
->find($content_id);
$view->setListing($listing);
And not:
$view->setListing($content_id);
Of course, if it turned out to be something else, I'd be curious to know.
:^)

Related

How to limit OneToMany/ManyToOne associations depth/loop in Doctrine2?

I've 3 doctrine entities. One is User, second is Product and third is ProductUsers.
So, User have OneToMany association with ProductUsers and the same Product have OneToMany association with ProductUsers. ProductUsers has ManyToOne association with both User and Product. Like so:
class Product
{
/**
* #var ProductUsers
*
* #ORM\OneToMany(targetEntity="ProductUsers", mappedBy="product")
*/
private $productUsers;
}
class ProductUsers
{
/**
* #var Product
*
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Product", inversedBy="productUsers")
* #ORM\JoinColumn(name="product_ID", referencedColumnName="ID")
*/
private $product;
/**
* #var User
*
* #ORM\Id
* #ORM\ManyToOne(targetEntity="User", inversedBy="productUsers")
* #ORM\JoinColumn(name="user_ID", referencedColumnName="ID")
*/
private $user;
// extra fields ...
}
class User
{
/**
* #var ProductUsers
*
* #ORM\OneToMany(targetEntity="ProductUsers", mappedBy="user")
*/
private $productUsers;
}
A user can use multiple products and a product can have multiple users. ProductUsers has some extra info about the relation other than just the relation.
The problem is when I fetch one User object it comes with associated ProductUsers and it's associated Product. Not only that but the Product also comes with all it's associated ProductUsers and it's respective User objects which is quite an overhead.
This question closely relates to my problem.
I'm looking to limit that at doctrine level just like what JMSSerializerBundle MaxDepth does. Is there a way to limit such overhead in doctrine?
I faced this issue long time back. I tried lazy loading. Which didn't work as expected and that was not a proper solution to my issue. So I did some R&D and came up with a solution that I don't need a bidirectional relationship from Product to ProductUsers.
I can manage same relationship with unidirectional handling only from ProductUsers side. You will need One-To-Many Association when you need a cascade-persist or similar feature. I wrote a small blog regarding this as well.
So, for your solution, just have Many-To-One association from ProductUsers with both Product and User entity. You will not need any change in your database association.
And when you need Products associated for a single user, you can always save a Querybuilder in Repository to use when you need associated data.
It will save a lot of performance. Hope it helps!

Symfony2 + Doctrine2 onDelete="restrict"

I want to restrict a delete action on my object, but it's not working.
My code from my first entity:
/**
* #ORM\ManyToMany(targetEntity="Season", inversedBy="clubs")
* #ORM\JoinTable(
* name="clubs_to_seasons",
* joinColumns={
* #ORM\JoinColumn(name="club_id", referencedColumnName="id", onDelete="cascade")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="season_id", referencedColumnName="id", onDelete="restrict")
* }
* )
**/
private $seasons;
And second:
/**
* #ORM\ManyToOne(targetEntity="League")
* #Assert\NotBlank(message="validation.custom.not_blank")
*/
private $league;
On database side everything is fine - I cannot delete a Season object, because it has a reference to Club object, but when I use a remove fuction from Entity Manager, Season object is deleted.
I know that on ORM side is a cascade={..} but I need a restrict, not cascade.
BUMP:
If I'm using one-to-many, many-to-one or one-to-one, everything is ok - when I try to delete an object (and I'm using onDelete="restrict" on the database side), then exceptions appears with message, that I cannot delete because I have other object connected with. But when I have many-to-many (as in my example), and I have a season associated with any club (and I have onDelete="restrict"), still I can delete a season using entity manager. But when I'm deleting season directly on the db side, message appears, and I cannot delete this.
What is wrong with many-to-many?
EDIT:
OK, now it's working.
My solution for the future:
I removed many-to-many relation from both entities. I have made a third entity - clubToSeason. Previously this entity was autogenerated, now it's not. And inside file of this third entity I have two many-to-one relations:
class ClubToSeason {
/**
* #ORM\ManyToOne(targetEntity="season", inversedBy="clubs")
**/
private $season;
/**
* #ORM\ManyToOne(targetEntity="club", inversedBy="seasons")
**/
private $club;
...
}

Symfony2, Sonata : Customize title of collection

I've been able to translate most of the titles but i still have some non-friendly titles on collections (Table of relation)
Aire\AppBundle\Entity\ProjectSupported:000000002d1a645a000000015441bb1f
How could i custom them?
At best it could be the name of the related object ($investor->getName() and $project->getName() for exemple), at worst just a string.
In that case i'm using en entity with 2 relations
/**
* Owning Side
*
* #ORM\ManyToOne(targetEntity="Investor", inversedBy="supportedProject")
* #ORM\JoinColumn(name="investor_id", referencedColumnName="id")
**/
private $investor;
/**
* Owning Side
*
* #ORM\ManyToOne(targetEntity="Project", inversedBy="supportedProject")
* #ORM\JoinColumn(name="project_id", referencedColumnName="id")
**/
private $project;
Any hints or solutions?
Sonata is using the __toString method for text representation of objects.

How do I map this relationship?

I'm having trouble mapping this relationship in Doctrine. I have a UseCase, which has many UseCaseSteps. A UseCaseStep has many sub-steps, which is a OneToMany on UseCaseStep. Here's the pertinent code I have atm:
/**
* UseCase
*
* #ORM\Table(name="use_cases")
* #ORM\Entity(repositoryClass="DesignCase\Bundle\Bundle\Entity\UseCaseRepository")
*/
class UseCase
{
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="Actor", inversedBy="use_cases", cascade={"persist", "remove"})
* #ORM\JoinTable(name="actors_use_cases")
*/
private $actors;
/**
* #var ArrayCollection
*
* #ORM\OneToMany(targetEntity="UseCaseStep", mappedBy="useCase", cascade={"persist", "remove"})
* #ORM\OrderBy({"order" = "ASC"})
*/
private $steps;
}
/**
* UseCaseStep
*
* #ORM\Table(name="use_case_steps")
* #ORM\Entity(repositoryClass="DesignCase\Bundle\Bundle\Entity\UseCaseStepRepository")
*/
class UseCaseStep
{
/**
* #var integer
*
* #ORM\ManyToOne(targetEntity="UseCase")
*/
private $useCase;
/**
* #var ArrayCollection
*
* #ORM\OneToMany(targetEntity="UseCaseStep", mappedBy="parent", cascade={"persist", "remove"})
* #ORM\OrderBy({"order" = "ASC"})
*/
private $subSteps;
/**
* #var UseCase
*
* #ORM\ManyToOne(targetEntity="UseCase")
*/
private $useCaseReference;
/**
* #var UseCaseStep
*
* #ORM\ManyToOne(targetEntity="UseCaseStep")
* #ORM\JoinColumn(nullable=true)
*/
private $parent;
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="BusinessRule", cascade={"persist", "remove"})
*/
private $businessRules;
}
That code isn't complete, but I think it has all the relevant information. What I want to do is create a new entity TestCase, which has many TestCaseSteps. A TestCase IS a UseCase with a little more information... same for TestCaseStep and UseCaseStep. IE, a TestCaseStep is a UseCaseStep with data input and expected output fields added to it. A user can create many TestCases from one UseCase.
I tried making UseCase and UseCaseStep #MappedSuperclass, but that doesn't have the desired effect. I get the obvious, "It is illegal to put an inverse side one-to-many or many-to-many association on mapped superclass" error. Plus, from the docs, I don't think that's the right approach anyway.
I'm having trouble wrapping my brain around it. Any thoughts? I hope I explained that well enough...
You have an issue there that is much more fundamental than Doctrine. You want to show inheritance in the database. For this approach there is no real correct solution. You could go with making an Entity TestCase that extends UseCase and overwrites the respective properties (need to make them protected) with another relation to TestCaseStep.
You do something similar with UseCaseStep and TestCaseStep. That way you have inheritance in the entities. Now you would have to make sure that you use another table and you end up with completely seperate entities database-wise. They just share the same properties in the entities but are seperate in database.
That approach would be in my opinion the easiest one to follow. Everything else seems to be very complicated as you cannot properly use one table with a different amount of properties for each entity. Each database table has a fixed set of properties that need to be reflected in an entity.
Another approach would surely be to just use the properties in the sub-entity that is used by this entity and create another relationship (many-to-one) between the TestCase and the UseCase or TestCaseStep and UseCaseStep respectively. But the latter approach isn't very easy and can end up being very complicated if you don't have a lot of knowledge about Doctrine, Symfony and databases in general.

ManyToMany on same table

I have a project in which I have a OneToMany relationship on the same database.
Currently it is designed like this:
/**
* #ORM\OneToMany(targetEntity="MyEntity", mappedBy="myCopiedItem")
*/
protected $mySource;
/**
* #ORM\ManyToOne(targetEntity="MyEntity", inversedBy="mySource")
* #ORM\JoinColumn(name="selected_myentity_copy_id", referencedColumnName="id")
*/
protected $myCopiedItem;
But now I have to make this relationship ManyToMany. So I did this:
/**
* #ORM\ManyToMany(targetEntity="MyEntity", mappedBy="myCopiedItem")
*/
protected $mySource;
/**
* #ORM\ManyToMany(targetEntity="MyEntity", inversedBy="mySource")
* #ORM\JoinTable(name="entity_has_copy")
*/
protected $myCopiedItem;
but the "entity_has_copy" table that symfony created has only 1 item (myentity_id) and I want to have 2 fields "myentity_id" & "selected_myentity_copy_id" which are both actualy id's from my "myentity" table...
What do I have to modify in order to have both id's in my generated table?
I'm sure I've missed something, but I cannot figure out WHAT :(
Note: Entity / table names were renamed for privacy
Solved this!
I had to add the relationship inside the definition...
So this is the correct definition for the JoinTable part:
/**
* #ORM\ManyToMany(targetEntity="MyEntity", inversedBy="mySource")
* #ORM\JoinTable(name="entity_has_copy",
* joinColumns={#ORM\JoinColumn(name="entity_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="entity_copy_id", referencedColumnName="id")}
* )
*/
protected $myCopiedItem;
Hope this will help others that are having same issue...
If you want to read more about how associations between entities are mapped with Doctrine, here's a good URL!

Resources