laravel carbon unset date - php

Right now I have a model that has a "followup" date that is rotected to convert to carbon (). The issue is in my controller if I have some dates that are not set and default (0000-00-00) Carbon returns them as -0001-11-30 00:00:00.000000. I get why, but trying to target those dates and just return "none" but cant figure out how.
in my controller:
foreach ($account->notes as $note) {
$notes[$i]['note'] = $note;
$notes[$i]['account'] = $account->name;
if($note->followup != '-0001-11-30 00:00:00.000000'){
$notes[$i]['followup'] = $note->followup->diffForHumans();
} else {
$notes[$i]['followup'] = 'None';
}
$i += 1;
}

The following approach should give you the output you're looking for:
foreach ($account->notes as $note) {
$notes[$i]['note'] = $note;
$notes[$i]['account'] = $account->name;
$notes[$i]['followup'] = (substr($note->followup, 0, 1) !== '-') ? $note->followup->diffForHumans() : 'None';
$i += 1;
}
But I'm confused as to why the approach you posted isn't working if you're checking for the precise value you're dumping out in your conditional statement.

Related

Laravel Trying to Get property of non object (from eloquent model)

Already read some of questions about this problem on stackoverflow and none of that answers apply to me.
When I run:
$item_price = ItemPrice::where('item_name',$itemname)->first();
and then
$item_price->price
I get Trying to get property of non-object but when I run:
dd($item_price = ItemPrice::where('item_name',$itemname)->first());
It's returning object with attributes name, price etc. I don't really understand what is happening here.
Full code:
foreach ($inventorydecoded->assets as $asset) {
$i = 0;
$a = 0;
while ($a < 1) {
if ($inventorydecoded->descriptions[$i]->classid == $asset->classid) {
$a = 1;
$classid = $inventorydecoded->descriptions[$i]->classid;
$itemname = $inventorydecoded->descriptions[$i]->market_hash_name;
$tradable = $inventorydecoded->descriptions[$i]->tradable;
$name_color = $inventorydecoded->descriptions[$i]->name_color;
;
}
$i++;
} // end of while
if ($tradable === 1 && strpos_arr($itemname, $blacklist) == false ) {
$item_price = ItemPrice::whereItemName($itemname)->first();
// dd(ItemPrice::where('item_name',$itemname)->first());
$items[] = ['assetid' => $asset->assetid,'classid'=> $classid,'itemname'=>$itemname,'name_color'=>$name_color,'price'=> $item_price->price];
$serialized_inventory = serialize($items);
}
} // end of foreach
You're using this query in loop, so one of those is empty and returns null. So you need to do simple check:
if (is_null($item_price)) {
// There is no price for this item, do something.
}
Try this:
$item_price = ItemPrice::whereItemName($itemname)->first();

How to check if two times overlap in PHP?

