Update large CakePHP model, but *don't* touch certain fields? - php

Using CakePHP 1.3
I have a fairly large model in CakePHP, and I'd like to have some hidden elements on the form page to (manually) compare/validate against before saving, but when doing a saveAll() (with validation), I don't want these fields present (essentially to avoid them being updated).
What's the proper way to handle this? Remove them from $this->data before handing that to saveAll()?

Use the 'fieldlist' option:
$this->Model->saveAll($data, array('fieldlist' => array('fields', 'to', 'save')));
$fields = array_keys($this->Model->_schema);
$fieldsNotToSave = array('field1', 'field2');
$fieldsToSave = array_diff($fields, $fieldsNotToSave);

I'll usually use unset() prior to the saveAll(). If you think about it, it's the smarest/easiest way. That is, unless you want to manually name the hidden input fields different than the default data[Model][field] that is generated by the form helper.
But then you'd have to access them manually and validate them manually.
unset() is fast and clear.

Related

Remove Element from within a view in Zend 2 Forms

When removing an element from a form I would usually use
$this->form->remove('foo');
How would I remove an element from a fieldset? for example my $blocks is a fieldset with multiple elements but this doesn't work to remove unwanted elements
$blocks = $this->form->get('page')->get('blocks');
$blocks->remove('active');
When you remove the Form\Element from within a view it will still be present after the creation of the Form that will be passed to the Controller. I strongly suggest for you to be doing a proper OOP approach to your problem. Mainly there's two solutions for this.
The base is always identical, have a Form\Fieldset that matches your Model / Entity. It can have as many child-fieldsets as you need.
Option 1 - Create different Forms and remove elements
Basically this approach would look something like this:
'EntitySubEditForm' => function ($fem) {
$form = new DefaultForm();
$form->get('fieldset')->remove('foo');
$form->get('fieldset')->remove('bar');
return $form;
}
This will basically function like the approach you went, only at the respective place.
The upside to this approach is that you can render your form using $this->formCollection().
The downside to this approach is that even though you may use caching it simply requires more cache-data (hdd-space). And even though it's cheap by now, no reason to waste it ;)
Option 2 - Just don't validate certain fields
You may choose just to ignore some data passed in your special form.
'EntitySubEditForm' => function($fem) {
$form = new DefaultForm();
$form->setValidationGroup(array(
'id', 'name', 'title',
'etc....'
)); // but NOT 'foo' or 'bar'
return $form;
}
This is the approach I'm going. The reason is that I am caching the created Form-Objects so that Form creation is faster. Setting up a validationGroup then allows me to simply ignore values that are sent having these keys. Remember: unvalidated data is NOT passed from Zend\Form.
The downside to this approach is, that you can't render your form using $this->formCollection(), because the elements are still there and would be rendered. You'd have to manually render respective rows using $this->formRow() or even more manually...
more to read...
You may further be interested in the /docs of DoctrineModule #github because it covers a good use-case and describes well how Zend\Form should be used when Forms for specific actions should have different fields. Iirc it uses Option 1.

How to bind Symfony2 form with an array (not a request)?

Let say I have an HTML form with bunch of fields. Some fields belong to Product, some to Order, some to Other. When the form is submitted I want to take that request and then create Symfony forms for Product, Order, and Other in controller. Then I want to take partial form data and bind it with appropriate forms. An example would something like this:
$productArray = array('name'=>$request->get('name'));
$pf = $this->createForm(new \MyBundle\Form\ProductType(), $product);
$pf->bind($productArray);
if($pf->isValid()) {
// submit product data
}
// Do same for Order (but use order data)
// Do same for Other (but use other data)
The thing is when I try to do it, I can't get $form->isValid() method working. It seems that bind() step fails. I have a suspicion that it might have to do with the form token, but I not sure how to fix it. Again, I build my own HTML form in a view (I did not use form_widget(), cause of all complications it would require to merge bunch of FormTypes into one somehow). I just want a very simple way to use basic HTML form together with Symfony form feature set.
Can anyone tell me is this even possible with Symfony and how do I go about doing it?
You need to disable CSRF token to manually bind data.
To do this you can pass the csrf_protection option when creating form object.
Like this:
$pf = $this->createForm(new \MyBundle\Form\ProductType(), $product, array(
'csrf_protection' => false
));
I feel like you might need a form that embed the other forms:
// Main form
$builder
->add('product', new ProductType)
->add('order', new OrderType);
and have an object that contains association to these other objects to which you bind to the request. Like so you just have to bind one object with the request and access embedded object via simple getters.
Am I clear enough?

How do you restore the values of the form in case if validation failed (in Kohana 3)

There is a sample in the bottom of the official documentation http://kohanaframework.org/3.2/guide/kohana/security/validation
But obviously it wont work at the request as long as $post['username'] in View is used but the $post array is empty on first request.
So how do you restore the values in this case? Any general solution?
PS: yes, I do understand I could do isset($post['username']) ? $post['username'] : ''; but it is just annoying
I use the model to display the data in the form. That way the initial form value is the initial value in the model.
I then update the model data with POST data in the controller, if there are validation errors, the model data will contain the POST data. This means I don't have to put any conditional logic in the view, and I just do: Form::input('name', $model->name)
Here's a more detailed explanation of this approach: Kohana ORM and Validation, having problems
I use Arr::get function:
echo Form::input('name', Arr::get($post, 'name'))
I was just looking at the old documentation on Building and Validating a Form.
You can see from the sample code that first you need to initialize an array with the form field names as the key and set the value to an empty string. And if there's an error, fill in the values of each element. In the views, you can simply call Form::input() normally without any if statement or some sort.
I guess Kohana has already been built this way from the start. And it doesn't seem to change. You'll probably just need to do the same thing.

