I'm really tired to figuring out how I can check in Doctrine 2 if related entity record exists in DB. Help me please.
For example I have two entities. One is the order status of certain delivery company. Another one is order.
Order.php
/**
* #ORM\OneToOne(targetEntity="Application\DeliveryBundle\Entity\DpdOrderStatus", mappedBy="order")
* #var DpdOrderStatus
*/
$dpdOrderStatus;
DpdOrderStatus.php
/**
* #ORM\Id
* #ORM\OneToOne(targetEntity="\Application\FrontendBundle\Entity\Order", inversedBy="dpdOrderStatus")
* #ORM\JoinColumn(onDelete="CASCADE")
* #var Order
*/
$order;
Order entity sometimes doesn't have status and I need to check if it has.
AFAIK if I will try to use is_null($order->getDpdOrderStatus()) it will always be false because Doctrine always create Proxy objects for its entities if EAGER mode is not specified.
So what is the most proper way to check if my status entity exists in database?
Add a method that checks if the order has an order status:
Order.php
public function hasOrderStatus(){
return ! is_null($this->dpdOrderStatus);
}
More information: Techniques to check if relationship exists in Doctrine2
This worked for me.
public function hasOrderStatus() {
return !is_null($this->dpdOrderStatus) && (bool) $this->dpdOrderStatus->getId();
}
Related
In my project I have two entities: planifications and selections.
There is a relation between these two objects: A planification MUST contain ONE selection. The same selection can be used by multiple planifications.
The generated code looks like this:
// Planification.php - class Planification
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Selection", inversedBy="planifications")
* #ORM\JoinColumn(name="selection_id", referencedColumnName="id")
*/
private $selection;
// Selection.php - class Selection
/**
* #ORM\OneToMany(targetEntity="App\Entity\Planification", mappedBy="selection")
*/
private $planifications;
What I would like to do is not allow a selection to be deleted if it is referenced by a planification. In other words, if a planification contains a selection - that selection can not be deleted. What happens to me is if I try to delete a selection that is in a planification, the operation completes successfully, and the $selection member in the Planification class contains NULL.
Would fixing this be possible in doctrine? I have tried adding nullable=false (on the $selection member) and onDelete="NO ACTION", and both solutions don't work.
The correct Doctrine annotation to disallow Planification::$selection to be null, would be:
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Selection", inversedBy="planifications")
* #ORM\JoinColumn(name="selection_id", nullable=false)
*/
private $selection;
(You do not need the referencedColumnName setting, since it defaults to id, and nullable=false goes in the #JoinColumn annotation).
Having the annotation will not update the DB to fit this particular definition.
Execute bin/console doctrine:schema:update --dump-sql to see the needed SQL to update your table definition, and run the resultant appropriate SQL statements against your DB to update the DB schema.
I come from a Rails background and am not really familiar with Doctrine. I am trying to set up a similar association to this one in Rails.
I have a UserRelation entity that contains a combination of user_id and company_id with a primary key. The same user can belong to multiple companies, and most data is stored with user_relation_id.
So, in this example I have a Template that has the following association set up which works fine:
/**
* The UserRelation entity who created the template.
*
* #ORM\ManyToOne(targetEntity="UserRelation")
* #ORM\JoinColumn(name="user_relation_id", referencedColumnName="id", nullable=false)
*/
protected $creator;
In this example I know I can just add a method to my template entity along the lines of:
public function getUser(): User
{
return $this->creator->getUser();
}
but I need it to be filterable so that I can get all Template entities by user_id or company_id in a repository or controller like this:
$company = $entityManager->getRepository('Company')->find($company_id);
$templatesForCompany = $entityManager->getRepository('Template')->findBy('company' => $company);
Is there any way to set up this relationship so I can query it like above, instead of having to resort to raw SQL?
Sorry about the title, it's quite hard to describe it with just a few words. Here's the problem:
I have a customer entity which has a OneToMany with Website and customerTrackingIds :
class Customer {
...
/**
* #var ArrayCollection
* #Serializer\Exclude()
* #ORM\OneToMany(targetEntity="AppBundle\Entity\WebSite", mappedBy="customer",cascade={"persist","remove"},orphanRemoval=true)
*/
private $webSites;
/**
* #var ArrayCollection
* #Serializer\Exclude()
* #ORM\OneToMany(targetEntity="AppBundle\Entity\CustomerTrackingId", mappedBy="customer",cascade={"persist","remove"})
*/
private $customerTrackingIds;
...
}
And Website:
class WebSite {
/**
* #var Customer
* #Serializer\MaxDepth(1)
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Customer", inversedBy="webSites")
* #ORM\JoinColumn(nullable=true, onDelete="SET NULL")
*/
private $customer;
/**
* #var ArrayCollection
* #Serializer\Exclude()
* #ORM\OneToMany(targetEntity="AppBundle\Entity\CustomerTrackingId", mappedBy="website")
*/
private $customerTrackingIds;
}
Customer has multiple website and multiple trackingIds. Each tracking ID is associated with one of the customer's website, but more trackingIds can exist for the same Website.
I use https://github.com/ninsuo/symfony-collection to handle the collection of website/trackingIds in the same page but when i go edit the information something really weird (at least for me) happens.
Looking in my debugger session i saw that when the form loads data from submit in my controller:
$formCustomer = $this->createForm( CustomerFormType::class, $customer );
$formCustomer->handleRequest( $request );
if ( $formCustomer->isSubmitted() && $formCustomer->isValid() ) {
$em = $this->getDoctrine()->getManager();
$em->persist( $customer );
$em->flush();
When the request is handled all of the elements of TrackingIds has their website correctly set, but inside the website the customer link gets lost (becomes null).
What happens next is that when all the data get persisted i lost in my database the phisical association between website <-> customer (customer becomes null)
How can i fix this?
If you will ever land here i solved the issue simply double-checking my website collection form type.
Since using https://github.com/ninsuo/symfony-collection i created a new FormTheme to render the collection add/delete stuff in my page with just one field for the website collection which was the website name.
Anyways, inside my website collection formType i had TWO fields, name AND, guess what, CUSTOMER.
Since the FormTheme was rendering just the name field, the other one becomes null automatically, so when it was handled by the controller he was actually doing that right.
I trying Symfony 4 for "fun". And for that I try to rewrite an old website without framework as the moment, with Symfony 4.
For that I configure my app on my database with existing datas. And I'd make login form.
BUT on my User classe, I have some colomn who make me some issues.
See bellow my user's class's annotations:
/**
* Utilisateur
*
* #ORM\Table(name="utilisateur", uniqueConstraints={#ORM\UniqueConstraint(name="mail", columns={"mail"})}, indexes={#ORM\Index(name="FK_UTILISATEUR_idDroit", columns={"idDroit"})})
* #ORM\Entity
*/
and my user's struct :
idutilisateur
nom
prenom
mail
password
dateinscription
datevalidation
token
iddroit
plainPassword
Like you can see, I create before iddroit as foreign key of droit's table.
Doctrine generated the propertie as
/**
* #var Droit
*
* #ORM\ManyToOne(targetEntity="Droit")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="idDroit", referencedColumnName="idDroit")
* })
*/
private $iddroit;
And created the getter as
public function getIddroit(): Droit
{
return $this->iddroit;
}
And after followed the documentation about registration / login, the debugger respond =>
Return value of App\Entity\Utilisateur::getIddroit() must be an
instance of App\Entity\Droit, null returned
So I imagine he want an object and not just an ID, even if in anotation it's making the Join rules. Any ID what's happened ?
And I understand to return an objet, but I have no idea how to return that.
If any suggestion.
Thanks guys ;)
Laurent
Doctrine NOOB here, trying to figure out how to prevent a duplicate record in an embed many property. I have a EmbededDocment like this:
<?
/**
* #EmbeddedDocument
*/
class Contact {
/**
* #Id
*/
private $id;
/**
* created timestamp
* #Date
*/
private $created;
/**
* modified timestamp
* #Date
*/
private $modified;
/**
* #String
*/
private $name;
/**
* #String
*/
private $name;
/**
* #String
*/
private $address;
}
what I want to happen is when I add a new contact, two contacts can have the same name, two contacts can have the same address, but two contacts can not have the same name and address. When checking for duplicates, doctrine will need to ignore the $id, $created and $modified properties as these will almost always be distinct. It is the combination of all the other fields that must be unique. How can this be accomplished using doctrine? Does this logic belong in a service layer or can doctrine do it for me?
UPDATE:
I do accept that Andrew's answer is the correct way to check for duplication using Mongo, I really want to know if doctrine can do this for me. Therefore, I'm starting a bounty.
You could implement an event listener which will listen to an preUpdate and prePersist event.
http://www.doctrine-project.org/docs/mongodb_odm/1.0/en/reference/events.html
In your event, you can do your own check.
You should validate your document before save it.
For example if user adding Contact with name="Name" and address="Address" you shoud check in mongodb if such Contact exists. And in case if it exists you just showing validation message, otherwise you adding contact to embedded contacts array.
So, suppose you have collection of users that's contains embedded array of contacts. To verify that new contact exists/not exists you can send request like this:
db.users.find({ userId: "userId" ,
contacts.name: "new contact name",
contacts.address: "new contact address"}).count();
If above query will return count >= 1 you no need add new contact, just show validation.