use firstOrCreate with whereRaw to compare date?
Hi. I'm adding stats functionality on a list which display providers to my visitors to know how much it has been displayed.
I want to detail the stats for each week, so I want to create a new entry in database every week if it doesn't exist.
First, I used this logic:
$stats = ProviderStats::firstOrCreate(['provider_id' => $event->provider->id]);
if($stats->created_at->weekOfYear != Carbon::now()->weekOfYear)
$stats = $event->provider->stats()->create();
$stats->increment('phone_displayed');
$stats->save();
It works But it create two ProviderStat in memory, and one is useless. Also I asked myself: "Is there a way to do it more fluently?". I know (for now) it's not possible to compare date in the firstOrCreate attributes comparison. So I tried to use whereRaw to do this:
firstOrCreate(['provider_id' => $event->provider->id])->whereRaw('WEEK(`created_at`) = '. Carbon::now()->weekOfYear)
But... It doesn't work :( the whereRaw is simply ignored!
I thinked: maybe I should create a "freshOrCreate" method? Or is there a way to compare date in firstOrCreateMethod?
Thanks for any suggestions.
[EDIT] Finally I can use fluent where and whereRaw directly into my event. The problem was the WEEK() SQL function which is different from Carbon::weekOfYear . I'm using WEEKOFDAY() SQL function and it's working.
For now I extended Model class with an abstract class Stat, which is implemented by my ProviderStat class, I still welcome any suggestions/agreements:
abstract class Stat extends Model
{
public static function boot()
{
parent::boot();
}
/**
* Get the first fresh(same week) record matching the attributes or create it.
*
* @param array $attributes
* @return static
*/
public static function freshOrCreate(array $attributes)
{
if ( ! is_null($instance = static::where($attributes)->whereRaw('WEEKOFYEAR(`created_at`) = '. Carbon::now()->weekOfYear .' AND YEAR(`created_at`) = ' . Carbon::now()->year)->first()))
{
return $instance;
}
return static::create($attributes);
}
}
Please or to participate in this conversation.