CodeIgniter - save method and redirects - forms

I have a page to manage courses, built with CI 3. When the user hits the save button, the form is submitted to the save method. My problem is how do I redirect the user to the previous page with the form populated with the data inserted?
At the moment what's happening is that after submit, the save method loads the views of the /new page, and the URL stays as /save with the data populated.
Already tried the redirect, but it loses the data the user had inserted.
Here a snippet of my save method:
public function save()
{
$this->checkIsAdmin();
$this->load->helper('form');
$this->load->library('form_validation');
$this->form_validation->set_rules('name', $this->lang->line('common_name'), 'required');
if ($this->form_validation->run() === FALSE)
{
$this->feedback_message->create('Please check fields', 'error');
$this->baseInfo['page_title'] = "Registar novo curso";
$this->mybreadcrumb->add('Registar curso', base_url('course/new'));
$data['schools'] = $this->School_model->listSchools();
$this->load->view('web/top', $this->baseInfo);
$this->load->view($this->templatesFolder.'tabs_start', array('courseId' => 0));
$this->load->view($this->templatesFolder.'manage', $data);
$this->load->view($this->templatesFolder.'tabs_end');
$this->load->view('web/footer');
/*redirect("/course/new", "location");*/
}else{
$saved = $this->Course_model->saveCourse();
if($saved){
$this->feedback_message->create('Success', 'success');
}else{
$this->feedback_message->create('Error '.$_POST['name'], 'error');
}
redirect('course/');
}
}

To re-populate the form you have to use the set_value('field_name') function in your input field like below:
<input type="text" name="name" value="<?php echo set_value('name'); ?>" />
Return the previous view as:
$this->load->view('view_name',$All_Data_For_View);
Still If you aren't understand then read the CI form validation again.

Related

codeigniter, form validation false verse first time visit

