Austin
Austin

Reputation: 406

symfony doctrine persist update/insert

I am using symfony with doctrine on a web project. I have a series of entities, one of which is revision, revisions then has a series of one to many relationships. I have am trying to edit a revision and save it as a new row (meaning I want to insert). However, when I persist doctrine updates the existing row instead of inserting. To solve this I explicitly change the revId (the tables primary key) to be different but it still updates. Persist is supposed to know to update if the id is different, so does anyone know why it is updating instead.

Note: I am filling the revision entity with an embedded form containing a series of collection type forms.

Revision Entity

/**
 * @ORM\Entity
 * @ORM\Table(name="policies_revisions")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\RevisionRepo")
 */
class PoliciesRevisions
{
/**
 * @ORM\Id
 * @ORM\Column(type="integer")
 * @ORM\GeneratedValue
 */
private $revId;

/**
 * @ORM\OneToOne(targetEntity="Policies", inversedBy="revisions", cascade={"persist"})
 * @ORM\JoinColumn(name="policy_id", referencedColumnName="policy_id")
 */
private $policies;

/**
 * @ORM\OneToMany(targetEntity="PoliciesApplicability", mappedBy="revision", cascade={"persist"})
 */
private $applicability;

/**
 * @ORM\OneToMany(targetEntity="PoliciesAuthority", mappedBy="revision", cascade={"persist"})
 */
private $authority;

/**
 * @ORM\OneToMany(targetEntity="PoliciesDefinitions", mappedBy="revision", cascade={"persist"})
 */
private $definition;

/**
 * @ORM\OneToMany(targetEntity="PoliciesExclusions", mappedBy="revision", cascade={"persist"})
 */
private $exclusions;

/**
 * @ORM\OneToMany(targetEntity="PoliciesInterpretation", mappedBy="revision", cascade={"persist"})
 */
private $interpretation;

/**
 * @ORM\OneToMany(targetEntity="PoliciesPolicy", mappedBy="revision", cascade={"persist"})
 */
private $policy;

/**
 * @ORM\OneToMany(targetEntity="PoliciesPurposes", mappedBy="revision", cascade={"persist"})
 */
private $purpose;

/**
 * @ORM\OneToMany(targetEntity="PoliciesResponsibilities", mappedBy="revision", cascade={"persist"})
 */
private $responsibilities;

/**
 * @ORM\OneToMany(targetEntity="PoliciesSanctions", mappedBy="revision", cascade={"persist"})
 */
private $sanctions;

/**
 * @ORM\OneToMany(targetEntity="PoliciesProcedures", mappedBy="revision", cascade={"persist"})
 */
private $procedures;

/**
 * @ORM\Column(type="integer")
 */
private $policyId;

/**
 * @ORM\Column(type="integer")
 */
private $submittedDatetime;
/**
 * @ORM\Column(type="integer")
 */
private $publishedDatetime;
/**
 * @ORM\Column(type="integer")
 */
private $createdByUserId;
/**
 * @ORM\Column(type="integer")
 */
private $revNum;
/**
 * @ORM\Column(type="boolean")
 */
private $published;

public function __construct()
{
    $this->applicability = new ArrayCollection();
    $this->authority = new ArrayCollection();
    $this->definition = new ArrayCollection();
    $this->exclusions = new ArrayCollection();
    $this->interpretation = new ArrayCollection();
    $this->policy = new ArrayCollection();
    $this->procedures = new ArrayCollection();
    $this->purpose = new ArrayCollection();
    $this->responsibilities = new ArrayCollection();
    $this->sanctions = new ArrayCollection();
}

Other entities (all follow this form)

/**
 * @ORM\Entity
 * @ORM\Table(name="policies_applicability_two")
 */
class PoliciesApplicability
{
/**
 * @ORM\Id
 * @ORM\Column(type="integer")
 * @ORM\GeneratedValue
 */
private $appId;

/**
 * @ORM\Column(type="integer")
 */
private $revId;

/**
 * @ORM\OneToOne(targetEntity="PoliciesRevisions", inversedBy="applicability", cascade={"persist"})
 * @ORM\JoinColumn(name="rev_id", referencedColumnName="rev_id")
 */
private $revision;

/**
 * @ORM\Column(type="string")
 */
private $applicabilityText;

public function getAppId()
{
    return $this->appId;
}
public function setAppId($appId)
{
    $this->appId = $appId;
}

public function getRevId()
{
    return $this->revId;
}
public function setRevId($revId)
{
    $this->revId = $revId;
}

public function getApplicabilityText()
{
    return $this->applicabilityText;
}
public function setApplicabilityText($applicabilityText)
{
    $this->applicabilityText = $applicabilityText;
}

public function getRevision()
{
    return $this->revision;
}
public function setRevision($revision)
{
    $this->revision = $revision;
}
}

Controller

if ($form->isSubmitted() && $form->isValid()) {

        $entityManager = $this->getDoctrine()->getManager();
        $maxRevNum = $this->getDoctrine()->getRepository(PoliciesRevisions::class)->findMaxRevNum($policyId);
        if ($maxRevNum[0][1] == NULL)
            $task->setRevNum(1);
        else
            $task->setRevNum($maxRevNum[0][1] + 1);

        $nextRevId = $this->getDoctrine()->getRepository(PoliciesRevisions::class)->findMaxRevId($policyId);
        if ($nextRevId[0][1] != NULL)
            $task->setRevId($nextRevId[0][1] + 1);

        $pol = $this->getDoctrine()->getRepository(Policies::class)->findOneBy(['policyId'=>$policyId]);
        $task->setPolicyId($policyId);
        $task->setPolicies($pol);
        $task->setPublished(0);
        $task->setPublishedDatetime(0);

        foreach ($task->getApplicability() as $i=>$object) {
            $object->setRevision($task);
            //print_r($task->getApplicability());
        }
        foreach ($task->getAuthority() as $i=>$object) {
            $object->setRevision($task);
        }
        foreach ($task->getDefinition() as $i=>$object) {
            $object->setRevision($task);
        }
        foreach ($task->getExclusions() as $i=>$object) {
            $object->setRevision($task);
        }
        foreach ($task->getInterpretation() as $i=>$object) {
            $object->setRevision($task);
        }
        foreach ($task->getPolicy() as $i=>$object) {
            $object->setRevision($task);
        }
        foreach ($task->getProcedures() as $i=>$object) {
            $object->setRevision($task);
        }
        foreach ($task->getPurpose() as $i=>$object) {
            $object->setRevision($task);
        }
        foreach ($task->getResponsibilities() as $i=>$object) {
            $object->setRevision($task);
        }
        foreach ($task->getSanctions() as $i=>$object) {
            $object->setRevision($task);
        }

        $entityManager->persist($task);
        $entityManager->flush();

Revision form

$builder->add('applicability', CollectionType::class, array(
        'entry_type' => ApplicabilityForm::class,
        'entry_options' => array('label' => false),
        'allow_add' => true,
        'allow_delete' => true,
        'by_reference' => true,
        'required' => false
    ));

Other forms (follow the same template)

class ApplicabilityForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $MainEntity = $builder->getData();
    $builder
        ->add('applicabilityText', TextareaType::class, array(
            'required' => false,
            'label' => 'Applicability',
            'attr' => array('class' => 'col-sm-10')
        ));
}

/**
 * {@inheritdoc}
 */
public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(array(
        'data_class'=>PoliciesApplicability::class,
    ));
}
}