Using Zend_filter_input standalone

Is it possible to use Zend_Filter_Input as a generic input filter? I want to use it to filter all form fields (strip tags etc but no validation). All the examples seem to include a $validators array and pre-suppose that I will know the names of the fields on the way in.
Because of the nature of the project, timescales etc, it is not possible to rewrite the forms using Zend_Form. There is a generic Form class which handles all form input so I need to do the filtering in there.
Thanks!
Luke.
You can simply pass an empty array for the $validators argument to skip validation and simply use filtering.
Are you saying that you don't know the field names you'll pass into the Zend_Filter_Input instance? You can use the wildcard *-field to apply a filter to all input fields. Is this what you're asking for?
$input = new Zend_Filter_Input(array(
'*' => 'StripTags'
), array(), $data);
will filter all values in $data with the Zend_Filter_StripTags filter.
EDIT:
Retrieve the values with
$escaped = $input->getEscaped(); // will be automatically run through an HTML-entities-filter
// or
$unescaped = $input->getUnescaped(); // the values as they come out of the filter-chain.

Handling input with the Zend Framework (Post,get,etc)

im re-factoring php on zend code and all the code is full of $_GET["this"] and $_POST["that"]. I have always used the more phpish $this->_request->getPost('this') and $this->_request->getQuery('that') (this one being not so much logical with the getquery insteado of getGet).
So i was wondering if my method was safer/better/easier to mantain. I read in the Zend Framework documentation that you must validate your own input since the request object wont do it.
That leaves me with 2 questions:
What is best of this two? (or if theres another better way)
What is the best practice for validating php input with this methods?
Thanks!
I usually use $this->_request->getParams(); to retrieve either the post or the URL parameters. Then I use the Zend_Filter_Input to do validation and filtering. The getParams() does not do validation.
Using the Zend_Filter_Input you can do application level validation, using the Zend Validators (or you can write your own too). For example, you can make sure the 'months' field is a number:
$data = $this->_request->getParams();
$validators = array(
'month' => 'Digits',
);
$input = new Zend_Filter_Input($filters, $validators, $data);
Extending Brian's answer.
As you noted you can also check out $this->_request->getPost() and $this->_request->getQuery(). If you generalize on getParams(), it's sort of like using the $_REQUEST superglobal and I don't think that's acceptable in terms of security.
Additional to Zend_Filter, you may also use simple PHP to cast the required.
E.g.:
$id = (int) $this->_request->getQuery('id');
For other values, it gets more complicated, so make sure to e.g. quote in your DB queries (Zend_Db, see quoting identifiers, $db->quoteIdentifier()) and in views use $this->escape($var); to escape content.
You can't write a one-size-fits-all validation function for get/post data. As in some cases you require a field to be a integer and in others a date for instance. That's why there is no input validation in the zend framework.
You will have to write the validation code at the place where you need it. You can of course write some helper methods, but you can't expect the getPost() to validate something for you all by itself...
And it isn't even getPost/getQuery's place to validate anything, it's job is to get you the data you wan't, what happens to it from there on should not be it's concern.
$dataGet = $this->getRequest()->getParam('id',null);
$valid = new Zend_Validate_Digits();
if( isset($dataGet) && $valid->isValid($dataGet) ){
// do some...
} else{
// not set
}
I have always used the more phpish $this->_request->getPost('this') and $this->_request->getQuery('that') (this one being not so much logical with the getquery insteado of getGet).
What is best of this two? (or if theres another better way)
Just a quick explanation on the choice of getQuery(). The wording choice comes from what kind of data it is, not how it got there. GET and POST are just request methods, carrying all sorts of information, including, in the case of a POST request, a section known as "post data". A GET request has no such block, any variable data it carries is part of the query string of the url (the part after the ?).
So, while getPost() gets the data from the post data section of a POST request, getQuery() retrieves data from the query string of either a GET or POST request (as well as other HTTP Request methods).
(Note that GET Requests should not be used for anything that might produce a side effect, like altering a DB row)
So, in answer to your first question, use the getPost() and getQuery() methods, this way, you can be sure of where the data source (if you don't care, getParams() also works, but may include additional data).
What is the best practice for validating php input with this methods?
The best place to validate input is where you first use it. That is to say, when you pull it from getParams(), getPost(), or getQuery(). This way, your data is always correct for where you need it, and if you pass it off, you know it is safe. Keep in mind, if you pass it to another Controller (or Controller Action), you should probably check it again there, just to be safe. How you do this depends on your application, but it still needs to be checked.
not directly related to the topic, but
to insure that you get an number in your input, one could also use $var+0
(however if $var is a float it stays a float)
you may use in most cases
$id = $this->_request->getQuery('id')+0;

Categories