Update an entity after inserting data into another

0

I urgently need to find some way to solve this problem that has been holding me for over a week. Once solved, I believe I can use this medium to do other operations that my system will have.

I have two tables, one call from Client and another from Budget , which are related 1: n and n: 1 respectively. It works like this: on the Budget form it has a select field that lists all the Client , and it assigns value / em> of each Client :

<div class="form-group">
    <select name="cdg_budget_type[client_id]" class="form-control">
        {% for client in clients %}
            <option value="{{ client.id }}">{{ client.name }}</option>
        {% endfor %}
    </select>
</div>

First, I should show the Client entity:

class Client
{
    private $id;

    private $name;

    private $phone;

    private $email;

    private $streetName;

    private $district;

    private $number;

    private $city;

    private $zipCode;

    private $budget;

    public function __toString()
    {
        return $this->name;
    }

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

    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setPhone($phone)
    {
        $this->phone = $phone;

        return $this;
    }

    public function getPhone()
    {
        return $this->phone;
    }

    public function setEmail($email)
    {
        $this->email = $email;

        return $this;
    }

    public function getEmail()
    {
        return $this->email;
    }

    public function setStreetName($streetName)
    {
        $this->streetName = $streetName;

        return $this;
    }

    public function getStreetName()
    {
        return $this->streetName;
    }

    public function setDistrict($district)
    {
        $this->district = $district;

        return $this;
    }

    public function getDistrict()
    {
        return $this->district;
    }

    public function setNumber($number)
    {
        $this->number = $number;

        return $this;
    }

    public function getNumber()
    {
        return $this->number;
    }

    public function setCity($city)
    {
        $this->city = $city;

        return $this;
    }

    public function getCity()
    {
        return $this->city;
    }

    public function setZipCode($zipCode)
    {
        $this->zipCode = $zipCode;

        return $this;
    }

    public function getZipCode()
    {
        return $this->zipCode;
    }

    function setBudget($budget)
    {
        $this->budget = $budget;
    }

    function getBudget()
    {
        return $this->budget;
    }
}

Now, the Budget entity:

class Budget
{
    private $id;

    private $clientId;

    private $address;

    private $installments;

    private $checkDays;

    private $dateStart;

    private $dateCreated;

    private $totalValue;

    public function __construct()
    {
        $this->dateCreated = new \DateTime();
    }

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

    public function setClientId(Client $clientId)
    {
        $this->clientId = $clientId;

        return $this;
    }

    public function getClientId()
    {
        return $this->clientId;
    }

    public function setAddress($address)
    {
        $this->address = $address;

        return $this;
    }

    public function getAddress()
    {
        return $this->address;
    }

    public function setInstallments($installments)
    {
        $this->installments = $installments;

        return $this;
    }

    public function getInstallments()
    {
        return $this->installments;
    }

    public function setCheckDays($checkDays)
    {
        $this->checkDays = $checkDays;

        return $this;
    }

    public function getCheckDays()
    {
        return $this->checkDays;
    }

    public function setDateStart($dateStart)
    {
        $this->dateStart = $dateStart;

        return $this;
    }

    public function getDateStart()
    {
        return $this->dateStart;
    }

    public function setDateCreated($dateCreated)
    {
        $this->dateCreated = $dateCreated;

        return $this;
    }

    public function getDateCreated()
    {
        return $this->dateCreated;
    }

    public function setTotalValue($totalValue)
    {
        $this->totalValue = $totalValue;

        return $this;
    }

    public function getTotalValue()
    {
        return $this->totalValue;
    }
}

Then with the file option , which lists all the fields contained in this table and the relationship with Budget :

CDG\PanelBundle\Entity\Client:
    type: entity
    table: client
    repositoryClass: CDG\PanelBundle\Entity\ClientRepository
    id:
        id:
            type: integer
            id: true
            generator:
                strategy: AUTO
    fields:
        name:
            type: string
            length: 255
        phone:
            type: string
            length: 255
        email:
            type: string
            length: 255
        streetName:
            type: string
            length: 255
            column: street_name
        district:
            type: string
            length: 255
        number:
            type: string
            length: 255
        city:
            type: string
            length: 255
        zipCode:
            type: string
            length: 255
            column: zip_code
    oneToMany:
        budget:
            targetEntity: Budget
            mappedBy: clientId
    lifecycleCallbacks: {  }

Here, Client.orm.yml and its relationship with Client :

