I have a form. There are two selectboxes which are cannot be 0: field1, field2.
If I set POST method then it works fine. If GET - wrong.
Here my controllers' part:
$this->view->searchForm = new Default_Form_Parameters();
$data = $this->getRequest()->getParams();
if ($this->view->searchForm->isValid($data)) {
}
If I have following request then isValid returns false. That's ok.
http://site.ru/?field1=0&field2=0
If I have another request like
http://site.ru/?crash
then isValid returns true. That is wrong.
Any ideas whats the problem?
PS here one of fields with validator:
$required = new Zend_Validate_NotEmpty();
$required->setType ($required->getType() | Zend_Validate_NotEmpty::INTEGER | Zend_Validate_NotEmpty::ZERO);
$input = new Zend_Form_Element_Select('cat');
$input->setLabel('theme')
->addMultiOptions(array('0' => ' ----------- ') + $categories)
->addValidators (array ($required));
Setting a Zend_Validate_NotEmpty validator isn't enough. It only applies if a value has been set to this field. If an empty value like '' would be set it wouldn't validate. However, by defaults it's set to Null I think and that means no value has been set. You have to tell it that it that is 'presence' => 'required', or use setRequired().
$data = $this->_request->getParam('getkey');
if($data)
{
//do something
}
else{
throw new Zend_Exception("No GET value");
}
This is how I use to work with forms...
public function createAction()
{
$form = new Application_Form_PageCreate();
if ($this->getRequest()->isPost()) {
if ($form->isValid($this->getRequest()->getPost())) {
//do what you need
}
}
$this->view->form = $form;
}
as you can see I use "getPost()" and not "getParams()" but that's in cause of my FORM method
Related
I am doing a validation using Code Igniter. I have a simple form which used to create / update a product record.
public function productSave($params) {
if (!$this->validate($params)) {
return FALSE;
}
$id_col_value = $params['product_id'];
if ($id_col_value) {
// update
$this->db->where("product_id", $id_col_value);
return $result = $this->db->update("product", $params);
} else {
// insert
return $result = $this->db->insert("product", $params);
}
}
My validation function looks like this,
protected function validate($params) {
$this->form_validation->set_rules("name", "", "trim|required");
$this->form_validation->set_data($params);
if ($this->form_validation->run() == FALSE){
$errors = $this->form_validation->error_array();
if ( $errors ){
return FALSE;
}
}
return TRUE;
}
Now the problem
When inserting (when product_id is null) it validates. But when we have a product_id it does not validates.
My payload ($params) looks like this,
Array
(
[product_id] => 1 // this is NULL when we do inserting
[name] => Test Name
)
I can't figure out what I am doing wrong here and why the validation not work for updating. I use the same code for both cases.
Please Help! Thanks in advance!
I figure it out.
"We have to call the set_data() method before defining any validation
rules."
Which is in the Documentation of CI.
So, basically, I call $this->form_validation->set_data($params); first
and then, I call $this->form_validation->set_rules("name", "", "trim|required");.
This will solve the problem.
Hope this helps anyone with the same error!!!
Check your params array. I have checked it using $params = array("product_id" => 34, "name" => "Test Name") & it's working perfectly.
If you have no inserted data with that product_id, it will not work. Suppose you have passed product_id=3 & this id is not available in table. Then how should it work?
I want to update a product in laravel, but it does not work properly,
my Controller's update method looks like this:
public function updateProduct(Request $request)
{
# Get input values
$data = $request->all();
$productID = $data['id'];
$product = Product::find($productID);
$product->fill($data);
# Validate input
$validator = Validator::make($request->all(), Product::$rules);
if ($product->save())
{
# save language selection
$lsCounter = 0;
$langSelecName = $request->input('language');
$langSelecFile = $request->file('language');
if ($langSelecName)
{
$projectPath = $dProjectPath . "languages";
foreach ($langSelecName as $langSelecNameKey => $langSelecNameValue)
{
if ($langSelecFile[$lsCounter]['input_vid_lang'] != null)
{
$langVidFileName = $langSelecFile[$lsCounter]['input_vid_lang']->getClientOriginalName();
$languages = new Language();
$languages['short_name'] = $langSelecNameValue;
$languages['input_video'] = $projectLangPath . '\\' . $langVidFileName;
$languages->product()->associate($product);
$langData = [
'languagesShortName' => $languages['short_name'],
'languagesInputVideo' => $languages['input_video']
];
$intProductID = intval($productID);
$findLangId = $languages->find($intProductID);
$findLangId->fill($langData);
if ($languages->save())
{
$langSelecFile[$lsCounter]['input_vid_lang']->move($projectLangPath, $langVidFileName);
}
}
$lsCounter++;
}
}
} else {
return redirect()->route('editProduct', $productID)->with('message', 'Error')->withInput();
}
I get the following error after I try to update it, the error looks like this:
Call to a member function fill() on null
And it points to this line:
$findLangId->fill($langData);
I appreciate some help, thank you.
Edit
Ok people said that $intProductRomID is null, but I get the correct product id if I dd($intProductRomID).
As per the comments, the following line is return null:
$findLangId = $languages->find($intProductRomID);
Meaning this won't be valid:
$findLangId->fill($langData);
In other words, if you were to var_dump out $languages->all(), you will not find $intProductRomID in there. If you are unsure, swap out ->find with ->findOrFail() (which, considering you aren't doing any error catching or checking, you probably should be using it instead).
Edit
After some conversation in the comments, it has been established that the wrong field was being used for reference. Use a where instead:
$languages->where('product_rom_id', $intProductRomID);
I've read through the tutorials/reference of the Form-Component in Zend-Framework 2 and maybe I missed it somehow, so I'm asking here.
I've got an object called Node and bound it to a form. I'm using the Zend\Stdlib\Hydrator\ArraySerializable-Standard-Hydrator. So my Node-object has got the two methods of exchangeArray() and getArrayCopy() like this:
class Node
{
public function exchangeArray($data)
{
// Standard-Felder
$this->node_id = (isset($data['node_id'])) ? $data['node_id'] : null;
$this->node_name = (isset($data['node_name'])) ? $data['node_name'] : null;
$this->node_body = (isset($data['node_body'])) ? $data['node_body'] : null;
$this->node_date = (isset($data['node_date'])) ? $data['node_date'] : null;
$this->node_image = (isset($data['node_image'])) ? $data['node_image'] : null;
$this->node_public = (isset($data['node_public'])) ? $data['node_public'] : null;
$this->node_type = (isset($data['node_type'])) ? $data['node_type']:null;
$this->node_route = (isset($data['node_route'])) ? $data['node_route']:null;
}
public function getArrayCopy()
{
return get_object_vars($this);
}
}
In my Controller I've got an editAction(). There I want to modify the values of this Node-object. So I am using the bind-method of my form. My form has only fields to modify the node_name and the node_body-property. After validating the form and dumping the Node-object after submission of the form the node_name and node_body-properties now contain the values from the submitted form. However all other fields are empty now, even if they contained initial values before.
class AdminController extends AbstractActionController
{
public function editAction()
{
// ... more stuff here (getting Node, etc)
// Get Form
$form = $this->_getForm(); // return a \Zend\Form instance
$form->bind($node); // This is the Node-Object; It contains values for every property
if(true === $this->request->isPost())
{
$data = $this->request->getPost();
$form->setData($data);
// Check if form is valid
if(true === $form->isValid())
{
// Dumping here....
// Here the Node-object only contains values for node_name and node_body all other properties are empty
echo'<pre>';print_r($node);echo'</pre>';exit;
}
}
// View
return array(
'form' => $form,
'node' => $node,
'nodetype' => $nodetype
);
}
}
I want to only overwrite the values which are coming from the form (node_name and node_body) not the other ones. They should remain untouched.
I think a possible solution would be to give the other properties as hidden fields into the form, however I don't wanna do this.
Is there any possibility to not overwrite values which are not present within the form?
I rechecked the code of \Zend\Form and I gotta be honest I just guessed how I can fix my issue.
The only thing I changed is the Hydrator. It seems that the Zend\Stdlib\Hydrator\ArraySerializable is not intended for my case. Since my Node-Object is an object and not an Array I checked the other available hydrators. I've found the Zend\Stdlib\Hydrator\ObjectProperty-hydrator. It works perfectly. Only fields which are available within the form are populated within the bound object. This is exactly what I need. It seems like the ArraySerializable-hydrator resets the object-properties, because it calls the exchangeArray-method of the bound object (Node). And in this method I'm setting the non-given fields to null (see code in my question). Another way would propably be to change the exchangeArray-method, so that it only sets values if they are not available yet.
So the solution in the code is simple:
$form = $this->_getForm();
$form->setHydrator(new \Zend\Stdlib\Hydrator\ObjectProperty()); // Change default hydrator
There is a bug in the class form.php, the filters are not initialized in the bindvalues method just add the line $filter->setData($this->data);
it should look like this after including the line
public function bindValues(array $values = array())
{
if (!is_object($this->object)) {
return;
}
if (!$this->hasValidated() && !empty($values)) {
$this->setData($values);
if (!$this->isValid()) {
return;
}
} elseif (!$this->isValid) {
return;
}
$filter = $this->getInputFilter();
$filter->setData($this->data); //added to fix binding empty data
switch ($this->bindAs) {
case FormInterface::VALUES_RAW:
$data = $filter->getRawValues();
break;
case FormInterface::VALUES_NORMALIZED:
default:
$data = $filter->getValues();
break;
}
$data = $this->prepareBindData($data, $this->data);
// If there is a base fieldset, only hydrate beginning from the base fieldset
if ($this->baseFieldset !== null) {
$data = $data[$this->baseFieldset->getName()];
$this->object = $this->baseFieldset->bindValues($data);
} else {
$this->object = parent::bindValues($data);
}
}
to be precious it is line no 282 in my zf2.0.6 library
this would fix your problem, this happen only for binded object situation
I ran into the same problem, but the solution of Raj is not the right way. This is not a bug as for today the code remains still similar without the 'fix' of Raj, adding the line:
$filter->setData($this->data);
The main problem here is when you bind an object to the form, the inputfilter is not stored inside the Form object. But called every time from the binded object.
public function getInputFilter()
...
$this->object->getInputFilter();
...
}
My problem was that I created every time a new InputFilter object when the function getInputFilter was called. So I corrected this to be something like below:
protected $filter;
...
public function getInputFilter {
if (!isset($this->filter)) {
$this->filter = new InputFilter();
...
}
return $this->filter;
}
I ran into the same issue today but the fix Raj suggested did not work. I am using the latest version of ZF2 (as of this writing) so I am not totally surprised that it didn't work.
Changing to another Hydrator was not possible as my properties are held in an array. Both the ObjectProperty and ClassMethods hydrators rely on your properties actually being declared (ObjectProperty uses object_get_vars and ClassMethods uses property_exists). I didn't want to create my own Hydrator (lazy!).
Instead I stuck with the ArraySerializable hydrator and altered my exchangeArray() method slightly.
Originally I had:
public function exchangeArray(array $data)
{
$newData = [];
foreach($data as $property=>$value)
{
if($this->has($property))
{
$newData[$property] = $value;
}
}
$this->data = $newData;
}
This works fine most of the time, but as you can see it blows away any existing data in $this->data.
I tweaked it as follows:
public function exchangeArray(array $data)
{
$newData = [];
foreach($data as $property=>$value)
{
if($this->has($property))
{
$newData[$property] = $value;
}
}
//$this->data = $newData; I changed this line...
//to...
$this->data = array_merge($this->data, $newData);
}
This preserves any existing keys in $this->data if they are missing from the new data coming in. The only downside to this approach is I can no longer use exchangeArray() to overwrite everything held in $this->data. In my project this approach is a one-off so it is not a big problem. Besides, a new replaceAllData() or overwrite() method is probably preferred in any case, if for no other reason than being obvious what it does.
Lets see the action (form is based on model)
$this->form->bind ($request->getParameter('task'));
if ($this->form->isValid())
{
// cakk
}
This all works good, its not valid when its really not valid etc.
But I want to edit some fields, for example a date must be always set to now. Or a password must be encoded. How can I do this?
You can override the doSave() method in the form .. something like this :
public function doSave($con = null)
{
$this->values['form field'] = 'newvalue';
parent::doSave($con);
}
$this->values is an array containing the values on the form.
Update
You could use a post validator .. like this (again in the form class) :
$this->validatorSchema->setPostValidator(
new sfValidatorCallback(array('callback' => array($this, 'methodName')))
);
public function methodName($validator, $values)
{
// check / change what you need to
$values['fieldname'] = 'new value';
// return values
return $values;
}
I'm overriding my doSave() method to basically do the following: I have a sfWidgetFormPropelChoice field that the user can either choose from, or type a new option. How can I change the widget's value? Or maybe I am approaching this the wrong way. So here is how I overrode the doSave() method:
public function doSave($con = null)
{
// Save the manufacturer as either new or existing.
$manufacturer_obj = ManufacturerPeer::retrieveByName($this['manufacturer_id']->getValue());
if (!empty($manufacturer_obj))
{
$this->getObject()->setManufacturerId($manufacturer_obj->getId()); // NEED TO CHANGE THIS TO UPDATE WIDGET'S VALUE INSTEAD?
}
else
{
$new = new Manufacturer();
$new->setName($this['manufacturer_id']->getValue());
$new->save();
$this->getObject()->setManufacturerId($new->getId()); // NEED TO CHANGE THIS TO UPDATE WIDGET'S VALUE INSTEAD?
}
parent::doSave($con);
}
You should use setDefault or setDefaults and then it will autopopulate with the bound values.
(sfForm) setDefault ($name, $default)
(sfForm) setDefaults ($defaults)
usage
$form->setDefault('WidgetName', 'Value');
$form->setDefaults(array(
'WidgetName' => 'Value',
));
You could do it in the action :
$this->form->getObject()->setFooId($this->foo->getId()) /*Or get the manufacturer id or name from request here */
$this->form->save();
But I prefer to do the kind of work you are doing with your manufacturer directly in my Peer so my business logic is always at the same place.
What I put in my forms is mainly validation logic.
Example of what to put in the save method of the Peer :
public function save(PropelPDO $con= null)
{
if ($this->isNew() && !$this->getFooId())
{
$foo= new Foo();
$foo->setBar('bar');
$this->setFoo($foo);
}
}
Two assumption here: a) your form gets the name of the manufacturer and b) your model wants the ID of a manufacturer
public function doSave($con = null)
{
// retrieve the object from the DB or create it
$manufacturerName = $this->values['manufacturer_id'];
$manufacturer = ManufacturerPeer::retrieveByName($manufacturerName);
if(!$manufacturer instanceof Manufacturer)
{
$manufacturer = new Manufacturer();
$manufacturer->setName($manufacturerName);
$manufacturer->save();
}
// overwrite the field value and let the form do the real work
$this->values['manufacturer_id'] = $manufacturer->getId();
parent::doSave($con);
}