Form validation for relational elements - cakephp

I have a form in CakePHP to save information to multiple models.
My first model is "World", I have no problem for these fields the validation is correct and it's saved correctly to the database.
The second model is "Country", I use something like this:
echo $this->Form->input('Country.0.name');
This is correctly saved to the database, but there is no validation (like stairs for required fields) and no automagic (autodetection of the content type).
The third model is "Region", I use the same code as for the second one but there is no validation, no automagic and no saving...
Can someone help ?
Thank you,
Sébastien

Without seeing the rest of your code, I am guessing that you are trying to save multiple countries at the same time. The model expects the data to come in a specific format:
$this->data['Model']['field'];
What you are passing is:
$this->data['Model'][0]['field'];
The model cannot interpret it. The way to resolve this is build a foreach when you collect the data and send each request independently.
foreach($country as $field) {
$data['Country']['field'] = $field;
// add other fields that are required
if($this->Country->validates($data)) {
$this->Country->create();
$this->Country->save($data);
} else {
// error handling
}
}
Good luck and happy coding!

Related

Cakephp 3 - Building an entity over several forms/actions

This is a design question.
I'm trying to build a booking system in cakephp3.
I've never done something like this with cake before.
I thought the best way might be to -- as the post title suggests -- build up an entity over several forms/actions.
Something like choose location -> enter customer details -> enter special requirements -> review full details and pay
So each of those stages becomes an action within my booking controller. The view for each action submits its content to the next action in the chain, and i use patch entity with the request data, and send the result to the new action's view.
I've started to wonder if this is a good way to do it. One significant problem is that the data from each of the previous actions has to be stored in hidden fields so that it can be resubmitted with the new data from the current action.
I want the data from previous actions to be visible in a read only fashion so I've used the entity that i pass to the view to fill an HTML table. That's nice and it works fine but having to also store that same data in hidden fields is not a very nice way to do it.
I hope this is making sense!
Anyway, I thought I'd post on here for some design guidance as i feel like there is probably a better way to do this. I have considered creating temporary records in the database and just passing the id but i was hoping I wouldn't have to.
Any advice here would be very much appreciated.
Cheers.
I would just store the entity in the DB and then proceed with your other views, getting data from the DB. Pseudo:
public function chooseLocation() {
$ent = new Entitiy();
patchEntity($ent,$this->request->data);
if save entity {
redirect to enterCustomerDetails($ent[id]);
}
}
public function enterCustomerDetails($id) {
$ent = $this->Modelname->get($id);
// patch, save, redirect again ...
}

CakePHP Form validation using other models to validate and/or save?

So my question is pretty much like the title. I have a form object called StudentApplicationForm. This uses some elements called grade_element_form.ctp, schools_element_form.ctp, student_element_form.ctp and guardian_element_form.ctp. All have their respective inputs built and sent to my StudentApplicationForm Model when the form is submitted. I want to use the Grade, School, Student and Guardian objects to validate the data before saving their respective information in their respective tables in the database.
I am able to build the appropriate arrays to be sent to the models of each of the objects of the form and save them to the database. Now I want to make sure they are validated before saving though. Is the best way to approach this by using the:
$this->ModelName->set($the_data)
if($this-ModelName->validate()){
//true
}else{
//false
}
As shown here: cakephp form validation
If the models are related, you can use $this->Model->saveAll() or $this->Model->saveAssociated() to save them all at once, by putting all the data in a single array, properly formatted, and saving that.
If they are not related, then you need to be using transactions, http://book.cakephp.org/2.0/en/models/transactions.html. With transactions, there's no need to call $this->ModelName->validate() before saving. Start the transaction, try to save each one, and if one of them fails, rollBack, and all the changes you attempted after you started the transaction will not be in the database. If everything succeeds, commit it.
Example:
$dataSource = $this->Model1->getDataSource();
$dataSource->begin();
if(!$this->Model1->save($array1))
{
$dataSource->rollback();
$this->Session->setFlash('There was an error saving model 1');
return;
}
//Continue the pattern for the other models...
//If all the saves succeeded then...
$dataSource->commit();

CakePHP - Prevent model data being save in a saveMany call when certain fields are blank

