Yii2 Update records resulting from query - mysql

I need to update month_no fields of the records resulting from a select query using some variables passed from controller but every field is written with the same value.
These are the variables:
$id_calc = 27
$from_y = "2013-05-01"
$to_y = "2015-11-31"
The table result:
id id_paid year_ref month_no
1 26 2012 12
2 26 2013 12
4 27 2013 12 (should be 8)
5 27 2014 12
6 27 2015 12 (should be 11)
This is model:
public function CorrectTable($id_calc, $from_y, $to_y)
{
$connection = Yii::$app->db;
$query = "SELECT * FROM my_table where id_paid='$id_calc'";
$data = $connection->createCommand($query)->queryAll();
// calculate no. of month first and last year
$month_no_begin = (13 - date("m",strtotime($from_y)));
$month_no_end = (date("m",strtotime($to_y)));
//
foreach($data as $row)
{
$id = $row['id'];
// calculate number of month per year
if ($row['year_ref'] = date("Y",strtotime($from_y)))
{
$month_no = $month_no_begin;
} elseif ($row['year_ref'] = date("Y",strtotime($to_y)))
{
$month_no = $month_no_end;
} else
{
$month_no = 12;
}
Yii::$app->db->createCommand()
->update('my_table', ['month_no' => $month_no], ['id' => $id])
->execute();
}
I tried to put the above code in controller with the same result.

A careless mistake once I had made before. You should use == or === in the if statement to test equal condition, instead of =
public function CorrectTable($id_calc, $from_y, $to_y)
{
$connection = Yii::$app->db;
$query = "SELECT * FROM my_table where id_paid='$id_calc'";
$data = $connection->createCommand($query)->queryAll();
// calculate no. of month first and last year
$month_no_begin = (13 - date("m",strtotime($from_y)));
$month_no_end = (date("m",strtotime($to_y)));
//
foreach($data as $row)
{
$id = $row['id'];
// use `==` instead of `=`
if ($row['year_ref'] == date("Y",strtotime($from_y)))
{
$month_no = $month_no_begin;
}
// use `==` instead of `=`
elseif ($row['year_ref'] == date("Y",strtotime($to_y)))
{
$month_no = $month_no_end;
}
else
{
$month_no = 12;
}
Yii::$app->db->createCommand()
->update('my_table', ['month_no' => $month_no], ['id' => $id])
->execute();
}
}

our if ... esleif ... else sequence seems not logig
as you done the else if is never executed
so you should change the condition this way the e
foreach($data as $row)
{
$id = $row['id'];
// assigne default value
$month_no = 12;
// check for month_begin
if ($row['year_ref'] == date("Y",strtotime($from_y)))
{
$month_no = $month_no_begin;
}
//check for month_end
if ($row['year_ref'] == date("Y",strtotime($to_y)))
{
$month_no = $month_no_end;
}
Yii::$app->db->createCommand()
->update('my_table', ['month_no' => $month_no], ['id' => $id])
->execute();
}

Related

What's the best process for upgrading my appointment scheduler in Laravel?

I got an idea to change the way I currently schedule appointments. Currently, I have an officehours table with 1 record per appointment time per day, as such weekday, appt_time, type_id, provider_id
I was thinking it might be better to have the officehours table instead have 1 record per day instead, with opening_time, closing_time, weekday, provider_id
I also have a closed table, which has open(time), close(time), closed (boolean), provider_id.
Then I have the appts table which saves appt_date, appt_time, client_id, appt_type_id, provider_id, etc
What I did in the past was create arrays of upcoming dates, booked appointments, officehours, and closures. I'd loop through the dates, and filter the arrays to match and run my logic. Anything that wasn't booked or closed would be pushed into an available array and I'd display that. Seems complicated, and it was.
I was wondering if it would be better to use Carbon dates, starting with the first day of the current week, and adding a day until 2 weeks of appointments is done. It's a lot of nested loops, though.
for each day, I have each provider (loop) and for each provider I'd use Carbon to start with the opening time and add the appointment if available and skip 10 minutes or the length of the appointment that is already booked before moving on to the next time.
This way I was using Eqoquent Collections instead of standard arrays, and I'm feeling as though they are slower and more difficult to work with but I'll stick it out if someone who knows better can help me understand.
Anyone have a great idea of how to make this happen in a great way (dare I say best)? I have a hard time simplifying things.
My old code:
public function index(Request $request)
{
$type = str_contains($request->path(), 'calendar') ? 1 : 2;
$doc = str_contains($request->path(), 'drdave') ? 2 : 1;
// getDates($displayWeeks, $daysInWeek) default 2, 4
$settings = Setting::where('type','public')->first();
$days = CalendarController::getDates($settings->weeks_visible ?: 2, $settings->days_in_week ?: 6);
$display = CalendarController::getApptCalendarData($days, $type, $doc);
return view('calendar', ['display'=>$display, 'daysInWeek'=>$settings->days_in_week, 'type'=>$type]);
}
// returns a list of days to be displayed on the calendar
public function getDates($displayWeeks = null, $daysInWeek = null) {
$today = date('Y-m-d',strtotime("today")); // today’s date
$thisday = date('w',strtotime("today")); // today’s weekday
$lastmon = date('m/d/Y',strtotime("last monday")); // last monday
$nextmon = date('m/d/Y',strtotime("next monday")); // next monday
$now = date("h:i:s"); // current time
$days = [];
// DETERMINE STARTING MONDAY
if ($thisday < 1 || $thisday > 6) // today is Sun, Fri, Sat
{
$day0 = date('m/d/Y',strtotime('-1 day', strtotime($nextmon)));
} elseif ($thisday > 1) // today is Tue, Wed, Thu, Fri
{
$day0 = date('m/d/Y',strtotime('-1 day', strtotime($lastmon)));
} else {
$day0 = date('m/d/Y',strtotime('-1 day', strtotime($today)));
}
// GENERATE LIST OF DATES
$displayWeeks = $displayWeeks ? $displayWeeks : 2; // # of weeks shown
// 4 = M-TH, 5 = M-F, 6 = M-Sat, 7 = full week
$daysInWeek = $daysInWeek ? $daysInWeek : 4;
$showSunday = $daysInWeek === 7 ? true : false;
// create array of dates to display
for ($w = 1; $w <= $displayWeeks; $w++) {
for ( $i = 0; $i < $daysInWeek; $i++ ) {
$x = $showSunday === false ? $i + 1 : $i;
$day = strftime("%Y-%m-%d", strtotime( '+' . $x .' day', strtotime($day0)));
array_push($days, $day);
}
// change to the next week
$day0 = strftime("%Y-%m-%d", strtotime( '+7 days', strtotime($day0)));;
}
return $days;
}
// returns list of appointments for doc (1 for Mel, 2 for Dave)
public function getApptCalendarData($days, $type = 0, $doc = 1) {
$start = $days[0];
$end = $days[count($days)-1];
// $closed = Closed::select('*')->where(['closed_date' >='$start', 'closed_date' <= '$end'])->orderBy('closed_date','ASC');
$closed = DB::select("SELECT AM_PM_DAY, closed_date, reason, open, close, date_format(open,'%l:%i %p') as opentime, date_format(close,'%l:%i %p') as closetime from closed WHERE closed_date >='$start' AND closed_date <= '$end' ORDER BY closed_date ASC");
$appointments = DB::select("SELECT appt_date, appt_time, appt_note, appt_reminder, reminder_cell, date_format(appt_time,'%l:%i %p') as time, patient_id, patient.id, patient.nickname, month(appt_date), year(appt_date), appt_type_id, appt_type.id, appt_type.appt_abbr, appt_type.appt_type_name, appt.id as appt_id, appt_status_id FROM appt, patient, appt_type WHERE appt.patient_id = patient.id and appt_date >= '$start' AND appt_date <= '$end' AND appt.appt_type_id = appt_type.id AND appt_status_id NOT IN ( '" . implode( "', '" , $this->RECALL ) . "' ) ORDER BY appt_date, appt_time ASC");
$available = $type > 0 ? DB::select("SELECT appt_time, dayslot, doctor_id, type, date_format(appt_time,'%l:%i %p') as time from officehour WHERE type = '$type' ORDER BY dayslot asc, appt_time asc") : DB::select("SELECT appt_time, dayslot, doctor_id, type, date_format(appt_time,'%l:%i %p') as time from officehour ORDER BY dayslot asc, appt_time asc");
$display = [];
// create an array of objects to display of date, closedInfo, appointments, and availability for each day
foreach($days as $day) {
$item = new class{};
$item->day = $day;
$item->isAdmin = false;
$item->today = date('Y-m-d',strtotime("today")) === date('Y-m-d', strtotime($day)); // today’s date
$item->show = date('Y-m-d', strtotime($day)) >= date('Y-m-d', strtotime('today'));
$item->displayDay = date("l F jS", strtotime($day));
$dayofweek = date('N',strtotime($day)); // for dayslot of office hours
$c = $closed;
$closedToday = array_filter(
$c,
function ($e) use (&$day) {
return $e->closed_date == $day;
}
);
$item->isclosed = count($closedToday) === 0 ? false : true;
if($item->isclosed === true) {
$item->closedInfo = head($closedToday);
$item->closedInfo->message = $item->closedInfo->AM_PM_DAY === 'DAY' ? "Closed Today" : ($item->closedInfo->AM_PM_DAY === 'AM' ? 'Morning Closed' : 'Afternoon/Evening Closed');
}
// filter booked appointments for this day
$existing = array_filter(
$appointments,
function ($e) use (&$day) {
return $e->appt_date == $day;
}
);
// LIST TIMES BOOKED FOR COMPArISON
$existing_times = array_column($existing, 'appt_time');
// office hours for this day of the week
$item->hours = array_filter(
$available,
function ($e) use (&$dayofweek) {
return $e->dayslot == $dayofweek;
}
);
// DISPLAY ARRAYS
$item->availability = [];
$item->adminAppts = [];
$appts = [];
// CHECK FOR AVAILABLE OR BOOKED, AND FILL LISTS
foreach($item->hours as $hour) {
// IS THE TIME BOOKED?
$freetime = (in_Array($hour->appt_time, $existing_times) === true) ? false : true;
// ADD the existing appt to the list
if($freetime === false && count($existing) > 0) {
// add this item to the admin appts list
$pushed = array_shift($existing);
array_push($appts, $pushed);
}
// CHECK IF TIME IS OPEN
$opentime = $item->isclosed === false ? true : false;
if($item->isclosed === true) {
$openAMPMDAY = (($item->closedInfo->AM_PM_DAY !== substr($hour->time, -2)) && ($item->closedInfo->AM_PM_DAY !== 'DAY'));
$openHOURS = (($hour->appt_time >= $item->closedInfo->open && $hour->appt_time <= $item->closedInfo->close));
$opentime = ($openHOURS === true && $openAMPMDAY === true);
}
// ADD THE OPEN TIME TO THE LIST
if($freetime === true && $opentime === true ) {
array_push($appts, $hour);
}
}
// ADD ANY REMAINING APPOINTMENTS TO THE LIST
foreach($existing as $remaining) {
array_push($appts, $remaining);
}
// sort the appointments by time
usort($appts, fn($a, $b) => strcmp($a->appt_time, $b->appt_time));
// split the appointments into 2 lists for column display
$count = ceil(count($appts) /2);
array_push($item->adminAppts, array_splice($appts, 0, $count, true));
array_push($item->adminAppts, array_diff_key($appts, $item->adminAppts));
// array_push($item->adminAppts, $session);
array_push($display, $item);
}
return $display;
}
To give you an idea of how it looks, https://adjust-me.com/calendar for existing, or https://adjust-me.com/newbies for new people. What it's NOT doing is displaying the closure info for each doctor with their appointments, the labeling sucks, and I need separate schedules depending on the type of appointment.
I was hoping to make things simpler for clients and allow them to book any time in the range, but newbies are 60 minutes so I'd need to switch from 1 record per time slot to make that work. That said I don't want it to lag.

Find time name between two dates

Is there any function that will give me the name of passed time with two dates in mysql? for example, after i've wrote a post then the page redirects me to the post page it must say " posted 4 seconds before", and afte five minutes later it will say posted 5 minutes before". If the time bigger than 60 minutes it will say xx hours before ...
15 days later it must say 2 weeks ago.
Something like wordpress meta info.
Same as time on my nick name at to right bottom of this post
I suggest you to write this on scripting side. If you are using PHP you can use the following code block to convert unixtime to relative phrase.
function relative_date($date)
{
$diff = time() - $date;
if ($diff < 0) {
return "just now";
} else {
$app = "ago";
}
$t_diff = $diff;
$days = floor($diff / 3600 / 24);
$diff = $diff - ( $days * 3600 * 24 );
$hours = floor($diff / 3600);
$diff = $diff - ( $hours * 3600 );
$minutes = floor($diff / 60);
$diff = $diff - ( $minutes * 60 );
$seconds = $diff;
if ($t_diff > 60 * 60 * 24) {
$str = ( $days . ' days' );
} else if ($t_diff > 60) {
$str = ( $hours ? "{$hours} hours" : "" ) . ( $minutes ? " $minutes minutes" : "" );
} else {
$str = ( $seconds ) . " seconds";
}
$str = $str . " $app";
return $str;
}
This is what I want
function formatDateDiff($start, $end=null) {
if(!($start instanceof DateTime)) {
$start = new DateTime($start);
}
if($end === null) {
$end = new DateTime();
}
if(!($end instanceof DateTime)) {
$end = new DateTime($start);
}
$interval = $end->diff($start);
$doPlural = function($nb,$str){
if ($nb > 1) {
switch ($str) {
case 'Yıl':
case 'Ay':
case 'Gün':
return $str.'e';
case 'Saat':
case 'Dakika':
case 'Saniye':
return $str.'n';
}
} else
return $str;
}; // adds plurals
$format = array();
if($interval->y !== 0) {
$format[] = "%y ".$doPlural($interval->y, "Yıl");
}
if($interval->m !== 0) {
$format[] = "%m ".$doPlural($interval->m, "Ay");
}
if($interval->d !== 0) {
$format[] = "%d ".$doPlural($interval->d, "Gün");
}
if($interval->h !== 0) {
$format[] = "%h ".$doPlural($interval->h, "Saat");
}
if($interval->i !== 0) {
$format[] = "%i ".$doPlural($interval->i, "Dakika");
}
if($interval->s !== 0) {
$format[] = "%s ".$doPlural($interval->s, "Saniye");
}
if(count($format)==0 || (count($format)==1 && $interval->s !== 0)) {
return "Az Önce";
}
// We use the two biggest parts
if(count($format) > 1) {
$format = array_shift($format).", ".array_shift($format);
} else {
$format = array_pop($format);
}
// Prepend 'since ' or whatever you like
return $interval->format($format);
}
Reference Address: https://www.php.net/manual/en/dateinterval.format.php
Thank you so much for your reply.

mysql get free time set set meeting

Ι have a table in MySQL with
date starttime endtime
11/2/2014 10:00:00 10:45:00
11/2/2014 10:45:00 11:15:00
11/2/2014 11:45:00 12:15:00
11/2/2014 12:15:00 13:30:00
I need the sql query to give back to me the time that I can set a new meeting for 30 min
$array_time = array();
$query = "SELECT starttime, endtime FROM table";
$result = $mysqli->query($query);
//fetch result
while ($array_time[] = $result->fetch_assoc()) {}
/*
$array_time = Array (
...
1 => array('starttime' => 10:45:00, 'endtime' => 11:15:00)
2 => array('starttime' => 11:45:00, 'endtime' => 12:15:00)
...
)
*/
//array of free time for your meeting
$free_time = array();
foreach($array_time as $i => $row){
if($i > 0) {
//if this is not the first time row
//get this row starttime
$this_starttime = strtotime($row['starttime']);
//and the last endtime
$prev_endtime = strtotime($array_time[$i-1]['endtime']);
//get the difference
$diff = $this_starttime - $prev_endtime;
//if difference is more or equal than 30 minutes
if($diff >= strtotime('30 minutes')) {
$free_time[] = array('starttime' => $row['starttime'], $array_time[$i-1]['endtime']);
}
}
}
I think you can't do this in MySQL query, so PHP could help you.
Hope it works, I have not tested it out.
But try to save your data by other way, this is not so effective, as you can see.

Propel criteria? or is it even possible to create such query?

I have 3 tables: product, product_parameter, product_parameter_item.
Product and product parameter have no foreign references, product_parameter_item has product_id and product_parameter_id.
For example i have 4 products:
1
2
3
4
Product_parametetrs:
1 - Model
2 - Color
Product_parameter_item:
id - product_id - product_paramter_id - value:
1 - 1 - 1 - Toyota
2 - 1 - 2 - white
3 - 2 - 1 - Toyota
4 - 2 - 2 - black
5 - 3 - 1 - Citroen
6 - 3 - 2 - white
7 - 4 - 1 - Citroen
8 - 4 - 1 - black
How can I get all products with Model = Toyota, Color = Black ?
$c->addJoin(ProductPeer::ID, ProductParameterItemPeer::PRODUCT_ID);
$c->addJoin(ProductParameterItemPeer::PRODUCT_PARAMETER_ID, ProductParameterPeer::ID);
foreach ($product_params as $i => $param){
$c1 = $c->getNewCriterion(ProductParameterPeer::ID, $param->getId());
$c2 = $c->getNewCriterion(ProductParameterItemPeer::VALUE, $value);
$c1->addAnd($c2);
$c->addAnd($c1);
}
Doesnt work
$c->addJoin(ProductPeer::ID, ProductParameterItemPeer::PRODUCT_ID);
foreach ($product_params as $i => $param){
$c1 = $c->getNewCriterion(ProductParameterItemPeer::ID, $param->getId());
$c2 = $c->getNewCriterion(ProductParameterItemPeer::VALUE, $value);
$c1->addAnd($c2);
$c->addAnd($c1);
}
Doesnt work either
$c->addJoin(ProductParameterItemPeer::PRODUCT_PARAMETER_ID, ProductParameterPeer::ID);
foreach ($product_params as $i => $param){
$c->add(ProductParameterPeer::ID, $param->getId());
$c->add(ProductParameterItemPeer::VALUE, $value);
}
I have made this function to get ids of products and add them to Criteria. Didnt find another way :(
$product_params = ProductParameterPeer::getParamsForFilter();
$ids = false;
if (count($product_params)){
$sql = '';
$clause = '';
$clauses = array();
$make_query = false;
foreach ($product_params as $i => $param){
if ($values[$param->getAlias()]){
$is_last = end($product_params) == $param;
$sql .= '(SELECT product_id FROM `product_parameter_item` WHERE `value` = "'.$values[$param->getAlias()].'" AND `product_parameter_id` = '.$param->getId().' ) t'.$i.($is_last?' ':', ');
$clauses[] = 't'.$i.'.product_id';
$make_query = 'SELECT t'.$i.'.product_id FROM ';
}
}
if (count($clauses) == 1) $clause = 'WHERE '.$clauses[0];
else if (count($clauses) == 2) $clause = 'WHERE '.$clauses[0].'='.$clauses[1];
else if (count($clauses) > 2){
$clause = 'WHERE ';
for ($i = 1; $i < count($clauses); $i++){
$clause .= '('.$clauses[0].'='.$clauses[$i].')'.($i == count($clauses)-1 ? '' : ' AND ');
}
}
if ($make_query){
$query = $make_query.$sql.$clause;
$con = Propel::getConnection();
$statement = $con->prepare($query);
$statement->execute();
$ids = array();
while($stmt = $statement->fetch(PDO::FETCH_ASSOC)) {
$ids[] = (int)$stmt['product_id'];
}
}
}
return $ids;

Display tree structure in ul li tag from preorder traversal table not working

Based on : Getting a modified preorder tree traversal model (nested set) into a <ul>
I have following table :
id name lft rgt level
1 company 1 22 0
75 Developer 26 31 1
76 Tester 24 27 1
77 Analyst 22 23 1
78 under developer 27 30 2
79 under tster 25 26 2
And following query/code for fetching nested records:
function getstructureInformation() {
$treeArr = array();
$tree = array();
$sql = "SELECT node.name, node.id, node.unit_id,
node.description,node.lft,node.rgt,node.level,
(COUNT(parent.name) - 1) AS depth
FROM tablename AS node
CROSS JOIN tablename AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.name
ORDER BY node.lft";
$query = $this->db->query($sql);
$data = $query->result();
foreach ($data as $datap) {
$treeArr['id'] = $datap->id;
$treeArr['unit_id'] = $datap->unit_id;
$treeArr['lft'] = $datap->lft;
$treeArr['rgt'] = $datap->rgt;
$treeArr['level'] = $datap->level;
$treeArr['name'] = $datap->name;
$treeArr['depth'] = $datap->depth;
$treeArr['description'] = $datap->description;
$tree[] = $treeArr;
}
return $tree;
}
Here the PHP code for displaying it into the view page:
$result = '';
$currDepth = -1; // -1 to get the outer <ul>
while (!empty($tree)) {
$currNode = array_shift($tree);
if ($currNode['depth'] > $currDepth) {
echo '<ul>';
}
if ($currNode['depth'] < $currDepth) {
$result .= str_repeat('</ul>', $currDepth - $currNode['depth']);
}
echo '<li>' . $currNode['name'] . '</li>';
$currDepth = $currNode['depth'];
if (empty($tree)) {
echo str_repeat('</ul>', $currDepth + 1);
}
}
But its not displaying properly like:
It displaying output as:
001 : Company Name
3 : Analyst
2 : Tester
33 : under tster
1 : Developer
44 : under developer
The desired output is like:
001 : Company Name
3 : Analyst
2 : Tester
33 : under tster
1 : Developer
44 : under developer
Is there any solution?
This should work :
function printTree ($tree) {
$last_level = -1;
foreach ($tree as $v) {
$diff = $v['level'] - $last_level;
if ($diff == 0) {
echo '<li>' .$v['name']. '</li>';
}
elseif ($diff > 0) {
for ($i = 0; $i < $diff; $i++)
echo '<ul>';
echo '<li>' .$v['name']. '</li>' ;
}
else {
for ($i = 0; $i > $diff; $i--)
echo '</ul>';
echo '<li>' .$v['name']. '</li>' ;
}
$last_level = $v['level'];
}
}
But with this function, you won't have the depth printed.
Tested and working with
$tree = array (
array (
'name' => 'Line',
'level' => 0
),
array (
'name' => 'Line',
'level' => 1
),
array (
'name' => 'Line',
'level' => 2
),
array (
'name' => 'Line',
'level' => 1
)
);
printTree ($tree);