I've created an entity that I can't update using doctrine-generated form. Here's an action:
public function executeEdit(sfWebRequest $request)
{
$this->forward404Unless($id = $request->getParameter('id'), "Required parameter 'id' must be present in request");
$this->forward404Unless($cart = Doctrine::getTable('ShoppingCart')->find($id), sprintf("No object could be retrieved by %s", $id));
$this->id = $id;
$this->form = new ShoppingCartForm($cart);
if($request->isMethod(sfRequest::POST)) {
$this->form->bind($request->getParameter('shopping_cart'));
if ($this->form->isValid())
{
$cart = $this->form->save();
$this->redirect(link_to('cart/show?id='.$cart->getId()));
}
}
}
Form's isNew() method returns false, but the sf_method is set to PUT. When I use sfRequest::PUT doctrine tries to add new entity with that id. It seems like it shouldn't behave like that so what I am doing wrong?
Related
How would you do a functional test (not unit tests) of a form binded to an entity ?
Context
Let's say you have an entity "Car", with a field "id" and another field "numberPlate", and a page to edit data about a car.
CarController.php :
//...
public function imsiDetailsChangeAction(Request $request)
{
$car_id = $request->get('car_id');
$car = $this->getDoctrine()->getRepository('ClnGsmBundle:Car')->Find($car_id);
if ($simCard != null)
{
$form = $this->createForm(new CarType()), $car);
if($request->isMethod('POST'))
{
$form->bind($request);
if ($form->isValid())
{
$em = $this->getDoctrine()->getManager();
$em->flush();
return $this->redirect($this->generateUrl('car_view', array('car_id' => $car->getId())));
}
}
}
else
{
throw new NotFoundHttpException();
}
return $this->render('SiteBundle:Car:carEdit.html.twig', array('car' => $car, 'form' => $form->createView()));
}
//...
What I want
A test using phpUnit doing the following :
create a Car entity with the numberPlate "QWE-456"
load the page with the form
using the crawler, replace the numberPlate with "AZE-123" in the form, and submit the form
assert that my car entity's numberPlate now equals "AZE-123"
What I tried
(just in case: my own code is a bit different, here is what I would do with the car example)
CarControllerTest.php :
//...
public function SetUp()
{
//start kernel, stores entity manager in $this->em and client in $this->client
}
//...
public function testEditForm()
{
$car = new Car();
$car->setNumberPlate("QWE-456");
$this->entityManager->persist($simCard);
$this->em->flush();
$crawler = $this->client->request('GET', '/fr/Car/edit/'.$car->getId());
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
$formNode = $crawler->filterXpath("//div[#id='main']//form");
$form = $formNode->form(array(
'car[plateNumber]'=>'AZE-123',
));
//var_dump($car->getPlateNumber());
$this->client->submit($form);
//var_dump($car->getPlateNumber());
$this->assertEquals('AZE-123',$car->getPlateNumber);
}
I expect this test to pass, and the second var_dump to print "AZE-123" instead of "QWE-456". But my entity isn't modified.
How should I do this ?
You should refresh the data reloading it from the database: the refresh method do it for you, so try this:
$this->client->submit($form);
$this->em->refresh($car);
$this->assertEquals('AZE-123',$car->getPlateNumber);
I suggest you to check before the HTTP Response in order to verify the correct interaction, as example:
$response = $this->client->getResponse();
$this->assertTrue($response->isRedirection());
Hope this help
I have developed Zend 2 application. There is form to edit existing data. Some fields in table is not included in the form. Thus, when editing those records, fields not in form are saved as NULL. How to fix it ?
Model -
namespace Employee\Model;
class Employee
{
public $id;
public $active;
public $type;
public $mailing_address;
public $permanent_address;
...
public function exchangeArray($data)
{
$this->id = (isset($data['id'])) ? $data['id'] : 0;
$this->active = (isset($data['active'])) ? $data['active'] : 0;
$this->type = (isset($data['type'])) ? $data['type'] : null;
$this->mailing_address = (isset($data['mailing_address'])) ? $data['mailing_address'] : null;
$this->permanent_address = (isset($data['permanent_address'])) ? $data['permanent_address'] : null;
...
Table -
public function saveEmployee(Employee $employee) {
$data = array(
'active' => $employee->active,
'type' => $employee->type,
'mailing_address' => $employee->mailing_address,
'permanent_address' => $employee->permanent_address,
...
$id = (int) $employee->id;
if ($id == 0) {
$inserted = $this->tableGateway->insert($data);
$inserted_id = $this->tableGateway->lastInsertValue;
} else {
if ($this->getEmployee($id)) {
$this->tableGateway->update($data, array('id' => $id));
$inserted_id = $id;
} else {
throw new \Exception('Employee does not exist');
}
}
return $inserted_id;
//\Zend\Debug\Debug::dump($inserted_ids);
}
Controller -
$employeeForm = new EmployeeForm();
$employeeForm->bind($employee);
$request = $this->getRequest();
if ($request->isPost()) {
$employeeForm->setData($request->getPost());
if ($employeeForm->isValid()) {
$this->getEmployeeTable()->saveEmployee($employee);
}
}
Assume type dosn't have form filed defined. So, it shouldn't get NULL when save.
How to fix it ?
try handling it with mysql. use the [default] function of each field wisely
CREATE TABLE `table` (
`type` tinyint(3) unsigned NOT NULL default '0',
.......................
If you are editing an existing record then you would need to first load all the data for that entity and then update the fields that have changed. In ZF2 this is achieved via a form hydrator; as you bind the 'populated' object to the form.
Therefore your controller code would need to change.
EmpolyeeController.php
// Fetch the form from the service manager
// allowing it to be created via factory and have our
// hydrator and entity class injected
$form = $this->serviceLocator()->get('MyModule\Form\EmployeeForm');
$request = $this->getRequest();
$id = $this->params('id'); // Employee ID as route param
// Load the employee data from the database
// (this will vary dependning your own strategy, however
// a service layer is assumed)
$employee = $this->employeeService->findById($id);
// Bind the **hydrated** entity to the form
$form->bind($employee);
if ($request->isPost()) {
// set the modified post data
$form->setData($request->getPost());
if ($form->isValid()) {
// Retrive the validated and updated entity
$employee = $form->getData();
}
}
You will also need to register a form factory to inject the hydrator (an other dependancies).
Module.php
public function getFormElementConifg()
{
return array(
'factories' => array(
'MyModule\Form\EmployeeForm' => function($formElementManager) {
$serviceManager = $formElementManager->getServiceLocator();
$hydrator = $serviceManager->get('MyModule\Stdlib\Hydrator\EmployeeHydrator');
$form = new Form\EmployeeForm();
$form->setHydrator($hydrator);
$form->bind(new Entity\Employee());
return $form;
}
),
)
}
I am new in YII framework. I am doing update operation using YII framework. I have controller with name sitecontroller.php, model jobseekerprofile.php, view personal.php.
I got the error:
Fatal error: Call to a member function isAttributeRequired() on a non-object in E:\wamp\www\yii\framework\web\helpers\CHtml.php on line 1414
My table is job_seeker_profile
Fields
1.id
2.user_id
3.contact_no
4.gender
5.dob
6.mstatus
7.address
8.location_id
I want to edit the data in contact_no and address according to user_id
Model-Jobseekerprofile.php - rules
public function rules()
{
return array(
array('contact_no,address','required'),
);
}
controller-Sitecontroller.php
class SiteController extends Controller {
public function actionpersonal()
{
$user_id = trim($_GET['id']);
$model=Jobseekerprofile::model()->find(array(
'select'=>'contact_no,address',"condition"=>"user_id=$user_id",
'limit'=>1,));
$model = Jobseekerprofile::model()->findByPk($user_id);
if(isset($_POST['Jobseekerprofile']))
{
$model->attributes=$_POST['Jobseekerprofile'];
if($model->save())
{
$this->redirect(array('profile','user_id'=>$model->user_id));
}
}
$this->render('personal',array('model' =>$model));
}
}
Anybody help me?
Seems that $model = Jobseekerprofile::model()->findByPk($user_id) is not finding anything, so $model is null, and that is why $model->isAttributeRequired() throws an error. Check your incoming params because of this and check if there a profile with such id (or maybe you should search by attributes instead of by id?).
Besides you can use
public function actionPersonal($id) {
$model = Jobseekerprofile::model()->findByPk($id);
//
}
Instead of
public function actionpersonal() {
$user_id = trim($_GET['id']);
$model = Jobseekerprofile::model()->findByPk($user_id);
//
}
public function actionpersonal() {
$user_id = trim($_GET['id']);
$model = Jobseekerprofile::model()->findByPk($user_id);
if (isset($_POST['Jobseekerprofile'])) {
$model->attributes = $_POST['Jobseekerprofile']; //post key edited
if ($model->save()) {
$this->redirect(array('profile', 'user_id' => $model->user_id));
}
}
$this->render('personal', array('model' => $model));
}
First Check what you are getting in $_POST
and if all is ok then try to save like
$model = Jobseekerprofile::model()->findByPk($user_id);
if (isset($_POST['Jobseekerprofile'])) {
$model->attributes = $_POST['jobseekerprofile'];
$model->contact_no= $_POST['Jobseekerprofile']['contact_no']; //post key edited
$model->address = $_POST['Jobseekerprofile']['address'];
if ($model->save()) {
$this->redirect(array('profile', 'user_id' => $model->user_id));
}
}
$this->render('personal', array('model' => $model));
if not work then check what model returns
$error=$model->getErrors();
print_r($error);
above code surely gives you idea why it is not saving
I have an issue where I have a form type that persists the associated entity even when the form is not valid.
I have confirmed that the form indeed has errors via $form->getErrorsAsString(). I have also confirmed that the logical if statement that checks if the form is valid or not comes out false. The entity still persists despite the fact that the form is never valid.
I'm not sure what I'm doing wrong here as I have no other spot that I can find that either persists the entity or flushes the entity manager. Here's my controller:
/**
* #Route("/settings/profile", name="settings_profile")
* #Template();
*/
public function profileAction()
{
$user = $this->getUser();
$profile = $user->getUserProfile();
if (null === $profile) {
$profile = new UserProfile();
$profile->setUser($user);
$profileDataModel = $profile;
} else {
$profileDataModel = $this->getDoctrine()->getManager()->find('MyAppBundle:UserProfile',$profile->getId());
}
$form = $this->createForm(new ProfileType(),$profileDataModel);
$request = $this->getRequest();
if ($request->getMethod() === 'POST') {
$form->bind($request);
if ($form->isValid()) {
// This logic never gets executed!
$em = $this->getDoctrine()->getManager();
$profile = $form->getData();
$em->persist($profile);
$em->flush();
$this->get('session')->setFlash('profile_saved', 'Your profile was saved.');
return $this->redirect($this->generateUrl('settings_profile'));
}
}
return array(
'form' => $form->createView(),
);
}
I must have a listener or something somewhere that is persisting the user.
My work around for this temporarily is to do:
$em = $this->getDoctrine()->getManager()
if ($form->isValid()) {
// persist
} else {
$em->clear();
}
Until I can ferret out what listener or other data transformer is causing this.
I want to save some data where part of it is from the user where they submit it through a form and the other part is generated in the actual controller. So something like:
# controller
use Acme\SomeBundle\Entity\Variant;
use Acme\SomeBundle\Form\Type\VariantType;
public function saveAction()
{
$request = $this->getRequest();
// adding the data from user submitted from
$form = $this->createForm(new VariantType());
$form->bindRequest($request);
// how do I add this data to the form object for validation etc
$foo = "Some value from the controller";
$bar = array(1,2,3,4);
/* $form-> ...something... -> setFoo($foo); ?? */
if ($form->isValid()) {
$data = $form->getData();
// my service layer that does the writing to the DB
$myService = $this->get('acme_some.service.variant');
$result = $myService->persist($data);
}
}
How do I get $foo and $bar into the $form object so that I can validate it and persist it?
Here's the general pattern I'm using:
public function createAction(Request $request)
{
$entity = new Entity();
$form = $this->createForm(new EntityType(), $entity);
if ($request->getMethod() == 'POST') {
$foo = "Some value from the controller";
$bar = array(1, 2, 3, 4);
$entity->setFoo($foo);
$entity->setBar($bar);
$form->bindRequest($request);
if ($form->isValid()) {
$this->get('some.service')->save($entity);
// redirect
}
}
// render the template with the form
}
Reading the code for the bind method of the Form class, we can read this:
// Hook to change content of the data bound by the browser
$event = new FilterDataEvent($this, $clientData);
$this->dispatcher->dispatch(FormEvents::BIND_CLIENT_DATA, $event);
$clientData = $event->getData()
So I guess you could use this hook to add your two fields.