I have scenario where I have 3 different models data being saved from one form, by means of the saveAll pass through method in CakePHP 2.x
The models on the form are:
Project
ProjectImage
ProjectAttachment
1 and 2 are saving perfectly, but I am having problems with the ProjectAttachment fields. If you look at the following image, the fields in question are at the bottom right, highlighted by a red frame: http://img.skitch.com/20120417-bnarwihc9mqm1b49cjy2bp13cf.jpg
Here is the situation:
I have named the fields as follows: *ProjectAttachment.0.project_id*, ProjectAttachment.0.name .... *ProjectAttachment.6.project_id* etc where the numbers are relative to the already present amount of attachments the user has added, as there is no limit. So if the user has ALREADY added 6 documents, the field would be called ProjectAttachment.7.id and so on. This is because of the naming convention when using the saveAll method.
I have made use of two hidden fields, one to store the user ID, the other to store the project ID.
The problem is that if the user does not fill in the Document Title and select a file to upload, the form fails! If I remove all validation rules, the form no longer fails BUT a blank ProjectAttachment record is inserted.
I suspect the problem may also be that the project_id and user_id fields (that are hidden) already have values in them?
I gave it some thought, and came up with a simple concept: In my controller, before the saveAll call, I would check to see if a blank Document Title field was submitted, and if so, I would completely eliminate the relevant array entry from the $this->request->data['ProjectAttachment'] array, but this did not seem to work.
To clarify, I am not looking for validation rules. If the user decides they only want to upload images and not touch the ProjectAttachment form, them the saveAll operation must not fail, it must simple not attempt to save the blank fields in the form, if this is at all possible.
Any suggestions?
Kind regards,
Simon
Well it seems that the solution was far simpler than I had initially thought! I was partially on the right track, and I had to unset the variable ProjectArray key in the $this->request->data array if I had encountered any blank fields.
I did this as follows:
if(!empty($this->request->data['ProjectAttachment'])){
foreach($this->request->data['ProjectAttachment'] as $key => $value){
if(is_array($value) && array_key_exists('upload_file', $value)){
if($value['upload_file']['name'] == ''){ // Blank document file
unset($this->request->data['ProjectAttachment']);
}
}
}
}
I hope someone finds this somehow useful in some form or another.
Kind regards,
Simon

CakePHP 1.3 controller save() does not save data

