Search code examples
phpdoctrine-ormzend-framework2persist

Error when doctrine persist many-to-one (people-to-company) duplicate company when saving


What do I want

I have saved in session an object of type App\Model\Company and at the time of inserting a new customer I need to proper reference is made to this company already registered.

Currently this happens

When saving a new record of App\Model\People, a new record of App\Model\ Company is created (with the same data record that is in session) and the new record of Crm\Model\People who I want to create is being related to the new App\Model\Company registration and not to the previous record.

Here's my People entity:

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="tbl_crm_people")
 */
class People extends Entity
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer");
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $people_id;

    /**
     * @ORM\ManyToOne(targetEntity="App\Model\Company", cascade={"all"})
     * @ORM\JoinColumn(name="people_company_id", referencedColumnName="company_id")
     */
    protected $people_company;

    /**
     * @ORM\Column(type="string", length=60)
     */
    protected $people_name;
}

and my Company entity

<?php
namespace App\Model;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="tbl_app_company")
 */
class Company extends Entity
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer");
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $company_id;

    /**
     * @ORM\Column(type="string", length=250)
     */
    protected $company_name;

    public function getId()
    {
        return $this->company_id;
    }
}

and the action:

public function saveAction()
{
    //INSTANCIA UM FORMULARIO
    $form = new PeopleForm();

    //INFORMAÇÕES SOBRE A REQUISIÇÃO
    $request = $this->getRequest();

    //SE TIVER SIDO UMA REQUIZIÇÃO POST
    if ($request->isPost()) {
        $people = new People;
        $form->setInputFilter($people->getInputFilter());
        $form->setData($request->getPost());

        // CASO O FORMULÁRIO SEJA VÁLIDO
        if ($form->isValid()) {

            // RECEBE DA SESSÃO UM OBETO REFERENTE AO USUÁRIO LOGADO
            $CurrentUser = $this->CurrentUserInfo();

            // ORGANIZA A ESTRUTURA DAS INFORMAÇÕES A SEREM SALVAS
            $data = $form->getData();
            unset($data['submit']);

            // DEFINE O ITEM COM UM OBJETO DO TIPO APP\MODEL\COMPANY
            $data['people_company'] = $CurrentUser->getCompany();

            //CASO SEJA ATUALIZAÇÃO EU SELECIONO O REGISTRO
            if (isset($data['people_id']) && $data['people_id'] > 0) {
                $people = $this->getEntityManager()->find('Crm\Model\People', $data['people_id']);
            }

            // PREENCHO O REGISTRO COM O RESTANTE DOS DADOS
            $people->setData($data);

            // SALVO O REGISTRO
            $this->getEntityManager()->persist($people);
            $this->getEntityManager()->flush();

            return $this->redirect()->toUrl('/crm/people/index');
        }
    }

    //SE FOR VISUALIZAÇÃO DO FORM
    $this->getServiceLocator()->get('ViewHelperManager')->get('HeadTitle')->set('Novo');
    $people_id = (int) $this->params()->fromRoute('id', 0);
    if ($people_id > 0) {
        $this->getServiceLocator()->get('ViewHelperManager')->get('HeadTitle')->set('Edição');
        $people = $this->getEntityManager()->find('Crm\Model\People', $people_id);

        $form->bind($people);
        $form->get('submit')->setAttribute('value', 'Salvar alteração');
    }

    //GERA A VISUALIZAÇÃO
    return new ViewModel(
        array('form' => $form)
    );
}

Solution

  • I would say you should try removing the cascade={"all"} from your People entity. You should only add this if you want to create/delete/update a company while you create/delete/update a user. I guess this is not the behavior you want. The cascade operation is why a new company is created when you post a new user.

    In principle it should not create a new company if the record already exists. So I guess there is also something inconsistent happening in your saveAction.

    Are you sure that $CurrentUser->getCompany() is returning a proper entity of type App\Model\Company

    Would it not better to create a method to set the company in your People entity and use that to set the company instead of setting the $data['people_company']. Advantage is also that the PHP will trow an exception if $company is not of type Company.

    public function setCompany(Company $company)
    {
        $this->people_company = $company
    
        return $this;
    }