We're using Zend Framework 1.12 and in several actions we have:
$postParams = $this->getAllParams();
...
$domainModel->update($postParams)
I was wondering if it's a good approach of handling params. Or is it better to define what parameters we want to get like:
$postParams = array(
'email' => $this->_getParam('email'),
'company' => $this->_getParam('company')
)
Or maybe use array intersection function to filter out unexpected parameters?
Best practice should be using
$postParams = array(
'email' => $this->_getParam('email'),
'company' => $this->_getParam('company')
);
Using array intersection may work (for checking the keys not values of course!)
Why is passing all params to $domainModel->update not so good?
Depends on logic of update but assuming that parameters are getting into database query, by manipulating http request i can inject some additional code or params into db query - maybe update the field you do not want to update by that particular action.
Downside of this approach is that when you change your model, you have to check your code for these params.
If all columns in table (including IDs) can be changed, you can use getAllParams. Except one problem: POST can contain variables that are not table columns, so you will get an error on update (column '...' not found).
Its not a good idea to pass all post parameters to model directly. Sometimes you may not want pass specific values to model.
Second, you may want to set some default values to the data in case its not provided in that case you can do $this->_getParam('company', DEFAULT_VALUE)
But i would say that usage of any method depends on your requirements and then you need to pick one which is most suitable for you.
Related
Is it OK to use
$id = $request->get('some_id');
instead of setting some parameters in Routes AND Controller like:
Route::get('some_page/{parameters}', 'controllerName#functionName');
function functionName($parameters)
{
$id = $parameters;
}
Appreciation
Of course it's good. When you're using GET, both ways are similar and if you like to use $request->get() for some reason, it's totally ok.
If you're using Form, it's the only right way. Plus, you can create custom Request class to use it for validation and other operations:
https://laravel.com/docs/master/validation#form-request-validation
They have two fundamentally different goals.
Using $request->get() is a way to retrieve a value from inside the php's REQUEST object regardless of its association with routing pattern you use.
Following HTTP's standards, you probably use $_GET to read some value without it changing the database [significantly] and you use $_POST to write data to you server.
While {pattern} in routing ONLY and ONLY should be used as a way for your application to locate something, some resource(s); in other words, its only goal is to help you route something in your server.
Nevertheless, in certain cases, such as /user/{id} the value of {id} might encounter some overlapping as to whether be treated as a route parameter or as a key of $_REQUEST.
Things such as tokens, filters criteria, sorting rules, referrers (when not significantly) etc. can be read right from $_REQUEST without interfering them into routing pattern of you application.
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.
Okay, so I'm fairly new to CakePHP. This is the setup:
I've got a Model (Reservation), and a controller, (ReservationController).
I'm trying to provide a simple add() functionality.
The request url is: www.example.com/reservations/add/3
Where 3 is the ID of the event this reservation is for.
So far, so good. The problem is, the form is constructed like this:
<h2>Add reservation</h2>
<?php echo $form->create('Reservation');
echo $form->input('first_name');
echo $form->input('last_name');
echo $form->input('email');
echo $form->input('tickets_student'); echo $form->input('tickets_nstudent');
echo $form->end('Add');?>
When I hit the send button, the request URL becomes simply www.example.com/reservations/add/, and the event id is lost.
I've solved it now by grabbing the id in the controller, and make it available to the form:
// make it available for the form
$this->set('event_id', $eventid);
And then, in the form:
$form->create('Reservation',array('url' => array($event_id)));
It works, but it strikes me as a bit ugly. Isn't there an easier way to make sure the form POST action gets made to the current url, instead of the url without the id?
Nik's answer will fail if the website isn't in the server public_html root.
This answer is more solid:
<?php echo $form->create('Reservation',array('url'=>'/reservation/add/'.$data['id']));?>
Following the strictest convention for just a moment, reading a URL like /reservations/add/3 would be, well, confusing. You're calling on the ReservationsController to act on the Reservation model, but passing it an event ID. Calling /reservations/edit/3 is far less confusing, but just as wrong for your situation since the id value, "3", would be assumed to be a reservation identifier.
Essentially, you're making an ambiguous request at best. This is a simple form to create a reservation and that reservation has to be associated with an event. In a "traditional" scenario, the form would allow the user to select an event from some kind of list. After all, the foreign key, probably event_id in this case, is really just another property of a reservation. The list would have to be populated in the controller; this is usually done via a find( 'list' ) call.
If you already know the event that you want to create the reservation against (which you apparently do), then I'd probably select the analogous method of using a hidden field in the form. You still have to set the value in the controller just as you're doing, but the end result is a bit more Cake-y. The hidden field would be named data[Reservation][event_id] (again, I'm assuming the name of your foreign key field).
$form->create('Reservation',array('action' => 'add',$eventId);
and in the controller:
function add($eventId = null)
{
if($eventId == null)
{
// error state
throw new NotFoundException('Invalid id');
}
...
}
I do it all the time.
You can do following:
$form->create('Reservation',array('url' => $this->Html->url()));
this way all your variables from the url will be added in the form action :)
As Rob Wilkerson suggests, the issue is your URL route doesn't accurately describe the operation being performed. It becomes further confusing when you want to edit the reservation: /reservations/edit/6. Now the number in the URL means something different.
The URL convention I use for situations like these (adapted to your particular case) is /events/3/reservations/add. It takes a bit more up-front to configure your routes, but I've found it's superior for clarity down the road.
Sample routes.php:
Router::connect(
'/events/:event_id/reservations/:action',
array('controller'=>'reservations','action'=>'index'),
array(
'pass' => array('event_id'), // pass the event_id as a param to the action
'event_id' => '[0-9]+',
'actions'=>'add|index' // only reverse-routes with 'action'=>'add' or
// 'action'=>'index' will match this route
)
)
// Usage: array('controller'=>'reservations','action'=>'add','event_id'=>3)
Router::connect(
'/events/:event_id/reservations/:id/:action',
array('controller'=>'reservations'),
array(
'pass' => array('id'), // pass the reservation id as a param to the action
'id' => '[0-9]+',
'event_id' => '[0-9]+',
'actions'=>'edit|delete' // only reverse-routes with 'action'=>'edit' or
// 'action'=>'delete' will match this route
)
)
// Usage: array('controller'=>'reservations','action'=>'edit','event_id'=>3,'id'=>6)
In your FormHelper::create call, you'd have to specify most of the reverse-route you want to follow, but again, the up-front cost will pay dividends in the future. It's usually better to be explicit with Cake than to hope its automagic always works correctly, especially as the complexity of your application increases.
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.
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;