Doctrine 2: OneToMany Relation, order by foreign key - symfony

I have three entities (Profile, ProfileValue and Value).
A Profile has a one-to-many relation with ProfileValue, which has a many-to-one relation with the Value entity.
Is it possible to get the rleated ProfileValues from the Profile, ordered by the value id?
If I add the orderby annotation for a non-foreign-key like the enabled field in ProfileValue, it works. But for a foreign key, it failed with the message "inrecognized field". Any ideas?
/**
*
* #ORM\Table(name="profile")
* #ORM\Entity
*/
class Profile {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer", nullable=false, options={"unsigned"=true})
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var array $profileCValues
* #ORM\OneToMany(targetEntity="ABC\XYZBundle\Entity\ProfileValue", mappedBy="profile", cascade={"persist"})
* #ORM\OrderBy({"value" = "ASC"})
*/
private $profileValues;
And here is the ProfileValue entity:
/**
* ABC\XYZBundle\Entity\ProfileValue
*
* #ORM\Table(name="profile_value", indexes={#ORM\Index(columns={"profile_id"}), #ORM\Index(columns={"value_id"}) })
* #ORM\Entity
*/
class ProfileValue {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer", nullable=false, options={"unsigned"=true})
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var integer $enabled
*
* #ORM\Column(name="enabled", type="boolean", length=1, nullable=true)
*/
private $enabled;
/**
* #var ABC\XYZBundle\Entity\Profile
* #ORM\ManyToOne(targetEntity="ABC\XYZBundle\Entity\Profile", inversedBy="profileValues")
* #ORM\JoinColumn(name="profile_id", referencedColumnName="id", nullable=true, onDelete="CASCADE")
*/
private $profile;
/**
* #var ABC\XYZBundle\Entity\Value
* #ORM\ManyToOne(targetEntity="ABC\XYZBundle\Entity\Value")
* #ORM\JoinColumn(name="value_id", referencedColumnName="id", onDelete="CASCADE")
*/
private $value;
}

Had the same problem and solved it by adding a new field with foreign key:
/**
* #var integer $valueId
*
* #ORM\Column(name="value_id", type="integer")
*/
private $valueId;
Then you can order it without problems:
/**
* #var array $profileCValues
* #ORM\OneToMany(targetEntity="ABC\XYZBundle\Entity\ProfileValue", mappedBy="profile", cascade={"persist"})
* #ORM\OrderBy({"valueId" = "ASC"})
*/
private $profileValues;

Does this work?
/**
* #var array $profileCValues
* #ORM\OneToMany(targetEntity="ABC\XYZBundle\Entity\ProfileValue", mappedBy="profile", cascade={"persist"})
* #ORM\OrderBy({"id" = "ASC"})
*/
private $profileValues;
I don't use XML but this works in YML:
oneToMany:
foos:
targetEntity: Company\ProjectBundle\Entity\Foo
mappedBy: bar
orderBy: { 'id': ASC }

Related

Symfony3 - The association refers to the owning side field which does not exist with ManyToMany and fields table

i'm trying to make a manyToMany relationship with more attributes than the ids, so I need two OneToMany relationships and two ManytoOne relationships having three tables/entities.
I have Product entity, Client entity and ProductClient entity:
class Client
{
/**
* #var integer
*
* #ORM\Column(name="id_client", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $idClient;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=100, nullable=false)
*/
private $name;
/**
* #var \ProductClient
*
* #ORM\OneToMany(targetEntity="ProductClient", mappedBy="client")
*/
private $products_clients;
}
class Product
{
/**
* #var integer
*
* #ORM\Column(name="id_product", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $idProduct;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=100, nullable=false)
*/
private $name;
/**
* #var \ProductClient
*
* #ORM\OneToMany(targetEntity="ProductClient", mappedBy="product")
*/
private $products_clients;
}
class ProductClient
{
/**
* #ORM\Column(name="product_id", type="integer")
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Product", inversedBy="products_clients")
* #ORM\JoinColumn(name="product_id", referencedColumnName="id_product", nullable=false)
*/
protected $product;
/**
* #ORM\Column(name="client_id", type="integer")
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Client", inversedBy="products_clients")
* #ORM\JoinColumn(name="client_id", referencedColumnName="id_client", nullable=false)
*/
protected $client;
/**
* #var bool
*
* #ORM\Column(name="status", type="boolean")
*/
private $status;
}
That's something like this (with its getters and setters and more attributes). But symfony launches two "invalid entities errors" when I go to the Product crud:
AppBundle\Entity\Product - The association AppBundle\Entity\Product#products_clients refers to the owning side field AppBundle\Entity\ProductClient#product which is not defined as association, but as field.
AppBundle\Entity\Product - The association AppBundle\Entity\Product#products_clients refers to the owning side field AppBundle\Entity\ProductClient#product which does not exist.
And the same result if I go to the Client crud. What's wrong?
As you can see in the error message, AppBundle\Entity\ProductClient#product is not defined as association, but as field.
Just remove this #ORM\Column(name="product_id", type="integer") and this #ORM\Column(name="client_id", type="integer").
class ProductClient
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Product", inversedBy="products_clients")
* #ORM\JoinColumn(name="product_id", referencedColumnName="id_product", nullable=false)
*/
protected $product;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Client", inversedBy="products_clients")
* #ORM\JoinColumn(name="client_id", referencedColumnName="id_client", nullable=false)
*/
protected $client;
/**
* #var bool
*
* #ORM\Column(name="status", type="boolean")
*/
private $status;
}