CDG\PanelBundle\Entity\Budget:
    type: entity
    table: budget
    repositoryClass: CDG\PanelBundle\Entity\BudgetRepository
    id:
        id:
            type: integer
            id: true
            generator:
                strategy: AUTO
    fields:
        address:
            type: string
            length: 255
        installments:
            type: integer
        checkDays:
            type: integer
            column: check_days
        dateStart:
            type: datetime
            column: date_start
        dateCreated:
            type: datetime
            column: date_created
        totalValue:
            type: decimal
            column: total_value
            nullable: true
    manyToOne:
        clientId:
            targetEntity: Client
            inversedBy: budget
            joinColumn:
                name: client_id
                referencedColumnName: id
    lifecycleCallbacks: {  }

So far I believe everything is fine, but now the problem starts. You must UPDATE the Budget field of the Client previously selected on the form as soon as a new Budget is inserted into the database.

In my Budget.orm.yml , the BudgetController.php function is this way below, and produces the following error:

  Warning: spl_object_hash () expects parameter 1 to be object, array given

public function addAction(Request $request)
{
    $form = $this->createForm(new BudgetType());
    $manager = $this->getDoctrine()->getManager();
    $Client = $manager->getRepository('PanelBundle:Client');
    $Budget = $manager->getRepository('PanelBundle:Budget');

    if ($request->getMethod() == 'POST') {
        $form->handleRequest($request);

        if ($form->isValid()) {
            $manager->persist($form->getData());
            $manager->flush();

            $ClientEntity = $manager->find('PanelBundle:Client', $form['client_id']->getData()->getId());
            $ClientEntity->setBudget($manager->getRepository('PanelBundle:Budget')->getLastId());

            $manager->persist($ClientEntity);
            $manager->flush();

            $this->addFlash('success', 'Novo orçamento adicionado');

            return $this->redirect($this->generateUrl('panel_budgets'));
        }
    }

    return $this->render('PanelBundle:Budget:add.html.twig', array(
        'clients' => $Client->findAll(),
        'form' => $form->createView()
    ));
}

Just to explain, the addAction() function that appears above returns the ID of the last Budget added:

public function getLastId()
{
    return $this->createQueryBuilder('b')
                ->select('b.id')
                ->getQuery()
                ->getResult();
}

Describing the function quickly, it adds the data to the budget table and then in the next part I need to retrieve this selected Client and modify its budget . The problem is that the entity has the getLastId() method that returns the name , which is displayed on the system home page, so no object will be returned and I do not know how to do it. In other attempts I got an error saying that it is not possible to call the method __toString() of NULL.

Looking for other media, I've built a function in setBudget() which have two parameters to provide the id of the Client to be updated and id in Budget that was newly included in the database, which produces the error:

  

[Semantical Error] line 0, col 34 near 'budget =? 1 WHERE': Error: Invalid PathExpression. StateFieldPathExpression or SingleValuedAssociationField expected.

public function addBudgetToClient($clientId, $budgetId)
{
    $query = $this->createQueryBuilder('b');
    $query->update('PanelBundle:Client', 'c')
          ->set('c.budget', '?1')
          ->where($query->expr()->eq('c.id', '?2'))
          ->setParameter(1, $budgetId)
          ->setParameter(2, $clientId)
          ->getQuery()
          ->execute();
}

In BudgetRepository.php , I just inserted between the first addAction() and flush() the following code snippet:

$Budget->addBudgetToClient($form['client_id']->getData()->getId(), $Budget->getLastId());

Thanks for any help, because it's already a week on top of a problem.

EDITION # 1

On request, setFlash() :

<?php

namespace CDG\PanelBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class BudgetType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('client_id', 'entity', array(
                    'class' => 'PanelBundle:Client',
                    'attr' => array(
                        'class' => 'form-control'
                    )
                ))
                ->add('address', 'text', array(
                    'attr' => array(
                        'class' => 'form-control'
                    )
                ))
                ->add('installments', 'choice', array(
                    'choices' => array(
                        '3' => '3x',
                        '4' => '4x'
                    ),
                    'attr' => array(
                        'class' => 'form-control',
                    )
                ))
                ->add('check_days', 'choice', array(
                    'choices' => array(
                        '30' => '30 dias',
                        '60' => '60 dias'
                    ),
                    'attr' => array(
                        'class' => 'form-control',
                    )
                ))
                ->add('date_start', 'date', array(
                    'attr' => array(
                        'format' => 'yyyy-MM-dd'
                    )
                ))
                ->add('total_value', 'money', array(
                    'attr' => array(
                        'class' => 'form-control',
                    )
                ));
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'CDG\PanelBundle\Entity\Budget',
            'csrf_protection' => false,
        ));
    }

    public function getName()
    {
        return 'cdg_budget_type';
    }

    public function serialize()
    {
        return serialize(array(
            'id' => $this->getId()
        ));
    }
    public function unserialize($serialized)
    {
        $data = unserialize($serialized);
        $this->id = $data['id'];
    }
}

