Doctrine 2: inserting data into an entity with associations - php

Solved by adding a conditional when adding a new entity to the database, it checks if the entity is not null... apparently there was null entities trying to get saved. Now the controller code looks like this:
...
$ciudades_id = explode(';', $this->getRequest()->getParam('ciudades_id'));
foreach($ciudades_id as $ciudad_id){
$ciudad = $this->_em->find("Application_Model_Ciudades", intval($ciudad_id));
if($ciudad!= null){
$carrera->getCiudad()->add($ciudad);
}
}
$instituciones_id = explode(';', $this->getRequest()->getParam('instituciones_id'));
foreach($instituciones_id as $institucion_id){
$institucion = $this->_em->find("Application_Model_Instituciones", intval($institucion_id));
if($institucion != null){
$carrera->getInstituciones()->add($institucion);
}
}
...
Thanks to the guys that helped at #doctrine IRC channel :)
This is my problem... I got an entity called "Carreras" (carreers) that has some associations, and the new carreers are added to the database with a web form. A carreer for me is a test, which has questions and other atttributes, and the user can select the cities and institutions that apply for that test.
So i'm getting this error when i try to save new data on the entity:
An error occurred
Application error
Exception information:
Message: A new entity was found through the relationship
'Application_Model_Carreras#ciudad' that was not configured
to cascade persist operations for entity: Doctrine\ORM\UnitOfWork#.
Explicitly persist the new entity or configure cascading persist
operations on the relationship. If you cannot find out which entity
causes the problem implement 'Application_Model_Ciudades#__toString()'
to get a clue.
This is the model for "Carreras"
use Doctrine\Common\Collections\ArrayCollection;
/**
* #Entity
* #Table(name="carreras")
*/
class Application_Model_Carreras
{
/**
* #Id #Column(type="integer")
* #GeneratedValue
*/
private $id;
/** #Column(type="string") */
private $nombre;
/**
* #ManyToMany(targetEntity="Application_Model_PruebasCarrera")
* #JoinTable(name="Carreras_PruebasCarrera",
* joinColumns={#JoinColumn(name="carreras_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="pruebascarrera_id", referencedColumnName="id")}
* )
*/
private $pruebas;
/** #Column(type="integer") */
private $valor;
/** #Column(type="date") */
private $fechainicio;
/** #Column(type="date") */
private $fechafin;
/**
* This association causes error
* #ManyToMany(targetEntity="Application_Model_Ciudades")
* #JoinTable(name="carrera_ciudades",
* joinColumns={#JoinColumn(name="carrera_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="ciudad_id", referencedColumnName="id")}
* )
*/
private $ciudad;
/**
* #ManyToMany(targetEntity="Application_Model_Instituciones")
* #JoinTable(name="carrera_instituciones",
* joinColumns={#JoinColumn(name="carrera_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="institucion_id", referencedColumnName="id")}
* )
*/
private $instituciones;
public function __construct()
{
$this->pruebas = new ArrayCollection();
$this->ciudad = new ArrayCollection();
$this->instituciones = new ArrayCollection();
}
public function setNombre($nombre){
$this->nombre = $nombre;
}
public function setValor($valor){
$this->valor = $valor;
}
public function setFechainicio($fechainicio){
$this->fechainicio = $fechainicio;
}
public function setFechafin($fechafin){
$this->fechafin = $fechafin;
}
public function getCiudad(){
return $this->ciudad;
}
public function getPruebas(){
return $this->pruebas;
}
public function getInstituciones(){
return $this->instituciones;
}
}
Now the action at controller:
/*
* This is an action for adding a new career
*/
public function agregarAction()
{
$formtest = new Admin_Form_AgregarCarrera();
$this->view->formtest = $formtest;
if ($this->getRequest()->isPost() && $this->view->formtest->isValid($this->_getAllParams()))
{
/*
* If the form is okay creating new Carreer model object
* This model has some attributes and three associations (for now)
* you can see them later in detail
*/
$carrera = new Application_Model_Carreras();
$carrera->setNombre($this->getRequest()->getParam("nombre"));
$carrera->setValor($this->getRequest()->getParam("valor"));
$carrera->setFechainicio(new \DateTime($this->getRequest()->getParam("fechainicio")));
$carrera->setFechafin(new \DateTime($this->getRequest()->getParam("fechafin")));
/*
* This is the first association. It's working fine (for now)
*/
$pruebas = $this->getRequest()->getParam("pruebas");
foreach($pruebas as $prueba){
if($prueba != '0'){
$tmp = $this->_em->find("Application_Model_PruebasCarrera", $prueba);
$carrera->getPruebas()->add($tmp);
}
}
/*
* This is the second associations, i'm getting the error with this one
*/
$ciudades_id = explode(';', $this->getRequest()->getParam('ciudades_id'));
foreach($ciudades_id as $ciudad_id){
$ciudad = $this->_em->find("Application_Model_Ciudades", intval($ciudad_id));
$carrera->getCiudad()->add($ciudad);
}
/*
* This is the third one. Nothing to say about this.
*/
$instituciones_id = explode(';', $this->getRequest()->getParam('instituciones_id'));
foreach($instituciones_id as $institucion_id){
$institucion = $this->_em->find("Application_Model_Instituciones", intval($institucion_id));
$carrera->getInstituciones()->add($institucion);
}
$this->_em->persist($carrera);
$this->_em->flush();
//$this->redirector->gotoSimpleAndExit('index','Carrera','admin');
}
}
Well i don't know what else to show... please comment if you can help me :)
--edit
I added cascade={"persist"} in the associations of the model "Carreras" and the error changed:
An error occurred
Application error
Exception information:
Message: Class Doctrine\ORM\UnitOfWork is not a
valid entity or mapped super class.
Now this is "Ciudades" model, it stores the cities available for the test and is associated with the institutions that exist on every city.
use Doctrine\Common\Collections\ArrayCollection;
/**
* #Entity
* #Table(name="ciudades")
*/
class Application_Model_Ciudades {
/**
* #Id #Column(type="integer")
* #GeneratedValue
*/
private $id;
/** #Column(type="string") */
private $ciudad;
/** #Column(type="string") */
private $departamento;
/** #Column(type="string") */
private $pais;
/**
* #ManyToMany(targetEntity="Application_Model_Instituciones")
* #JoinTable(name="Ciudades_Instituciones",
* joinColumns={#JoinColumn(name="ciudades_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="instituciones_id", referencedColumnName="id")}
* )
*/
private $instituciones;
public function __construct()
{
$this->instituciones = new ArrayCollection();
}
public function getCiudad(){
return $this->ciudad;
}
public function getId(){
return $this->id;
}
public function getInstituciones(){
return $this->instituciones;
}
}
Now this is "Instituciones" Model, it stores the institutions available for the tests.
/**
* #Entity
* #Table(name="instituciones")
*/
class Application_Model_Instituciones {
/**
* #Id #Column(type="integer")
* #GeneratedValue
*/
private $id;
/** #Column(type="string") */
private $nombre;
public function getId(){
return $this->id;
}
public function getNombre(){
return $this->nombre;
}
}
Now this is "PruebasCarrera" Model, for me this model entity stores the questions of the tests, and every question can have a partner who supports the question:
use Doctrine\Common\Collections\ArrayCollection;
/**
* #Entity
* #Table(name="pruebas_carrera")
*/
class Application_Model_PruebasCarrera extends Application_Model_PruebasBase{
/**
* #Id #Column(type="integer")
* #GeneratedValue
*/
private $id;
/**
* #ManyToMany(targetEntity="Application_Model_Patrocinadores")
* #JoinTable(name="pruebascarrera_patrocinadores",
* joinColumns={#JoinColumn(name="pruebas_id", referencedColumnName="id", unique="true")},
* inverseJoinColumns={#JoinColumn(name="patrocinadores_id", referencedColumnName="id", unique=false)}
* )
*/
protected $patrocinadores;
/** #Column(type="string") */
private $respuesta;
public function __construct() {
$this->patrocinadores = new ArrayCollection();
}
public function setRespuesta($respuesta){
$this->respuesta = $respuesta;
}
public function getPatrocinadores(){
return $this->patrocinadores;
}
public function getId(){
return $this->id;
}
public function getRespuesta(){
return $this->respuesta;
}
}

