Add date on Laravel - laravel

When i am using this code it shows an error "Call to a member function addDays() on string"
public function showJobCategoryContent($id)
{
$jobsInfoById = DB::table('jobs')->where('category_id', '=', $id)->where('published', '=', 1)->paginate(3);
$jobsInfoById = $jobsInfoById->map(function ($job) {
return $job->created_at->addDays(30);
});
return $jobsInfoById->pluck('created_at');
}

Because you're using DB instead of Jobs, you are getting back raw database data instead of a carbon instance. If you did the same thing with Jobs, you'd get models and the dates would be Carbon:
$jobsInfoById = Jobs::where('category_id', '=', $id)->where('published', '=', 1)->paginate(3);
To fix it without using Eloquent, do:
use Carbon\Carbon; //including Carbon already
$jobsInfoById = $jobsInfoById->map(function ($job) {
return ['created_at' => Carbon::parse($job->created_at)->addDays(30)];
});
Carbon instance is created when you are doing the map on the result.

Related

Laravel, eloquent, query: problem with retriving right data from DB

I'm trying to get the right data from the database, I'm retriving a model with a media relation via eloquent, but I want to return a photo that contains the 'main' tag stored in JSON, if this tag is missing, then I would like to return the first photo assigned to this model.
how i assign tags to media
I had 3 ideas:
Use orWhere() method, but i want more likely 'xor' than 'or'
$models = Model::with(['media' => function ($query) {
$query->whereJsonContains('custom_properties->tags', 'main')->orWhere();
}]);
return $models->paginate(self::PER_PAGE);
Raw SQL, but i don't really know how to do this i tried something with JSON_EXTRACT and IF/ELSE statement, but it was to hard for me and it was a disaster
Last idea was to make 2 queries and just add media from second query if there is no tag 'main'
$models = Model::with(['media' => function ($query) {
$query->whereJsonContains('custom_properties->tags', 'main');
}]);
$models_all_media = Model:: with(['media']);
return $models->paginate(self::PER_PAGE);
but i tried something like
for($i=0; $i<count($models); $i++) {
$models->media = $models_all_media
}
but i can't do this without get() method, beacuse i don't know how to change this to LengthAwarePaginator class after using get()
try using whereHas https://laravel.com/docs/9.x/eloquent-relationships
Model::with('media')
->whereHas('media',fn($media)=>$media->whereJsonContains('custom_properties->tags', 'main'))
->paginate(self::PER_PAGE);
as per your comment you can use
$models = Model::with(['media' => function ($query) {
$query->whereJsonContains('custom_properties->tags', 'main');
}])
->leftJoin('media', function ($join) {
$join->on('models.id', '=', 'media.model_id')
->whereNull('media.custom_properties->tags->main');
})
->groupBy('models.id')
->paginate(self::PER_PAGE);
return $models;

How to get data HasMany() using WhereHas in Laravel

I want to get data from my table " Package " by using its model " Package "
and in this model " Package " it have a HasMany() named histories() relation to model " History "
so i want to only get data that have histories
here is my controller
public function getIncomeMPW(Request $request)
{
if ($request->expectsJson()) {
$this->getSearch($request);
$query = new Package();
$query->with(['histories', 'items', 'items.prices', 'origin_regency', 'origin_district', 'origin_sub_district', 'destination_regency', 'destination_district', 'destination_sub_district', 'code', 'attachments']);
$query->whereHas('histories', function (Builder $query) {
$query->whereNotNull('partner_id');
});
$query->orderBy('created_at', 'desc');
return (new Response(Response::RC_SUCCESS, $this->query->paginate(request('per_page', 15))))->json();
}
}
here is my Package model relation histories HasMany()
public function histories(): HasMany
{
return $this->hasMany(History::class, 'package_id', 'id');
}
and last here is my response that showing right now
i already try using whereHas(), Has(), whereDoesntHave(), and its seems like there is no impact on my response, can anyone help me please ?
In your response you simply access a different query as it seems.
return (new Response(Response::RC_SUCCESS, $this->query->paginate(request('per_page', 15))))->json();
Uses $this->query
While
$query = new Package();
$query->with(['histories', 'items', 'items.prices', 'origin_regency', 'origin_district', 'origin_sub_district', 'destination_regency', 'destination_district', 'destination_sub_district', 'code', 'attachments']);
$query->whereHas('histories', function (Builder $query) {
$query->whereNotNull('partner_id');
});
$query->orderBy('created_at', 'desc');
Defines a $query without $this. I'd expect your $this->getSearch($request); to define $this->query (as the function is not posted in the question, i cannot tell). So either remove $this in your response - or change everything to $this and ensure to now overwrite it in the first line.
Quickfix should be
return (new Response(Response::RC_SUCCESS, $query->paginate(request('per_page', 15))))->json();
UPDATE:
Quick answer: Change
return (new Response(Response::RC_SUCCESS, $this->query->paginate(request('per_page', 15))))->json();
To
return (new Response(Response::RC_SUCCESS, $query->paginate(request('per_page', 15))))->json();
Wwhat whereHas and whereDoesntHave functions do in the backstage is that they make a sub query such as:
Select * from packages where exists (select * from histories where CONDITIONS YOU HAVE MENTIONED)
And the problem here is that when you use with method you eager load table history which adds one extra query that is not related to the first one such as:
Select * from histories where package_id in (1,2,3,4,5,6)
So since we cleared that out, what I suggest you do is that you assign a function to a variable in this way:
$historyFunction = function ($query) {
$query->whereNotNull('partner_id');
};
and than call it in with and in whereHas methods as shown below:
$query->with(['histories' => $historyFunction, otherRelations... ]);
$query->whereHas('histories', $historyFunction);
And what this does is that it tells eloquent: When you eager load Histories relationship add this conditions to the query you are about to make.

