I am having this strange issue with Doctrine .
When I use find(id) to find an entity, all fields are null except the id. I have double checked the values in database and they are are not null.
The strange thing is when I issue a native mysql query and try to find the entity that doctrine tries to fetch I get non Null value so probably it's a doctrine way of fetching values problem.
Here is my entity :
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
*
*
* #ORM\Entity()
* #ORM\Table(name="hui_address")
*/
class Address
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="integer", nullable=true)
*/
protected $client_id;
/**
* #ORM\Column(type="integer", nullable=true)
*/
protected $region_id;
/**
* #ORM\Column(type="text", nullable=true)
*/
protected $street;
/**
* #ORM\Column(type="text", nullable=true)
*/
protected $city;
/**
* #ORM\Column(name="`state`", type="text", nullable=true)
*/
protected $state;
/**
* #ORM\Column(type="text", nullable=true)
*/
protected $zip_code;
/**
* #ORM\Column(type="float", precision=10, scale=6, nullable=true)
*/
protected $latitude;
/**
* #ORM\Column(type="float", precision=10, scale=6, nullable=true)
*/
protected $longitude;
/**
* #ORM\Column(type="text", nullable=true)
*/
protected $notes;
/**
* #ORM\Column(name="`status`", type="boolean", nullable=true)
*/
protected $status;
/**
* #ORM\Column(type="smallint", nullable=true)
*/
protected $archive;
/**
* #ORM\Column(type="datetime")
*/
protected $created_at;
/**
* #ORM\OneToMany(targetEntity="Store", mappedBy="address")
* #ORM\JoinColumn(name="id", referencedColumnName="address_id")
*/
protected $Stores;
/**
* #ORM\ManyToOne(targetEntity="Client", inversedBy="Addresses")
* #ORM\JoinColumn(name="client_id", referencedColumnName="id")
*/
protected $client;
/**
* #ORM\OneToMany(targetEntity="Client", mappedBy="PPBAddress")
* #ORM\JoinColumn(name="id", referencedColumnName="ppb_address_id")
*/
protected $clientHQ;
/**
* #ORM\ManyToOne(targetEntity="Region", inversedBy="Addresses")
* #ORM\JoinColumn(name="region_id", referencedColumnName="id")
*/
protected $region;
public function __construct()
{
if (!$this->created_at) {
$this->created_at = new \DateTime();
}
$this->Clients = new ArrayCollection();
$this->Stores = new ArrayCollection();
}
public function __toString()
{
return (!$this->street || strlen($this->street) == 0 || !$this->city || !$this->city)
? "Address incomplete"
: sprintf('%s, %s %s %s', $this->street, $this->city, $this->state, $this->zip_code);
}
public function __sleep()
{
return array('id', 'client_id', 'region_id', 'street', 'city', 'state', 'zip_code', 'latitude', 'longitude', 'notes', 'status', 'archive', 'created_at');
}
}
You are missing getters and setters in the entity class.
php bin/console doctrine:generate:entities *your bundle*
will generate them automatically
There was nothing wrong with doctrine. It turns out that the address is fetched from a native query and only the id is selected , that's why I am getting the value for id and null for the rest.
This is how addresses are found :
$query = $this->getManager()->createNativeQuery('SELECT .... ')
Related
I have 3 entities which are User, Problem and Submission. I'm trying to restrict a user from solving the same question more than once if that user already solved it. I created a method in User entity by checking the Submissions for each user. However I couldn't figure out a way to match the problem_id and user_id fields so I can see if the submission was correct or not.
Here are the entites;
Problem.php
class Problem
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=255, unique=True)
* #Assert\NotBlank(message="Please enter a valid title")
*/
protected $title;
/**
* #ORM\Column(type="text")
* #Assert\NotBlank(message="Please enter a valid description")
*/
protected $description;
/**
* #ORM\Column(type="string")
* #Assert\NotBlank(message="Please enter a valid value")
*/
protected $points;
/**
* #ORM\Column(type="string")
* #Assert\NotBlank(message="Please enter a valid flag")
*/
protected $flag;
/**
* #ORM\Column(type="string")
* #Assert\NotBlank(message="Please enter a valid value")
*/
protected $category;
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\User", inversedBy="problems")
* #ORM\JoinColumn(name="createdby", referencedColumnName="id")
*/
protected $createdby;
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\Submission", mappedBy="problem_id")
*/
protected $submissions;
/**
* #Gedmo\Slug(fields={"title"})
* #ORM\Column(type="string", length=255, unique=false,)
*/
protected $slug;
/**
* #ORM\Column(type="datetime")
*/
private $createdAt;
/**
* #ORM\Column(type="datetime")
*/
private $updatedAt;
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\Discussion", mappedBy="problem")
*/
private $discussions;
/**
* #ORM\Column(type="boolean")
*/
protected $isPublished = True;
}
Submission.php
class Submission
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Problem", inversedBy="submissions")
* #ORM\JoinColumn(name="problem_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $problem_id;
/**
* #ORM\Column(type="boolean")
*/
protected $correct = false;
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\User", inversedBy="submissions")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user_id;
/**
* #ORM\Column(type="string")
* #Assert\NotBlank(message="Flag cannot be blank")
*/
protected $submission_flag;
/**
* #ORM\Column(type="datetime")
*/
private $createdAt;
/**
* #ORM\Column(type="datetime")
*/
private $updatedAt;
}
User.php
class User implements UserInterface
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=255, unique=true)
* #Assert\NotBlank(message="Please enter a valid email address")
* #Assert\Email()
*/
private $username;
/**
* #ORM\Column(type="string", length=255, unique=true)
* #Assert\NotBlank(message="Please enter a valid email address")
*/
private $usrname;
/**
* #Assert\NotBlank()
* #Assert\Length(max=4096)
*/
private $plainPassword;
/**
* The below length depends on the "algorithm" you use for encoding
* the password, but this works well with bcrypt.
*
* #ORM\Column(type="string", length=64)
*/
private $password;
/**
* #ORM\Column(type="string", length=255, unique=true)
* #Assert\NotBlank(message="Please enter a valid name")
*/
private $fullname;
/**
* #var array
* #ORM\Column(name="roles", type="json_array")
*/
protected $roles;
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\Problem", mappedBy="createdby")
*/
protected $problems;
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\Feed", mappedBy="createdby")
*/
protected $feeds;
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\Comment", mappedBy="createdby")
*/
protected $comments;
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\Submission", mappedBy="user_id")
*/
protected $submissions;
}
You may be able to try #UniqueConstraint on your Submission entity. Something like:
/**
* #Entity
* #Table(uniqueConstraints={#UniqueConstraint(name="unique_user_submission", columns={"name", "email"})})
*/
class Submission
{
}
I think that'll make those two fields a composite unique field.
http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/annotations-reference.html#annref-uniqueconstraint
I have defined two database entities
Project:
use Doctrine\ORM\Mapping as ORM;
use \Kdyby\Doctrine\Entities\MagicAccessors;
/**
* #ORM\Entity
*/
class Project extends \Kdyby\Doctrine\Entities\BaseEntity
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
public $id;
/**
* #ORM\Column(type="string")
*/
public $title;
/**
* #ORM\Column(type="text")
* #var string
*/
public $description;
/**
* #ORM\Column(type="datetime", nullable=true)
* #var DateTime
*/
public $created;
/**
* #ORM\Column(type="boolean")
* #var string
*/
public $public;
/**
* #ORM\Column(type="blob")
* #var string
*/
public $thumbnail;
public function __construct()
{
$this->created = new \DateTime();
$this->public = 0;
}
}
and Personage:
use Doctrine\ORM\Mapping as ORM;
use \Kdyby\Doctrine\Entities\MagicAccessors;
/**
* #ORM\Entity
*/
class Personage extends \Kdyby\Doctrine\Entities\BaseEntity
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
public $id;
/**
* #ORM\Column(type="string")
*/
public $name;
/**
* #ORM\Column(type="text", nullable=true)
* #var string
*/
public $shortDescription;
/**
* #ORM\Column(type="text", nullable=true)
* #var string
*/
public $playerDescription;
/**
* #ORM\Column(type="datetime")
* #var DateTime
*/
public $created;
/**
* #ORM\Column(type="integer")
* #var string
*/
public $creator;
/**
* #ORM\Column(type="boolean", options={"default" = false})
* #var boolean
*/
public $inGraph;
/**
* #ORM\Column(type="boolean", nullable=false, options={"default" = 0})
* #var boolean
*/
public $deleted;
/**
* #ORM\ManyToOne(targetEntity="Project", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="project", referencedColumnName="id", onDelete="CASCADE")
* #var string
*/
public $project_id;
public function __construct()
{
$this->deleted = 0;
$this->inGraph = 0;
}
}
Every Personage entity belongs to some project. But whenever I try to remove Personage either this way:
public function removeChar($id)
{
$a = $this->EntityManager->find('App\Personage', $id);
if($a->deleted)
{
$this->EntityManager->remove($a);
$this->EntityManager->flush();
}
}
or using dql. It removes the whole project row as well. What i want is whenever project is removed it removes all characters corresponding but NOT other way around.
I tried to remove
cascade={"persist", "remove"}
part from Project entity declaration (and updating database via console) but it said everything was in sync and did nothing. So I removed whole database and build it without cascade={"persist", "remove"}, but the problem was not solved.
remove onDelete="CASCADE" from
#ORM\JoinColumn(name="project", referencedColumnName="id", onDelete="CASCADE")
and add
#ORM\OneToMany(targetEntity="Personage", mappedBy="project_id",cascade={"remove"})
private $personages;
in the project entity.
I'm very new to symfony2 and i want to create a form. The values of fields should base on user data.
I have projects and users with a n:m-relation and now i want to embed a form in twig where I can assign users (multiple with one click) and projects. My class for user looks like:
// src/Pso/LogBundle/Entity/User.php
namespace Pso\LogBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Table(name="users", options={"collate"="utf8_general_ci", "charset"="utf8", "engine"="InnoDB"})
* #ORM\Entity(repositoryClass="Pso\LogBundle\Entity\UserRepository")
*/
class User implements AdvancedUserInterface, \Serializable
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=25, unique=true)
*/
private $username;
/**
* #ORM\Column(type="string", length=32)
*/
private $salt;
/**
* #ORM\Column(type="string", length=250)
*/
private $password;
/**
* #ORM\Column(type="string", length=60, unique=true)
*/
private $email;
/**
* #ORM\Column(name="is_active", type="boolean")
*/
private $isActive;
/**
* #ORM\ManyToMany(targetEntity="Role", inversedBy="users")
* #ORM\JoinTable(name="user_role",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="role_id", referencedColumnName="id")}
* )
*
*/
private $roles;
The class for project looks like:
// src/Pso/ProjectBundle/Entity/Project.php
namespace Pso\ProjectBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Table(name="project", options={"collate"="utf8_general_ci", "charset"="utf8", "engine"="InnoDB"})
* #ORM\Entity(repositoryClass="Pso\ProjectBundle\Entity\ProjectRepository")
*/
class Project
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id()
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=255, unique=true, nullable=false)
*/
private $project_nr;
/**
* #ORM\ManyToOne(targetEntity="Pso\ProjectBundle\Entity\Mandator", inversedBy="projects")
* #ORM\JoinColumn(name="mandator_id", referencedColumnName="id")
*/
private $mandator;
/**
* #ORM\Column(type="string", length=80, nullable=false)
*/
private $project_name;
/**
* #ORM\Column(type="string", length=50)
*/
private $customer;
/**
* #ORM\Column(type="string", length=50)
*/
private $label;
/**
* #ORM\Column(type="date")
*/
private $shipping_date;
/**
* #ORM\Column(type="float")
*/
private $advance_payment;
/**
* #ORM\Column(type="integer", length=1)
*/
private $probability;
/**
* #ORM\Column(type="blob")
*/
private $special_demand;
/**
* #ORM\Column(type="string", length=4)
*/
private $currency;
/**
* #ORM\Column(type="integer", length=1, nullable=false)
*/
private $status;
/**
* #ORM\Column(type="string", length=100)
*/
private $contract_nr;
/**
* #ORM\Column(type="datetime", nullable=false)
*/
private $dbinsert;
/**
* #ORM\Column(type="datetime", nullable=false)
*/
private $dbupdate;
/**
* #ORM\ManyToMany(targetEntity="Pso\LogBundle\Entity\User", cascade={"persist", "remove"})
*/
private $users;
public function __construct() {
$this->user = new \Doctrine\Common\Collections\ArrayCollection();
}
My ProjectuserType looks like:
namespace Pso\ProjectBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
use Doctrine\ORM\EntityRepository;
class ProjectuserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('project','text')
;
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) {
$form = $event->getForm();
$formOptions = array(
'class' => 'Pso\LogBundle\Entity\User',
'property' => 'username',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('x')->FROM('PsoLogBundle:user', 'u')
->WHERE('u.id = :id')
->setParameter('id',5)
;
// or call a method on your repository that returns the query builder
// the $er is an instance of your UserRepository
// return $er->findnotsignedusers();
},
);
// or call a method on your repository that returns the query builder
// the $er is an instance of your UserRepository
// return $er->createOrderByFullNameQueryBuilder();
},
);
// create the field, this is similar the $builder->add()
// field name, field type, data, options
$form->add('user', 'entity', $formOptions);
}
);
}
public function getName()
{
return 'Projectuser';
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => null,
));
}
}
With the Type I oriented on the post and on documentation about chapter "How to dynamically Generate Forms Based on user Data"
With my Code I always get the error "Class Pso\ProjectBundle\Form\EntityRepository does not exist". I think I doesn't get right documentation. I don't want to get the data out of my ProjectRepository. This exists but the namespace is Pso\ProjectBundle\Form.
But my intention ist to get the data with the querybuilder in my EventListener. Every tipp would be appreciated.
Add this line in your ProjectuserType class : use Doctrine\ORM\EntityRepository
Hope it's helpful.
Best regards.
I got hired about 2 weeks in a company, and my first task was to update and implement new features in an existing software written in symfony2-doctrine. But one of the changes I must make is just breaking my back.
The previous model was: one "cliente" (costumer) could have only one "credito" (credit) and one "credito" could have many "venta" (sales)
The new model should be: one "cliente" (costumer) can have many "credito" and one "credito" can have many "venta" (Im keeping the onetomany association for backwards compatibity)
This is how my entities look like this:
cliente.php
class Cliente {
//put your code here
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #ORM\Column(type="string")
* #Assert\NotBlank()
*/
protected $nombre;
/**
* #ORM\Column(type="string", unique=true)
* #Assert\NotBlank()
*/
protected $documento;
/**
* #ORM\Column(type="string", nullable=true)
*/
protected $direccion;
/**
* #ORM\Column(type="string", nullable=true)
*/
protected $telefono;
/**
* #ORM\Column(type="string", nullable=true)
*/
protected $celular;
/**
* #ORM\Column(type="string", nullable=true)
* #Assert\Email()
*/
protected $email;
/**
* #ORM\Column(type="string", nullable=true)
*/
protected $ciudad;
/**
* #ORM\Column(type="string", nullable=true)
*/
protected $departamento;
/**
* #ORM\Column(type="string", nullable=true)
*/
protected $referenciaFamiliar;
/**
* #ORM\Column(type="string", nullable=true)
*/
protected $referenciaFamiliarTelefono;
/**
* #ORM\Column(type="string", nullable=true)
*/
protected $referenciaPersonal;
/**
* #ORM\Column(type="string", nullable=true)
*/
protected $referenciaPersonalTelefono;
/**
* #ORM\OneToMany(targetEntity="Credito", mappedBy="cliente", cascade={"all"})
*/
protected $credito;
/**
* #ORM\Column(type="string", nullable=true, length=255)
*/
protected $photo;
/**
* #Assert\File(maxSize="300k", mimeTypes={"image/jpeg","image/png"},mimeTypesMessage="Debe subir una imagen JPG o PNG",maxSizeMessage="La imagen no puede pesar más de 300 kb.")
*/
protected $file;
credito.php
class Credito {
//put your code here
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #ORM\Column(type="string",nullable=true)
* #Assert\NotBlank()
*/
protected $cc;
/**
* #ORM\Column(type="datetime",nullable=false)
* #Assert\DateTime()
*/
protected $fechaRegistro;
/**
* #ORM\ManyToOne(targetEntity="Cliente",cascade={"persist"})
* #ORM\JoinColumn(name="cliente_id",referencedColumnName="id")
*/
protected $cliente;
/**
* #ORM\OneToMany(targetEntity="Venta", mappedBy="credito",cascade={"all"})
*/
protected $ventas;
/**
* #ORM\OneToMany(targetEntity="Abono", mappedBy="credito",cascade={"persist"})
*/
protected $abonos;
/**
* #ORM\Column(type="datetime",nullable=true)
* #Assert\DateTime()
*/
protected $fechaProximoPago;
/**
* #ORM\Column(type="decimal",scale=3, precision=23)
* #Assert\NotBlank()
*/
protected $valorProximoPago;
/**
* #ORM\Column(type="integer")
* #Assert\NotBlank()
*/
protected $cuotasTotales;
/**
* #ORM\Column(type="integer")
* #Assert\NotBlank()
*/
protected $cuotasPagadas;
/**
* #ORM\ManyToOne(targetEntity="ModoPagoNom")
* #ORM\JoinColumn(name="modo_pago_id",referencedColumnName="id")
*/
protected $modoPago;
/**
* #ORM\Column(type="decimal",scale=3, precision=23)
* #Assert\NotBlank()
*/
protected $valorFinanciado;
/**
* #ORM\Column(type="decimal",scale=3, precision=23)
* #Assert\NotBlank()
*/
protected $cupo;
/**
* #ORM\Column(type="decimal",scale=3, precision=23)
* #Assert\NotBlank()
*/
protected $cupoUsado;
venta.php
class Venta{
//put your code here
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #ORM\Column(type="datetime")
* #Assert\DateTime()
*/
protected $fecha;
/**
* #ORM\Column(type="datetime")
* #Assert\DateTime()
*/
protected $fechaPrimerPago;
/**
* #ORM\Column(type="string")
* #Assert\NotBlank()
*/
protected $numeroFactura;
/**
* #ORM\Column(type="string")
* #Assert\NotBlank()
*/
protected $numeroAutorizo;
/**
* #ORM\Column(type="decimal",scale=3, precision=23)
* #Assert\Min(limit="0", message="El valor de la factura debe ser positivo")
*/
protected $valorFactura;
/**
* #ORM\Column(type="integer")
* #Assert\Type("integer")
* #Assert\Min(limit="1", message="Debe especificar al menos una cuota")
*/
protected $numeroCuotas;
/**
* #ORM\Column(type="integer")
* #Assert\Min(0)
*/
protected $cuotasPagadas;
/**
* #ORM\ManyToOne(targetEntity="ModoPagoNom")
* #ORM\JoinColumn(name="modo_pago_id",referencedColumnName="id")
*/
protected $modoPago;
/**
* #ORM\ManyToOne(targetEntity="Credito",cascade={"persist"})
* #ORM\JoinColumn(name="credito_id",referencedColumnName="id")
*/
protected $credito;
/**
* #ORM\Column(type="decimal",scale=3, precision=23)
* #Assert\Min(0.0)
*/
protected $valorFinanciado;
/**
* #ORM\Column(type="decimal",scale=3, precision=23)
* #Assert\Min(0.0)
*/
protected $valorCuota;
/**
* #ORM\Column(type="decimal",scale=3, precision=23)
* #Assert\Min(0.0)
*/
protected $valorPrimeraCuota;
/**
* #ORM\ManyToOne(targetEntity="Almacen")
* #ORM\JoinColumn(name="almacen_id",referencedColumnName="id")
*/
protected $almacen;
/**
* Get id
*
* #return integer
*/
The problem is: everytime I insert a new "credito", it wont be linked to the existing "cliente" instead of that, it will try to insert a duplicate entry of "cliente".
I've tried many things but none of them had any effect.
I appreciate any help, cause Im stuck with that.
If further information or code is required I will gladly provide it.
The cascade={"persist"} should be the core of your problem:
class Credito {
......
/**
* #ORM\ManyToOne(targetEntity="Cliente",cascade={"persist"})
* #ORM\JoinColumn(name="cliente_id",referencedColumnName="id")
*/
protected $cliente;
It tells doctrine to persist cleinte always when you persist Credito.
See docs for more details http://doctrine-orm.readthedocs.org/en/latest/reference/working-with-associations.html#transitive-persistence-cascade-operations
Always tell Doctrine how to do in both sides of an association :
// credito.php
/**
* #ORM\ManyToOne(targetEntity="Cliente", inversedBy="credito", cascade={"persist"})
* #ORM\JoinColumn(name="cliente_id",referencedColumnName="id")
*/
protected $cliente;
And
// venta.php
/**
* #ORM\ManyToOne(targetEntity="Credito", inversedBy="ventas", cascade={"persist"})
* #ORM\JoinColumn(name="credito_id",referencedColumnName="id")
*/
protected $credito;
In this problem Deep Cloning I thought my issue was due to a deep/shallow copy.
I have vainly tested clone() and unserialize(serialize()) methods.
So I tried to write my own clone function using all setters/getters and then I realized what was really my issue, a persisting one.
The fact is I already succeeded in persisting a clone of my entity, in another context.
The main difference between my two situations is that in one case my original object is already managed by doctrine (this is the case where i'm blocked), and in the second case, my original object is just persisted, I don't have called flush() yet (and it's works fine).
So this is the situation when persist do not persist the many to many relations :
public function duplicateCourseAction(Request $request) {
if ($this->getRequest()->isXmlHttpRequest() == false) {
return new Response("Bad request", 405);
}
$em = $this->getDoctrine()->getManager();
$parameters = $request->request->all();
$course = $em->getRepository('EntTimeBundle:Course')->findOneById($parameters['id']);
$duplicate = clone $course;
$duplicate->setId(null);
$duplicate->setDate(new \DateTime($parameters['date']));
$em->persist($duplicate);
$em->flush();
return new Response("200");
}
And this is the situation whe it's works like a charm
$em->persist($obj);
while ($new_date < $up_to) {
if ($this->isAvailable($holidays, $new_date)) {
$new_course = clone $obj;
$new_course->setDate($new_date);
$new_course->setUuid($uuid);
$new_date = clone $new_date;
$em->persist($new_course);
}
$new_date->modify($modifier);
}
$em->flush();
Why is it working for only one situation ? There are almost identical...
EDIT 1 : Entities Mapping
-Course :
class Course {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=50, unique=true, nullable=true)
*/
protected $name;
/**
* #ORM\JoinColumn(onDelete="CASCADE")
* #ORM\ManyToOne(targetEntity="Ent\HomeBundle\Entity\Campus", inversedBy="courses")
* #Assert\NotBlank
**/
protected $campus;
/**
* #ORM\JoinColumn(onDelete="CASCADE")
* #ORM\ManyToOne(targetEntity="Ent\HomeBundle\Entity\Room", inversedBy="courses")
* #Assert\NotBlank
**/
protected $room;
/**
* #ORM\ManyToMany(targetEntity="Ent\UserBundle\Entity\User", inversedBy="courses", cascade={"persist"})
* #ORM\JoinTable(name="course_teacher",
* joinColumns={#ORM\JoinColumn(name="course_id", referencedColumnName="id", onDelete="CASCADE")},
* inverseJoinColumns={#ORM\JoinColumn(name="teacher_id", referencedColumnName="id", onDelete="CASCADE")}
* )
* #Assert\NotBlank
*/
private $teachers;
/**
* #ORM\JoinColumn(onDelete="CASCADE")
* #ORM\ManyToOne(targetEntity="Matter", inversedBy="courses")
* #Assert\NotBlank
**/
protected $matter;
/**
* #ORM\JoinColumn(onDelete="CASCADE")
* #ORM\ManyToOne(targetEntity="\Ent\UserBundle\Entity\Grade", inversedBy="courses")
* #Assert\NotBlank
**/
protected $grade;
/**
* #ORM\Column(type="datetime")
* #Assert\NotBlank
**/
protected $date;
/**
* #ORM\Column(type="time")
* #Assert\NotBlank
**/
protected $duration;
/**
* #ORM\Column(type="string", length=30, nullable=true)
*/
protected $uuid;
/**
* #ORM\ManyToMany(targetEntity="Ent\TimeBundle\Entity\Course", mappedBy="courses")
* #Exclude
*/
protected $alerts;
public function __toString() {
if (empty($this->getName())) {
$string = $this->getMatter().' - '.$this->getRoom().' - ';
foreach ($this->getTeachers() as $count => $teacher) {
$string = $string . $teacher;
if ($count < count($this->getTeachers()) - 1) {
$string = $string . ', ';
}
}
return $string;
} else {
return $this->getName().' - '.$this->getRoom();
}
}
/**
* Constructor
*/
public function __construct() {
$this->teachers = new ArrayCollection();
$this->alerts = new ArrayCollection();
}
public function __clone() {
// $this->id = null;
// $this->teachers = clone $this->teachers;
}
}
-User (Teacher) :
class User implements UserInterface, \Serializable {
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=30)
* #Assert\NotBlank
*/
protected $firstName;
/**
* #ORM\Column(type="string", length=30)
* #Assert\NotBlank
*/
protected $lastName;
/**
* #ORM\Column(type="string", length=70, unique=true)
* #Assert\NotBlank
*/
protected $username;
/**
* #Gedmo\Slug(fields={"username"}, updatable=false)
* #ORM\Column(length=50, unique=true)
*/
protected $slug;
/**
* #ORM\Column(type="string", length=32)
* #Exclude
*/
protected $salt;
/**
* #ORM\Column(type="string", length=40)
* #Exclude
*/
protected $password;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
protected $picture_path;
/**
* #Assert\File(maxSize="10M", mimeTypesMessage="Please upload a valid Image")
*/
protected $picture;
/**
* #ORM\Column(type="string", length=60, unique=true)
* #Exclude
* #Assert\NotBlank
*/
protected $email;
/**
* #ORM\Column(name="is_active", type="boolean")
*/
protected $isActive;
/**
* #ORM\ManyToOne(targetEntity="Group", inversedBy="users")
* #ORM\JoinColumn(name="role_group", referencedColumnName="role", onDelete="CASCADE")
*/
protected $group;
/**
* #ORM\ManyToMany(targetEntity="Ent\HomeBundle\Entity\Campus", inversedBy="users")
* #Exclude
**/
protected $campuses;
/**
* #ORM\OneToMany(targetEntity="\Ent\NewsBundle\Entity\News", mappedBy="user")
* #Exclude
*/
protected $news;
/**
* #ORM\ManyToMany(targetEntity="\Ent\TimeBundle\Entity\Matter", inversedBy="teachers", cascade={"persist"})
* #ORM\JoinTable(name="user_matter",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCADE")},
* inverseJoinColumns={#ORM\JoinColumn(name="matter_id", referencedColumnName="id", onDelete="CASCADE")}
* )
*/
protected $matters;
/**
* #ORM\ManyToMany(targetEntity="Ent\UserBundle\Entity\Grade")
* #Assert\NotBlank
* #Exclude
**/
protected $grades;
/**
* #ORM\ManyToMany(targetEntity="Ent\TimeBundle\Entity\Course", mappedBy="teachers")
* #Exclude
**/
protected $courses;
/**
* #ORM\OneToMany(targetEntity="\Ent\TimeBundle\Entity\Alert", mappedBy="teacher")
* #Exclude
**/
protected $alerts;
protected $temp;
public function __construct() {
$this->isActive = true;
$this->salt = md5(uniqid(null, true));
}
public function __toString() {
return $this->getFullName();
}
}
EDIT 2 : Solution
Thanks to Paul Andrieux this is the function we made to clone my object :
public function course_deep_clone($course) {
$em = $this->getDoctrine()->getManager();
$clone = clone $course;
$clone->setTeachers(array());
$teachers = $course->getTeachers();
foreach ($teachers as $teacher) {
$clone->addTeacher($teacher);
}
return $clone;
}
Thing is that ManyToMany related entities are not cloned, try that:
public function duplicateCourseAction(Request $request) {
if ($this->getRequest()->isXmlHttpRequest() == false) {
return new Response("Bad request", 405);
}
$em = $this->getDoctrine()->getManager();
$parameters = $request->request->all();
$course = $em->getRepository('EntTimeBundle:Course')->findOneById($parameters['id']);
$duplicate = clone $course;
$teachers = $course->getTeachers();
$duplicate->setTeachers($teachers);
$duplicate->setId(null);
$duplicate->setDate(new \DateTime($parameters['date']));
$em->persist($duplicate);
$em->flush();
return new Response("200");
}
This way, you are persisting new relationship and new join table between you two entities
EDIT:
Maybe its a cascading problem, what gives you this ? :
$teachers = $course->getTeachers();
foreach ($teachers as $teacher) {
$teacher->addCourse($duplicate);
$em->persist($teacher);
}