can a doctrine entity have multiple one to one relationships where from and to fields are similar?

class Order{
/**
* #var integer
*
* #ORM\Column(name="order_id", type="bigint")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $orderId;
/**
* #ORM\OneToOne(targetEntity="OrderDiscount")
* #ORM\JoinColumn(name="order_id", referencedColumnName="order_id")
*/
private $discount;
/**
* #ORM\OneToOne(targetEntity="OrderTax")
* #ORM\JoinColumn(name="order_id", referencedColumnName="order_id")
*/
private $tax;
/**
* #ORM\OneToOne(targetEntity="OrderPayments")
* #ORM\JoinColumn(name="order_id", referencedColumnName="order_id")
*/
private $payment;
}
class OrderDiscount{
/**
* #var integer
*
* #ORM\Column(name="order_id", type="bigint")
* #ORM\Id
*/
private $id;
/**
* #var float
*
* #ORM\Column(name="discount", type="float", precision=10, scale=0, nullable=false)
*/
private $discount;
}
class OrderPayments{
/**
* #var integer
*
* #ORM\Column(name="order_id", type="bigint", nullable=false)
* #ORM\Id
*/
private $id;
/**
* #var float
*
* #ORM\Column(name="payment_amount", type="float", precision=10, scale=0, nullable=true)
*/
private $paymentAmount;
}
class OrderTax{
/**
* #var integer
*
* #ORM\Column(name="order_id", type="bigint", nullable=false)
* #ORM\Id
*/
private $id;
/**
* #var float
*
* #ORM\Column(name="tax_amount", type="float", precision=10, scale=0, nullable=false)
*/
private $taxAmount;
}
Here is my code (showing just basic code here).
when i migrate this schema doctrine says that an index is already exists, when i check in database that index do not exist.
Because doctrine in using column names to generate indexes, because all associations have same columns thats why doctrine says index already exists.
Is there any other better way to do this?
Yes, there is a better way to do this.
What you are trying to do, simply does not work because doctrine tries to create a foreign key from the "order_id" column from Order entity `s table that point to each of the "order_id" columns of Discount, Tax, Payments entities' tables.
What you actually want is to make the primary key order_id from Order to be a foreign key and also a primary key on Discount, Tax and Payments tables.
To achieve this:
Make the relation Bidirectional
Define the owning side on the Discount, Tax and Payments entities.
Here is the code:
class Order{
/**
* #var integer
*
* #ORM\Column(name="order_id", type="bigint")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $orderId;
/**
* #ORM\OneToOne(targetEntity="OrderDiscount", mappedBy="orderId")
*/
private $discount;
/**
* #ORM\OneToOne(targetEntity="OrderTax")
* #ORM\JoinColumn(name="order_id", referencedColumnName="order_id")
*/
private $tax;
}
class OrderDiscount{
/**
* #var integer
*
* #ORM\OneToOne(targetEntity="Order", inversedBy="discount")
* #ORM\JoinColumn(name="order_id", referencedColumnName="order_id")
* #ORM\Id
*/
private $orderId;
/**
* #var float
*
* #ORM\Column(name="discount", type="float", precision=10, scale=0, nullable=false)
*/
private $discount;
}
class OrderTax{
/**
* #var integer
*
* #ORM\OneToOne(targetEntity="Order", inversedBy="tax")
* #ORM\JoinColumn(name="order_id", referencedColumnName="order_id")
* #ORM\Id
*/
private $orderId;
/**
* #var float
*
* #ORM\Column(name="tax_amount", type="float", precision=10, scale=0, nullable=false)
*/
private $taxAmount;
}
Note
that ORM\JoinColumn is used on the owning side, so you do not need this your Order entity relation fields definition.
You do not need #ORM\Column(name="order_id", type="bigint", nullable=false) on Discount, Tax, Payments as it is defined as a foreign key and it will be created as the same type as the column it "points" to(in this case order_id of Order).

Symfony2 Entities: Many-To-One relationship between user and posts

How can I add relationship between user and posts using users id? I saw some examples, but I couldn't follow what inversedBy and mappedBy are for... Is it possible to store profile_id and not the object?
User profile entity:
class Profiles
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="email", type="string", length=255)
*/
private $email;
/**
* #var string
*
* #ORM\Column(name="password", type="string", length=255)
*/
private $password;
Posts/Comments entity:
class Comments
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var Profiles
*
* #ORM\ManyToOne(targetEntity="Profiles")
* #ORM\JoinColumn(name="profile_id", referencedColumnName="id")
*/
private $profile;
OK example
///User Enity
/**
* #ORM\OneToMany(targetEntity="Car", mappedBy="user")
*/
private $cars;
// Car Entity
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="cars")
* #ORM\JoinColumn(name="users_id", referencedColumnName="id")
*/
private $user;
So it sill take the user id and populate this against the Car users_id column in that record
So meaning the a user can be associated to many cars

How persist one to one entity unidirectionally in Symfony2

I have a problem with two entities in Symfony2 with Doctrine:
This is the first Entity:
/**
* Pedidos
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="RestCarta\Bundle\FrontendBundle\Entity\PedidosRepository")
*/
class Pedidos
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="usuario", type="string", length=100)
*/
private $usuario;
/**
* #var string
*
* #ORM\Column(name="mesa", type="string", length=3)
*/
private $mesa;
/**
* #var integer
*
* #ORM\OneToOne(targetEntity="Articulos")
* #ORM\JoinColumn(name="articulo_id", referencedColumnName="id")
*/
private $articulo;
/**
* #var string
*
* #ORM\Column(name="precio", type="decimal")
*/
private $precio;
This is the second Entity:
/**
* Articulos
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="RestCarta\Bundle\FrontendBundle\Entity\ArticulosRepository")
*/
class Articulos
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="referencia", type="string", length=100)
*/
private $referencia;
/**
* #var string
*
* #ORM\Column(name="nombre", type="string", length=255)
*/
private $nombre;
/**
* #var string
*
* #ORM\Column(name="descripcion", type="string", length=255)
*/
private $descripcion;
/**
* #var string
*
* #ORM\Column(name="precio", type="decimal")
*/
private $precio;
/**
* #var string
*
* #ORM\Column(name="imagen", type="string", length=255)
*/
private $imagen;
/**
* #ORM\ManyToOne(targetEntity="Categorias", inversedBy="articulos")
* #ORM\JoinColumn(name="categoria_id", referencedColumnName="id")
*/
protected $categoria;
And now the problem.
How i can persist one "Pedido" with contain one "Articulo" ??
I can read all "Pedido" and the LEFT JOIN with "Articulo" work perfectly, (data inserted manually via phpMyAdmin) but when I persist more data with this code:
$em = $this->getDoctrine()->getManager();
$pedido = new Pedidos();
$pedido->setUsuario('blablabla');
$pedido->setMesa('blablabla');
$pedido->setArticulo($identi);
$pedido->setPrecio('blablabla');
$em->persist($pedido);
$em->flush();
$identi = corresponds to an id of "Articulos"
The result is:
Warning: spl_object_hash() expects parameter 1 to be object, string
given in
/Applications/MAMP/htdocs/RestCarta/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php
line 1388 500 Internal Server Error - ContextErrorException
Please, anyone can help me?
Thanks in Advance
$identi must be a entity object, not only the ID you can use
$em->getReference('YourNamespace\Articulos', $identi);

Doctrine2 Map entities with composite foreign keys in the composite primary keys

I have a model which has many tables, but in this case we only need three.
The point is that the composite primary key of one is also the foreing key (composite too) and Symfony throws this exception:
MappingException: It is not possible to map entity 'Your\SomethingBundle\Entity\Empleado' with a composite primary key as part of the primary key of another entity 'Your\SomethingBundle\Entity\EmpleadoHorario#empleado'.
Here I explain the relationship:
1º Salon, it has a primary key ID
2º Empleado, it has a composite primary key ID, Salon_id and, also in the primary key, a foreing key referencing Salon: Salon_id
3º EmpleadoHorario: it has a composite primary key Fecha, Empleado_id, Salon_id and, also in the primary key, two a foreing keys referencing Salon: Salon_id, and Empleado: Empleado_id, Salon_id
All the relations has also the inverse union. Here is the code:
The Salon Entity:
/**
* Salon
*
* #ORM\Table(name="salon")
* #ORM\Entity
*/
class Salon
{
/**
* #var string
*
* #ORM\Column(name="id", type="string", length=50, nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
// More fields...
/**
* #var array_collection
*
* #ORM\OneToMany(targetEntity="Empleado", mappedBy="salon")
*/
private $empleados;
/**
* #var array_collection
*
* #ORM\OneToMany(targetEntity="EmpleadoHorario", mappedBy="salon")
*/
private $empleadoHorarios;
// Getters & Setters...
}
The Empleado Entity:
/**
* Empleado
*
* #ORM\Table(name="empleado")
* #ORM\Entity
*/
class Empleado
{
/**
* #var integer
*
* #ORM\Column(name="id", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
*/
private $id;
/**
* #var string
*
* #ORM\JoinColumn(name="salon_id", referencedColumnName="id", nullable=false)
* #ORM\ManyToOne(targetEntity="Salon", inversedBy="empleados")
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
*/
private $salon;
// More fields...
/**
* #var array_collection
*
* #ORM\OneToMany(targetEntity="EmpleadoHorario", mappedBy="salon")
*/
private $empleadoHorarios;
// Getters & setters...
}
And finally the EmpleadoHorario Entity:
/**
* EmpleadoHorario
*
* #ORM\Table(name="empleado_horario")
* #ORM\Entity
*/
class EmpleadoHorario
{
/**
* #var \DateTime
*
* #ORM\Column(name="fecha", type="date", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
*/
private $fecha;
/**
* #var string
*
* #ORM\JoinColumn(name="salon_id", referencedColumnName="id", nullable=false)
* #ORM\ManyToOne(targetEntity="Salon", inversedBy="empleadoHorarios")
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
*/
private $salon;
/**
* #var integer
*
* #ORM\ManyToOne(targetEntity="Empleado", inversedBy="empleadoHorarios")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="salon_id", referencedColumnName="salon_id", nullable=false),
* #ORM\JoinColumn(name="empleado_id", referencedColumnName="id", nullable=false)
* })
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
*/
private $empleado;
// More fields...
// Getters & Setters...
}
As I said above, the problem seems to be in the EmpleadoHorario.empleado field, which is part of a composite primary key and also composite foreing key.
Other answers across StackOverflow.com suggest the Mapping Inheritance, but I don't even know how it works. I tried twice after reading this but I couldn't solve my problem.
This sample code is illustration of my (temporary) solution :
<?php
namespace X;
use Doctrine\ORM\Mapping as Orm;
/**
* #Orm\Entity
* #Orm\Table(name="A")
*/
class A {
/**
* #Orm\Id
* #Orm\Column(name="id", type="integer")
* #Orm\GeneratedValue(strategy="NONE")
*
* #var integer
*/
private $id;
/**
* #Orm\Id
*
* #var string
*/
private $otherId;
/**
* #Orm\OneToMany(targetEntity="B", fetch="LAZY", mappedBy="a")
*
* #var array
*/
private $collectionOfB;
// getter, setter and other props/methods
}
/**
* #Orm\Entity
* #Orm\Table(name="B")
*/
class B {
/**
* #Orm\Id
* #Orm\Column(name="code")
*
* #var string
*/
private $code;
/**
* #Orm\Id
* #Orm\Column(name="a_id", type="integer")
*
* #var integer
*/
private $a_id;
/**
* #Orm\Id
* #Orm\Column(name="a_other_id")
*
* #var integer
*/
private $a_other_id;
/**
* #Orm\ManyToOne(targetEntity="A", fetch="LAZY", inversedBy="collectionOfB")
* #Orm\JoinColumns({#Orm\JoinColumn(name="a_id", referencedColumnName="id"), #Orm\JoinColumn(name="a_other_id", referencedColumnName="other_id")})
*
* #var A
*/
private $a;
/**
* #Orm\OneToOne(targetEntity="C", fetch="LAZY", mappedBy="b")
*
* #var C
*/
private $c;
// bla bla bla
}
/**
* #Orm\Entity
* #Orm\Table(name="C")
*/
class C {
/**
* #Orm\Id
* #Orm\Column(name="a_id", type="integer")
*
* #var integer
*/
private $a_id;
/**
* #Orm\Id
* #Orm\Column(name="a_other_id")
*
* #var integer
*/
private $a_other_id;
/**
* #Orm\Id
* #Orm\Column(name="b_code")
*
* #var string
*/
private $b_code;
/**
*
* #Orm\OneToOne(targetEntity="B", fetch="LAZY", inversedBy="c")
* #Orm\JoinColumns({#Orm\JoinColumn(name="a_id", referencedColumnName="a_id"), #Orm\JoinColumn(name="a_other_id", referencedColumnName="a_other_id"), #Orm\JoinColumn(name="b_code", referencedColumnName="b_code")})
*
* #var B
*/
private $b;
// bla bla bla
}
Another also ugly solution is just to give AUTOINCREMENT unique PK for EmpleadoHorario like id for instance and remove #ORM\Id and #ORM\GeneratedValue(strategy="NONE") notations from EmpleadoHorario. So finally it will look like:
/**
* EmpleadoHorario
*
* #ORM\Table(name="empleado_horario")
* #ORM\Entity
*/
class EmpleadoHorario
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var \DateTime
*
* #ORM\Column(name="fecha", type="date", nullable=false)
*/
private $fecha;
/**
* #var string
*
* #ORM\JoinColumn(name="salon_id", referencedColumnName="id", nullable=false)
* #ORM\ManyToOne(targetEntity="Salon", inversedBy="empleadoHorarios")
*/
private $salon;
/**
* #var integer
*
* #ORM\ManyToOne(targetEntity="Empleado", inversedBy="empleadoHorarios")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="salon_id", referencedColumnName="salon_id", nullable=false),
* #ORM\JoinColumn(name="empleado_id", referencedColumnName="id", nullable=false)
* })
*/
private $empleado;
// More fields...
// Getters & Setters...
}

Resources