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. : -)