UPDATE: I fixed some of the problems, by changing the flush line I stopped the old row from updating which is what I wanted.

$entityManager->flush($task);

The revision table is adding a new row with all the information I would expect. However, no rows are added to tables with a foreign key related to revision. I tried to fix this by making the persistent collections with I used to fill the forms to ArrayCollections, this is how I did it

foreach ($task->getApplicability() as $i=>$object) {
            $object->setRevision($task);
            $task->setApplicability(new ArrayCollection());
            $task->getApplicability()->add($object);
        }

This did not fix my problem. Sorry for this question being so long, lots of possibly relevant information.

Upvotes: 1

Views: 14274

Answers (2)

Charlie Lucas
Charlie Lucas

Reputation: 290

You cant simply change the primaryKey, your entity is attach to doctrine. You can detach your entity with :

$em->detach($entity);

Then doing your relations and persist.

or if you using a form i think its better to build your form with a new Object and dont use the object you get with the Request.

PS: Dont do yours onetomanys relations like that, define bidirectionnals relations and/or define new setters in your entity like :

public function setExclusions($exclusions){
    foreach ($exclusions as $exclusion) {
        $exclusion->setRevision($this);
    }
}

Upvotes: 0

Pavel Alazankin
Pavel Alazankin

Reputation: 1395

You should not change existed entity and then try to save it as new. Instead of this you should create new instance of your entity, fill it with new values and then save:

  if ($form->isSubmitted() && $form->isValid()) {

      $newTask = new Task();
      ...
      $newTask->setPolicyId($policyId);
      $newTask->setPolicies($pol);
      $newTask->setPublished(0);
      $newTask->setPublishedDatetime(0);
      ...
      $entityManager->persist($newTask);
      $entityManager->flush();
  }

Upvotes: 1

Related Questions