Based on one example, I wrote BudgetType.php in another way, but this time the following error occurs, which is strange because my client actually in its addAction() gives __construct() to < in> budget , but even removing, the error persists.

  Catchable Fatal Error: Argument 1 passed to Doctrine \ Common \ Collections \ ArrayCollection :: __ construct () must be of the type array, given in / home / gabriel / Documents / CasaDoGesso / vendor / doctrine / orm / lib / Doctrine / ORM / UnitOfWork.php on line 555 and defined

public function addAction(Request $request)
{
    $Budget = new \CDG\PanelBundle\Entity\Budget();
    $form = $this->createForm(new BudgetType(), $Budget);
    $manager = $this->getDoctrine()->getManager();

    if ($request->getMethod() == 'POST') {
        $form->handleRequest($request);

        if ($form->isValid()) {
            $manager->persist($Budget);
            $manager->flush();

            $Client = $manager->find('CDG\PanelBundle\Entity\Client', $form['client_id']->getData()->getId());
            $Client->setBudget($Budget);

            $manager->persist($Client);
            $manager->flush();  // Stack Trace marca aqui.

            $this->addFlash('success', 'Novo orçamento adicionado');

            return $this->redirect($this->generateUrl('panel_budgets'));
        }
    }

    return $this->render('PanelBundle:Budget:add.html.twig', array(
        'clients' => $manager->getRepository('PanelBundle:Client')->findAll(),
        'form' => $form->createView()
    ));
}

EDITION # 2

Below the list of the Client and Budget tables, as per request. The primary key for Client and Budget is the id field, and Budget , the foreign key is client , which will store the customer ID that the budget belongs to. Please ignore "[1. ]" and "" on the right side of the fields, I tried to do cardinality using Astah. : -)

    
asked by anonymous 10.09.2015 / 01:51

1 answer

0

The first thing I noticed is that there is an error fetching client_id from the form, in addition to a small refactoring:

public function addAction(Request $request)
{
    $form = $this->createForm(new BudgetType());
    $manager = $this->getDoctrine()->getManager();
    $Client = $manager->getRepository('PanelBundle:Client');
    $Budget = $manager->getRepository('PanelBundle:Budget');

    if ($request->getMethod() == 'POST') {
        $form->handleRequest($request);

        if ($form->isValid()) {

            $BudgetEntity = $form->getData();
            $manager->persist($BudgetEntity);
            $manager->flush();

            // o client_id já retorna um objeto do tipo client
            $ClientEntity = $form->get('client_id')->getData();

            // a variável $Budget já contém o repositório de budget
            $ClientEntity->setBudget($Budget->getLast());

            $manager->persist($ClientEntity);
            $manager->flush();

            $this->addFlash('success', 'Novo orçamento adicionado');

            return $this->redirect($this->generateUrl('panel_budgets'));
        }
    }

    return $this->render('PanelBundle:Budget:add.html.twig', array(
        'clients' => $Client->findAll(),
        'form' => $form->createView()
    ));
}

(Actually, you do not even need to get the last budget in the bank, just give $ClientEntity->setBudget($BudgetEntity) ; if you do, the getLast method becomes unnecessary.)

In addition, in the budgets repository, I would create a getLast method that searches the last inserted budget (I do not know user the query builder, so I will solve it with a DQL):

public function getLast()
{
    return $this
        ->getEntityManager()
        ->createQuery('
            SELECT b
            FROM PanelBundle:Budget b
            ORDER BY id DESC')
        ->setMaxResults(1)
        ->getSingleResult();
}

Try to implement these two changes without implementing the addBudgetToClient method, and if more difficulties arise, I'll update the response. :)

PS: Do not create the budgets' relationship with the client using a $clientId attribute, as this may lead you to believe that the attribute only holds the client id. My suggestion for improvement is to change the attribute simply to $client .

Suggested changes to models

After you've posted the templates image, I've seen that part of your modeling is incorrect.

The bid is as follows: The Client entity has a 1-to-n relationship with the Budget entity (hence the Budget entity has an n-to-1 relationship with the Client entity).

What does this mean? That while a Budget has one and only one Client, a Client can have many Budgets.

This implies the following change in class Client : instead of having a setBudget method (implying that the Client has only one Budget - which is not true), it should have methods addBudget , removeBudget and setBudgets (those reflecting a 1-to-n relationship). In the Budget class, the relationship is correct.

I suggest the following: remove all methods from the Client and Budget classes, and generate the methods with the following command:

app/console doctrine:generate:entities CDG\PanelBundle

So the methods that will be present in both classes will reflect the relationships between them.

Another useful command that can help you:

app/console doctrine:schema:update --dump-sql

With this command, Doctrine will compare the table schema suggested in the application with the currently existing table schema, and show the divergences between the models. This way, you can make any corrections to avoid problems in the future.

    
10.09.2015 / 18:35