So I'm trying to figure out how to check if two times overlap using PHP and a MySQL database.
This is the function I'm using to check if they are overlapping:
function testRange($start_time1,$end_time1,$start_time2,$end_time2) {
return ($end_time1 < $start_time2) ? false : ($start_time1 > $start_time2) && ($start_time1 > $end_time2) ? false : true;
}
AFAIK that should work fine so I go to check if the times are overlapping and add any that do overlap to an array:
$clashes = [];
$idTracker = [];
foreach ($userBands as $show) {
foreach ($userBands as $show1) {
if(!($show->id == $show1->id)) {
if(strcmp($show->date, $show1->date) == 0 && testRange(strtotime($show->time), strtotime($show->time) + ($show->length*60), strtotime($show1->time), strtotime($show1->time) + ($show1->length*60))) {
array_push($clashes, [
"s1_id" => $show->id,
"s2_id" => $show1->id
]);
}
}
}
}
foreach ($clashes as $clash) {
foreach ($clashes as $clash1) {
//If Clash1->ID1 == Clash2->ID1 then
}
print_r($clash);
echo "<br>";
}
However when I print out the entries of the $clashes array I get this as my output:
which is just wrong completely as this is the contents of the database:
27 and 26 should not be clashing with 25, but they are being tracked into the $clashes array. Why is this happening?
Database Info:
Date is of the Date SQL type, Time is of the Time SQL type and Length is a double(8,2) SQL type
$userBands Info:
The $userBands variable is a Laravel collection of the Show model
First:
You can change the SQL query to get end-time like so:
SELECT *,
ADDTIME(
CONCAT(time,'.0'),
CONCAT(CONCAT(CONCAT( length DIV 60, ':' ), length MOD 60) ,':0.0')
) AS EndTime
FROM `table`;
So now you have a column named EndTime,
So this code can work:
if(strcmp($show->date, $show1->date) == 0 &&
newTestRange(
strtotime($show->time),
strtotime($show->EndTime),
strtotime($show1->time),
strtotime($show1->EndTime)
) ) {
I have no idea why this works:
function newTestRange($start_time1,$end_time1,$start_time2,$end_time2) {
// 12:30:00 13:20:00 12:45:00 13:45:00
// return ($end_time1 < $start_time2) ? false : ($start_time1 > $start_time2) && ($start_time1 > $end_time2) ? false : true;
$ret = false; // its all okay.
if ($start_time1 < $start_time2 ){
if ($end_time1 > $start_time2 ){
$ret = true;echo "\n case1-$start_time1-colide-$start_time2 \n";
}
} else if ($end_time2 > $start_time1){
$ret = true; echo "\n case2-$start_time1-colide-$start_time2 \n";
}
return $ret;
}
but you must consider 4 different scenarios:
So if one event contains another event, you will find it.
Best!
Fixed it by changing the algorithm for comparing the times.
New version:
function testRange($s1, $e1, $s2, $e2) {
return $s1 <= $e2 && $s2 <= $e1;
}
Don't know why this works over the previous one however.

Versatile format for date validations?

I am looking for a versatile method for validating dates.
What I want, is some way of achieving validation rules such as:
First monday of month
monday or friday
Fourth day of month
Is there anything that can handle such requirements? Or does anyone have any pointers as to how i could achieve this?
Edit: I appreciate the answers, but heres what i ended up using for now:
Thanks for all the answers. What i actually ended up using (At least till i find the perfect solution) is roughly this function:
function isDateValid($rule,$date){
$DATE = (int) $date;
/* Make it safe for eval */
preg_match_all('/:\w:|&&|\|\||<|=|>|!|\(|\)|\d+/i',$rule,$filteredRule);
$rule = implode('',$filteredRule[0]);
//replace rule notations
$f = function($str){
return "date('$str[1]',\$DATE)";
};
//Or if php < 5.3: $f = create_function('$str', 'return "date(\'$str[1]\',\$DATE)";');
$rule = preg_replace_callback('/:(\w):/i', $f, $rule);
//Evaluate expression
return #eval("return $rule;");
}
//Example of usage testing first of month:
var_dump( isDateValid(':d:==1',time()) );
This lets me handle all the requirements i have in, well PHP code. The people who use this is very limited (<5 persons) and most of them have some degree of php experience. Now i can make rules such as:
first monday of month : :w:==1 && :d: <= 7
monday or friday : :w:==1 || :w:==5
Fourth day of month : :d: == 4
I would appreciate an even better more flexible solution or feedback regarding security (Can this be injected with mallicious php code?)
I would define a set of rules something like:
$ordinals = array("First", "Second"...);
$days = array("Monday", "Tuesday"...);
$rules = array(
array("%1 %2 of month", $ordinals, $days),
array("%1 or %1", $days),
etc
)
Then, do a foreach(rule) and generate all possible allowed strings
$alloweds = array();
foreach($rules as $rule){
$str = $rule[0];
for($i = 1; $i < sizeof($rule); $i++){
for($a = 0; $a < sizeof($rule[$i]); $a++){
$alloweds[] = str_replace($str, "%$i", $rule[$i][$a]);
}
}
}
Then do a foreach(allowed string) compare to what we have
foreach($alloweds as $allowed){
if(preg_match($allowed, $input){
//its valid
}
}
you could set up your rules to be quite complicated - however its worth noting that the more complex they are the longer this will take - in its current form its clearly an exponential time algorithm, but its a starting point.
Not the most versatile solution, but this actually does EXACTLY what you want to do:
Class:
<?php
class validate {
private static $month;
private static $year;
private static $day;
private static $day_literal;
function __construct() {
self::$year = date("Y");
self::$month = date("m");
self::$day = date("d");
self::$day_literal = date("l");
}
public function firstInMonth($required,$day,$month,$year) {
$firstday;
for ($i = 1; $i < 31; $i++) {
if (checkdate($month,$i,$year)) {
if (trim(strtolower(date("l",mktime(0,0,0,$month,$i,$year)))) == trim(strtolower(trim($required)))) {
$firstday = $i;
break;
}
else {
continue;
}
}
}
if (strtotime(date("Y-m-d",mktime(0,0,0,$month,$i,$year))) == strtotime(date("Y-m-d",mktime(0,0,0,$month,$day,$year)))) {
return "{$year}/{$month}/{$day} is the first {$required} of the month.";
}
else {
return "Nope.";
}
}
public function checkDayLiteral($literal,$day,$month,$year) {
if (trim(strtolower(date("l",mktime(0,0,0,$month,$day,$year)))) == trim(strtolower($literal))) {
return true;
}
else {
return false;
}
}
public function dayPosition($day,$month,$year) {
return date("jS",mktime(0,0,0,$month,$day,$year));
}
}
?>
I don't know what's the purpose of your checking, so I've also implemented the construct method to compile the "today" values, which are NOT used in the code. If you need them, feel free to call them using self::
How to use:
<?php
$validate = new validate;
echo $validate->firstInMonth("Monday",2,9,2013);
echo "<br />";
echo $validate->checkDayLiteral("Monday",2,9,2013);
echo "<br />";
echo $validate->dayPosition(2,9,2013);
?>
Change the class according to WHAT you need to get (I mean: edit the returns I've set).
In this case, the above code returns:
2013/9/2 is the first Monday of the month.
1
2nd
while this:
echo $validate->firstInMonth("Tuesday",2,9,2013);
echo "<br />";
echo $validate->checkDayLiteral("Wednesday",15,9,2013);
echo "<br />";
echo $validate->dayPosition(24,9,2013);
returns this:
Nope.
24th
Of course, this is not as versatile as whatever you want, but this works.
Hope this helps.
If it does not do exactly what you want I'm sorry, just take this as an idea, I think it's pretty clear how you can get whatever information you want from this code.

Baffled as to why PHP is giving simple logic error on if statement

Like the title says, PHP is really confusing me on a simple if comparison statement that's returning the opposite of what it should be returning. I'm trying to compare 2 datetime's that are first converted to strings:
//Fetched db query, this returns 2012-06-23 16:00:00
$databaseDateTime = strtotime($row['time']);
//This now returns 1340481600
//today's date and time I'm comparing to, this returns 2012-06-22 17:14:46
$todaysDateTime = strtotime(date("Y-m-d H:i:s"));
//this now returns 1340399686
Great, everything works perfect so far. Now here's where things get hairy:
if ($databaseDateTime < $todaysDateTime) { $eventType = 'past'; }
And this returns 'past', which of course it shouldn't. Please tell me I'm missing something. My project kind of depends on this functionality being airtight.
**EDIT***
Thanks guys for taking the time to help me out. Let me post the entire code because a few of you need more context. The request is coming from an IOS5 to my backend code and json is being sent back to the phone.
<?php
//all included files including $link to mysqli_db and function sendResponse()
function getEvents($eventType, $eventArray) {
global $link;
global $result;
global $i;
global $todaysDateTime;
foreach ($eventArray as $key => $value) {
$sqlGetDeal = mysqli_query($link, "SELECT time FROM deals WHERE id='$value' AND active='y' LIMIT 1") or die ("Sorry there has been an error!");
while ($row = mysqli_fetch_array($sqlGetDeal)) {
//compare times to check if event already happened
$databaseDateTime = strtotime($row['time']);
if ($databaseDateTime < $todaysDateTime) { $eventType = 'past'; }
$result[$i] = array(
'whenDeal' => $eventType,
'time' => $databaseDateTime,
);
$i++;
}//end while
}//end foreach
}
if (isset($_GET['my'])) {
//$_GET['my'] comes in as a string of numbers separated by commas e.g. 3,2,6,3
$myDeals = preg_replace('#[^0-9,]#', '', $_GET['my']);
$todaysDateTime = strtotime(date("Y-m-d H:i:s"));
$result = array();
$kaboomMy = explode(",", $myDeals);
$i = 1;
if ($myEvents != "") {
getEvents('future', $kaboomMy);
}//end if
sendResponse(200, json_encode($result));
} else {
sendResponse(400, 'Invalid request');
} //end $_POST isset
?>
Found a quick hack around the issue. I just added a local variable to my function and rearranged my compare statement
//added local variable $eventTyppe to function
$eventTyppe;
changed compare from:
if ($databaseDateTime < $todaysDateTime) { $eventType = 'past'; }
to:
if ($todaysDateTime < $databaseDateTime ) {
$eventTyppe = $eventType;
} else {
$eventTyppe = 'past';
}
Notice if I rearrange compare:
if ($databaseDateTime < $todaysDateTime ) {
$eventTyppe = 'past';
} else {
$eventTyppe = $eventType;
}
I still get the same error. This is the weirdest thing I've ever seen and the first PHP bug I've run into (I'm assuming it's a PHP bug).
Could you print the values of the times right before this line?
if ($databaseDateTime < $todaysDateTime) { $eventType = 'past'; }
Since that one is declared as global I'm wondering if is it coming back incorrectly.

PHP loops to check that a set of numbers are consecutive

I'm trying to loop through a set of records, all of which have a "number" property. I am trying to check if there are 3 consecutive records, e.g 6, 7 and 8.
I think i'm almost there with the code below, have hit the wall though at the last stage - any help would be great!
$nums = array();
while (count($nums <= 3))
{
//run through entries (already in descending order by 'number'
foreach ($entries as $e)
{
//ignore if the number is already in the array, as duplicate numbers may exist
if (in_array($e->number, $num))
continue;
else
{
//store this number in the array
$num[] = $e->number;
}
//here i need to somehow check that the numbers stored are consecutive
}
}
function isConsecutive($array) {
return ((int)max($array)-(int)min($array) == (count($array)-1));
}
You can achieve the same result without looping, too.
If they just have to be consecutive, store a $last, and check to make sure $current == $last + 1.
If you're looking for n numbers that are consecutive, use the same, except also keep a counter of how many ones fulfilled that requirement.
$arr = Array(1,2,3,4,5,6,7,343,6543,234,23432,100,101,102,103,200,201,202,203,204);
for($i=0;$i<sizeof($arr);$i++)
{
if(isset($arr[$i+1]))
if($arr[$i]+1==$arr[$i+1])
{
if(isset($arr[$i+2]))
if($arr[$i]+2==$arr[$i+2])
{
if(isset($arr[$i+3]))
if($arr[$i]+3==$arr[$i+3])
{
echo 'I found it:',$arr[$i],'|',$arr[$i+1],'|',$arr[$i+2],'|',$arr[$i+3],'<br>';
}//if3
}//if 2
}//if 1
}
I haven't investigated it thoroughly, maybe can be improved to work faster!
This will confirm if all items of an array are consecutive either up or down.
You could update to return an array of [$up, $down] or another value instead if you need direction.
function areAllConsecutive($sequence)
{
$up = true;
$down = true;
foreach($sequence as $key => $item)
{
if($key > 0){
if(($item-1) != $prev) $up = false;
if(($item+1) != $prev) $down = false;
}
$prev = $item;
}
return $up || $down;
}
// areAllConsecutive([3,4,5,6]); // true
// areAllConsecutive([3,5,6,7]); // false
// areAllConsecutive([12,11,10,9]); // true
Here's an example that can check this requirement for a list of any size:
class MockNumber
{
public $number;
public function __construct($number)
{
$this->number = $number;
}
static public function IsListConsecutive(array $list)
{
$result = true;
foreach($list as $n)
{
if (isset($n_minus_one) && $n->number !== $n_minus_one->number + 1)
{
$result = false;
break;
}
$n_minus_one = $n;
}
return $result;
}
}
$list_consecutive = array(
new MockNumber(0)
,new MockNumber(1)
,new MockNumber(2)
,new MockNumber(3)
);
$list_not_consecutive = array(
new MockNumber(5)
,new MockNumber(1)
,new MockNumber(3)
,new MockNumber(2)
);
printf("list_consecutive %s consecutive\n", MockNumber::IsListConsecutive($list_consecutive) ? 'is' : 'is not');
// output: list_consecutive is consecutive
printf("list_not_consecutive %s consecutive\n", MockNumber::IsListConsecutive($list_not_consecutive) ? 'is' : 'is not');
// output: list_not_consecutive is not consecutive
If u don't wanna mess with any sorting, picking any of three numbers that are consecutive should give you:
- it either is adjacent to both the other numbers (diff1 = 1, diff2 = -1)
- the only number that is adjacent (diff = +-1) should comply the previous statement.
Test for the first condition. If it fails, test for the second one and under success, you've got your secuence; else the set doesn't comply.
Seems right to me. Hope it helps.
I think you need something like the following function (no need of arrays to store data)
<?php
function seqOfthree($entries) {
// entries has to be sorted descending on $e->number
$sequence = 0;
$lastNumber = 0;
foreach($entries as $e) {
if ($sequence==0 or ($e->number==$lastNumber-1)) {
$sequence--;
} else {
$sequence=1;
}
$lastNumber = $e->number;
if ($sequence ==3) {
// if you need the array of sequence you can obtain it easy
// return $records = range($lastNumber,$lastNumber+2);
return true;
}
}
// there isn't a sequence
return false;
}
function isConsecutive($array, $total_consecutive = 3, $consecutive_count = 1, $offset = 0) {
// if you run out of space, e.g. not enough array values left to full fill the required # of consecutive count
if ( $offset + ($total_consecutive - $consecutive_count ) > count($array) ) {
return false;
}
if ( $array[$offset] + 1 == $array[$offset + 1]) {
$consecutive_count+=1;
if ( $consecutive_count == $total_consecutive ) {
return true;
}
return isConsecutive($array, $total_consecutive, $consecutive_count, $offset+=1 );
} else {
return isConsecutive($array, $total_consecutive, 1, $offset+=1 );
}
}
The following function will return the index of the first of the consecutive elements, and false if none exist:
function findConsecutive(array $numbers)
{
for ($i = 0, $max = count($numbers) - 2; $i < $max; ++$i)
if ($numbers[$i] == $numbers[$i + 1] - 1 && $numbers[$i] == $numbers[$i + 2] - 2)
return $i;
return false;
}
Edit: This seemed to cause some confusion. Like strpos(), this function returns the position of the elements if any such exists. The position may be 0, which can evaluate to false. If you just need to see if they exist, then you can replace return $i; with return true;. You can also easily make it return the actual elements if you need to.
Edit 2: Fixed to actually find consecutive numbers.

Categories