Do a server side validation using multiple form fields - joomla

Overriding the JFormRule function "test", I need to implement a server side validation of a value of the form field against the value of another form field in the same form. I am struggling with a probably very easy thing: How can I get the value of this other form field?
Here's an extract of my form definition easyfpu.xml:
<?xml version="1.0" encoding="utf-8"?>
<form addrulepath="/administrator/components/com_easyfpu/models/rules">
<fieldset
name="details"
label="COM_EASYFPU_EASYFPU_DETAILS"
>
<field
name="id"
type="hidden"
/>
<field
name="calories"
type="text"
label="COM_EASYFPU_EASYFPU_CALORIES_LABEL"
description="COM_EASYFPU_EASYFPU_CALORIES_DESC"
size="40"
class="inputbox validate-numfracpos"
validate="numfracpos"
required="true"
hint="COM_EASYFPU_EASYFPU_CALORIES_HINT"
message="COM_EASYFPU_EASYFPU_ERRMSG_NUMBER_FRAC"
/>
<field
name="carbs"
type="text"
label="COM_EASYFPU_EASYFPU_CARBS_LABEL"
description="COM_EASYFPU_EASYFPU_CARBS_DESC"
size="40"
class="inputbox validate-numfracpos"
validate="carbs"
required="true"
hint="COM_EASYFPU_EASYFPU_CARBS_HINT"
message="COM_EASYFPU_EASYFPU_ERRMSG_NUMBER_FRAC"
/>
</fieldset>
</form>
The value of the "carbs" field needs to be assessed against the value of the "calories" field. Here's my test routine "carbs.php":
class JFormRuleCarbs extends JFormRule
{
public function test(SimpleXMLElement $element, $value, $group = null, JRegistry $input = null, JForm $form = null)
{
// Check if value is numeric
if (!is_numeric($value)) {
$element->attributes()->message = JText::_('COM_EASYFPU_EASYFPU_ERRMSG_NUMBER_FRAC');
return false;
}
// Check if calories from carbs do not exceed total calories (1g carbs has 4 kcal)
$caloriesFromCarbs = $value * 4;
$totalCalories = $form->getValue('calories');
if ($caloriesFromCarbs > $totalCalories) {
$element->attributes()->message = JText::_('COM_EASYFPU_EASYFPU_ERRMSG_TOOMUCHCARBS');
return false;
}
return true;
}
}
Unfortunately the code $totalCalories = $form->getValue('calories'); won't return anything, probably because it's part of a fieldset. How can I get the value of this field within this test routine?

Solved!
The $form variable of the test function is not yet filled with the data from the form to be stored when the test function is called. Makes sense, as otherwise the potential errors you want to exclude by performing the test would already be stored.
Retrieve the required form value from the $input variable instead, and all is set! Here's the correct code:
​class JFormRuleCarbs extends JFormRule
{
public function test(SimpleXMLElement $element, $value, $group = null, JRegistry $input = null, JForm $form = null)
{
// Check if value is numeric
if (!is_numeric($value)) {
$element->attributes()->message = JText::_('COM_EASYFPU_EASYFPU_ERRMSG_NUMBER_FRAC');
return false;
}
// Check if calories from carbs do not exceed total calories (1g carbs has 4 kcal)
$caloriesFromCarbs = $value * 4;
$totalCalories = $input->get('calories', 0); // <-- THIS IS HOW IT WORKS!
if ($caloriesFromCarbs > $totalCalories) {
$element->attributes()->message = JText::_('COM_EASYFPU_EASYFPU_ERRMSG_TOOMUCHCARBS');
return false;
}
return true;
}
}

Related

Why does the old() method not work in Laravel Blade?