Please show code of related entities:
Application_Model_Ciudades
Application_Model_PruebasCarrera
Application_Model_Instituciones
At this moment look https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/working-with-associations.html#transitive-persistence-cascade-operations
At this moment i think you should add cascade={"persist"} to the Application_Model_Ciudades entity.

Related

completely unrelated exception while saving many to many relationship doctrine and php

so, I have multiple entities in my app, between them:
Product* - *Order
User* - 1UserRole
Order
class Order
{
...
/**
* #ManyToMany(targetEntity="Product", inversedBy="orders", cascade={"persist"})
* #JoinTable(
* name="orders_products",
* joinColumns={
* #JoinColumn(name="order_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #JoinColumn(name="product_id", referencedColumnName="id")
* }
* )
*/
private Collection $products;
...
public function __construct()
{
$this->products = new ArrayCollection();
}
...
public function addProduct(Product $product):self
{
$this->products[] = $product;
return $this;
}
}
Product
class Product
{
...
/**
* #ManyToMany(targetEntity="Order", mappedBy="products")
*/
protected Collection $orders;
...
public function __construct()
{
$this->orders = new ArrayCollection();
}
public function addOrder(Order $order): self
{
$this->orders[] = $order;
return $this;
}
}
User
class User
{
/**
* #ManyToOne(targetEntity="UserRole")
* #JoinColumn(name="role_id", referencedColumnName="id")
*/
protected $role;
}
And UserRole:
class UserRole
{
/** #Id #Column(type="integer") #GeneratedValue */
protected $id;
/** #Column(type="string", nullable=false, unique=true, length=20) */
protected $name;
/** #Column(type="integer", unique=true, nullable=false) */
protected $rolePriority;
/**
* Many Users have Many Stores.
* #ManyToMany(targetEntity="UserRoleAction", inversedBy="user_role_actions", fetch="EAGER", cascade={"persist"})
*/
protected Collection $userRoleActions;
/**
* UserRole constructor.
*/
public function __construct()
{
$this->userRoleActions = new ArrayCollection();
}
...
}
Ok so far, my issue is the following, when I try to save a new order that has many selected products:
class OrderService
{
public function createFromRequest(HttpRequest $request)
{
...
$products = $this->entityManager->getRepository(Product::class)->findWhatever(); //products are coming from this without issues.
foreach ($products as $product) {
$order->addProduct($product);
}
$this->entityManager->persist($order);
$this->entityManager->flush();
return $order;
}
}
I get:
Blockquote Expected value of type "UserRole" for association field "User#$role", got "__PHP_Incomplete_Class" instead.
I mean, how is this in any way related with the other entities??? I have no clue where to go to be fair. Any recommendations? Is doctrine doing some absolutely unrelated validation behind the scenes? wth?

