How can I add a minimum date validation rule in a Model?
Example:
I have a column dt_ini as DATE, which I need to restrict the input as D+7, on create.
If today is: october 1st, 2012
the minimum valid date on create would be: october 8th, 2012.
Otherwise, I would throw a validation error as: Your date must be at least 7 days from now.
The code I would expect is something like this: (this is NOT tested, and probably won't work)
public function rules(){
return array('dt_ini', 'date', 'minDate' => '+7'),
}
Thanks.
Is this what you are looking for?
Create custom valid rule as follows:
class YourModel extends CActiveModel
{
// some....
public function rules(){
return array('dt_ini', 'dateValid', 'minDate' => '+7 day', 'on' => 'create');
}
public function dateValid($attribute, $params)
{
$valid=null;
$today = date('Y-m-d', time());
if(isset($params['minDate']))
$valid = date('Y-m-d', strtotime($params['minDate'])); //+7 day
if( !is_null($valid) )
{ //for increamental date
if($this->dt_ini > $valid || $this->dt_ini < $today )
$this->addError($attribute, 'enter error message');
}
}
}
Related
Here is what I am trying to accomplish: turn off a True/False Advanced Custom Fields(ACF) option on a post if the current date is on or past a selected date on the same post. Also after that code, turn off a Sample Lesson True/False option inside of the lessons attached to the current post.
At first, all I had was the update_sample_child_lessons function with an 'init' action (i.e.add_action( 'init', 'update_sample_child_lessons' );), but that seemed to only run when I clicked update on the post. It did work and everything switched over, but it only ran when I manually clicked Update on the post. So then I did a little research and found that a Cron job should do the trick if I want the code to run automatically without me having to click update, but for some reason I can't seem to get it to work.
So if you know of a way to accomplish what I am trying to do with the code below, or with other code that is completely different, any suggestions or help would be much appreciated.
//CRON JOB TO RUN EVERYDAY
function myprefix_custom_cron_schedule( $schedules ) {
$schedules['every_day'] = array(
'interval' => 86400, //24 HOURS IN SECONDS
'display' => __( 'Every 24 hours' ),
);
return $schedules;
}
add_filter( 'cron_schedules', 'myprefix_custom_cron_schedule' );
if ( ! wp_next_scheduled( 'myprefix_cron_hook' ) ) {
wp_schedule_event( time(), 'every_day', 'myprefix_cron_hook' );
}
//AUTOMATICALLY ADJUSTS SAMPLE LESSON FREE OPTIONS AND FREE BANNER IF DATE IS PASSED
add_action( 'myprefix_cron_hook', 'update_sample_child_lessons' );
function update_sample_child_lessons() {
$allcourses = array(
'post_type' => 'sfwd-courses', //CUSTOM POST TYPE: COURSES
'posts_per_page' => -1 //QUERY ALL OF THEM
);
$query = new WP_Query($allcourses);
if ($query->have_posts()) {
global $post;
if ( ( in_array( $post->post_type, array( 'sfwd-courses' ), true ) )) { //ONLY DO ACTION IF ON CPT OF COURSES
while ($query->have_posts()) {
$query->the_post();
$course_id = learndash_get_course_id( $post->ID ); //GET THE COURSE ID
$free = get_field('display_free_lessons', $course_id); //GET THE FREE COURSE OPTION (TRUE/FALSE TICKER)
if (!empty($free)) { //ONLY DO REST OF CODE IF FREE OPTION IS TURNED ON
$freeDate = get_field('free_until', $course_id); //GET THE DATE FIELD THAT THE COURSE IS FREE UNTIL
$currentDate = date('Ymd'); //GET CURRENT DATE
$diff = strtotime($freeDate) - strtotime($currentDate); //GET THE DIFFERENCE BETWEEN THE TWO DATES
if ($diff <= 0) { //ONLY DO REST OF CODE IF DATE DIFFERENCE IS LESS THAN OR EQUAL TO ZERO
$value = '';
update_field('display_free_lessons', $value, $course_id); //UPDATES THE FREE OPTION FIELD TO FALSE(OR NOTHING)
//LESSON CODE
$lessons = array_slice(learndash_course_get_lessons($course_id), 1); //GET ALL THE LESSONS FROM THE COURSE EXCEPT FOR THE FIRST ONE
foreach ($lessons as $lesson) {
$lessonID = $lesson->ID; //GET THE LESSON ID
$lesson_meta = get_post_meta($lessonID); //GET THE METADATA FOR THE LESSON
if ( is_array( $lesson_meta ) ) {
foreach ( $lesson_meta as $meta_key => $meta_value ) {
if ( '_sfwd-lessons' === $meta_key ) {
$lesson_settings = maybe_unserialize( $meta_value[0] ); //SOME OF THE ARRAYS ARE SERIALIZED, SO UNSERIALIZE IF NEEDED
if ( isset( $lesson_settings['sfwd-lessons_sample_lesson'] ) ) {
$lesson_settings['sfwd-lessons_sample_lesson'] = ''; //TURN OFF THE SAMPLE LESSON OPTION ON THE LESSONS
}
update_post_meta( $lessonID, $meta_key, $lesson_settings );
}
}
}
} //END FOREACH
} //END IF DIFF IS 0
wp_reset_postdata();
}
}
}
}
}
Thanks for the comment #Luke Chaffey, I was actually able to figure it out after finding I had my cron actions reversed. Below is the final code that I got working so that it runs every day at 12am:
//CRON JOB TO RUN EVERYDAY
function custom_cron_schedule( $schedules ) {
$schedules['every_day'] = array(
'interval' => 86400,
'display' => __( 'Every 24 hours' ),
);
return $schedules;
}
add_filter( 'cron_schedules', 'custom_cron_schedule' );
$ve = get_option('gmt_offset') > 0 ? '-' : '+';
if ( ! wp_next_scheduled('cron_sample_lesson' ) ) {
wp_schedule_event(strtotime('00:00 tomorrow ' . $ve .
absint(get_option('gmt_offset')) . ' HOURS'), 'daily','cron_sample_lesson' );
}
add_action('cron_sample_lesson', 'update_sample_child_lessons' );
function update_sample_child_lessons() {...
I thought this would be fairly simple but it's not playing ball currently.
I have 2 tables for this question, 'applications' & 'application_call_logs'.
This query needs to return all from the applications table where the latest call log doesn't have a status of X.
Here's the current query:
$query = Application::query();
$query->where(function($query) {
$query->whereDoesntHave('call_logs');
$query->orWhereHas('latest_call_log', function($q) {
$q->where('status', '!=', 'not interested');
});
});
return $query->get();
This should return all rows that either have no call logs, or where the latest call log doesn't have the status field equaling a specific string.
This here:
$q->where('status', '!=', 'not interested');
Seems to have no affect if the call_logs has more than 1 row, even though I'm querying the latest relationship. I've also verified the latest is returning the correct latest record.
The two relationships in the Application model are:
public function call_logs()
{
return $this->hasMany('App\ApplicationCallLog', 'lead_id', 'id');
}
public function latest_call_log()
{
return $this->hasOne('App\ApplicationCallLog', 'lead_id', 'id')->latest();
}
Checked the SQL generated:
select * from `applications` where (not exists (select * from `lead_call_logs` where `applications`.`id` = `lead_call_logs`.`lead_id`) or exists (select * from `lead_call_logs` where `applications`.`id` = `lead_call_logs`.`lead_id` and `status` != ?))
there is a solution around should be good for this situation:
i think that this line has the week point of the code:
return $this->hasOne('App\ApplicationCallLog', 'lead_id', 'id')->latest();
this should be hasMany, but you use hasOne to limit the result to one.
and if you tried:
return $this->hasMany('App\ApplicationCallLog', 'lead_id', 'id')->latest()->limit(1);
it simply won't work, because the result will be limited to ApplicationCallLog for all of the results ....
will, there is a package staudenmeir/eloquent-eager-limit that is made especially for this situations:
composer require staudenmeir/eloquent-eager-limit:"^1.0"
class Application extends Model
{
use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
public function latest_call_log()
{
return $this->hasMany('App\ApplicationCallLog', 'lead_id', 'id')->latest()
->limit(1);
}
}
class ApplicationCallLog extends Model
{
use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
}
using this package will limit ApplicationCallLog for every result in your query not one for all of the result, and that will have the same effect for hasOne ....
with this minor enhancement, i think:
$q->where('status', '!=', 'not interested');
will work ...
more about eloquent-eager-limit package in:
https://github.com/staudenmeir/eloquent-eager-limit
I'm using symfony 2 doctrine orm to update record. But each time updating record, TIMESTAMP field called createdAt value is changing ( set current date time ). How to prevent this behavior? see my code,
public function newsDetailsAction(Request $request)
{
....
$post = $this->getDoctrine()->getRepository('AdminBundle:BlogPostEntity')->findOneBy(array('postId' => $postid ));
$views = $post->getPostViews();
$post->setPostViews($views + 1);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($post);
$entityManager->flush();
...
}
My Bad. I was using timestamp for type. That's the issue.
I'm using node.js to connect to an SQL database (SQL Server 2016 specifically). My table, called transactionCounts, has the following tables and data types:
staff_id: varchar(50), date: Date, count: int;
The 'date' field is just a date, not a DateTime, for clarity. Records look like this: "2017-08-07"
I'm using the mssql package, const sql = require('mssql');
So basically, I have a function which accepts a start date and an end date and does this with them:
function(start, end) {
let ps = new sql.PreparedStatement(transactionRegisterSqlPool);
ps.input('start', sql.Date);
ps.input('end', sql.Date);
ps.prepare('SELECT staff_id, SUM(Count) TotalCount FROM [TransactionRegister].[dbo].[transactionCounts] ' +
'WHERE date >= #start AND date < #end GROUP BY staff_id', err => {
.execute({start: start, end: end}, (err, result) => {});
});
};
I've simplified the function for illustrations sake (it normally returns a promise), but here's what's going wrong:
I pass in the dates of Aug 20 midnight, and Aug 27 midnight, and what I'm expecting to get back is the sum for the dates 20,21,22,23,24,25 and 26 naturally (7 days, a week).
26th isn't being included though (definitely), and I'm not entirely sure but I'd wager that the 19th is being included. I think it's a daylight-savings issue, because these dates, when i call .toISOString(), look like 2017-08-19T23:00:00.000Z and 2017-08-26T23:00:00.000Z respectively (11pm the night prior).
I've modified my function to use strings instead of dates, and this seems to work and returns the correct Sums:
function(start, end) {
let ps = new sql.PreparedStatement(transactionRegisterSqlPool);
ps.input('start', sql.VarChar);
ps.input('end', sql.VarChar);
start = `${start.getFullYear()}/${start.getMonth() + 1}/${start.getDate()}`;
end = `${end.getFullYear()}/${end.getMonth() + 1}/${end.getDate()}`;
ps.prepare('SELECT staff_id, SUM(Count) TotalCount FROM [TransactionRegister].[dbo].[transactionCounts] ' +
'WHERE date >= #start AND date < #end GROUP BY staff_id', err => {
ps.execute({start: start, end: end}, (err, result) => {});
});
};
But it seems...wrong to take my dates and turn them into strings to work my way around this issue. What is the correct way to deal with dates between Javascript Dates and SQL Dates, so that this apparent Daylight-Savings-caused issue is avoided?
Your problem is that JavaScript does not have a "date" type, only "datetime", yet SQL does have a "date" type. Because of that, you will have to do the conversion.
If you wrap it in a function, it is still readable:
function toDateString(d) {
return `${d.getFullYear()}/${d.getMonth() + 1}/${d.getDate()}`;
}
ps.prepare('SELECT staff_id, SUM(Count) TotalCount FROM [TransactionRegister].[dbo].[transactionCounts] ' +
'WHERE date >= #start AND date < #end GROUP BY staff_id', err => {
ps.execute({start: toDateString(start), end: toDateString(end)}, (err, result) => {});
});
I try to do an query in my controller, I want find all entity where the start and en date are between NOW(),
if $start and $end are between NOW() so show all entity, but i didn't succeed
My find is :
$day = date('l');
$now = Time::now();
$tvs = $this->Tvs
->find('all')
->contain(['Users'])
->where(['Tvs.day' => $day])
->andWhere(function($exp) {
return $exp->between($now, 'Tvs.start', 'tvs.end', $now);
});
How make this query ?
Thanks for you'r help !
Assuming you are trying to find all twhe record having $now between start and end the query is
sice the manual says that the first argument of the between fucntion should be name of the field (so it can't be a date) instead of between you can use two comparison
$tvs = $this->Tvs
->find('all')
->contain(['Users'])
->where(['Tvs.day' => $day])
->andWhere(function($exp) use($now) {
$exp->lte('Tvs.start', $now);
$exp->gte('Tvs.end', $now);
return $exp;
});
anyway you can make use of the mysql NOW() function directly into the query if the $now variable contains the same value of the NOW() function
->andWhere(function($exp, $q) {
return $exp->between($q->func()->now(), 'Tvs.start', 'Tvs.end');
});
there's anothe method: you can use BETWEEN and a palceholder to bind the value of $now
->andWhere([':now BETWEEN Tvs.start AND Tvs.end'])
->bind(':now', $now, 'datetime');
or using cakephp sql functions
->where(function($exp, $q) {
return $exp->between(':now', 'Tvs.start', 'Tvs.end');
})
->bind(':now', $now, 'datetime');
Since CakePHP 3.6 you can use identifiers:
return $query->where(function ($exp, $q) {
$today = $q->func()->now();
$start = $q->identifier('Tvs.start');
$end = $q->identifier('Tvs.end');
return $exp
->between($today,$start,$end);
});