My environment is Laravel 6.0 with PHP 7.3. I want to show the old search value in the text field. However, the old() method is not working. After searching, the old value of the search disappeared. Why isn't the old value displayed? I researched that in most cases, you can use redirect()->withInput() but I don't want to use redirect(). I would prefer to use the view(). method
Controller
class ClientController extends Controller
{
public function index()
{
$clients = Client::orderBy('id', 'asc')->paginate(Client::PAGINATE_NUMBER);
return view('auth.client.index', compact('clients'));
}
public function search()
{
$clientID = $request->input('clientID');
$status = $request->input('status');
$nameKana = $request->input('nameKana');
$registerStartDate = $request->input('registerStartDate');
$registerEndDate = $request->input('registerEndDate');
$query = Client::query();
if (isset($clientID)) {
$query->where('id', $clientID);
}
if ($status != "default") {
$query->where('status', (int) $status);
}
if (isset($nameKana)) {
$query->where('nameKana', 'LIKE', '%'.$nameKana.'%');
}
if (isset($registerStartDate)) {
$query->whereDate('registerDate', '>=', $registerStartDate);
}
if (isset($registerEndDate)) {
$query->whereDate('registerDate', '<=', $registerEndDate);
}
$clients = $query->paginate(Client::PAGINATE_NUMBER);
return view('auth.client.index', compact('clients'));
}
}
Routes
Route::get('/', 'ClientController#index')->name('client.index');
Route::get('/search', 'ClientController#search')->name('client.search');
You just need to pass the variables back to the view:
In Controller:
public function search(Request $request){
$clientID = $request->input('clientID');
$status = $request->input('status');
$nameKana = $request->input('nameKana');
$registerStartDate = $request->input('registerStartDate');
$registerEndDate = $request->input('registerEndDate');
...
return view('auth.client.index', compact('clients', 'clientID', 'status', 'nameKana', 'registerStartDate', 'registerEndDate'));
}
Then, in your index, just do an isset() check on the variables:
In index.blade.php:
<input name="clientID" value="{{ isset($clientID) ? $clientID : '' }}"/>
<input name="status" value="{{ isset($status) ? $status : '' }}"/>
<input name="nameKana" value="{{ isset($nameKana) ? $nameKana : '' }}"/>
...
Since you're returning the same view in both functions, but only passing the variables on one of them, you need to use isset() to ensure the variables exist before trying to use them as the value() attribute on your inputs.
Also, make sure you have Request $request in your method, public function search(Request $request){ ... } (see above) so that $request->input() is accessible.
Change the way you load your view and pass in the array as argument.
// Example:
// Create a newarray with new and old data
$dataSet = array (
'clients' => $query->paginate(Client::PAGINATE_NUMBER),
// OLD DATA
'clientID' => $clientID,
'status' => $status,
'nameKana' => $nameKana,
'registerStartDate' => $registerStartDate,
'registerEndDate' => $registerEndDate
);
// sent dataset
return view('auth.client.index', $dataSet);
Then you can access them in your view as variables $registerStartDate but better to check if it exists first using the isset() method.
example <input type='text' value='#if(isset($registerStartDate)) {{registerStartDate}} #endif />

codeigniter pagination - how to keep on same page after deleting row

