I think I have a relatively simple question, I just think I'm misunderstanding an aspect of it.
I have an index page where in one of the table cells I have an if statement:
#if (Carbon\Carbon::parse($shipment->due_date)->diffInDays(false) > 0 && Carbon\Carbon::parse($shipment->due_date)->diffInDays(false) < 10)
Where the falses are is where I would like to declare that if the day is in the future, say like tomorrow compared to today, I will have a -1 returned, whereas if I refer to yesterday, I will have a 1 returned.
The problem is I am trying to use the docs but they are lining up for me no matter what sort of way I try them: http://carbon.nesbot.com/docs/#api-humandiff
However I should mention that on the same layout I can do this:
{{Carbon\Carbon::parse($shipment->due_date)->diffInDays()}}
and return the number of days in the past or future (even though both are positive) so I know the above works (in a way, but I still need the positive or negative mentioned).
You need to provide a Carbon date as the first parameter for diffInDays(). So, the logic will be:
Carbon\Carbon::parse($shipment->due_date)->diffInDays(now(), false)
Or:
now()->diffInDays(Carbon\Carbon::parse($shipment->due_date), false)
Depending on what exactly you're trying to achieve.
false as the second parameter makes the method return signed value (positive or negative).
You can use:
Carbon\Carbon::parse($shipment->due_date)->diffInDays(null, false)
in place of
Carbon\Carbon::parse($shipment->due_date)->diffInDays(false)
This is becuase method signature looks like this:
public function diffInDays(Carbon $dt = null, $abs = true)
{
$dt = $dt ?: static::now($this->getTimezone());
return (int) $this->diff($dt, $abs)->format('%r%a');
}
In addition looking at your logic I think it's too complicated. I think it would be enough to use:
#if (Carbon\Carbon::parse($shipment->due_date)->diffInDays(null, false) < 10)
the first condition is not necessary I believe
Also in case you are using Laravel 5.5 you should rather use:
Illuminate\Support\Carbon
instead of
Carbon\Carbon
in case you wanted to add some custom methods to this class.
Related
I want to pass the average time and the user e-mail in consoletvs/charts i worte the SQL for that
$currentTime = Carbon::today();
$time_difference = DB::select(DB::raw("SELECT `acu_name` ,AVG(TIMESTAMPDIFF(MINUTE, acu_at, acu_et)) as averageTime
FROM `active_user`
WHERE acu_at <= '$currentTime' GROUP BY `acu_name`"));
in this SQL result is coming when i get this through foreach method but if pass this through charts it's showing an error
$chart = Charts::create('bar', 'highcharts')
->title('Total Clients Average Using Time')
->elementLabel("Total")
->labels($time_difference->acu_name)
->values($time_difference->averageTime)
->responsive(false);
Error Message is :
I can't understand what is the issues please help me to find out the issue
and i attached my database structure and dummy data screen shots.
My php version is 7.3.2
Laravel version is 5.5
When you do DB::select() it gives you array having stdClass objects representing the found rows. So even if you expect one resultant row coming out of your DB::select() query, the result will be still inside an array.
So when you are doing following :
$currentTime = Carbon::today();
$time_difference = DB::select(DB::raw("SELECT `acu_name` ,AVG(TIMESTAMPDIFF(MINUTE, acu_at, acu_et)) as averageTime
FROM `active_user`
WHERE acu_at <= '$currentTime' GROUP BY `acu_name`"));
It is returning an array and inside that there are records matching.
You either need to do foreach() to loop through $time_difference array or do $time_difference[0]-> acu_name
Also, your DB::raw contains a user defined variable which is a danger for SQL injections.
Update :
Please check documentation where there are nice examples for the eloquent way of doing this.
To me it looks indeed strange that this specific error is being thrown. However we can see in you provided code that you store the following in your $time_difference variable:
DB::select(...);
Usually this returns an instance of Illuminate\Database\Query\Builder which is an object if I am not mistaking.
If you take a look into the source code you can see that this function does return $this which is an instance of the above mentioned.
What I can say that is missing is the execution of the query. Usually a select() is followed by a get() or a first() as shown in the documentation.
Another action you should undertake is to validate of anything has been returned after the execution of your query. You final code with some tweaks could look like:
$time_difference = DB::table('active_user')
->select([
'acu_name',
DB::raw('AVG(TIMESTAMPDIFF(MINUTE, acu_at, acu_et)) as averageTime'),
])
->where('acu_at', '<=', $currentTime)
->groupBy('acu_name')
->first(); // Be aware this will only return the first row. Not sure if this is what you inted to do.
if (is_null($time_difference)) {
// Do something when it has not been found.
}
$chart = Charts::create('bar', 'highcharts')
->title('Total Clients Average Using Time')
->elementLabel("Total")
->labels($time_difference->acu_name)
->values($time_difference->averageTime)
->responsive(false);
We are designing a new sensor that sends some data to a webapplication. We use similar sensors, but they use data channels to divide the value send to the application into different data types.
However, this new sensor will send either data or a 32 bit time, with miliseconds. It doesn't send a identifier bit to see whether the value is data or a timestamp.
Because both the data and timestamp are integer value's, How can i check which one it is?
The timestamp will be
YYYY/MM/DD HH:MI:SS:vv
I already found preg_match, like this:
if (preg_match('/[0-9]{4}-[0-9]{2}-[0-9]{2}/', $value))
But how do i include the miliseconds? Or is there a better way than a simple if else?
Update
I expect that the date recieved by the application will be in int16.
So it might be easier to count the values recieved and handle value 9 and 10 like datetimes..
You could use the createFromFormat() method from the PHP DateTime object.
You would create a function that checks the method errors :
function is_valid_date($date, $format = 'Y/m/d H:i:s.u')
{
$d = DateTime::createFromFormat($format, $date);
$errors = DateTime::getLastErrors();
return (
$errors['warning_count'] == 0 &&
$errors['error_count'] == 0 &&
$d !== false
);
}
Hope it helps.
EDIT :
Added the u (for microseconds) on the default format.
You could use this regular expression:
With preg_match_all:
preg_match_all("/(\d{4})\/(\d{2})\/(\d{2})\s(\d{2})\:(\d{2})\:(\d{2})\:(\d{2})/", $input_lines, $output_array);
With preg_match:
preg_match("/(\d{4})\/(\d{2})\/(\d{2})\s(\d{2})\:(\d{2})\:(\d{2})\:(\d{2})/", $input_line, $output_array);
Beware, it only checks for the numbers, the backslashes and the ':' character. It doesn't check if the given numbers are valid.
Once you've run the regular expression, you can then check the output array and see if it's empty or not (if it isn't empty it matched the format)
The regular expression matches this range:
0000/00/00 00:00:00:00
9999/99/99 99:99:99:99
I fixed it in a different way:
we determined that the first 2 16bit values in a message are always the timestamps, so i just made a valuecounter and used a if $value is 1 or 2 then do this, else do that.
This was a lot easier for me then to check each value.
I know i can reduce the column value in laravel using this query
DB::table('users')->decrement('votes', 5);
But i want to restrict the value from being become negative value.
Is there anyway to do this with laravel?
You'll need to use raw queries for that.
The following code should do the trick for all DB engines that support GREATEST function:
DB::table('users')->update(['votes' => DB::raw('GREATEST(votes - 5, 0)')]);
It will decrement votes column in users table by 5, but won't go below zero - that's what GREATEST function is used for.
If you really want to use decrement in this case (could be handy if you're accessing it through a relationship for example), you could do something like:
$thing->decrement('votes', $thing->votes - $amount <= 0 ? $thing->votes : $amount);
Where $amount is 5 in your case. It's pretty ugly in my opinion. Worth noting if you already have $thing (say via a relationship) it won't trigger an additional query when accessing votes.
If you are only incrementing by 1, a simply if wrapped around is cleaner:
if($thing->votes > 0) {
$thing->decrement('votes');
}
Lets say I have a table that holds information about festivals.
Each festival has a start and end date.
I want to select all the festivals that are live (that happen) on a given date.
Meaning, I want to select all the festivals that their start date is before or on a given date, and that their end date is after or on a the same given date.
So I went on to the repository class of the festival entity, and created a method to do just that.
But the criteria argument "findBy" expects is an array, which all the examples only treat as a simple criteria (e.g. "array('name' => 'billy')" will select all the rows that have the value billy in their name column), which uses only the comparison operator.
How can I use other operators such as
>, <, !=, IN, NOT IN, LIKE
and etc. ?
Doctrine 2.3 added a matching() method that lets you use Criteria.
The example by Jeremy Hicks may be written like this (note, this returns an ArrayCollection instead of an array).
public function findActiveFestivals($start, $end)
{
$expr = Criteria::expr();
$criteria = Criteria::create();
$criteria->where($expr->gte('start', $start));
$criteria->andWhere($expr->lte('end', $end);
return $this->matching($criteria);
}
Personally, I wouldn't use andWhere here, and use a few more lines to improve readability, like this:
public function findActiveFestivals($start, $end)
{
$expr = Criteria::expr();
$criteria = Criteria::create();
$criteria->where(
$expr->andX(
$expr->gte('start', $start),
$expr->lte('end', $end)
)
);
return $this->matching($criteria);
}
Using an IN clause is very simple.
public function findFestivalsByIds($ids)
{
$expr = Criteria::expr();
$criteria = Criteria::create();
$criteria->where($expr->in('id', $ids));
return $this->matching($criteria);
}
The Criteria class is in Doctrine's not-really-ORM-or-DBAL Common's namespace, like their ArrayCollection (which has supported Criteria longer than EntityRepository).
Its meant to be a decoupled way for non-repository code to create sophicated criteria. So it should be fine to use this class outside of the repository. QueryBuilder supports Criteria recently as well. So even when building more sophisticated queries that require QueryBuilder, you can use Criteria to give the non-database code flexibility in what it requests.
You'll need to write your own query (probably using DQL) if you want something that specific. I believe the built in "findBy" methods are more for just grabbing objects quickly if you have less specific criteria. I don't know your entity names or where they are stored. Could be something like this as a function in your Festival Repository.
public function findActiveFestivals($start, $end)
{
$qb = $this->_em->createQueryBuilder();
$qb->select('f')
->from('Festival', 'f')
->where('f.start >= :start')
->andWhere('f.end <= :end')
->setParameters(array('start' => $start, 'end' => $end));
return $qb->getQuery()->getArrayResult();
}
thats not the answer for Doron question
doctrine have entity repository that not make us using query at all...
$this->em->getRepository($this->entity)->findBy(array $criteria);
but what did he asked is how to complex operator in array $criteria
normal format of array $criteria is array('field'=> $value);
I have had the same problem a while back, where my Doctrine repositories became very ugly due to complex queries. I also had to convert Yii ActiveRecord (with Criteria objects) to Doctrine, and Doctrine did not have Criteria objects at the time.
I found a blogpost by Benjamin Eberlei which has an interesting solution to this problem based on the specification pattern.
It gives you the ability to defer the manipulation of the Query Builder object to other classes.
$spec = new AndX(
new Equals('ended', 0),
new OrX(
new LowerThan('endDate', new \DateTime()),
new AndX(
new IsNull('endDate'),
new LowerThan('startDate', new \DateTime('-4weeks'))
)
)
);
return $this->em->getRepository('Advertisement')->match($spec)->execute()
Furthermore you can compose 2 or more classes together, which creates nice reusable building blocks:
public function myQuery(User $user)
{
$spec = new AndX(
new ExpiredAds(),
new AdsByUser($user)
);
return $this->em->getRepository('Advertisement')->match($spec)->execute();
}
In this case ExpiredAds() and AdsByUser() contain a structure like in the first code example.
If you think that solution would work for you, let me suggest two libraries which you can install through composer:
Happyr\Doctrine-Specification
RikBruil\Doctrine-Specification (disclaimer: I'm the author of this one)
I have two msyql tables, Badges and Events. I use a join to find all the events and return the badge info for that event (title & description) using the following code:
SELECT COUNT(Badges.badge_ID) AS
badge_count,title,Badges.description
FROM Badges JOIN Events ON
Badges.badge_id=Events.badge_id GROUP
BY title ASC
In addition to the counts, I need to know the value of the event with the most entries. I thought I'd do this in php with the max() function, but I had trouble getting that to work correctly. So, I decided I could get the same result by modifying the above query by using "ORDER BY badgecount DESC LIMIT 1," which returns an array of a single element, whose value is the highest count total of all the events.
While this solution works well for me, I'm curious if it is taking more resources to make 2 calls to the server (b/c I'm now using two queries) instead of working it out in php. If I did do it in php, how could I get the max value of a particular item in an associative array (it would be nice to be able to return the key and the value, if possible)?
EDIT:
OK, it's amazing what a few hours of rest will do for the mind. I opened up my code this morning, and made a simple modification to the code, which worked out for me. I simply created a variable on the count field and, if the new one was greater than the old one, changed it to the new value (see the "if" statement in the following code):
if ( $c > $highestCount ) {
$highestCount = $c; }
This might again lead to a "religious war", but I would go with the two queries version. To me it is cleaner to have data handling in the database as much as possible. In the long run, query caching, etc.. would even out the overhead caused by the extra query.
Anyway, to get the max in PHP, you simply need to iterate over your $results array:
getMax($results) {
if (count($results) == 0) {
return NULL;
}
$max = reset($results);
for($results as $elem) {
if ($max < $elem) { // need to do specific comparison here
$max = $elem;
}
}
return $max;
}