Laravel: hasMany relationship breaks query with where clause

This is my first Laravel project, so maybe I'm misunderstanding something.
I have Clients and Campaigns contollers, and clients are setup with hasMany campaigns
class Client extends Model
{
public function campaigns(){
return $this->hasMany('App\Campaign');
}
}
in the Clients Show method, this query doesn't work:
$client = Client::find($id);
$campaigns = $client->campaigns
->where(function($query) use($startdate, $enddate) {
$query->wherebetween('start_date', [$startdate, $enddate])
->orwherebetween('end_date', [$startdate, $enddate]);
})
->sortBy('start_date')
->groupBy(function($val) {
return Carbon::parse($val->start_date)->format('F Y');
});
I get the error:
explode() expects parameter 2 to be string, object given
The error page shows a red line on the }) after the orwhereBetween clause.
But this query does work:
$campaigns = DB::table('campaigns')
->where('client_id', $client->id)
->where(function($query) use($startdate, $enddate) {
$query->wherebetween('start_date', [$startdate, $enddate])
->orwherebetween('end_date', [$startdate, $enddate]);
})
->orderBy('start_date')
->get()
->groupBy(function($val) {
return Carbon::parse($val->start_date)->format('F Y');
});
My problem is, the second query doens't let me access $campaign->tasks once I'm on the show view, which I need.
So, does anyone know why the where clause would cause an issue when accessing $client->campaigns but not when using DB?
That's because before you call get method the object is an instance of Eloquent Builder class and the groupBy method doesn't accepts any parameter as a closure. However after calling the get method it changes to an instance of Collection class which has groupBy method as well and it accepts closure.
By the way sortBy doen't belong to Eloquent builder instead you have to use orderBy before executing your query using get method.
Here are the available methods of Collection
https://laravel.com/docs/5.7/collections#available-methods
Try this code out and don't forget to call the methods camel case otherwise it can make you serious problems on deployment.
$dates = $client->campaigns()
->where(function($query) use($startdate, $enddate) {
$query->whereBetween('start_date', [$startdate, $enddate])
->orWhereBetween('end_date', [$startdate, $enddate]);
})
->orderBy('start_date')
->get()
->groupBy(function($val) {
return Carbon::parse($val->start_date)->format('F Y');
});
foreach($dates as $campaigns){
foreach($campaigns as $campaign){
dump($campaign->tasks);
}
}

How to add subqueries in eloquent db of laravel 5?

I am building an api in laravel 5.3 using eloquent if I use /api/location/event_name/event_status then I am getting results.
But when I use /api/location/event_name or /api/location/ nothing comes.
How to write the query so that all my link show result?
class events_api extends Controller
{
public function events($location = "",$event_name="",$event_status="")
{
$events = DB::table('event_table')
->join('event_details', 'event_table.event_id', '=', 'event_details.event_id')
->join('venue', 'event_details.venue_id', '=', 'venue.venue_id')
->where('venue.venue_city','=',$location)
->where('event_table.event_name','=','$event_name')
->where('event_table.event_status','=','$event_status')
->where('event_table.event_post_status','=','publish')
->select('event_table.event_title','event_details.event_start_ts','event_details.event_views','venue.venue_name','venue.venue_city','venue.venue_location')
->get();
echo $events;
}
}``
If you would like to make a subQuery try using toSql method:
class events_api extends Controller
{
public function events($location = "",$event_name="",$event_status="")
{
$subQuery = DB::table('event_table')
->join('event_details', 'event_table.event_id', '=', 'event_details.event_id')
->join('venue', 'event_details.venue_id', '=', 'venue.venue_id')
->where('venue.venue_city','=',$location)
->where('event_table.event_name','=','$event_name')
->where('event_table.event_status','=','$event_status')
->where('event_table.event_post_status','=','publish')
->select('event_table.event_title','event_details.event_start_ts','event_details.event_views','venue.venue_name','venue.venue_city','venue.venue_location');
DB::table(DB::raw("{$subQuery->toSql()} as main_query"))
->mergeBindings($subQuery->getBindings())
// build your query here
->get()
}
}
You'll also need to mergeBindings if you use any bindings in subquery

How to query created_at field in Laravel

When trying to find all records where the created_at time is larger than a certain value, it does not seem to work.
For example I have tried this:
return Foo::where('created_at', '>', '1457408361')->get();
But it keeps returning all the records!
Use the whereDate() query method:
$date = Carbon::yesterday(); // Create date however you want
Foo::whereDate('created_at', '>', $date);
If you do these types of queries a lot, I’d consider wrapping it into a query scope:
use DateTimeInterface;
class Foo extends Model
{
public function scopeCreatedAfter(DateTimeInterface $date)
{
return $query->whereDate('created_at', '>', $date);
}
}
Usage:
Foo::createdAfter($date)->get();
You can always use Carbon to convert the UNIX timestamp:
Foo::where('created_at', '>=', Carbon::createFromTimestamp(1457408361))->get();
So you can convert your integer to Carbon instance and compare it as above.
You can read about Carbon here: http://carbon.nesbot.com/docs/

Resources