I have a action class for saving some data to a database.In action class iam getting a id through url.I have to save the id in table.
I am getting the id by $request->getParameter('id')
I used this code for saving
$this->form->bind($request->getParameter('question_answers'));
if ($this->form->isValid())
{
$this->form->save();
$this->redirect('#homepage');
}
in model class i used a override save method to save extra field
public function save(Doctrine_Connection $conn = null)
{
if ($this->isNew())
{
$now=date('Y-m-d H:i:s', time());
$this->setPostedAt($now);
}
return parent::save($conn);
so i want to get the id value here .
So how can i pass id value from action class to model class
is any-other way to save the id in action class itself
Thanks in advance
Just use
$this->form->getObject()->setQuestionId($request->getParameter('id'));
$this->form->save();
QuestionId=field name
$request->getParameter('id')= is the default value
Most probably not the best solution but you can save that id value in a session variable and use it later anywhere you need. something like:
$this->getUser()->setAttribute('id', $request->getParameter('id')); // in action class
and
sfContext::getInstance()->getUser()->getAttribute('id'); // in model class
If your model has a field for this ID already (eg in your example posted_id), then you can do one of 2 things:
1: Pass the ID to your form when you create it, as an option:
$this->form = new MyForm(array(), array("posted_id" => $id));
and then you can override your form's doSave() method to set the field:
// ...
$this->getObject()->posted_id = $this->getOption("posted_id");
// ...
or similar
2: Add a widget to your form in the configure() method with a corresponding validator, and pass in the ID when you get the values from the request:
$values = $request->getParameter('question_answers');
$values["posted_id"] = $request->getParameter("id");
$this->form->bind($values);
If you're rendering your form manually, just don't render this new field in your view template.
Either way, saving the model as a result of the form saving it will include this new field I believe. The second one is from memory, but it should technically work... :-)
Best practice I'm using consists of 2 steps:
Pass additional data to forms' options (2nd constructor's parameter or just $form->setOption('name', 'value'));
override protected method doUpdateObject in way like this:
protected function doUpdateObject($values)
{
$this->getObject()->setFoo($this->getOption('foo'));
parent::doUpdateObject($values);
}
Enjoy!
You could use (sfUser)->setFlash and (sfUser)->getFlash instead of setAttribute, it's more secure...
Related
So in my mvc 5 app, I got this default 'Index' action, which simply redirects to the search action, with the default model values:
[Route]
public ActionResult Index()
{
var model = new T();
return RedirectToAction("Search", model);
}
What i got puzzled about is how i end up with the url like '.../search?xxx=xxx...'? Is there anything i can do to customize or at least inject/replace the url generation, especially the query string part? e.g. i might want to display 1/0 for bool properties in the search model, and customize query string key names etc?
and why would someone vote down for my question? psst...
The query string generated depend on the model property name and type + value you passed in.
For example, say if your pass in model is like
public class MyModel
{
bool IsSort{get;set;}
}
If your model is like this and IsSort value is true, then you will get url like /search?IsSort=true
Say you want to change your query string to 1/0 instead of true or false, then create viewModel which has property string then assing it properly like:
public class MyModel
{
string IsSort{get;set;}
}
var model = new MyModel();
model.IsSort = true? "1":"0";
same apply to querystring key (which correspond to property name)
i new to zenframework 2. i have correctly set up zendframework 2,doctrine and zfcUser.All work correctly.
my issue now is now regarding how to prepoulated a form if a member is already logged in.
this is where i extend zfcUser to obtain the Id of a loggged in member:
public function setid( $id)
{
$this->id = $id;
}
public function getId()
{
if (!$this->id) {
$this->setid($this->zfcUserAuthentication()->getAuthService()->getIdentity()->getId());
}
return $this->id;
}
i know want to use that Id to obtain the values from the database and then populate the form with those values.
this is my form:
public function aboutYouAction()
{
$id = $this->getId() ;
$form = new CreateAboutYouForm($this->getEntityManager());
$aboutYou = new AboutYou();
$form->setInputFilter($aboutYou->getInputFilter());
$form->bind($aboutYou);
if ($this->request->isPost())
{
$form->setData($this->request->getPost());
if ($form->isValid())
{
$post = $this->request->getPost();
$this->getEntityManager()->persist($aboutYou);
$this->getEntityManager()->flush();
return $this->redirect()->toRoute('worker', array('action' => 'aboutYou'));
}
}
$messages='';
// return array('form' => $form);
return new ViewModel(array('form' => $form, 'messages' => $messages));
}
To set the values on the form all you need to do is $form->bind($aboutYou)
The bind() method is designed to take the passed entity instance and map it to the forms elements; This process being referred to as form hydration.
Depending on the hydrator attached to the form or fieldset (With doctrine this would normally be the DoctrineModule\Stdlib\Hydrator\DoctrineObject) this should be able to evaluate the AboutYou fields, including any entity references/associations, and set the corresponding form elements values. I'm assuming that one of these fields is user.
In you specific case it seems you are binding a new entity (which therefore will not have any properties set, such as your user)
$aboutYou = new AboutYou(); // Brand new entity
$form->bind($aboutYou); // Binding to the form without any data
What this means is that the form is trying to set the values of the elements but the provided AboutYou class has no data to set (as its new and was not loaded via doctrine) and/or the properties of the AboutYou class to not correctly map to the form's elements.
If you wish to bind the user you will need to fetch the populated instance. This can be done using doctrine ($objectManager->find('AboutYou', $aboutYouId)) or if you need to set the current logged in user call the controller plugin ZfcUser\Controller\Plugin\ZfcUserAuthentication from within the controller and no where else.
You workflow should be similar to this (illustration purposes only)
// Controller
public function aboutYouAction()
{
// Get the id via posted/query/route params
$aboutYouId = $this->params('id', false);
// get the object manager
$objectManager = $this->getServiceLocator()->get('ObjectManager');
// Fetch the populated instance
$aboutYou = $objectManager->find('AboutYou', $aboutYouId);
// here the about you entity should be populated with a user object
// so that if you were to call $aboutYou->getUser() it would return an user object
// Get the form from the service manager (rather than creating it in the controller)
// meaning you should create a factory service for this
$form = $this->getServiceLocator()->get('MyForm');
// Bind the populated object to the form
$form->bind($aboutYou);
//... rest of the action such as handle edits etc
}
I am trying to reuse the same form for adding and editing employee information. I am using knockout js and on my view I make the knockout model:
var koModel = new EmployeeModel(div);
and if I want to populate the fields from the server I want to do something like this:
var koModel = new EmployeeModel(unserializedModelFromController, div);
I was wondering what is the best way to distinguish if the request is for a new employee or if it is to edit an existing employee.
If you turn your parameters around you can write a single constructor function.
var EmployeeModel = function(div, model) {
if (model) {
// Existing model has been passed, it's an edit request
} else {
// No model has been passed, it's a new request
}
}
This can be called like:
new EmployeeModel(div);
or
new EmployeeModel(div, model);
You can send a parameter with a default value to the view.
If you are editing an employee, you can send the value of id, you're creating not send.
The function that receives a request to store or edit could have a default value.
public void SaveOrEditEmployee(int id=0, ...) //id=0 is a default value
{
if(id==0)
{
//SaveEmployee
}else
{
//EditEmployee
Employee empl = (x => employee.id == id);
...
}
}
Or you can do likewise, receive full model and assess whether the property 'id' already exists in your database
Should an input model for creating or updating entities have an ID field to identify the entity, or should your edit action accept an ID parameter?
Compare
Input Model
[HttpPost]
public ActionResult(EntityInputModel input)
{
var entity = _unitOfWork.CurrenSession.Get<MyEntity>(input.Id);
// do editing
// ...
}
Action Parameter
[HttpPost]
public ActionResult(Guid id, EntityInputModel input)
{
var entity = _unitOfWork.CurrenSession.Get<MyEntity>(id);
// ...
}
Personally I prefer the first. I always define a specific view model for each POST action. So if this action requires an id I include it as part of this specific view model.
I'm trying to create a form that change the validation of a field based on the select option from the html form field.
Ex: if user select a option 1 from drop down field "options", I want the field "metric" to validate as sfValidatorInteger. If user select option 2 from field "options", I want the field "metric" to validate as sfValidatorEmail, etc.
So inside the public function configure() { I have the switch statement to capture the value of "options", and create the validator based on that value returned from the "options".
1.) How do I capture the value of "options" ? I've tried:
$this->getObject()->options
$this->getTaintedValues()
The only thing that's currently working for me is but it's not really MVC:
$params = sfcontext::getInstance()->getRequest()->getParameter('options');
2.) Once I've captured that information, how can I assign the value of "metric" to a different field? ("metric" is not a real column in db). So I need to assign the value of "metric" to different field such as "email", "age" ... Currently I'm handling this at the post validator like this, just wondering if I can assign value within the configure():
$this->validatorSchema->setPostValidator(new sfValidatorCallback(array('callback' => array($this, 'checkMetric'))));
public function checkMetric($validator, $values) {
}
Thanks!
You want to use a post validator. Try doing something like this in your form:
public function configure()
{
$choices = array('email', 'integer');
$this->setWidget('option', new sfWidgetFormChoice(array('choices' => $choices))); //option determines how field "dynamic_validation" is validated
$this->setValidator('option', new sfValidatorChoice(array('choices' => array_keys($choices)));
$this->setValidator('dynamic_validation', new sfValidatorPass()); //we're doing validation in the post validator
$this->mergePostValidator(new sfValidatorCallback(array(
'callback' => array($this, 'postValidatorCallback')
)));
}
public function postValidatorCallback($validator, $values, $arguments)
{
if ($values['option'] == 'email')
{
$validator = new sfValidatorEmail();
}
else //we know it's one of email or integer at this point because it was already validated
{
$validator = new sfValidatorInteger();
}
$values['dynamic_validation'] = $validator->clean($values['dynamic_validation']); //clean will throw exception if not valid
return $values;
}
1) In a post validator, values can be accessed by using the $values parameter. Just use $values['options'] and it should be fine... or did you want to access this values from another part of you code? $this->getObject()->widgetSchema['options'] should work too I think, once your form is bound to an object.
2) The configure() method is called at the end of the form constructor, so values are not bound nor accessible yet, unless you are initializing your form with an object from the db (which does not require any validation). But if you want to initialize your form from $_POST, a post validator is definitely the way to go IMHO.
I got the validation error to appear alongside the field by throwing a sfValidatorErrorSchema instead of a sfValidatorError.
$values['dynamic_validation'] = $validator->clean($values['dynamic_validation']);
…becomes…
try
{
$values['dynamic_validation'] = $validator->clean($values['dynamic_validation']);
}
catch(sfValidatorError $e)
{
$this->getErrorSchema()->addError($e, 'dynamic_validation');
throw $this->getErrorSchema();
}
Not sure if this is the best way to get this result, but it seems to be working for me at the moment.