Doctrine query crashing - symfony

Very very weird. I have used this method from doctrine hundreds of times. I have a simple controller that takes an id as parameter. The query that Doctrine generates is wrong and crash.
/**
* #Security("has_role('ROLE_ADMIN')")
* #return Response
*/
public function editSellerAction($id)
{
$em = $this->getDoctrine()->getManager();
$seller = $em->getRepository('SiteUserBundle:Seller')->find($id);
// ...
$form = $this->createForm(new SellerType(), $seller, array(
'method' => 'POST'
));
// ...
}
The query generated is the following
[2/2] DBALException: An exception occurred while executing 'SELECT t1.id AS id2, t1.username AS username3, t1.password AS password4, t1.firstname AS firstname5, t1.lastname AS lastname6 FROM seller t1 WHERE t0.id = ? LIMIT 1' with params ["2"]:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 't0.id' in 'where clause' +
The error thrown makes sense because it's looking at "WHERE t0.id" when it should be looking at "WHERE t1.id". I tried the query with t1 using phpmyadmin and it works.
Any idea what might cause this issue?
/**
* Seller have access to their customer and are able to RW access to the customers
*
* #ORM\Table("seller")
* #ORM\Entity
* #author Michael Villeneuve
*/
class Seller extends User
{
/**
* #var array
*
* #ORM\OneToMany(targetEntity="Customer", mappedBy="seller", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="seller_id", referencedColumnName="id")
**/
protected $customers;
/**
* #var string
*
* #ORM\Column(name="firstname", type="string", length=255, nullable=false)
*/
protected $firstname;
/**
* #var string
*
* #ORM\Column(name="lastname", type="string", length=255, nullable=false)
*/
protected $lastname;
// Other attributes and only getters/setter
/**
*
* #ORM\Entity
*/
class User implements UserInterface
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=255, unique=true)
*/
private $username;
/**
* #ORM\Column(type="string", length=64)
*/
private $password;
I have 3 entities that extends the User (customer, admin and seller).

Updated link: https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/inheritance-mapping.html
Read up a bit on mapped super classes: http://docs.doctrine-project.org/en/latest/reference/inheritance-mapping.html. Basically, your abstract base user class cannot itself be an entity.
So take the #ORM\Entity line out of your User class. That is where the table 0 (t0) is coming from.

You have 2 options:
The first one is to create an abstract User entity and inherit all values from it. This is useful if you have many entities with the same behaviour. I e.g. like to create a BaseEntity with a ID field and some basic methods. All entities can extend this one and automatically have an ID. Cerad explained in his answer how this is done.
The second option are so called discriminator fields. Basically they allow you to have one User table and sub-tables for every extended entity. You can read about them in the official docs.
Which one you end up using is probably case dependent.