I am using codeigniter pagination library and doing update and delete through form. The problem is when I delete or update any record after delete or update I redirected back to 1st page even if I am at 4th page. How I can redirected to the same page at which I have done update or delete.
Here is my controller code for update and delete functions:
public function update_att(){
if(isset($_POST['update'])){
$u_id = $_POST['at_id'];
if($_POST['status']=="Present"){
$data = array(
'status'=>"Absent"
);
$this->db->where('at_id', $u_id);
$this->db->update('attendence', $data);
}elseif ($_POST['status']=="Absent") {
$data = array(
'status'=>"Present"
);
$this->db->where('at_id', $u_id);
$this->db->update('attendence', $data);
}
redirect("usr/att_list", "refresh");
}
}
public function delete_att(){
if (isset($_POST['delete'])) {
$at_id = $_POST['at_id'];
$this->db->where('at_id', $at_id);
$this->db->delete('attendence');
}
redirect("usr/att_list" );
}
Currently I am redirecting to the first page , any suggestion how I redirect to that page where I have done delete or update.
Add <input type='hidden' name='current_page' value='<?php echo $current_page?>' /> to your form.
Keep in mind you need to populate $current_page with something like
$current_page = ''; // empty means first page
if( isset($_REQUEST['current_page'] ){
$current_page = $_REQUEST['current_page'];
}
Then based on your sample you just modifiy the redirect path as follows (for both your functions):
public function delete_att(){
if (isset($_POST['delete'])) {
$at_id = $_POST['at_id'];
$this->db->where('at_id', $at_id);
$this->db->delete('attendence');
}
redirect("usr/att_list".(strlen($current) ? "?".$current : "" );
}
Note:
Your path to your page should look something like this domain.com/controller/your_page_with_pagination/?current_page=A_NUMBER then in your controller/your_page_with_pagination you adjust the data you wish to output based on $_GET['current_page']
Edit based on your link:
public function att_list($id = ""){
/**
* Keep your data in array
*/
$this->data = array();
/**
* Add the page number ($id) to the array
* Check for url /:id first , or else check for a $_GET/$_POST current_page (this will be triggered when you submit your form)
*/
$this->data['current_page'] = is_numeric($id) ? $id : (isset($_REQUEST['current_page'] ? $_REQUEST['current_page']: 0);
/**
* This is your 'keep on the same page' line
* $this->data['current_page'] will act as an offset in your query
* You can read about 'offset' here https://www.w3schools.com/php/php_mysql_select_limit.asp
* $this->data['my_desired_records'] must be generated into your <form> ... </form> , and the same form must contain the input with name='current_page'
*/
$this->data['my_desired_records'] = $this->your_model->get_data($this->data['current_page']);
/**
* Pass the whole array into your view
*/
$this->load->view('path/to/view', $this->data);
}
Then in your view add in your form <input type='hidden' name='current_page' value='<?php echo $this->data['current_page']?>' />

LARAVEL 5 How to store empty DateTime input to Null value instead of 0000:00:00 00:00 value

i had two input Datetime field.
User can choose to fill in either these two field.
For the empty input Datetime field, i want it to store as Null value in Database.
But currently the empty input Datetime field is store as 0000:00:00 00:00 value in Database. What code should i modified?
you can use model observers to unset the attribute before saving when it is empty. But be sure that the fields are nullable
class Flight extends Model
{
public static function boot()
{
parent::boot();
self::saving(function ($flight_model) {
if(empty($flight_model->arriveDateTime)) unset($your_model->attributes['your_date_field1'];
if(empty($flight_model->departDateTime)) unset($your_model->attributes['your_date_field2'];
});
}
}
this discussion would be a good reference
Update
to do the limitation in the controller you'll use required_without_all:foo,bar,... which as described in doc.s
The field under validation must be present and not empty only when all of the other specified fields are not present
to use it we'll add new rules like
$rules = array(
'arriveDateTime' => 'required_without_all:departDateTime',
'departDateTime' => 'required_without_all:arriveDateTime',
);
$validator = Validator::make(Input::all(), $rules);
and if you're using rules already just append this two roles to them. that's for the controller validation part.
for the view part I'll assume you've two inputs with id="arriveDateTime" and id="departDateTime" the code would be like
$(function() {
<!-- if the first input value changed disable the second input -->
$('#arriveDateTime').on('change', function() {
if ($(this).val() == '') {
$('#departDateTime').prop("disabled", false);
} else {
$('#departDateTime').prop("disabled", true);
}
});
<!-- if the second input value changed disable the first input -->
$('#departDateTime').on('change', function() {
if ($(this).val() == '') {
$('#arriveDateTime').prop("disabled", false);
} else {
$('#arriveDateTime').prop("disabled", true);
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<input type="text" id="arriveDateTime" />
<input type="text" id="departDateTime" />
All you need is Eloquent Mutators.
Below a simplified example, basically from https://laravel.com/docs/5.4/eloquent-mutators#defining-a-mutator
class User extends Model
{
/* Set or mutate value of property */
public function setDateInputAttribute($value)
{
$this->attributes['date_input'] = $this->dateTimeOrNull($value);
}
/* This method should get another place, because it's not the core of this model */
private function dateTimeOrNull($value)
{
/*
Check if given datetime is valid. Yes? Return original $value
For simplicity, I use PHP's DateTime class
*/
if (DateTime::createFromFormat('Y-m-d H:i:s', $value) !== false) {
return $value;
}
/* Datetime is not valid. Return null */
return null;
}
}
Further
I suppose your datetime format is like yyyy-mm-dd hh:ii:ss
You can uses laravel mutators. Here's one for date of birth.
public function setDob($value)
{
$this->attributes['dob'] = strlen($value)? Carbon::createFromFormat('d/m/Y', $value) : null;
}

codeigniter get returned data variable from model in controller and use it in conditional statement

what is wrong with my search implementation, here what i wish to achieve.
view page(form) -> controller(form data variable) -> model(query database and pass to controller) if there's a result return TRUE else return FALSE -> controller(get data from model) if true display data in table else if FALSE display a no results returned message.
here are my pages:
view:
<form action="<?php echo site_url('retrieve')?>" method="post">
<input type="text" name="id">
....
</form>
model:
public function retrieve($id)
{
$search = "SELECT * FROM table";
$result = $this->db->conn_id->prepare($search);
$result->execute();
if($result->rowCount()>0){
return $query_result = $result->fetchAll(PDO::FETCH_ASSOC);
}
}
controller:
public function retrieve_info()
{
$id = $this->input->post('id'),
$this->load->model('search_model');
$this->search_model->retrieve($id);
$data['query_result'] = $this->search_model->retrieve($id);
$this->load->view('display',$data);
}
First the form action is linking to the retrieve function in the controller. However, from your example there is no retrieve function in your controller, only in your model.
view:
<form action="<?php echo site_url('retrieve')?>" method="post">
<input type="text" name="id">
....
</form>
model:
public function retrieve($id)
{
$search = "SELECT * FROM table";
$result = $this->db->conn_id->prepare($search);
$result->execute();
if($result->rowCount()>0){
return $query_result = $result->fetchAll(PDO::FETCH_ASSOC);
}
}
controller:
public function retrieve()
{
if($_POST){
$id = $this->input->post('id'),
$this->load->model('search_model');
$data['query_result'] = $this->search_model->retrieve($id);
$this->load->view('display',$data);
}else {
//form failed to submit via post
}
}

codeigniter update database with "TRUE" for checked items and "FALSE" for remaining unchecked items

I am new to php/codeignitor and trying to post changes on form checkboxes to my db. The row to modify is assigned by the gl_id below.
I am not sure how to use my update_checked function in the model to
post TRUE to each of these fields where gl_id =x and FALSE using to the remaining fields not in the array. I can create and view the array of checked values using $_POST['checked'] in the controller
and passing it to the model. Now I need to use this array to post to the db where gl_id = the value from the form in the view.
In View
<h1>Update GL id <?php echo $gl_field['gl_id'];?></h1>
<label>Stat</label>
<input type="checkbox" <?php if ($gl_field['stat'] == "TRUE") {echo "checked = checked";} ?>
name = "checked[]" id="stat" value= "stat" /><BR CLEAR="all">
<label>Exclude</label>
<input type="checkbox" <?php if ($gl_field['exclude'] == "TRUE") {echo "checked = checked";} ?>
name="checked[]" id="exclude" value= "exclude"><BR CLEAR="all">
<label>Override</label>
<input type="checkbox" <?php if ($gl_field['override'] == "TRUE") {echo "checked = checked";} ?>
name= "checked[]" id= "override" value = "override"/><BR CLEAR="all">
In Controller
public function update_table(){
$this->load->helper('form');
$this->page_nav_model->update_table();
$checked_array = $_POST['checked'];
$this->page_nav_model->update_checked($checked_array);
$this->load->view('pages/success');
}
In Model
foreach($checked_array as $true){
echo $true;
}
To clarify when I pull the information into the form in the example above all of the checkboxes are set to "TRUE" in the db so they are checked. If I uncheck stat and click submit I am able to see an array with the values (exclude, override).
I appreciate any help that sets me in the right direction.
To update your table with CI all at once, you need an array like this:
$data = array(
'column_1_name' => 'value_to_insert'
'column_2_name' => 'value_to_insert'
'column_2_name' => 'value_to_insert'
);
Right now, you have an array like this $checked_array = ('stat', 'exclude', 'override') - with more or fewer members.
To create the array that you can use in your update statement (like $data above), what you need to do is create another array with the name of each column and a value equal to 1 if it is in $checked_array or 0 if it was not in $checked array.
The function add_values() below can do that for you. You have to supply two arguments:
$all_possibilities is an array of each column name that you will want to update to either 1 or 0. In this case, it should look like $all_possibilities = array('stat', 'exclude', 'override');
$selected: this is an array with the names of the boxes that were actually selected - it is a subset of $all_possibilities (or it is the same if all the boxes were checked).
This function goes in your controller.
function add_values($all_possibilities, $selected) {
$array_for_query = array();
// this goes through each possible box that can be checked to see if that possibility was actually selected
foreach($all_possibilities as $array_member) {
// this checks to see if the current member of $all_possibilities is found in the $selected array
if (in_array($array_member, $selected)) {
// if it is, it adds that as a member of a new query $array_for_query and gives it a value of 1 (true)
$array_for_query[$array_member] = 1;
} else {
// if it is not, same as above, but gives it a value of 0
$array_for_query[$array_member] = 0;
}
}
// once all the possibilities have been checked and added to the query array, that array is returned
return $array_for_query;
}
Now you can call the function and pass the two arguments in. The returned array is assigned to $checked_and_unchecked.
$data['checked_and_unchecked'] = add_values($possibilities, $checked_array);
Make sure you also grab the gl_id from the form. You can do that with a hidden field in your view:
<input type="hidden" name="gl_id" value="<?php echo $gl_field['gl_id'];?>" />
In the controller, grab that value with
$data['gl_id'] = $this->input->post('gl_id');
Then you can pass the information to your model and update your table passing in the name of the table and the array you created.
$this->model_name->model_method($data);
This will then go in the model:
$this->db->update('table_name', $checked_and_unchecked);
$this->db->where('gl_id', $gl_id);
If a checkbox is unchecked in the HTML, the value does not get sent via $_POST. This is not accounted for in CodeIgniter. This is how I deal with this issue. In the controller:
/**
* Set post values for unchecked boxes.
*
* #access private
* #return void
*/
private function _section_checkboxes()
{
if (!$this->input->post('is_active')) {$_POST['is_active'] = 0;}
// other checkboxes here...
}
/**
* if form validation passes, run this to edit a section
*
* #access public
* #return void
*/
public function do_edit_section()
{
$this->_section_checkboxes();
if ($this->section_model->edit_section($this->input->post()))
{
redirect('success_page');
}
}
And in the model:
/**
* updates a section with active record, returns success.
*
* #access public
* #param array $data
* #return bool
*/
public function edit_section(array $data)
{
$this->db->where('id', $data['id']);
return $this->db->update('sections', $data);
}
And in the view, using the form helper:
<?=form_checkbox(array('name' => 'is_active', 'id' => 'is_active_field', 'value' => '1', 'checked' => (bool)$item->is_active))?>
Now your unchecked checkboxes are set as 0 when unchecked, 1 when checked. I hope this answers your question.
So I still needed help getting the final touches on the overall project so I wanted to post the final results here for anyone as green as I looking to control checkboxes from the db and the db from checkboxes.
Controller:
[function from Tayler and]
$all_checkbox_fields = array('stat','exclude','override');
$checked_array = $_POST['checkbox'];
$data['checkbox'] = $this->add_values($all_checkbox_fields, $checked_array);
$data['gl_id'] = $this->input->post('gl_id');
$this->page_nav_model->update_checked($data);
$this->load->view('pages/success');
Model:
public function update_checked($data){
$this->default_db->where('gl_id', $data['gl_id']);
$this->default_db->update('oracle_table', $data['checkbox']);
}
View:
<label>Stat</label>
<input type="checkbox" <?php if ($gl_field['stat'] == "1") {echo "checked = checked";} ?>
name = "checkbox[]" id="stat" value= "stat"/><BR>
<label>Exclude</label>
<input type="checkbox" <?php if ($gl_field['exclude'] == "1") {echo "checked = checked";} ?>
name="checkbox[]" id="exclude" value= "exclude"/><BR>
<label>Override</label>
<input type="checkbox" <?php if ($gl_field['override'] == "1") {echo "checked = checked";} ?>
name= "checkbox[]" id= "override" value = "override" ><BR>

Resources