I am submitting a form and in my controller I use handleRequest to validate the form.
Lets say I try to update my object name 'object' - It has an id, name and color field.
On the same page I also show a lost with the names of all my objects that I fetch from the database
Here is my code:
$object = self::getObjectById($objectId);
$objects = self::getAllObjects();
$objectForm = self::CreateObjectForm($object);
$objectFormForm->handleRequest($request);
dd($objects);
When I submit the form and I leave the name field open,
It throws an error that the field is required when it reloads the page, the name field of the form is still empty which is normal.
But here is the problem, in the list of objects that is also showing on this page the name of the object I tried to update has no name showing anymore in this list.
I don't know why this is happening since I fetched this list of objects completely separately from the form object. When I dd() the objects after the handleRequest() I cans see in the dumped vars that indeed the name field is empty. When I check the database, the name field is not empty and still holds the old name. Which makes sense because the object is not persisted and flushed to de db.
When I dd() the same list before the handleRequest() everything is normal.
How can I prevent this behavior? And why is this happening?
I don't know why this is happening since i fetched this list of objects completely seperatly from the form object.
It's referencing the same entity which get's dumped in it's current, live, dirty state as submitted by the form.
If you need to render the clean, persisted values then you just need to store them in a variable as a string instead of as the object, and before handling the request.
Try something like this:
$object = self::getObjectById($objectId);
$objects = self::getAllObjects();
$persistedObjects = [];
foreach($objects as $obj){
$persistedObjects[$obj->getId()] = $obj->getName();
}
$objectForm = self::CreateObjectForm($object);
$objectFormForm->handleRequest($request);
dd($persistedObjects);
Related
I am trying to access image uri's in an array within a field collection but I don't know how to access them. If I look in the devel module, I can see the location of the first image uri in the array looks like this:
['field_text_and_image'][0]['entity']['field_collection_item'][2474]['field_about_accreditation_image'][0]['#item']['uri']
I am puzzled because I have 'field_get_items' method to access the field collection I am targeting like so...
$text_and_image_field = field_get_items('node', $node, 'field_text_and_image');
... and if I print/render this variable, I would expect to see an array printed on the page but instead nothing gets created. However, I made a condition on the page that checks to see if the '$text_and_image_field' field collection exists, and if it does to create an element, and it does indeed create an element which shows that the field exists. I just can't seem to access any of it's content.
So, why isn't the field collection printing anything and how can I loop through the 'field_about_accreditation' array to print out all of the image uri's?
EDIT*
I've taken a few more stabs at the problem and realized that I made the mistake of trying to render the value of the '$text_and_image_field' when I should have been using print_r, which now doing so gives me this array value:
Array ( [0] => Array ( [value] => 2474 [revision_id] => 174439 ) )
Based on older code where field collections are accessed, what has happened every other time a value has been assigned to a field collection is to write the following statements:
$value = field_view_value('node', $node, '$field_text_and_image', $text_and_image_field[$i]);
$field_collection = $value['entity']['field_collection_item'][key($value['entity']['field_collection_item'])];
However, when I try to print out $value (which I expect would be '2474') nothing is displayed.
Hi field collections are stored as a seperate entity so you will need to do an entity load to get the data.
$text_and_image_field = entity_load('field_collection_item', array($entity_id));
In this case it looks like the entity id is 2474 from there you can manipulate the array as you need to.
Your end code could be something like so:
$imageuri = entity_load('field_collection_item', array(2474))[2474]->field_about_accreditation_image['und'][0]['uri'];
Let' say that you have loaded $node and inside it you have field collection field field_images. Then you can get first element of it as:
$collection_entity_id = $node->field_photo['und'][0]['value'];
Now you have entity id and you have to load full entity:
$full_entity = field_collection_item_load($collection_entity_id);
And whey you loaded entity you can access entity fields the usual way:
$title = $full_box->title;
$image_path =- $full_entity->field_image_path['und'][0]['value'];
And yes, I know it's not cleanest way to get the values, please don't rub it in my face.
I have a form using the multiform module. I have a checkboxsetfield populated by a dataobject.
When saving the form I am getting strange results. For instance if I select the first and third checkboxes then this is how the array appears in the database: 1{comma}3 when I expected to see 1,3
MyDataObject.php
<?php
...
if($SomeData = DataObject::get('SomeData')->sort('SortColumn'){
$fields->push( new CheckboxSetField('SomeData', 'Field Name', $SomeData->map('ID', 'Name')
));
}
MultiForm.php
<?php
...
public function finish($data, $form){
if(isset($_SESSION['FormInfo']['MultiForm']['errors'])){
unset($_SESSION['FormInfo']['Form']['errors']);
}
parent::finish($data, $form);
$steps = DataObject::get('MultiFormStep', "SessionID = {$this->session->ID}");
$MyStep = $this->getSavedStepByClass('MyStep');
if($this->getSavedStepByClass('MyStep')){
if($MyStep->loadData()){
$MyDataObject = new MyDataObject();
$MyStep->saveInto($MyDataObject);
$MyDataObject->write();
}
}
...
Any ideas how to process the array?
CheckboxSetField does have code which refers to {comma} when saving to the DB or when calling the dataValue function. This is essentially escaping any commas that were defined as values in the string when saving to a single column.
This tells me that either your multiform isn't providing the right input to CheckboxSetField or that there is more to this situation than your code is showing.
If CheckboxSetField gets an array like array('1,3'), that is when I would expect to see that type of result. Calling map like you have returns an SS_Map object which may not automatically convert the way you are expecting. Try adding ->toArray() after the map call when you are passing the values into the CheckboxSetField.
If that doesn't solve the issue, we probably will need to see the DataObject itself and a few other bits and pieces of information.
I want to make a single revision option for saving certain objects in Sonata Admin.
I though to do this in the following way:
user edits entry
form is validated
the new information is saved as a separate entry (i'll call it revision)
the original object is not modified, except for a relation to the revision
So the code looks something like this (source Sonata\AdminBundle\Controller\CRUDController::editAction()):
$object = $this->admin->getObject($id);
$this->admin->setSubject($object);
$form = $this->admin->getForm();
$form->setData($object);
$form->bind($this->get('request')); // does this persist the object ?
// and here is what I basically want to do:
$object->setId(null);
$orig = $em->getRepository("MedtravelClinicBundle:Clinic")->find($id);
$orig->setRevision($object);
$this->admin->update($orig);
The problem is that $orig loads the already modified, so var_dump($orig === $object) is true.
I also tried $em->getUnitOfWork()->getOriginalEntityData($object); - which grabs the correct data, but as an array, not as an object (this will probably be the last resort).
So, how can I get (and save) the original object after the form bind took place ?
I think you should use the clone keyword to get a independent instance of the object you want to store. It should works by following these steps:
Load the original entity ($object)
Clone the original entity to get a new temporary entity ($newObject)
Alter the $newObject to make it a new entry: $newObject->setId(null);
Bind $newObject to the form
Save (persist) $newObject as a revision
Add the revision to ($object) and persist it too
I hope that if the form is invalid you won't lose all the data sent by the user.
Just in case, I used this answer to find the differences between the original entity and the one modified by the form.
First, let me say, that I find the sfFormPropel form's interface inconsistent.
There is bind(), which returns nothing, but triggers validation, save() which returns the saved object, and bindAndSave(), which returns boolean, actually the return value of isValid(). Now, I have a working application, but I don't feel the code is right, and I'm quite new to symfony, so perhaps I'm missing something.
The object I need to create needs some external properties, that are not presented in the form, are external to the model, and are handled by the application (for example, the userId of the user, that created the entity, an external-generated guid, etc.).
Right now the flow is as follows:
get values from request and bind them to form
check if form is valid
if it's valid, add additional values and bind them to form one more time
save the form and return the object
The obvious answer would to add application-specific values to the values, retrieved from request, but It does not make sense to bind the application-specific values if the form is not valid, since they can be potentially expensive operations, may create database records, etc. Additionally, it should not be possible to pass those values with the post request, they should come from application only.
Now, I though that I have to let the model do these things, but since the data is external to the model, action still need to pass it to the model. The problem is, if I call $form->getObject() after bind(), it still has the old data, and not the data submitted.
What is the correct way to implement this kind of post-processing?
Second bounty is started to award the other valuable answer
The correct way would be setting your default values on the object you are passing to the form constructor. For example if you want to set the logged in user id on an object you are creating:
$article = new Article();
$article->setUserId($this->getUser()->getId());
$form = new ArticleForm($article);
if ($request->isMethod('post')) {
$form->bind($request->getParameter('article'));
if ($form->isValid()) {
$form->save();
}
}
Likewise for existing object, you can load the record and change any properties before passing it to the form constructor.
EDIT:
If you want to modify the object after validating, you can use $form->updateObject() like Grad suggests in his response. If the generated values depend on the submitted values, you can override sfFormObject::processValues():
class UserForm {
public function processValues($values) {
$values['hash'] = sha1($values['id'] . $values['username']);
return parent::processValues($values);
}
}
In case you need something from the action, you can always pass it as an option to the form:
$form = new UserForm($user, array('foo' => $bar));
That way, you can use $this->getOption('foo') anywhere in your form code, eg. in processValues().
It kind of depends of who has "knowledge" about the extra attributes. If they're really request specific, thus need to be processed in the controller, I go for binding, testing if valid and then update the bound object. To get the updated object with the bound (and validated) fields use the updateObject function.
$form->bind(..)
if ($form->isValid()) {
$obj = $form->updateObject(); // Updates the values of the object with the cleaned up values. (returns object)
$obj->foo = 'bar';
$obj->save();
}
But since this normally is also behaviour that is form specific, I usually go for overriding the Form class. By overriding the doUpdateValues() function you can easily access submitted data, and append your own data. Of course you can also go higher in the chain, and override the save() function.
To set custom data for this form, you can also 'publish' public methods, which can then be used by the controller.
A submitted form on my site returns an array of request data that is accessible with
$data = $this->getRequest();
This happens in the controller which gathers the data and then passes this array to my model for placing/updating into the database.
Here is the problem. What if I want to manipulate one of the values in that array? Previously I would extract each value, assigning them to a new array, so I could work on the one I needed. Like so:
$data = $this->getRequest();
$foo['site_id'] = $data->getParam('site_id');
$foo['story'] = htmlentities($data->getParam('story'));
and then I would pass the $foo array to the model for placing/updating into the database.
All I am doing is manipulating that one value (the 'story' param) so it seems like a waste to extract each one and reassign it just so I can do this. Additionally it is less flexible as I have to explicitly access each value by name. It's nicer to just pass the whole request to the model and then go through getting rid of anything not needed for the database.
How would you do this?
Edit again: Looking some more at your question what I am talking about here all goes on in the controller. Where your form`s action will land.
Well you have a couple of options.
First of all $_GET is still there in ZF so you could just access it.
Second there is:
$myArray = $this->_request->getParams();
or
$myArray = $this->getRequest()->getParams();
Wich would return all the params in an array instead of one by one.
Thirdly if the form is posted you have:
$myArray = $this->_request()->getPost();
Wich works with $this->_request->isPost() wich returns true if some form was posted.
About accessing all that in your view you could always just in controller:
$this->view->myArray = $this->_request->getParams();
edit: right I taught you meant the view not the model. I guess I do not understand that part of the question.
If you want to deal with the post data inside your model just:
$MyModel = new Model_Mymodels();
$data = $this->_request->getParams();
$data['story'] = htmlentities($data['story']);
$myModels->SetItAll($data);
And then inside your model you create the SetItAll() function (with a better name) and deal with it there.
Edit: oh wait! I get it. You hate sanytising your input one by one with your technique. Well then what I showed you about how to access that data should simplify your life a lot.
edit:
There is always the Zend_Form route if the parameters are really coming from a form. You could create code to interface it with your model and abstract all this from the controller. But at the end of the day if you need to do something special to one of your inputs then you have to code it somewhere.