I want to validate my fine_amount against 2 input date. But it does not return any error. Without validating this method it saved data.
I also looked into
Yii2: how to use custom validation function for activeform? but for me no solution.
Below is my code
Controller method
$model = $this->findModel($id);
$model->payment_date=date('d-M-Y',strtotime($model->payment_date));
$model->payment_expected_date=date('d-M-Y',strtotime($model->payment_expected_date));
if ($model->load(Yii::$app->request->post())) {
$model->payment_date=date('Ymd',strtotime($model->payment_date));
$model->payment_expected_date=date('Ymd',strtotime($model->payment_expected_date));
if($model->validate()){
$model->save();
return $this->redirect(['view', 'id' => $model->id]);
}
else{
$model->payment_date=date('d-M-Y',strtotime($model->payment_date));
$model->payment_expected_date=date('d-M-Y',strtotime($model->payment_expected_date));
return $this->render('update', [
'model' => $model,
]);
}
}
return $this->render('update', [
'model' => $model,
]);
My Rule
['fine_amount' , 'fine_required'] ,
Validation function
public function fine_required() {
$this->payment_date = date ( 'Ymd' , strtotime ( $this->payment_date ) );
$this->payment_expected_date = date ( 'Ymd' , strtotime ( $this->payment_expected_date ) );
if ( $this->payment_date > $this->payment_expected_date ) {
if ( $this->fine_amount <= 0 ) {
$this->addError ( 'fine_amount' , 'Fine Amount Must be add.' );
}
return false;
}
return true;
}
You need to use conditional validation for your case, use when and whenClient respectively see below add to your rules section and remove any other validations. This will handle frontend and backend both validations
[ 'fine_amount' , 'required' , 'when' => function($model) {
if ( $model->payment_date > $model->payment_expected_date ) {
if ( $model->fine_amount <= 0 ) {
return true;
}
}
return false;
} , 'whenClient' => 'function (attribute, value) {
var d1 = new Date($("#' . Html::getInputId($this, 'payment_date') . '").val());
var d2 = new Date($("#' . Html::getInputId($this, 'payment_expected_date'). '").val());
if(d1>d2){
if(value<=0){
return true;
}
}
return false;
}' , 'message' => 'Fine Amount Must be add.' ] ,
EDIT
Replaced strtolower ( \yii\helpers\StringHelper::basename ( get_class ( $this ) ) ) with Html::getInputId as it is more suitable for this case.
Related
I want to retrieve some data from 'tbl_karyawan' and input into 'tbl_absen' which is if the NIP exist from 'tbl_karyawan' then parshing some data into 'tbl_absen'. I was create the code, and the data is going well. but i have something trouble with
i want the data input in Nip_kyn be like 'KIP001' not [{"Nip_kyn":"KIP001"}].
this is my Model
public function presensi($data)
{
$isExist = DB::table('tbl_karyawan')
->where('Nip_kyn', $data)->exists();
if ($isExist) {
$namakyn = DB::table('tbl_karyawan')->where($data)->get('Nama_kyn');
$nippppp = DB::table('tbl_karyawan')->where($data)->select('Nip_kyn')->get($data);
$values = array('Nip_kyn' => $nippppp, 'Nama_kyn' => $namakyn, 'Jam_msk' => now(), 'Log_date' => today());
DB::table('tbl_absen')->insert($values);
} else {
echo 'data not available';
}
}
this is my controller
public function get()
{
$day = [
'time_in' => $this->AbsenModel->timeIN(),
'time_out' => $this->AbsenModel->timeOut(),
'break' => $this->AbsenModel->break(),
// absen here
's' => $this->AbsenModel->absensi(),
];
$data = [
'Nip_kyn' => Request()->Nip_kyn,
];
$this->AbsenModel->presensi($data);
return view('v_absen', $data, $day);
}
Yup, I finally got it, the problem is on my model.
$nama_karyawan = DB::table('tbl_karyawan')->where($data)->value('Nama_kyn');
$nipkyn = DB::table('tbl_karyawan')->where($data)->value('Nip_kyn');
I just change 'get' to 'value'.
I am new to cakephp.Below the number being bold is the time the data is being created and code to validate .My problem is to validate the data should between 8 hours not more that using Model. is there any wrong in my code?
sample data=L02A-180129-1215-A
The code to find the table based on data
public function sa01() {
$trv_no = $this->data[$this->alias]['TRV_No_01'];
$line_no = intval(substr($trv_no, 1, 2));
$table_name = 'Ticket_L' . $line_no;
$this->Ticket->setSource($table_name);
$this->Ticket->recursive =-1;
code for validation
Batch_time is a column name for the table
$time = $this->Ticket->find('all',array('conditions' => array('Ticket.Batch_Time >=' => date('Y-m-d H:i:s', strtotime('-8 hour')))));
if(empty($time))
{
$table_name = 'Ticket_L0';
$this->Ticket->setSource($table_name);
//$ticket = $this->Ticket->find('first', array('conditions' => array('Ticket.TRV_No' => $trv_no)));
$time = $this->Ticket->find('all',array('conditions' => array('Ticket.Batch_Time >=' => date('Y-m-d H:i:s', strtotime('-8 hour')))));
if(empty($time)) { return false; } else { return true; }
}
else
{ return true; }
}
I want to dynamically fill in my form (see picture)
countries states and cities
The states select (html tag) is populated with a json file by the javascript function :
function onChangeCountries(countries, states) {
$(countries).on("change", function(ev) {
var countryId = $(this).val();
if (countryId != '') {
states.empty();
states.append('<option selected="true" disabled>Choose state</option>');
states.prop('selectedIndex', 0);
$.getJSON(statesUrl, function (data) {
$.each(data['states'], function (key, entry) {
if (entry.country_id == countryId) {
states.append($('<option></option>').attr('value', entry.id).text(entry.name));
}
})
});
}
});
}
countries and states parameters correspond to the two firsts select.
This function populate the states select corresponding to the country selected. The same mechanism operates with the cities select.
Now I want to use Symfony 4, here is my form :
<?php
// src/Form/LocationType.php
namespace App\Form;
use App\Entity\Location;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class LocationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$countries = json_decode(file_get_contents("js/countries.json"), TRUE)['countries'];
$countriesChoices = array();
foreach($countries as $country) {
$countriesChoices[$country['name']] = $country['id'];
}
$states = json_decode(file_get_contents("js/states.json"), TRUE)['states'];
$statesChoices = array();
foreach($states as $state) {
$statesChoices[$state['name']] = $state['id'];
}
$cities = json_decode(file_get_contents("js/cities.json"), TRUE)['cities'];
$citiesChoices = array();
foreach($cities as $city) {
$citiesChoices[$city['name']] = $city['id'];
}
$builder
->add('country', ChoiceType::class, array(
'choices' => $countriesChoices
))
->add('area', ChoiceType::class, array(
'choices' => $statesChoices
))
->add('city', ChoiceType::class, array(
'choices' => array(
'Choose city' => $citiesChoices
))
->add('zip_code', TextType::class)
->add('street', TextType::class)
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Location::class,
));
}
}
The problem here is that I can not fill in the choices depending on user inputs.
Also I'm receiving an OutOfMemoryException (there is more than 40 000 cities in cities.json).
Edit
After dlondero answer, I haven't resolve my problem, here is my new LocationType class :
<?php
// src/Form/LocationType.php
namespace App\Form;
use App\Entity\Location;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
class LocationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$countries = json_decode(file_get_contents("js/countries.json"), TRUE)['countries'];
$countriesChoices = array();
foreach($countries as $country) {
$countriesChoices[$country['name']] = $country['id'];
}
$builder
->add('zip_code', TextType::class)
->add('street', TextType::class)
->add('country', ChoiceType::class, array(
'choices' => $countriesChoices
))
->add('area', ChoiceType::class, array(
'choices' => array()
))
->add('city', ChoiceType::class, array(
'choices' => array()
))
;
$formModifierStates = function (FormInterface $form, $countryId = null) {
$statesChoices = array();
if (null !== $countryId) {
$states = json_decode(file_get_contents("js/states.json"), TRUE)['states'];
foreach($states as $state) {
if ($countryId == $state['country_id']) {
$statesChoices[$state['name']] = $state['id'];
}
}
}
$form->add('area', ChoiceType::class, array(
'choices' => $statesChoices
));
};
$formModifierCities = function (FormInterface $form, $stateId = null) {
$citiesChoices = array();
if (null !== $stateId) {
$cities = json_decode(file_get_contents("js/cities.json"), TRUE)['cities'];
foreach($cities as $city) {
if ($stateId == $city['state_id']) {
$citiesChoices[$city['name']] = $city['id'];
}
}
}
$form->add('city', ChoiceType::class, array(
'choices' => $citiesChoices
));
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifierStates) {
$data = $event->getData(); // country id
$formModifierStates($event->getForm(), $data);
}
);
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifierCities) {
$data = $event->getData(); // state id
$formModifierCities($event->getForm(), $data);
}
);
$builder->get('country')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifierStates) {
// It's important here to fetch $event->getForm()->getData(), as
// $event->getData() will get you the client data (that is, the ID)
$country = $event->getForm()->getData();
// since we've added the listener to the child, we'll have to pass on
// the parent to the callback functions!
$formModifierStates($event->getForm()->getParent(), $country);
}
);
$builder->get('area')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifierCities) {
// It's important here to fetch $event->getForm()->getData(), as
// $event->getData() will get you the client data (that is, the ID)
$state = $event->getForm()->getData();
// since we've added the listener to the child, we'll have to pass on
// the parent to the callback functions!
$formModifierCities($event->getForm()->getParent(), $state);
}
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Location::class,
));
}
}
After filling in the form, I've got the message : "The choice "..." does not exist or is not unique". The choice is refering to the id (value of option) of the city selected in the select.
The problem is that I can't figure out how to populate the city ChoiceType?
You'd need to load them dynamically based on the choice made for the previous select. Approach is a lot similar to your with JS.
You can see an example in the official documentation: Dynamic Generation for Submitted Forms.
Using Cakephp 2.6.1, I have successfully captured and stored single characters in my database using the following code
echo $this->Form->input('grade', array('options' => array( 'G' => 'Good', 'P' => 'Pass','R'=>'Practice Required','F'=>'Fail')));
What I would like to know is how to convert these values back to the display values when retrieving them from the database, ie if the database contains 'P', I want to display 'Pass' in the view and index pages.
I'm certain the answer is simple and straightforward, and sheepishly apologise in advance for my ignorance.
Step-1
Create two new files under Vendor folder.
master-arrays.php
common-functions.php
and Import this two files
Process of import :
Dir : app\Config\bootstrap.php
Add this two lines:
App::import('Vendor', 'common-functions');
App::import('Vendor', 'master-arrays');
Step-2
Now open 'master-arrays.php'
and add this array
function grade_type()
{
$GRADE_TYPE['G'] = 'Good';
$GRADE_TYPE['P'] = 'Pass';
return $GRADE_TYPE;
}
Step-3
Change your view -
echo $this->Form->input('grade', array('options' =>grade_type())));
Step-4
Now add this function in 'common-functions.php'
function id_to_text($id, $arr_master=array()) {
$txt_selected = "";
$id = ''.$id; //Added this as it was creating some warnings online for wrong parameter types
if(is_array($arr_master) && array_key_exists($id,$arr_master)) {
$txt_selected = $arr_master[$id];
} else {
$txt_selected = "";
}
return $txt_selected;
}
Step-5
In Controller or in view
Input:
id_to_text('P',grade_type());
Output:
Pass
Try this,
// In controller
function fun()
{
$grade = array(
'G' => 'Good',
'P' => 'Pass',
'R' => 'Practice Required',
'F' => 'Fail'
);
$this->set('grade', $grade);
if ($this->request->data) {
$key = $this->request->data['Model']['grade'];
$this->request->data['Model']['grade'] = $grade[$key];
$this->Model->save($this->request->data);
}
}
// in view
echo $this->Form->input('grade', array(
'options' => $grade
));
Updated Code
// add in Model
function afterFind($results) {
foreach ($results as $key => $val) {
if (isset($val['MyModel']['status'])) {
$results[$key]['MyModel']['grade_text'] = $this->getGradeText($results[$key]['MyModel']['grade']);
}
}
return $results;
}
public function getGradeText($key)
{
$grades = array(
'G' => 'Good',
'P' => 'Pass',
'R' => 'Practice Required',
'F' => 'Fail'
);
$txt_selected = "";
if(array_key_exists($key,$grades)) {
$txt_selected = $grades[$key];
} else {
$txt_selected = "";
}
return $txt_selected;
}
// in controller
public function index() {
$this->set('data' , $this->paginate('MyModel'));
}
// in view
foreach($data as $value) {
echo $value['MyModel']['grade_text'];
}
I hope it will be help you.
I've created a new meta box for my 'cases' post type. And when I publish a new 'cases' post I want to insert the meta id into a new table created by me called 'sort'. I used this code:
function save_postdata( $post_id ) {
global $post, $new_meta_boxes, $wpdb;
foreach ($new_meta_boxes as $meta_box) {
if ( !wp_verify_nonce( $_POST[$meta_box['name'].'_noncename'], plugin_basename(__FILE__) )) {
return $post_id;
}
if ( 'cases' == $_POST['post_type'] ) {
if ( !current_user_can( 'edit_page', $post_id ))
return $post_id;
} else {
if ( !current_user_can( 'edit_post', $post_id ))
return $post_id;
}
$data = $_POST[$meta_box['name'].'_value'];
if(get_post_meta($post_id, $meta_box['name'].'_value') == "") {
add_post_meta($post_id, $meta_box['name'].'_value', $data, true);
$meta_id = get_post_meta($post_id, 'meta_id', true);
$wpdb->insert( 'sort', array('meta_id'=>$meta_id, 'column_order' => 1));
}
elseif($data != get_post_meta($post_id, $meta_box['name'].'_value', true))
update_post_meta($post_id, $meta_box['name'].'_value', $data);
elseif($data == "")
delete_post_meta($post_id, $meta_box['name'].'_value', get_post_meta($post_id, $meta_box['name'].'_value', true));
}
}
The sort table has three fields: id, meta_id and column_order. Can someone sees what I'm doing wrong?
Make sure that on your insert statement you add 'NULL'
$wpdb->insert( 'sort', array('NULL', 'meta_id'=>$meta_id, 'column_order' => 1));
This could be causing the issue, and also make sure that it's the correct order of your columns.