Try to add id field to the Seller entity instead of User
/**
* Seller have access to their customer and are able to RW access to the customers
*
* #ORM\Table("seller")
* #ORM\Entity
*/
class Seller extends User
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var array
*
* #ORM\OneToMany(targetEntity="Customer", mappedBy="seller", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="seller_id", referencedColumnName="id")
**/
protected $customers;
/**
* #var string
*
* #ORM\Column(name="firstname", type="string", length=255, nullable=false)
*/
protected $firstname;
/**
* #var string
*
* #ORM\Column(name="lastname", type="string", length=255, nullable=false)
*/
protected $lastname;
// Other attributes and only getters/setter
/**
*
* #ORM\Entity
* #author Michael Villeneuve<michael#panierdachat.com>
*/
class User implements UserInterface
{
/**
* #ORM\Column(type="string", length=255, unique=true)
*/
private $username;
/**
* #ORM\Column(type="string", length=64)
*/
private $password;

Related

How to use Gedmo nested tree for storing multiple trees in one single table?

I have a table which store a tree for each username.
My entity looks like this:
/**
* Confsaves
* #Gedmo\Tree(type="nested")
* #ORM\Table(name="confsaves")
*#ORM\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\NestedTreeRepository")
*/
class Confsaves
{
/**
* #var string
*
* #ORM\Column(name="Name", type="string", length=200, nullable=true)
*/
private $name;
/**
* #var string
*
* #Gedmo\TreeRoot
* #ORM\Column(name="Username", type="string", length=50, nullable=true)
*/
private $username;
/**
* #Gedmo\TreeParent
* #ORM\ManyToOne(targetEntity="Confsaves", inversedBy="children")
* #ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="CASCADE", nullable=true)
*/
private $parent;
/**
* #ORM\OneToMany(targetEntity="Confsaves", mappedBy="parent")
* #ORM\OrderBy({"lft" = "ASC"})
*/
private $children;
/**
* #var integer
*
* #Gedmo\TreeLeft
* #ORM\Column(name="lft", type="integer", nullable=true)
*/
private $lft;
/**
* #var integer
*
* #Gedmo\TreeRight
* #ORM\Column(name="rght", type="integer", nullable=true)
*/
private $rght;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
I want build a different tree for each user.
In my controller I have created the repository like this:
$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('MyBundle:Confsaves');
How can I set the scope of the repository only on the user connected?
Is level necessary for build tree function?
I use an existing database that only have left, right and parent arguments.
Has been a long time, but for the record:
If you want a tree for each user, you must establish a relationship between your Confsaves and User entities, more specifically, between the root property of your Confsaves entity and your User one. Doctrine Extensions supports relationships on the root property of your tree since 2.4. Make sure you are using the right version. Cost me a day of debugging.
So, to relate your nested set tree to a user entity, just perform a ManyToOne in your User, and the inverse relationship in your Tree entity.

Embeed forms - inserting to database

I created two entities automatically ( using this manual http://symfony.com/doc/2.8/doctrine/reverse_engineering.html) based on ER model generated in Workbench. My intention was to create one-to-one relationship but annotation show it is one-to-many relationship. I created also embeed forms. I would like to insert client and new adress to database. I still get an error:
A new entity was found through the relationship 'UlaBundle\Entity\Client#adres' that was not configured to cascade persist operations for entity: qqq. 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"}).
Error is shown even if i set #ManyToOne(..,cascade={"persist"}) and __toString function. What is the problem? Please help. Below my code:
///Client Entity
class Client
{
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=45, nullable=true)
*/
private $name;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var \UlaBundle\Entity\Adres
*
* #ORM\ManyToOne(targetEntity="UlaBundle\Entity\Adres", cascade= {"persist"})
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="adres_id", referencedColumnName="id")
* })
*/
private $adres;
/// Adres Entity
class Adres
{
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=45, nullable=true)
*/
private $name;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
///Controller
/**
* #Route("/client", name="client")
*/
public function clientAction(Request $request) {
$c = new Client();
$form = $this->createForm(ClientType::class,$c);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$m = $this->getDoctrine()->getManager();
$m->persist($c);
$m->flush();
return new Response('Added');
}
return $this->render('UlaBundle:Default:client_form.html.twig', array('form' => $form->createView()));
}
I think your problem come from the blank space in cascade= {"persist"}, you should remove it
/**
* #var \UlaBundle\Entity\Adres
*
* #ORM\ManyToOne(targetEntity="UlaBundle\Entity\Adres", cascade={"persist"})
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="adres_id", referencedColumnName="id")
* })
*/
private $adres;

Doctrine2 relation for non Id column