Add fields for Sonata UserBundle

I have a question about extending Sonata UserBundle entity. I need to add more fields to the entity.
Firstly, I extended Sonata UserBundle to my project on the folder src\Application\Sonata\UserBundle
Then I tried to add these fields on the User Entity available on the same folder:
<?php
namespace App\Application\Sonata\UserBundle\Entity;
use Sonata\UserBundle\Entity\BaseUser as BaseUser;
/**
* This file has been generated by the SonataEasyExtendsBundle.
*
* #link https://sonata-project.org/easy-extends
*
* References:
* #link http://www.doctrine-project.org/projects/orm/2.0/docs/reference/working-with-objects/en
*/
class User extends BaseUser
{
/**
* #var int $id
*/
protected $id;
/**
* Get id.
*
* #return int $id
*/
public function getId()
{
return $this->id;
}
/**
* #var string
* #ORM\Column(type="string")
*/
protected $accountType;
/**
* #var int
* #ORM\ManyToOne(targetEntity="App\Entity\Specialty")
*/
protected $specialty;
/**
* Get AccountType
* #return string
*/
public function getAccountType()
{
return $this->accountType;
}
/**
* Set AccountType
* #param string $accountType
* #return $this
*/
public function setAccountType($accountType)
{
$this->accountType = $accountType;
return $this;
}
/**
* Get Specialty
* #return int
*/
public function getSpecialty()
{
return $this->specialty;
}
/**
* Set Specialty
* #param int $specialty
* #return Specialty
*/
public function setSpecialty($specialty)
{
$this->specialty = $specialty;
return $this;
}
}
On the fos_user.yml I mapped this entity. But when I try to update my schema, by running this command:
php bin/console doctrine:s:u --force
I have a message that states that Nothing to update - your database is already in sync with the current entity metadata.
The added field isn't added on my table. I'm not an expert on Symfony, so I tried to explain my situation as possible as I can.
Specialty entity:
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Table(name="specialties")
* #ORM\Entity
*/
class Specialty
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Icon")
*/
private $icon;
/**
* #ORM\Column(type="boolean")
*/
private $status;
public function getId()
{
return $this->id;
}
public function setId($id)
{
$this->id = $id;
}
/**
* Get string
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set name
* #param string $name
* #return Specialty
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* #return mixed
*/
public function getIcon()
{
return $this->icon;
}
/**
* #param mixed $icon
* #return $this
*/
public function setIcon($icon)
{
$this->icon = $icon;
return $this;
}
public function getStatus()
{
return $this->status;
}
public function setStatus($status)
{
$this->status = $status;
return $this;
}
public function __toString()
{
return $this->getId() ? (string) $this->getName() : '-';
}
}
Did you run php bin/console make:migration after adjusting the Entity?
php bin/console make:entity (create or update the Entity)
If you prefer to add new properties manually, the make:entity command can generate the getter & setter methods for you: php bin/console make:entity --regenerate
php bin/console make:migration
inspect src/Migrations/ folder
run the migrations php bin/console doctrine:migrations:migrate
read