In Codeigniter, the following code is typically used for a page that has a form. But the first time a user lands on the page and a form validation fails gets routed through the same path.
As this example shows, the flash data will trigger. even if the user just land on the page and have not submit any form yet.
I am trying to echo a new class name to some input field to highlight them if validation fails. but currently it highlights the field on first load as well.
I am aware I can echo a validation_error or form_error. is there a way to echo a generic message that is not tied to a field-name and only after submission fails
// rules and other stuff above
if ($this->form_validation->run() == FALSE){
$this->session->set_flashdata('errorClass',"is-invalid");
$this->load->view('defaultOrFalse');
}else{
$this->load->view('success');
}
//view file
<input class=" <?php $this->session->flashdata('errorClass') ; ?>">
Basically I am trying to get bootstrap 4's input validation to show up
https://getbootstrap.com/docs/4.0/components/forms/#server-side
I don't know your exact setup but you can do logic like the following:
<?php
class Some_controller extends CI_Controller {
// controller/search/{$term}
public function some_method($term = null) {
// where some_field is some field in your form
// that gets posted on submit
if ($this->input->post('some_field')) {
// or if (isset($_POST)) {
if ($this->form_validation->run() == FALSE) {
$this->session->set_flashdata('errorClass', "is-invalid");
$this->load->view('defaultOrFalse');
} else {
$this->load->view('success');
}
} else {
// default view
}
}
}
?>
For your second question:
<h5>Username</h5>
<?php echo form_error('username'); ?>
<input type="text" name="username" value="<?php echo set_value('username'); ?>" size="50" <?php if (!empty(form_error('username'))) { echo "class='error'"; } ?> />
Can also make a helper and use instead of form_error to check if field has error for your class (haven't verified this works but it should).
/**
* Checks if form validation field by name
* has error
*
* #param string $field Name of field
* #return boolean
*/
function field_has_error($field) {
$CI = &get_instance();
$CI->load->library('form_validation');
$arr = $CI->form_validation->error_array();
if (isset($arr[$field])) {
return true;
}
return false;
}
Usage:
<?php if (field_has_error('username')) { echo "class='error'"; } ?> />

cakephp edit form with file type not overidding http with put and post occurs twice with empty data

First off I'm new to cakephp.... I'm pulling survey questions from a database and building a form of type=file.
echo $this->Form->create('PersonalDetail', array('type' => 'file', 'id' => 'editProfileForm', 'class' => 'form-horizontal'));
echo $this->Form->hidden('id');
echo $this->Form->hidden('PersonalDetail.id');
echo $this->Form->input('PersonalDetail.field_name', array('label' => false, 'div' => false, 'readonly' => false));
echo $this->Form->submit('Update Profile', array('class' => 'btn btn-primary', 'id' => 'editProfileSubmitBtn'));
echo $this->Form->end();
According to cakephp docs "Since this is an edit form, a hidden input field is generated to override the default HTTP method." But I can't seem to figure out how to tell cake this is an edit form. It always inserts a hidden POST not PUT method:
<form action="/editForm" id="editProfileForm" class="form-horizontal" enctype="multipart/form-data" method="post" accept-charset="utf-8">
<div style="display:none;">
<input type="hidden" name="_method" value="POST"/>
<input type="hidden" name="data[_Token][key]" value="ff8b198e82d800a35581" id="Token836"/></div>
<input type="hidden" name="data[id]" id="id"/>
<input type="hidden" name="data[PersonalDetail][id]" id="PersonalDetailsId"/>
<label class="control-label required">Username</label>
<input name="data[PersonalDetail][field_name]" maxlength="255" type="text" id="PersonalDetailsFieldName"/>
<input class="btn btn-primary" id="editProfileSubmitBtn" type="submit" value="Update Profile"/>
<div style="display:none;">
<input type="hidden" name="data[_Token][fields]" value="a2f722badf82c0d8991ab8%3APersonalDetail.id%7Cid" id="TokenField020"/> <input type="hidden" name="data[_Token][unlocked]" value="" id="TokenUnlocked1562820470"/> </div></form>
The problem is when I submit the form and watch with Firefox's Tamper Data the form posts the data fine, but then it posts again immediately again with all the data missing.
On a working form example, I see the same behaviour, except the hidden input field is "PUT" and when the form submits, it is first a PUT with data, then the immediate second submission is with the POST with data instead of begin blank.
I assume I'm missing something basic here, but I'm really confused.
Here's the controller where PersonalForm is a database of questions passed to an element that builds the forms. PersonalDetail is supposed contain the answers but for this first time this is run the user won't have any answers.
public function editForm() {
$userId = $this->UserAuth->getUserId();
if (!empty($userId)) {
$user_account_type = $this->UserDetail->read('account_type', $userId);
$user_account_type = $user_account_type['UserDetail']['account_type'];
$this->set('user_acct_type', $user_account_type);
$this->loadModel('Usermgmt.PersonalForm');
$forms = $this->PersonalForm->find('all');
$this->set('forms', $forms);
if ($this->request->isPut() || $this->request->isPost()) {
//put in ajax verification
//$this->PersonalDetail->saveAssociated($this->request->data);
$this->Session->setFlash(__('Your answers have been successfully updated'));
$this->redirect('/dashboard');
} else {
// read user's original responses and populate form
$this->loadModel('Usermgmt.PersonalDetail');
$answers = $this->PersonalDetail->read(null, $userId);
$this->request->data = null;
if (!empty($answers)) {
$this->request->data = $answers;
}
}
} else {
$this->redirect('/dashboard');
}
}
I'm using cakephp 2.3.7 and I'm running the debugKit plugin (maybe causing more than one submission? I don't know.) Edit: Also I'm using UserAuth and Security modules.
EDIT: I oversimplified the example when I removed the hidden id fields. Now I included the two hidden input elements. However the first time this form is loaded there is no edit data so it is a create instead of add case. So I don't understand why it is posting twice and losing the data on the second post. Perhaps that is the real problem and not that it should be PUT vs POST? I'm obviously missing something fundamental in how cake is processing the post data.
Perhaps I should mention this is form is part of a plugin. Could the routing have something to do with the loss of data and the second post?
You are missing the vital part of an edit form, the id:
echo $this->Form->input('id');
Without its presence cake assumes that this is not an update (edit), but a create (add).
Also mind your casing, its not $this->Form->Submit() but $this->Form->submit().
EDIT:
At second look: I also guess that you violated more than 5 other conventions, including the most important one: Models are singular, Controllers plural. Meaning:
$this->Form->create('PersonalDetail');
If your model is PersonalDetail (which from your controller code it looks like).
This would explain why the data doesnt end up where it is supposed to.
Again my recommendation: Bake your code to see how its done.
It appears this is related to a security module problem.
I was able to prevent the double empty data posts by adding the following to the beforeFilter:
if (isset($this->Security) && ($this->RequestHandler->isAjax() || $this->action == 'editForm')) {
$this->Security->csrfCheck = false;
$this->Security->validatePost = false;
}
Now I need to research the reasons for this security problem with my form to fix it.

CodeIgniter form_open() action not working correctly

I have have a view in which there's a form that manages products (either add new product or -if an id passed- editing an existing one). If an id is passed then the form action should be eg 'admin/product/manage/5', if no id passed then it should be like this 'admin/product/manage'.
<?php echo form_open('admin/product/manage/{optional product id}', array('class' => 'ajax-form')); ?>
I have also created and this route:
$route['admin/product/manage'] = "admin/product/manage";
$route['admin/product/manage/(:num)'] = "admin/product/manage/$1";
How can I make my form action work correctly? is it possible to put inside the action the route somehow??
This is my Controller:
public function manage($id = NULL){
//fetch a single product to edit or create a new one
if (isset($id) === true) {
$data['prod'] = $this->product_model->get($id);
$data['vers'] = $this->product_version_model->get_by('product_id',$id);
} else {
$data['prod'] = $this->product_model->make_new();// this returns $product->product_name = ''; in order to be empty the input field and not throughing errors
}
$this->product_model->save_product();
$this->product_version_model->save_version();
// load the view
$this->layout->view('admin/products/manage', $data);
}
This is my view:
<?php echo form_open('admin/product/manage', array('class' => 'ajax-form')); ?>
<p>
<label for="product_name">Product *</label>
<input type="text" name="product_name" value="<?php echo set_value('product_name', $prod->product_name); ?>" />
<?php echo form_error('product_name'); ?>
</p>
<?php echo form_close() . PHP_EOL; ?>
You need to declare both possible routes in order of importance, so:
$route['admin/product'] = "admin/product/manage";
$route['admin/product/(:num)'] = "admin/product/manage/$1";
From the Codeigniter Docs:
Routes will run in the order they are defined. Higher routes will always take precedence over lower ones.
Edit:
According to the changes you have made to your question I can say the following:
First of all isset() returns boolean only, so you don't need the type check "=== true". isset($id) is sufficient.
In order to have your form action set to the id you need to include it either in a hidden field or in the action itself.
So for example:
$action_id = (isset($id) ? '/'.$id : ''); // Using ternary operators here
echo form_open('admin/product/manage'.$action_id, array('class' => 'ajax-form'));
and add the id to the view data in your controller:
$data['id'] = $id;
As a side note: In order to comply with SoC (Separation of Concerns) you'd prepare all data in your controller (with e.g. models all having their own task) and pass the processed data to the view instead of partially generating data in the view itself.

Joomla 2.5 - component development - using form

I am trying to add some form to my component, but I am not shure what naming conventions must be applied to work it correctly.
Currently I have a working form - it displays fields stored in XML file and loads data from database to it. However, when i try to submit this form (edit or add new records), it doesn't work. After pressing submit (save() method) it just redirects me and displays that record was edited successfuly but it wasn't. When I try to edit existing record, after pressing submit nothing happens and when I try to add new record, it just adds empty/blank record.
So I was doing a little debug and discovered, that problem is in the JController::checkEditId() method. It always returns false which means that JControllerForm::save() returns false as well and that's why it doesn't save it correctly. HTML code of form is correct and I can access the data by using global array $_POST.
I suspect that this problem is because of naming conventions in methods loadFormData, getForm of JModelAdmin class. I am not sure how to name that form.
So here is my code related to this problem:
Subcontroller for displaying the form - controllers/slideshowform.php
class SlideshowModelSlideshowForm extends JModelAdmin{
public function getForm($data = array(), $loadData = true){
return $this->loadForm('com_slideshow.slideshowform', 'editform', array('load_data' => $loadData, 'control' => 'jform'));
}
protected function loadFormData(){
$data = JFactory::getApplication()->getUserState('com_slideshow.edit.slideshowform.data', array());
if (empty($data))
{
$data = $this->getItem();
}
return $data;
}
public function getTable($table = "biometricslideshow"){
return parent::getTable($table);
}
}
views/slideshowform/view.html.php
class SlideshowViewSlideshowForm extends JView{
public function display($tmpl = null){
if (count($errors = $this->get('Errors')))
{
JError::raiseError(500, implode('<br />', $errors));
return false;
}
$this->form = $this->get('form');
$this->item = $this->get('item');
JToolBarHelper::save('slideshowform.save');
parent::display();
}
}
views/slideshowform/tmpl/default.php
<?php
defined('_JEXEC') or die('Restricted access');
JHtml::_('behavior.tooltip');
?>
<form method="post" action="<?php echo JRoute::_("index.php?option=com_slideshow&id=".(int) $this->item->id)?>" name="adminForm" id="slideshow-form">
<fieldset class="adminform">
<legend>Edit slide</legend>
<table>
<input type="hidden" name="task" value="">
<?php echo JHtml::_('form.token'); ?>
<?php
foreach($this->form->getFieldset() as $field){
?>
<tr><td><?php echo $field->label ?></td><td><?php echo $field->input ?></td></tr>
<?php
}
?>
</table>
</fieldset>
</form>
Can someone take o look, please?
you have to add controller SlideshowControllerSlideshowForm and code save method. In there you have to validate the form data and call SlideshowModelSlideshowForm->save event, then redirect with success/failure message.

CakePHP Cancel button does not fire

In my view, I have a form with submit and cancel buttons. Both actions return me to my index page. The only difference is Submit does a normal db submit and displays the message 'Your Invoice has been updated.', whereas the Cancel should cancel the update and display 'Update canceled.'. Here's the controller code:
public function edit($id = null) {
$this->Invoice->id = $id;
$this->set('invoice', $this->Invoice->read(null, $id));
//Check for $_GET
if ($this->request->is('get')) {
$this->request->data = $this->Invoice->read();
} else {
// Bail if cancel button pressed
if (isset($this->params['form']['cancel'])) {
$this->Session->setFlash('Update canceled.');
$this->redirect(array('action' => 'index'));
} else if ($this->Invoice->save($this->request->data)) {
$this->Session->setFlash('Your Invoice has been updated.');
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash('Unable to update your Invoice.');
}
}
}
And here is the view:
<fieldset>
<legend>Enter New Values</legend>
<li><?php echo $this->Form->input('purchaseOrderNumber'); ?></li>
<li><?php echo $this->Form->input('siteAddress'); ?></li>
<li><?php echo $this->Form->input('siteCity'); ?></li>
<li><?php echo $this->Form->input('siteState'); ?></li>
<?php
echo $this->Form->button('Submit Form', array('type' => 'submit'));
echo $this->Form->submit('Cancel', array('div' => false, 'name' => 'cancel'));
?>
However, no matter which button is pressed, it ALWAYS returns the first message. It also performs the db submit.
I tried unsuccessfully using XDebug with Netbeans but that's a story for a different time. Usually my mistakes are obvious to others. So, I'm hoping someone can set me back on track.
I was just working on the same problem, and I found a solution that works without simply linking back to index. At Wylie's suggestion to debug $this->params, I noticed that the 'form' array was not being created. However, there was an array called 'data' in which the 'cancel' parameter was defined.
So in the controller where you are checking which button was pressed, instead of
if (isset($this->params['form']['cancel'])) {
use
if (isset($this->params['data']['cancel'])) {
and you will get a working cancel button.