I'm building a simple web-service using Symfony 3, Doctrine 2.5 and stuck at ORM relations described below in simplified structure.
I have an Action entity containing many actions with ManyToOne relation...
class Action
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
*
* #ORM\ManyToOne(targetEntity="\AppBundle\Entity\Status")
* #ORM\JoinColumn(referencedColumnName="code", nullable=false)
*/
private $status;
and the Status Entity with a few statuses.
class Status
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(type="integer", unique=true)
*/
private $code;
I cannot get proper way to set referencedColumnName="code" column (not 'Id' as usual) for Action entity.
Configured this way repo throws wxception at persist moment with "Notice: Undefined index: code";
I guess that it is mappedBy or inversedBy annotation parameter... but can't figure out "how".
Unfortunately it's not supported in Doctrine (reference).
You may edit your Status entity like this (ensure that code is set before persist):
class Status
{
/**
* #ORM\Column(name="code", type="integer", unique=true)
* #ORM\Id
*/
private $code;
}
If autoincremented field is your requirement you can take a look on this answer for possible solutions.
Just thought I'd add you can still use the non-primary keys as many to many, by using the entity itself as the join table. This will work but you still need to set your relationship keys correctly.
Example:
/**
* #ORM\Entity
*/
class Car {
/**
* #var integer
*
* #ORM\Column(name="id", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #ORM\Column(name="registration_code", type="text", length=128, nullable=false)
* #var string
*/
public $registrationCode;
/**
* #var \Doctrine\Common\Collections\Collection
* #ORM\ManyToMany(targetEntity="Registration", mappedBy="Cars")
* #ORM\JoinTable(name="car",
* joinColumns={#ORM\JoinColumn(name="id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="registration_code", referencedColumnName="registration_code")}
* )
*/
public $Registrations;
public function __construct() {
$this->Cars = new ArrayCollection();
}
}
/**
* #ORM\Entity
*/
class Registration {
/**
* #var integer
*
* #ORM\Column(name="id", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #ORM\Column(name="registration_code", type="text", length=128, nullable=false)
* #var string
*/
public $registrationCode;
/**
* #var ArrayCollection
* #ORM\ManyToMany(targetEntity="Car", mappedBy="Registrations")
* #ORM\JoinTable(name="car",
* joinColumns={#ORM\JoinColumn(name="registration_code", referencedColumnName="registration_code")},
* inverseJoinColumns={#ORM\JoinColumn(name="id", referencedColumnName="id")}
* )
*/
public $Cars;
public function __construct() {
$this->Cars = new ArrayCollection();
}
}
The upside is that it works fine as a workaround.
Keep in mind a few things:
it's a collection not a single instance;
column has to be managed manually on your end;
you must set up constraints correctly (indexes, keys, etc);
check your queries still perform!

symfony 2 Doctrine leftJoin NOT IN

How can I solve a query where I want to get all data from the left table which isn't existing in the right table?
left table: ID | NAME | DATE
right table: ID | ID_left_table | NAME | DATE
It is confusing me a bit since I haven't got that experience with doctrine.
My entitys look like:
class NameData
{
/**
* #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, nullable=false)
*/
private $name;
/**
* #var \DateTime
*
* #ORM\Column(name="date", type="datetime")
*/
private $date;
.
.
.
and
class ValueData
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="TestBundle\Entity\NameData")
*/
private $nameid;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255, nullable=false)
*/
private $name;
/**
* #var \DateTime
*
* #ORM\Column(name="date", type="datetime")
*/
private $date;
.
.
.
1) First of all, fix $nameid property annotation in ValueData entity to this:
/**
* #ORM\ManyToOne(targetEntity="NameData")
* #ORM\JoinColumn(name="name_id", referencedColumnName="id")
**/
private $nameData;
This is basic Doctrine annotation mapping for relationships, in this case ManyToOne.
2) Modify valueData table to add foreign key, by typing php app/console doctrine:schema:update --force or with migrations
3) let Symfony generate the right setters and getters for ValueData entity, by running command in your console php app/console doctrine:generate:entities TestBundle:ValueData.
4) And then, if you need to get data in controller:
$valueData = $this->getDoctrine()->getRepository('TestBundle:ValueData')->find(1);//Find by ID 1 OR ->findAll() to get all records
$nameData = $valueData->getNameData(); //This line of code behind the scenes will
//join the valueData table with nameData, and get associated data
Add a comment if you will need help along the way.
Edit:
Below is the query builder to select all NameDatas which dont have any ValueData:
$nameDataRepo = $this->getDoctrine()->getRepository('TestBundle:NameData');
$nameDatasWithoutDatavalues = $nameDataRepo->createQueryBuilder('nameData')
->leftJoin('nameData.dataValues', 'dataValue')
->where('dataValue.id IS NULL')
->getQuery()
->getResult
Also, make sure to write bi-directional part of doctrine relationships, to be able to access children from parent entity NameData.php:
/**
* #var \Doctrine\Common\Collections\ArrayCollection
*
* #ORM\OneToMany(targetEntity="ValueData", mappedBy="nameData")
*/
private $valueDatas;
/**
* Constructor
*/
public function __construct()
{
$this->valueDatas = new \Doctrine\Common\Collections\ArrayCollection();
}
And in ValueData.php, edit $nameData property annotation to this:
/**
* #ORM\ManyToOne(targetEntity="NameData", inversedBy="valueDatas")
* #ORM\JoinColumn(name="name_id", referencedColumnName="id")
**/
private $nameData;