Doctrine Inheritance and user types

im new to Doctrine and ORM in general.
I got 4 user types (Admin, Caretaker, Child, Personal).
They all got some of the same columns (id, name, mail, password, created, type & group)
and they got a few columns special to each of them (Caretaker has a child id etc.)
I'm not quite sure how i should map this.
Like should i make my user types extend the User, giving the Child table the user columns, or what would be best practice here?
I assume the the option to use extend would force some more work when doing a login?
User.php
/**
* #MappedSuperclass
* #Entity #Table(name="users")
*/
class User
{
/**
* #Id #GeneratedValue #Column(type="integer")
* #var int
**/
protected $id;
/**
* #Column(type="string")
* #var string
**/
protected $name;
/**
* #Column(type="string")
* #var string
**/
protected $mail;
/**
* #Column(type="string")
* #var string
**/
protected $password;
/**
* #Column(type="datetime")
**/
protected $created;
/**
* #Column(type="datetime")
**/
protected $lastlogin;
/**
* #ManyToOne(targetEntity="Group")
* #JoinColumn(name="group_id", referencedColumnName="id")
*/
protected $group;
/**
* #ManyToOne(targetEntity="Type")
* #JoinColumn(name="type_id", referencedColumnName="id")
*/
protected $type;
public function __construct() {}
public function getId() { return $this->id; }
public function getName() { return $this->name; }
public function getMail() { return $this->mail; }
public function getCreated() { return $this->mail; }
public function getLastLogin() { return $this->lastlogin; }
public function getGroup() { return $this->group; }
public function getType() { return $this->type; }
public function setName($name) { $this->name = $name; }
public function setMail($mail) { $this->mail = $mail; }
public function setCreated() { $this->created = new DateTime("now"); }
public function setLastLogin() { $this->lastlogin = new DateTime("now"); }
public function setGroup($group) { $this->group = $group; }
public function setType($type) { $this->type = $type; }
}
Child.php
// src/Child.php
use Doctrine\Common\Collections\ArrayCollection;
/**
* #Entity #Table(name="child")
*/
class Child extends User
{
/**
* #Id #OneToOne(targetEntity="User")
* #JoinColumn(name="id", referencedColumnName="id")
**/
protected $id;
/**
* #Column(type="string")
*/
protected $image;
/**
* #ManyToMany(targetEntity="User")
* #JoinTable(name="child_Contacts",
* joinColumns={#JoinColumn(name="child_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="contact_id", referencedColumnName="id")}
* )
*/
protected $currentContacts;
/**
* #OneToMany(targetEntity="Alarm", mappedBy="child")
*/
protected $alarms;
public function __construct()
{
$this->alarms = new ArrayCollection();
}
}
You can easily solve this problem with doctrine and InheritanceType mapping.
Basically, you can do something like this :
/**
* #MappedSuperclass
* #Entity #Table(name="users")
* #InheritanceType("JOINED")
* #DiscriminatorColumn(name="discr", type="string")
* #DiscriminatorMap({"Admin" = "Admin", "Caretaker" = "Caretaker", "Child" = "Child", "Personal" = "Personal"})
*/
class User
{
/**
* #Id #GeneratedValue #Column(type="integer")
* #var int
**/
protected $id;
/**
* #Column(type="string")
* #var string
**/
protected $name;
/**
* #Column(type="string")
* #var string
**/
protected $mail;
/**
* #Column(type="string")
* #var string
**/
protected $password;
/**
* #Column(type="datetime")
**/
protected $created;
/**
* #Column(type="datetime")
**/
protected $lastlogin;
/**
* #ManyToOne(targetEntity="Group")
* #JoinColumn(name="group_id", referencedColumnName="id")
*/
protected $group;
}
And then, in each 4 different classes,
// src/Child.php
use Doctrine\Common\Collections\ArrayCollection;
/**
* #Entity #Table(name="child")
*/
class Child extends User
{
/**
* #Id #OneToOne(targetEntity="User")
* #JoinColumn(name="id", referencedColumnName="id")
**/
protected $id;
/**
* #Column(type="string")
*/
protected $image;
/**
* #ManyToMany(targetEntity="User")
* #JoinTable(name="child_Contacts",
* joinColumns={#JoinColumn(name="child_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="contact_id", referencedColumnName="id")}
* )
*/
protected $currentContacts;
/**
* #OneToMany(targetEntity="Alarm", mappedBy="child")
*/
protected $alarms;
public function __construct()
{
$this->alarms = new ArrayCollection();
}
}
The doctrine docs is really good for this problem : http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/inheritance-mapping.html
And you don't need an extra check at login because doctrine create automatically the right class for you.

