I have an entity offer which has a oneToOne relation with a product and I have a user who would like to get all the offers he got on his products.
I would like to access to the user who has made the product from an offer in my SQL request.
So it's something like that:
$user = $this->getUser();
$listofofferusergot = $em->getRepository('blabla:Offer')->findBy(array('product.autor.id' => $user->getId()));
(ps : Offer has a OneToOne relation with product)
(ps2: the thing I wrote doesn't work )
So the question is general Can I simply access to a subfield (like id in my case) or must I do a $em->createQuery() stuff
offer class:
<?php
namespace Nemi\TwigBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Offer
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Nemi\TwigBundle\Entity\OfferRepository")
*/
class Offer
{
/**
* #ORM\ManyToOne(targetEntity="Nemi\TwigBundle\Entity\Product")
* #ORM\JoinColumn(nullable=false)
*/
private $product;
...
}
for the product class:
<?php
namespace Nemi\TwigBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Product
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Nemi\TwigBundle\Entity\ProductRepository")
*/
class Product
{
/**
* #ORM\ManyToOne(targetEntity="Nemi\UserBundle\Entity\User")
* #ORM\JoinColumn(nullable=false)
*/
private $autor;
....
}
You could add this method in your OfferRepository:
public function findOffersByProductAuthor(User $user)
{
return $this->createQueryBuilder('offer')
->join('offer.product', 'product')
->join('product.author', 'author')
->where('author = :user')
->setParameter('user', $user)
->getQuery()
->getResults();
}
Then, call:
$em->getRepository('blabla:Offer')-> findOffersByProductAuthor($this->getUser());
Related
I want to create a custom authentication system by separating passwords from user entity . each user can have more than a password and the latest one is used , and when user try to updated his password i want to prevent him to use an old password , as like as it is described in the link bellow .
Please i need your help and thank you .
https://filebin.net/wa6jrfy0t0xcqru7/Screenshot_from_2019-04-14_00-46-20.jpg?t=n9vnajox
For me is not a custom authentication system, you just need to change the body of the method getPassword. you will find below an example.
password.php
<?php
namespace your\name\space;
use Doctrine\ORM\Mapping as ORM;
use DateTime;
class Password
{
/**
* #ORM\ManyToOne(targetEntity="your\name\space\User", inversedBy="passwords")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=false)
*
* #var User
*/
private $user;
/**
* #ORM\Column(name="inserted_at", type="datetime")
*
* #var DateTime
*/
private $insertedAt;
}
User.php
<?php
namespace your\name\space;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
class User implements UserInterface
{
/**
* #ORM\OneToMany(targetEntity="your\name\space\Password", mappedBy="user")
* #ORM\OrderBy(value={"insertedAt" = "DESC"})
*
* #var Collection
*/
private $passwords;
/**
* User constructor.
*/
public function __construct()
{
$this->passwords = new ArrayCollection();
}
/**
* {#inheritDoc}
*/
public function getPassword()
{
if ($this->passwords->isEmpty()) {
return null;
}
return $this->passwords->first();
}
}
I have two tables named jobs and attachments.A job may or may not have one or more than one attachments.I have created one to may relation with job and attachment.But when I trying to persist it gives me an error,
A new entity was found through the relationship 'AppBundle\Entity\JotJobs#attachments' that was not configured to cascade persist operations for entity: AppBundle\Entity\JotJobAttachments#000000004d40cceb00000000fe114bdc. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example #ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'AppBundle\Entity\JotJobAttachments#__toString()' to get a clue.
Then I have tried to set cascade persist in jobs entity, after that it always asking for a mandatory attachment for each jobs.Otherwise it will gives an error with job_id can't be null in attachment table.I were trying to correct it for the last few hours.Please help.
My entities are,
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* JotJobs
*
* #ORM\Table(name="jot_jobs")
* #ORM\Entity
*/
class JotJobs
{
/**
* #var \JotJobAttachments
*
* #ORM\OneToMany(targetEntity="JotJobAttachments" ,mappedBy="jotJobs")
* #ORM\JoinColumn(name="ID", referencedColumnName="job_id")
*/
private $attachments;
/**
* Constructor
*/
public function __construct()
{
$this->attachments = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get subTechnologies
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getSubTechnologies()
{
return $this->subTechnologies;
}
/**
* Add attachments
*
* #param \AppBundle\Entity\JotJobAttachments $attachments
* #return JotJobs
*/
public function addAttachment(\AppBundle\Entity\JotJobAttachments $attachments=null)
{
$this->attachments[] = $attachments;
return $this;
}
/**
* Remove attachments
*
* #param \AppBundle\Entity\JotJobAttachments $attachments
*/
public function removeAttachment(\AppBundle\Entity\JotJobAttachments $attachments)
{
$this->attachments->removeElement($attachments);
}
}
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* JotJobAttachments
*
* #ORM\Table(name="jot_job_attachments")
* #ORM\Entity
*/
class JotJobAttachments
{
/**
* #var \JotJobs
*
* #ORM\ManyToOne(targetEntity="JotJobs", inversedBy="attachments")
* #ORM\JoinColumn(name="job_id", referencedColumnName="ID", nullable=true)
*/
private $jotJobs;
/**
* Set jotJobs
*
* #param \AppBundle\Entity\JotJobs $jotJobs
* #return JotJobAttachments
*/
public function setJotJobs(\AppBundle\Entity\JotJobs $jotJobs = null)
{
$this->jotJobs = $jotJobs;
return $this;
}
/**
* Get jotJobs
*
* #return \AppBundle\Entity\JotJobs
*/
public function getJotJobs()
{
return $this->jotJobs;
}
}
In my controller,
$newJob = new JotJobs();
$newJob->setJobName($data->getJobName());
.
.
.
$attachments = $data->getAttachments();
$jobDir = $this->container->getParameter('uploads_directory').'/jobs';
foreach ($attachments as $key => $value) {
if($value->getAttachment()!=null)
{
/** #var Symfony\Component\HttpFoundation\File\UploadedFile $file */
$file = $value->getAttachment();
$fileName = md5(uniqid()).'.'.$file->guessExtension();
$file->move($jobDir, $fileName);
$jobAttachment = new JotJobAttachments();
$jobAttachment->setAttachment($fileName);
$jobAttachment->setAttachmentName($file->getClientOriginalName());
$newJob->addAttachment($jobAttachment);
}
}
$entityManager->persist($newJob);
$entityManager->flush();
$lId = $newJob->getId();
You have two things going on here.
The first, as mentioned before, is that you need cascade={"all"} on your OneToMany relation. Use all instead of persist snce if you delete a job you almost certainly want the attachments to be deleted as well.
The second is that you need to set the job reference in your attachment. That is why you getting those null errors.
public function addAttachment(\AppBundle\Entity\JotJobAttachment $attachment=null)
{
$this->attachments[] = $attachment;
$attachment->setJotJob($this); // ADD THIS
return $this;
}
You might also consider changing thing like JotJobAttachments to JotJobAttachment. Makes your code easier to understand.
And don't pay much attention to the down voters. This cross referencing requirement catches many developers and is not easy to search for.
I have two entities related by a OneToMany relation:
<?php
namespace CRMBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* User
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="CRMBundle\Entity\ContactRepository")
*/
class User
{
/*...*/
/**
* #ORM\OneToMany(targetEntity="CRMBundle\Entity\Message", mappedBy="user", cascade={"persist"})
* #ORM\OrderBy({"datetime" = "DESC"})
*/
protected $messages;
/*...*/
}
And
<?php
namespace CRMBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Message
*
* #ORM\Table()
* #ORM\Entity
*/
class Message
{
/*...*/
/**
* #ORM\ManyToOne(targetEntity="CRMBundle\Entity\User", inversedBy="messages")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="SET NULL")
*/
private $user;
/**
* #var \DateTime
*
* #ORM\Column(name="Datetime", type="datetime", nullable=true)
*/
private $datetime;
/*...*/
}
My question is how to create a query in the UserController to get every user with the last message (i.e. the most recent according to the datetime attribute) of each user?
I think what you are looking for is in one of my previous answers to one of my own questions ^^
You have to use a subquery to select dynamically the most recent datetime value of one user's messages, and to join the message having this value.
To do this, you must define the (sub) query selecting the MAX value of message.datetime:
$qb2= $this->createQueryBuilder('ms')
->select('MAX(ms.datetime) maxDate')
->where('ms.user = u')
;
And then use it in your join clause, the whole function being in your UserRepository:
$qb = $this->createQueryBuilder('u');
$qb ->leftJoin('u.messages', 'm', 'WITH', $qb->expr()->eq( 'm.datetime', '('.$qb2->getDQL().')' ))
->addSelect('m');
Your User (each of them) will then have a messages Collection, containing one (or null if no message from the user) message, which you will get this way:
$user->getMessages()->first();
But if you use the lazy loading function of Symfony, as you have already defined an orderby annotation on your user.messages attribute, calling
$user->getMessages()->first()
should return to you the most recent message (but will also load all the others silently).
To avoid this silent second DB query, you can join it directly to the query requesting your users:
$qb = $this->createQueryBuilder('u');
$qb ->leftJoin('u.messages', 'm')
->addSelect('m');
In the example below $type can be both 'brand' or 'category', and $slug will be either a brand or a category.
How would I approach this when I want to filter my results on a category and a brand at the same time?
public function getGroupAction($slug, $type = null, $grouped = true)
{
$group = $this->getDoctrine()
->getRepository('AudsurShopBundle:'.$type)
->findOneBy(array( 'name' => $slug ))
->getProducts();
return $this->render('AudsurShopBundle:Default:productOverview.html.twig', array(
'group' => $group
)
);
}
To do what you want to do, you have to use Class table inheritance with the system of a discriminator column.
For your example, create the following entity :
<?php
namespace ...
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="discriminator", type="string")
* #ORM\DiscriminatorMap({"category" = "Category", "brand" = "Brand"})
*/
abstract class NameHolder
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
// Getters and setters
}
and then make your 2 entities inherit this class:
<?php
namespace ...;
use Doctrine\ORM\Mapping as ORM;
/**
* FirstChild
*
* #ORM\Table()
* #ORM\Entity
*/
class Category extends NameHolder
{
// all methods and properties except from the "name"
}
and:
<?php
namespace ...;
use Doctrine\ORM\Mapping as ORM;
/**
* FirstChild
*
* #ORM\Table()
* #ORM\Entity
*/
class Brand extends NameHolder
{
// all methods and properties except from the "name"
}
So now you can make a query like this:
$group = $this->getDoctrine()
->getRepository('AudsurShopBundle:NameHolder')
->findOneBy(array('name' => $slug))
->getProducts();
This will return an array collection with both Brand and Category entities.
However I am not sure a NameHolder class really makes sense. An other solution would be to make separate queries for both entities without changing any of your entities, but that's not what you seem to be looking for.
I've tried to search for this error but the fact that I haven't found anything leads me to believe that I'm doing something silly. I'll include the relevant code below, but basically I'm using multiple table inheritance (or Class Table Inheritance) and trying to use the Doctrine ORM findBy() method to query based on the discriminator column, which results in the following ORMException being thrown: "Unrecognized field: type".
Here is the code that triggers the exception:
// $this->em is an instance of \Doctrine\ORM\EntityManager
$repository = $this->em->getRepository('JoeCommentBundle:Thread');
return $repository->findOneBy(array(
'type' => $this->type,
'related_id' => $id
));
Here is the relevant code for the 'base' abstract entity:
<?php
namespace Joe\Bundle\CommentBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="comment_threads")
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="type", type="string")
* #ORM\DiscriminatorMap( {"story" = "Joe\Bundle\StoryBundle\Entity\StoryThread"} )
*/
abstract class Thread
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(name="related_id", type="integer")
*/
protected $relatedId;
/** MORE FIELDS BELOW.... **/
And finally, here is the code for the concrete thread entity:
<?php
namespace Joe\Bundle\StoryBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Joe\Bundle\CommentBundle\Entity\Thread as AbstractThread;
/**
* #ORM\Entity
* #ORM\Table(name="story_comment_threads")
*/
class StoryThread extends AbstractThread
{
/**
* #ORM\OneToOne(targetEntity="Story")
* #ORM\JoinColumn(name="story_id", referencedColumnName="id")
*/
protected $story;
}
I've double checked my schema, and the type column definitely exists, so I'm not sure what could be causing this. Any ideas? Thanks.
Rob, when querying your actually using the parent entity and trying to filter on the discriminator value. Instead, work on the repository relative to the child entity you want to fetch. Doctrine will do the rest for you. So in your case you want to get the repository for StoryThread.
$repository = $this->em->getRepository('JoeCommentBundle:StoryThread');
return repository->find($id);
You cannot use the discriminator column as a standard entity property.
Instead you may do the following:
$dql = 'SELECT e FROM JoeCommentBundle:Thread e
WHERE e.related_id = :related_id AND e INSTANCE OF :type';
$query = $em->createQuery($dql);
$query->setParameters(array(
'type' => $this->type,
'related_id' => $id
));
$record = $query->getSingleResult();