How can I make this loop faster? - php

I'm using Laravel 5.2 for a project I'm working on. Does anyone have any tips regarding how I can leverage Laravel to make this loop run more quickly?
foreach ($purchaseYears as $purchaseYear){
$totalInventory = \App\Inventory::where('purchase_year', $purchaseYear)->count();
if ($purchaseYear < 1960) { $purchaseYear = 'Pre 1960'; }
else if ($purchaseYear >= 1960 && $purchaseYear < 1965) { $purchaseYear = '1960-64'; }
else if ($purchaseYear >= 1965 && $purchaseYear < 1970) { $purchaseYear = '1965-69'; }
else if ($purchaseYear >= 1970 && $purchaseYear < 1975) { $purchaseYear = '1970-74'; }
else if ($purchaseYear >= 1975 && $purchaseYear < 1980) { $purchaseYear = '1975-79'; }
else if ($purchaseYear >= 1980 && $purchaseYear < 1985) { $purchaseYear = '1980-84'; }
else if ($purchaseYear >= 1985 && $purchaseYear < 1990) { $purchaseYear = '1985-89'; }
else if ($purchaseYear >= 1990 && $purchaseYear < 1995) { $purchaseYear = '1990-94'; }
else if ($purchaseYear >= 1995 && $purchaseYear < 2000) { $purchaseYear = '1995-99'; }
else if ($purchaseYear >= 2000 && $purchaseYear < 2005) { $purchaseYear = '2000-04'; }
else if ($purchaseYear >= 2005 && $purchaseYear < 2010) { $purchaseYear = '2005-09'; }
else if ($purchaseYear >= 2010 && $purchaseYear < 2015) { $purchaseYear = '2010-14'; }
else if ($purchaseYear >= 2015 && $purchaseYear < 2019) { $purchaseYear = '2015-19'; }
if (isset($chartData[$purchaseYear])) {
$prev = $chartData[$purchaseYear];
$chartData[$purchaseYear] = $totalInventory + $prev;
$prev = null;
} else {
$chartData[$purchaseYear] = $totalInventory;
}
}

I believe the most time consuming part should be executing the query. If you use whereIn, then I think you can execute the query only once, and then loop over the results. I haven't tested it, but it should be something like this:
$purchasesByYear = \App\Inventory::select('purchase_year',
DB::raw('count(*) as purchase_count'))
->whereIn('purchase_year', $purchaseYears)
->groupBy('purchase_year')->get();
I think reducing the number of query executions will be the main opportunity to keep this from running slowly. Also, I think adding an index to purchase_year should be helpful if you have not already done so.
Instead of a lot of elseif conditions to handle grouping the years, you could use some math. This might actually be slightly slower, but the code would be a little less repetitive, and I believe anything you do to this part will be a micro-optimization compared to what you can do with the query part. My suggestion:
foreach ($purchasesByYear as $purchaseYear) {
$year = $purchaseYear->purchase_year;
if ($year < 1960) {
$yearRange = 'Pre 1960';
} else {
// subtract one until the year is a multiple of five
while ($year % 5) { $year--; }
// then construct the range string using the starting number
$yearRange = $year.'-'.($year+4);
}
if (isset($chartData[$yearRange])) {
$chartData[$yearRange] += $purchaseYear->purchase_count;
} else {
$chartData[$yearRange] = $purchaseYear->purchase_count;
}
}