I want to add a new user to the database, and do so by making them fill in a form and submitting this. All seems to work fine. Just before my save() call in the controller I return all data and all necessary data is there. It is valid(ated), since no errors are returned.
But then nothing happens. I'm being returned to my form without any errors being shown.
This is my 'save-line':
if($this->Registratie->save($this->data)) {
I'm not making use of any beforeSave() methods.
Using debug($this->validationErrors); shows:
app/controllers/registratie_controller.php (line 45)
Which is the line of code from above.
I've been going through my code over and over. What could the problem be?
When you create a form using the FormHelper it will generate input names like:
<input type='text' name='data[Registratie][first_name]'>
Once the form is submitted cake will push that into the $this->data array with an index of 'Registratie'
You probably need to pass the index to the model when saving
if ($this->Registratie->save( $this->data['Registratie'] ) ) {
I would also do a var_dump($this->data) or print_r($this->data) to make sure your form fields are coming through.
I had the same problem, fixed doing exactly what Jack B Nimble told. Using CakePHP 1.3
Sample:
Model: Contacts
$this->data['contact']

How do you perform Form validation without a model in Cakephp?

I need to perform some validation. I don't have the model in the application.
Does anyone know how to do the validation without a model?
Can you show me using a small sample or statement?
Honestly, I'd create a model just for the validation. You can create a model that doesn't use a table by adding
var $useTable = false;
And then create a validation array with rules for each field you want to validate:
var $validate = array('login' => 'alphaNumeric','email' => 'email','born' => 'date');
Then, in your controller, do something like:
$this->MyModel->set($this->data);
if($this->MyModel->validates()){
// do stuff with valid data
}
If you really, really can't use a model, then you'll have to simply loop over each value in $this->data in your controller action and validate it against a regular expression or use the Validation::[rule]() stuff, like:
if(Validation::email($someThingThatMightBeAnEmailAddress)){
// do stuff with valid email address.
}
You can perform validation of form data in CakePHP without having to create a model.php file. There are many times when I need to do this, and storing model.php files that do nothing more then validation is a poor usage of the model design pattern.
Another problem with CakePHP is that sometimes validation rules are common across multiple models. It would be nice to move validation out of the model, much in the way behaviors are to their own subfolder. That way we can re-use them or use them without a model.
Another problem with validation is that it's dependent upon the model alias. If you have a model called "Email" without a table to perform validation, then the posted form must also use "Email". If the form uses a alias different from the controller, then you have to set the action. A lot of extra steps just to do validation. You can't re-use that model again if your form uses a different model.
So here is my alternative approach.
In your controller's action that receives the posted form data. You can create a default CakePHP model, add some validation rules and then use that model for validation.
An example action might look like this;
function edit()
{
$model = ClassRegistry::init(array('class'=>'Email','table'=>false,'type'=>'Model'));
if(!empty($this->data))
{
$model->validate = array(
'subject'=>array(
'rule'=>'notEmpty',
'required'=>true
),
'message'=>array(
'rule'=>'notEmpty',
'required'=>true
)
);
if($model->save($this->data))
{
// validation was successful, but no data was actually saved
}
}
}
The key here is the creation of an automatic model by CakePHP.
$model = ClassRegistry::init(array('class'=>'Email','table'=>false,'type'=>'Model'));
The above attempts to find a model by Email in the applications model folder. When it is not found CakePHP will auto-create an in memory model for that class. Since we set the value of 'table' to false, then this should tell CakePHP that this model doesn't use a table.
This works as long as there really isn't a email.php file in the applications model folder. Once this model is created in memory. It's accessible from the built in Form help. That means validation errors will be passed correctly to the view.
Here is an example view file.
<?php echo $this->Form->create('Email',array('action'=>array('controller'=>'mycontroller','action'=>'edit'))); ?>
<?php echo $this->Form->input('subject'); ?>
<?php echo $this->Form->input('message',array('type'=>'textarea')); ?>
<?php echo $this->Form->submit(); ?>
The view will now render the validation errors from the Email model using the Form helper. This is because CakePHP class registry has saved a copy of the EMail auto model in memory that the Form helper will access.
If you want to use custom validation rules, then you will have to put the callback methods in the app_model.php file.
These methods tested in CakePHP 1.3
#ThinkingMedia's answer got me going in the right direction, but $model->save($this->data) was returning false for me unfortunately, even when the form was valid. I'm using CakePHP 2.3.9 for reference.
It turned out that even with 'table' => false parameter set, the returned$success of save() was based on a $count > 0 of the rows that were created/updated/modified. In my table-less case, this meant a $count of 0 and $success was false. I ended up blending the referenced answer with this similar question's solution to have validation work properly without a model file:
function edit()
{
$model = ClassRegistry::init(array('class'=>'YourFormName','table'=>false,'type'=>'Model'));
if($this->request-is('post'))
{
$model->validate = array(
'some_field'=>array(
'rule'=>'notEmpty',
'required'=>true
),
'another_field'=>array(
'rule'=>'notEmpty',
'required'=>true
)
);
$model->set($this->request->data)
if($model->validates($this->request->data) && empty($model->validationErrors))
{
// validation was successful, but no data was actually saved
}
}
}
Came across this question since I also had a similar issue. I have a form that needs to collect data and generate a PDF. So there is no data saving involved nor there is a maching model class. The PDF is a user contract and the user will fill the online form and the data filled will be used to generate the PDF which they must print and mail back. But I need to validate whether the fields are not empty, whether email is really an email format, and date inputs are really date inputs.
First I did without a model class then saw this quesion. Now I'm using a dummy model class to have my validations put in there since the code in controller action looks much neat.
Class Validation which is a subclass of Object is used by model class to perform validation against validation rules specified in it.
One can directly instantiate Validation class inside any controller or model and use its methods for performing validation on any data, not only inputs from forms.
I think my first question would be this: if you don't have a model...what are you validating? Typically data collection would be done to populate a model. If you're using an alternative data repository (file, web services, etc.), a model would still be the appropriate way to access and manipulate that data.
In short, in order to better answer this, I think a little more context would be helpful and maybe even necessary.

Resources