Symfony2 - Database table relationships

I was working on an app and had everything set up nicely. I have an Alert entity which takes the following form.
/**
* Alert
*
* #ORM\Table(name="alert")
* #ORM\Entity(repositoryClass="Nick\AlertBundle\Repository\AlertRepository")
*
*/
class Alert
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="search_command", type="string", length=256, nullable=false)
*/
private $searchCommand;
/**
* #var string
*
* #ORM\Column(name="is_connecting", type="string", length=20, nullable=false)
*/
private $isConnecting;
/**
* #var \DateTime
*
* #ORM\Column(name="last_updated", type="datetime", nullable=false)
*/
private $lastUpdated;
/**
* #var boolean
*
* #ORM\Column(name="is_deleted", type="boolean", nullable=false)
*/
private $isDeleted;
/**
* #var string
*
* #ORM\Column(name="alert_status", type="string", length=11, nullable=false)
*/
private $alertStatus;
/**
* #ORM\OneToMany(targetEntity="Nick\AlertBundle\Entity\BookingClass", mappedBy="availabilityAlert")
*/
private $bookingClass;
/**
* #ORM\OneToMany(targetEntity="Nick\AlertBundle\Entity\Pseudos", mappedBy="availabilityAlert")
*/
private $pseudo;
/**
* #ORM\OneToMany(targetEntity="Nick\AlertBundle\Entity\FlightNumbers", mappedBy="availabilityAlert")
*/
private $flightNumbers;
/**
* #ORM\OneToMany(targetEntity="Nick\AlertBundle\Entity\Availability", mappedBy="availabilityAlert")
*/
private $availability;
/**
* Constructor
*/
public function __construct()
{
$this->bookingClass = new ArrayCollection();
$this->pseudo = new ArrayCollection();
$this->flightNumbers = new ArrayCollection();
$this->availability = new ArrayCollection();
}
//other methods
}
So I had this app working, but now I have decided to add a log in system. Each Alert should now be associated to a user - a user can have none to many alerts.
So I have created my user class and set up all the security. The entity looks like
/**
* User
*
* #ORM\Table(name="user_table")
* #ORM\Entity()
*
*/
class User implements UserInterface
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="username", type="string", length=255, nullable=false)
*/
private $username;
/**
* #var string
*
* #ORM\Column(name="password", type="string", length=255, nullable=false)
*/
private $password;
//other functions
}
So whats the best way to associate Alerts to a User? Should I set it up like I do the with the other Entities in my Alert class? Should I add an Alert variable within the user class which is an Array Collection of Alerts?
Really just looking for a bit of advice how to best handle this.
Thanks
Yes you should add one to many relation ship in user entity and link with alert entity and in alert entity point back to user entity in many to one way
class User
{
/**
* #ORM\OneToMany(targetEntity="Alert", mappedBy="user")
*/
protected $alerts;
public function __construct()
{
$this->alerts= new ArrayCollection();
}
//... other getters amd setters
}
class Alert
{
// ...
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="alerts")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user;
}
Reference
I dont really see here any other solutions besides using ManyToOne association in the Alert entity or ManyToMany in case one Alert has to be associated with more then 1 user.
Should I add an Alert variable within the user class which is an Array Collection of Alerts?
Heck, why not? That way you can easily get users with joined alerts.

Resources