I think you can break the dates into a pattern, rather than just testting for each decade, something like this:
if ($purchaseYear < 1960) {
$purchaseYear = 'Pre 1960';
} else {
$prefix = substr($purchaseYear,0,2);
$decade = substr($purchaseYear,1,1);
$suffix = substr($purchaseYear,-1);
$purchYear = $prefix . $decade
if ($suffix<5) {
$purchYear .= '0-' . $decade . '4';
} else {
$purchYear .= '5-' . $decade . '9'
}
Haven't tested this, but I think it will do what you'd like.

Related

How to check whether GET is empty?

I am setting some vars from GET
$start = $_GET['start'];
$end = $_GET['end'];
From which I get:
start=1-11-2018&end=30-11-2018
And then I am doing:
if((!$start) && (!$end)) {
if (($dateFormat >= $start) && ($dateFormat <= $end)) {
} else {
echo "no dates";
}
And to close it
if((!$start) && (!$end)) {
}
}
But this isn't happening
if((!$start) && (!$end)) {
UPDATE
Now this is working but it doesn't go in else if no GET
if((!empty($_GET['start'])) && (!empty($_GET['end']))) {
if (($dateFormat >= $start) && ($dateFormat <= $end)) {
} else {
echo "No dates";
}
Check via isset()
if you are calling : http://example.com?start=1-11-2018&end=30-11-2018
1. The isset() is checking query string "start"/"end" is having or not.
2. The empty() is checking query string "start"/"end" is empty/blank or not
if( isset($_GET['start']) && isset($_GET['end']) ){ // check the GET method is set or not
if((!empty($_GET['start'])) && (!empty($_GET['end']))) {
if (($dateFormat >= $start) && ($dateFormat <= $end)) {
}
else {
echo "Empty dates";
}
}
else{
echo "Start / End date query string is missing...";
}
This is how I resolved it:
if((!empty($start)) && (!empty($end))) {
if (($dateFormat >= $start) && ($dateFormat <= $end)) {
}
// here the content which
// in case those vars are not empty,
// would get filtered by that logic.
if((empty($start)) && (empty($end))) {
// Close the condition for second if when not empty
} else {
echo "No dates";
}

Matching user time logs to day shift in an attendance system

I'm trying to create a simple attendance application with Laravel. I'm just a little stuck with the logic side.
What I'm trying to do is to match up the time logs of users to the correct schedule.
So in our office, we could have from 2 to 3 breaks, so a typical work shift will look like this:
Time In - 06:00 AM
Break Out 1 - 07:15 AM
Break In 1 - 07:30 AM
Break Out 2 - 11:30 AM
Break In 2 - 12:00 PM
Time Out - 03:00 PM
Now a user typically just uses the biometric device and selects "in" or "out".
My problem is given something like this:
05:58 AM, in
07:17 AM, out
07:31 AM, in
05:58 AM, out
How can the system tell which time log (07:17 AM) belongs to which time slot (Break Out 1)?
Thank you so much for the help, and if my question is unclear, I'm sorry.
Here's a sample code of what I've done so far. It works but I think it's really messy:
$day_shift = [
"time_in" => date('H:i:s', strtotime("06:00 AM")),
"break_out_1" => date('H:i:s', strtotime("07:15 AM")),
"break_in_1" => date('H:i:s', strtotime("07:30 AM")),
"break_out_2" => date('H:i:s', strtotime("11:30 AM")),
"break_in_2" => date('H:i:s', strtotime("12:00 PM")),
"break_out_3" => '',
"break_in_3" => '',
"time_out" => date('H:i:s', strtotime("03:00 pM")),
];
foreach ($day_shift as $key => $userScheduleTime) {
if ($userScheduleTime !== "") {
$time = $logDate->date." ".$userScheduleTime;
} else {
$time = "";
}
$schedules[] = array('time' => $time, 'type' => $types[$i%2],'name'=>$key);
$i++;
}
// logTimes is a collection of time logs
foreach ($logTimes as $logTime) {
$logs[] = $logTime->toArray();
}
$cloneLogs = $logs;
$lastlog = end($cloneLogs);
if ($lastlog["log_type"] == "login") {
$dayOut = "";
} else {
$dayOut = $lastlog["log_time"];
}
$lastout = null;
$size = count($logs);
do {
if ($logs[$size-1]['log_type'] == 'logout') {
$lastout = $logs[$size-1];
break;
}
$size--;
} while ($size > 0);
$lastlog = null;
for ($i = 0; $i < count($schedules); $i++) {
$logTime = current($logs);
if ($lastlog == $logTime['log_type']) {
next($logs);
}
// checks the first log, calculates how late the person is
if ($i == 0) {
if ($logTime['log_type'] == "login") {
$timein = $schedules[0]['time'];
if (strtotime(date("Y-m-d H:i", strtotime($logTime['log_time']))) >
strtotime(date("Y-m-d H:i", strtotime($timein)))) {
$lates[$logTime['log_time']] = true;
$lates["totallate"] += getDifferenceInMinutes($logTime['log_time'], $timein);
}
$lastlog = $logTime["log_type"];
next($logs);
}
}
if ($schedules[$i]['type']==$logTime['log_type'] && $i!=0 && $lastlog !== $logTime["log_type"]) {
$nextSched = isset($schedules[$i+1])?$schedules[$i+1]:$schedules[$i];
$j = 1;
while ($nextSched['time']=="" && ($i+$j)<=count($schedules)) {
$nextSched = $schedules[$i+$j];
$j++;
}
if (strtotime($nextSched['time'])>strtotime($logTime['log_time']) && $logTime["log_time"] != $dayOut) {
// checks and calculates if the user has undertime
if (strtotime($nextSched['time']) > strtotime($logTime['log_time']) && $nextSched['type']=='login') {
if (strtotime($logTime['log_time']) < strtotime($schedules[$i]['time'])) {
$lates[$logTime['log_time']] = true;
$lates["totalunder"] += getDifferenceInMinutes($logTime['log_time'], $schedules[$i]['time']);
}
}
// checks and calculates if the user has overbreaks
if (date('H:i', strtotime($schedules[$i]['time'])) <
date('H:i', strtotime($logTime['log_time'])) &&
$logTime['log_type'] == 'login') {
$lates[$logTime['log_time']] = true;
$lates["totalover"] += getDifferenceInMinutes($schedules[$i]['time'], $logTime['log_time']);
}
$lastlog = $logTime["log_type"];
next($logs);
}
if ($i+1==count($schedules)) {
next($logs);
}
if ($logTime["log_time"] == $dayOut && $dayOut !== null) {
$timeOut = $schedules[count($schedules)-1]["time"];
if (strtotime(date("Y-m-d H:i", strtotime($logTime["log_time"]))) <
strtotime(date("Y-m-d H:i", strtotime($timeOut)))) {
$lates[$logTime["log_time"]] = true;
$lates["totalunder"] += getDifferenceInMinutes($logTime['log_time'], $timeOut);
$lastlog = $logTime["log_type"];
}
break;
}
}
}

(PHP) Verifying if given date is between two other dates

I'm having an issue with some code that someone else has previously worked on.
The goal is to iterate through a directory and push any files that are within a certain date range to an array (files are in mmddyyy.txt format).
The (terribly named, not by my own doing) variables in the code represent the following:
$aYear - A given year, read in from a text file. This variable changes during every iteration of the loop. The same goes for $aMonth and $aDay.
$sYear1 - Start year. $sMonth1 and $sDay1 are used in respect to $sYear1.
$sYear2 - End year. $sMonth2 and $sDay2 are used in respect to $sYear2.
$isGood - File will be added to the array.
$isGood = false;
if($aYear >= $sYear1 && $aYear <= $sYear2)
{
if($aYear == $sYear1)
{
if($aMonth == $sMonth1)
{
if($aDay >= $sDay1 && $aDay <= $sDay2)
{
$isGood = true;
}
}
else
{
if($aMonth >= $sMonth1 && $aMonth <= $sMonth2)
{
$isGood = true;
}
}
}
else if($aYear == $sYear2)
{
if($aMonth == $sMonth2)
{
if($aDay <= $sDay2)
{
$isGood = true;
}
}
else
{
if($aMonth <= $sMonth2)
{
$isGood = true;
}
}
}
else
{
$isGood = true;
}
}
if($isGood)
{
//echo "Found good article";
$a = $a . "===" . $file;
array_push($result, $a);
}
I'm not getting the results that I expected. I'm looking for some help as to how I can simplify this code and get it working properly. I do need to keep this solution in PHP.
Thank you in advance.
It seems to me Month statement if($aMonth >= $sMonth1 && $aMonth <= $sMonth2) needs work
eg start date- 03 Aug 2013 end date- 04 Sep 2016 and check date say 08 Nov 2013
would make isGood=false whereas it should be true.
Removing && $aDay <= $sDay2 and && $aMonth <= $sMonth2 should work.
As #Sandeep pointed out you're issues are with:
if ($aMonth >= $sMonth1 && $aMonth <= $sMonth2)
and
if ($aDay >= $sDay1 && $aDay <= $sDay2)
as you don't need to be comparing the date with end dates as well.
That being said you can clear up your code completely by doing something like:
$date = (new DateTime)->setDate($aYear, $aMonth, $aDay);
$start = (new DateTime)->setDate($sYear1, $sMonth1, $sDay1);
$end = (new DateTime)->setDate($sYear2, $sMonth2, $sDay2);
if ($start <= $date && $date <= $end) {
//echo "Found good article";
$a = $a . "===" . $file;
array_push($result, $a);
}
Hope this helps!

i want to sum all digit in a number

i want to add all digit in a number and if it is 11,22 then i want to display only 11 or 22 else i want to make it a single digit.
example 30=3+0=3
28=2+8=10=1+0=1
i just made a codebut it have an error
please help.
<?php
$day = 17;
$month = 8;
$year = 1993;
function sumday($day)
{
if ($day == 11)
{
$sday = 11;
}
elseif ($day == 22)
{
$sday = 22;
}
elseif ($day == 29)
{
$sday = 11;
}
else
{
do {
$nday = $day . "";
$sday = 0;
for ($i = 0; $i < strlen($nday); ++$i)
{
$sday += $nday[$i];
}
while ($sday <=9);
}
return $sday;
}
First of all I would suggest you to learn to separate the tasks that a function do.
You ask to sum up the digits of a number, you may first create a function called sum_digits
<?php
function sum_digits($num) {
if ($num < 10)
return $num;
return $num % 10 + sum_digits(floor($num/10));
}
and then via conditional do whatever you need to do.
please refer to unnikked's answer, that's a good answer.
And here's the full code, combined with unnikked's answer
<?php
$day = 17;
$month = 8;
$year = 1993;
function sumday($day)
{
if ($day == 11)
{
$sday = 11;
}
elseif ($day == 22)
{
$sday = 22;
}
elseif ($day == 29)
{
$sday = 11;
}
else{
$sday = $day;
do {
$sday = $sday % 10 + floor($sday/10);
} while ($sday >= 10);
}
return $sday;
}
?>
EDIT: If you want to return the sum if it's 11,22,33 in the while loop, then put the conditions in the while loop rather than using if else condition, it's much simpler tho :)
function sumday($day)
{
$sday = $day;
while ($sday >= 10 && $sday != 11 && $sday != 22 && $sday != 29){
$sday = $sday % 10 + floor($sday/10);
}
return $sday;
}
EDIT: here's the logic that can split the day and sum them
function sumday($day)
{
$sday = $day;
$arrday = str_split($sday); // split the day into array
$sumarrday = 0;
for($i = 0; $i < strlen((string)$sday); $i++){
$sumarrday = $sumarrday + $arrday[$i]; // sum the day from the array
}
$sday = $sumarrday;
// here you can modify the condition of while statement for your needs
// for example, if you want to return 29 when 29 shows up, add this to your condition, && $sday != 29
while ($sday >= 10){
$sday = $sday % 10 + floor($sday/10);
}
return $sday;
}
Try this:
else {
$nday = $day . ""; //moved out wrom loop
do {
$sday = 0;
for ($i = 0; $i < strlen($nday); ++$i)
{
$sday += $nday[$i];
}
$nday = $sday . ""; // you forget this line
while ($sday <=9);
}

PHP Switch case & if statement not returning correct values

I'm kind of new to PHP and I'm trying to write a script that counts points after a user inputs values.
Here's the code:
<?php
$pla = $_GET['players'];
$plu = $_GET['plugins'];
$type = $_GET['type'];
$location = $_GET['location'];
totalPoints();
function typePoints($type) { //Returns points depending on server type
switch (strtolower($type)) { //Switch the type of server between all types and see how many points to return :)
case "standard minecraft": return 1;
break;
case "snapshot": return 2;
break;
case "craftbukkit": return 2;
break;
case "bungeecord": return 1;
break;
case "spigot": return 2;
break;
case "paperspigot": return 2;
break;
case "feed the beast": return 3;
break;
case "technic": return 3;
break;
case "pixelmon": return 3;
break;
default: echo 'Incorrect Server Type!';
exit;
break;
}
}
function playerPoints($players) { //Returns points depending on amount o players
if ($players >= 2 && $players <= 5) {
return 2;
} elseif ($players >= 6 && $players <= 10) {
return 4;
} //Between 6-10, return 4 points... AND SO ON...
elseif ($players >= 11 && $players <= 16) {
return 8;
} elseif ($players >= 17 && $players <= 25) {
return 12;
} elseif ($players >= 26 && $players <= 30) {
return 16;
} elseif ($players >= 31 && $players <= 36) {
return 18;
} elseif ($players >= 37 && $players <= 45) {
return 20;
} elseif ($players >= 46 && $players <= 50) {
return 22;
} elseif ($players >= 51 && $players <= 56) {
return 24;
} elseif ($players >= 57 && $players <= 65) {
return 26;
} elseif ($players >= 66 && $players <= 70) {
return 28;
} elseif ($players >= 71 && $players <= 76) {
return 30;
} elseif ($players >= 77 && $players <= 85) {
return 32;
} elseif ($players >= 86 && $players <= 90) {
return 34;
} elseif ($players >= 91 && $players <= 96) {
return 36;
} elseif ($players >= 97 && $players <= 105) {
return 38;
} elseif ($players >= 106 && $players <= 110) {
return 40;
} elseif ($players > 110) {
return 44;
}
}
function pluginPoints($plugins) {
if ($plugins == 0) {
return 0;
} elseif ($plugins >= 1 && $plugins <= 3) {
return 2;
} //Between 1-3, return 2 points.... AND SO ON...
elseif ($plugins >= 4 && $plugins <= 15) {
return 6;
} elseif ($plugins >= 16 && $plugins <= 30) {
return 10;
} elseif ($plugins >= 31 && $plugins <= 40) {
return 14;
} elseif ($plugins >= 41 && $plugins <= 50) {
return 20;
} elseif ($plugins > 50) {
return 24;
}
}
function locationPoints($location) {
switch (strtolower($location)) { //Switch between locations, easy to add a new one later in the future. :)
case "montreal": return 1;
break;
case "france": return 1;
break;
default: echo "Incorrect Location!";
exit;
break;
}
}
function totalPoints() { //Call this function to get the amount of points finally.
$totalPoints = typePoints($type) + playerPoints($pla) + pluginPoints($plu) + locationPoints($location);
echo 'Total points: ' . $totalPoints;
}
?>
The problem is the switch statement in function typePoints($type) always returns the default: echo 'Incorrect Server Type!'; exit; break;.
Also, function playerPoints($players) returns 0 even though I put in a number like 37.
I used this:
http://website.com/planpicker.php?players=121&location=france&plugins=80&type=technic
Can anyone tell me why?
This is not a duplicate question, the "marked duplicate" talks about different files, but this is within the same file.
The 4 variables are not accessible from totalPoints function. You should pass those parameters to function. You should call function as :
totalPoints($type,$pla,$plu,$location);
And define the function as
function totalPoints($type,$pla,$plu,$location)
It's because you call your functions in another function without passing the values in parameter.
The totalPoints function is not aware of the value of $type or $pla for example as they are not GLOBALS.
You have to pass the variables to the function you want to call :
function totalPoints($type, $pla, $plu, $location) //Call this function to get the amount of points finally.
{
$totalPoints = typePoints($type) + playerPoints($pla) + pluginPoints($plu) + locationPoints($location);
echo 'Total points: '.$totalPoints;
}
And then call the function like this :
totalPoints($type,$pla,$plu,$location);
The variables that were decared outside of the functions need to be made accessible to the totalPoints function. The easiest way is to use global
function totalPoints() {
global $pla;
global $plu;
global $type;
global $location;
$totalPoints = typePoints($type) + playerPoints($pla) + pluginPoints($plu) + locationPoints($location);
echo 'Total points: '.$totalPoints;
}

Categories