problem in Doctrine Two Entities with many to many relationship , cli tool reports an error when creating schema (SchemaException)

I created two Doctirne entities , which has many to many relationship together in between them. But when i trying to created the db tables from that schema , i am getting a weird exception which is a SchemaException saying "Table with somename already exists" but as i double checked the database , it does not contain any tables at all. Please guide me to resolve this issue. Thanks
Entity Doctor
<?php
use Doctrine\Common\Collections\ArrayCollection;
/**
* #Entity
* #Table(name="doctors")
*/
class Default_Model_Doctor
{
/**
* #Id #Column(type="integer")
* #GeneratedValue(strategy="AUTO")
*/
private $id;
/** #Column(type="string") */
private $name;
/**
* #ManyToMany(targetEntity="Default_Model_Patient", inversedBy="doctors")
* #JoinTable(name="doctors_patients",
* joinColumns={#JoinColumn(name="doctor_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="patient_id", referencedColumnName="id")}
* )
*/
private $patients;
public function __construct()
{
$this->patients = new ArrayCollection();
}
public function setName($string) {
$this->name = $string;
return true;
}
public function getName() {
return $this->name;
}
}
Entity Patient
<?php
use Doctrine\Common\Collections\ArrayCollection;
/**
* #Entity
* #Table(name="doctors")
*/
class Default_Model_Patient
{
/**
* #Id #Column(type="integer")
* #GeneratedValue(strategy="AUTO")
*/
private $id;
/** #Column(type="string") */
private $name;
/**
* #ManyToMany(targetEntity="Default_Model_Doctor", mappedBy="patients")
*/
private $doctors;
public function __construct()
{
$this->doctors = new ArrayCollection();
}
public function setName($string) {
$this->name = $string;
return true;
}
public function getName() {
return $this->name;
}
}
This is the error i receive from Doctrine cli tool when creating the Schema.
Please follow this link for the screenshot i have attached which shows the error clearly.
Change #Table(name="doctors") in your Patients model to #Table(name="patients")

retrieve the Many side of association in Doctrine2

I have two entities one is Role and other is User , I want to build forms and reports to add and show each role with their users , and to create a user with one Role so its User:Role (One-To-Many), I managed to add role to a user via Doctrine 2 but I cannot show users fro each role below is my code
<?php
/**
* Description of Role
* #Entity
* #Table=(name"Roles")
* #author alaaqashou
*/
class Role {
//put your code here
/**
*
* #var integer $id
* #Column(name="id", type="integer",nullable=false)
* #Id
* #GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #Column(length=100,nullable=false,unique=true)
* #var type
*/
private $name;
/**
* #OneToMany(targetEntity="User" ,mappedBy="Role")
* #var type
*/
private $users;
public function __construct() {
$this->users=new \Doctrine\Common\Collections\ArrayCollection();
}
public function getUsers() {
return $this->users;
}
public function setUsers($user) {
$this->users->add($user);
}
}
/**
* Description of User
*#Entity
* #Tabel(name="Users")
* #author alaaqashou
*/
class User {
//put your code here
/**
*
* #var integer $id
* #Column(name="id", type="integer",nullable=false)
* #Id
* #GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
*
* #Column(length=255,nullable=false,unique=true)
*
*
* #var type
*
*/
private $role;
function __construct() {
$this->created=new \DateTime(date("Y-m-d H:i:s"));
}
public function getRole() {
return $this->role;
}
public function setRole($role) {
$this->role = $role;
}
}
I got the Notice: Undefined index: Role error when I try to do the following
my Service
public function listAllRole()
{
return $this->em->getRepository('sihha\Entity\Role')->findAll();
}
$roles=$this->roleService->listAllRole();
$users=$roles[0]->getUsers();
// I even tried $users=$roles[0]->getUsers()->toArray();
$user=$users[0];
Please Help!!!
I think your problem lies in the annotations. Try replacing mappedBy='Role' width mappedBy='role' (i.e. type "role" in lowercase).
I just tried mappedBy="Table" in one of my entities and it gave me the same result you seem to be having.

Categories