relationship of an instantiated class - Laravel/Eloquent - laravel

I'm working on an api for a website, where I have the tables of blogs and categories
every blog belongs to category
and each category has many blogs
OK?
So, I created a BlogController and configured the routes to access the corresponding function.
/api/blog/ url via GET is redirected to the index function of my controller, and the function looks like this:
public function index()
{
$blog = Blog::with('category')->get();
return response()->json($blog, 200);
}
which returns this (correct)
[
{
"id": 1,
"title": "title from blog",
"body": "texto do meu blog",
"category_id": 1,
"created_at": "2018-09-05 21:08:21",
"updated_at": "2018-09-05 21:08:21",
"category": {
"id": 1,
"name": "Web development",
"created_at": "2018-09-05 20:54:54",
"updated_at": "2018-09-05 20:54:54"
}
}
]
/api/blog/ url via POST is redirected to the store function of my controller, to store the data in the database and the function looks like this:
public function store(Request $request)
{
$blog = new Blog($request->all());
$saved = $blog->save();
if ($saved) {
return response()->json($blog, 200);
}
return response()->json([
'message' => '400 Bad Request'
], 400);
}
then returns (missing category information)
{
"title": "title from blog",
"body": "texto do meu blog",
"category_id": "2",
"updated_at": "2018-09-06 00:56:13",
"created_at": "2018-09-06 00:56:13",
"id": 12
}
then, missing category information
after storing data in the database, I need it to come in response to category information for that specific blog
someone to help?

I can with
$blog->load('category');

Related

data limiting global scope with laravel model

i have a model named "Page" and
I want the first of my model's image arm data to be written, I wonder how can I do it?
public function index($lang)
{
$data = Page::where('language', $lang)->orderBy('order', 'ASC')->with('categori')->get();
if ($data) {
return response()->json($data);
}
return response()->json(['message' => 'Record not found.'], 404);
}
{
"id": 3,
"title": "Conporta",
"contents": "<p>Conporta</p>",
"slug": "hakkimizda",
"image": [
"/storage/page/Conporta/40-banner-1659203850.jpg",
"/storage/page/Conporta/40-banner-small-1659203850.jpg",
"/storage/page/Conporta/40-banner-medium-1659203850.jpg"
],
"language": "en",
"is_home": "false",
"status": "on",
"seo": null,
"order": "0",
"category_id": 2,
"created_at": "2022-07-30T17:57:30.000000Z",
"updated_at": "2022-07-30T17:57:30.000000Z",
}
You can hide the image attribute from model and create new attribute that should hold one image.
...
protected $hidden = ['image'];
protected $appends = ['img'];
...
public function getImgAttribute(){
return $this->image[0];
}

Laravel Eloquent with query

I want to pull the invoice detail with the "id" number of 3 in the tools table from the "invoice_details" table. "plate" "invoice_details" relationship "plate_no" in the "trucks" table, but when I pull the data, a different data is coming, where am I making a mistake?
public function getTruck($id)
{
$truck = Truck::find($id)->with(['truckHistory'])->first();
return $truck;
}
Truck extends Model
public function truckHistory(){
return $this->hasMany(InvoiceDetail::class,'plate_no','plate');
}
Normally the incoming data is TRUE when I don't write a with condition
THIS IS TRUE
$truck = Truck::find(3);
{
"id": 3,
"plate": "73AD323",
"created_at": "2021-10-13T08:38:23.000000Z",
"updated_at": "2021-10-13T08:38:23.000000Z"
}
When I type a condition, the id is wrong.
$truck = Truck::find(3)->with(['truckHistory'])->first();
{
"id": 1,
"plate": "33EER36",
"created_at": "2021-10-11T06:01:29.000000Z",
"updated_at": "2021-10-11T06:01:29.000000Z",
"truck_history": [
{
"id": 1,
"plate_no": "33EER36",
"created_at": "2021-10-11T06:03:16.000000Z",
"updated_at": "2021-10-11T06:03:16.000000Z"
},
{
"id": 2,
"plate_no": "33EER36",
"created_at": "2021-10-11T06:06:18.000000Z",
"updated_at": "2021-10-11T06:06:18.000000Z"
}
]
}
Using first will return the first record of the trucks table, to do so you can use
Truck::with(['truckHistory'])->find($id);

Laravel How to orderby()->first() in eager loading

I have this query which is working just fine except when i call ->first() function on it, the data from certain relations disappear.
What I am trying to achieve:
I am trying to get the sp_services where price is lowest. The first object (id: 1) in data array has two sp_services, the second object inside data array (id: 13) has only one sp_services. When i do $query->orderBy('sp_services.price', 'DESC')->first(); The object from first one is there but the second one where (id: 6, name: car wash) disappears and there is only empty array.
In the below mentioned JSON I'm only showing the relevant data here. Can anyone please tell me what am i doing wrong here ? and why is it not working. Also is there a better way to achieve desired result.
Query:
$branchesQuery = SpBranch::query();
$branchesQuery->where('status', true);
$branchesQuery->when($request->filled('price'), function($query) use($request) {
return $query->with(['service_provider' => function($query) use($request) {
$query->whereHas('sp_services')
->with(['sp_services' => function($query) use($request) {
$query->orderBy('sp_services.price', 'DESC'); //->first();
}]);
}]);
});
$branches = $branchesQuery->paginate($perPageLimit);
return $branches;
Models:
class SpBranch extends Model
{
public function service_provider()
{
return $this->belongsTo(ServiceProvider::class, 'sp_id');
}
}
class ServiceProvider extends Model
{
public function sp_services()
{
return $this->hasMany(SpService::class, 'sp_id', 'id');
}
}
JSON:
{
"data": [
{
"id": 1,
"sp_id": 1,
"name": "Branch 01",
"status": 1,
"service_provider": {
"id": 1,
"name": "Service Provider 01",
"sp_services": [
{
"id": 3,
"sp_id": 1,
"branch_id": null,
"name": "Service 03",
"price": 50
},
{
"id": 4,
"sp_id": 1,
"branch_id": null,
"name": "Service 04",
"price": 70
}
]
}
},
{
"id": 13,
"sp_id": 5,
"name": "Branch 13",
"status": 1,
"service_provider": {
"id": 5,
"name": "Service Provider 05",
"sp_services": [
{
"id": 6,
"sp_id": 5,
"branch_id": null,
"name": "car wash",
"price": 300
}
]
}
}
]
}
You cannot order or group by a eager loaded table on database, because what WITH method does is that it fires a new query meaning that is not connected to the first one at all, what you can do is you can order or group them in collections meaning after the data is fetch from db you can order them, I think function is called ->sortBy() which will order by the field you want, but it will cost you on performance. If performance is important in your case, you can always use joins to join both tables which will enable you order results directly from database.
class ServiceProvider extends Model
{
public function sp_services()
{
return $this->hasMany(SpService::class, 'sp_id', 'id')->orderBy('price', 'asc');
}
}

Extract mentioned users in post like Facebook comment

I followed this Laracast tutorial - https://laracasts.com/series/lets-build-a-forum-with-laravel/episodes/56 - to get "mentions" inside body. However I now want to fetch all the data for a thread, so I want all posts, and all related users, specifically mentioned users.
I am fetching all posts like this:
public function get(Thread $thread) {
return $thread->with(['posts'=>function($query) { return $query->with('user'); }]);
}
This returns to me data like this:
{
"id": 1,
"posts": [
{
"id": 1,
"user_id": 13,
"body": "Hi #14 and #15",
"user": {
"id": 13,
"name": "Joe"
}
},
{
"id": 2,
"user_id": 14,
"body": "Hi back at you"
"user": {
"id": 14,
"name": "Bob"
}
}
]
}
We see I get the author user's just fine. But I also need the mentioend users.
We see in the first one, during the store process, I converted #string to #USER_ID.
I did this in the store:
preg_match_all('/\#[^\s\.]+)/', $post->body, $matches);
And repalced with user_id.
Now however on fetch, I want to extract the user_id's from the post and attach to the resulting data these users. Is this possible?
My goal:
{
"id": 1,
"posts": [
{
"id": 1,
"user_id": 13,
"body": "Hi #14 and #15",
"users": [
{
"id": 13,
"name": "Joe"
},
{
"id": 14,
"name": "Bob"
},
{
"id": 15,
"name": "Ryan"
}
},
{
"id": 2,
"user_id": 14,
"body": "Hi back at you",
}
]
}
Is there a way to run the regex on each body and select the mentioned users too?
I think your goal isn't the correct one. You should think a good database design.
In your case, It's good to have mentions relation in your post (not users). Then you can attach the mentioned users to the post mentions. Something like,
preg_match_all('/\#[^\s\.]+)/', $post->body, $matches);
// get the author of the post
$author = $request->user();
// get all the user account for every #, except the author itself
$mentions = User::where(function ($query) use ($matches) {
foreach ($matches as $item) {
$query->orWhere('username', 'LIKE', $item);
}
})->where('id', '!=', $author->id)->get();
// attach the author to the post
$post->user()->save($author);
// attach $mentions to the post
$post->mentions()->saveMany($mentions);
// notify user were mentioned
Notification::send($mentions, new YouWereMentioned($post));
then to fetch the posts, you can do like so,
public function get(Thread $thread) {
return $thread->with([
'posts'=> function($query) {
return $query->with('user', 'mentions');
}
]);
}
Note. The laracasts video is only for the subscriber. You shouldn't make a question using a private resource. Or you must explain it all.

Transform Laravel Eloquent result

When I execute this in my Controller
$data = User::with('teams')->find(2);
return response(['data' => $data]);
I get this as result
{
"id": 2,
"country_id": 1,
"first_name": "John",
"last_name": "Doe",
"created_at": "-0001-11-30 00:00:00",
"updated_at": "2015-02-02 23:08:21",
"full_name": "John Doe",
"teams": [
{
"id": 1,
"name": "Helpdesk medewerker",
"description": ""
},
{
"id": 2,
"name": "Retentie",
"description": ""
}
]
}
Im not interested in the full teams data, but only interested in the teamNames of the user.
I've done this by adding this
$data->each(function($user) {
$user->team_names = $user->teams->lists('name');
unset($user->teams);
});
I was wondering if this is the correct way of modifying the Eloquent result.
You can use an attribute accessor for that. Add this to your model:
protected $hidden = ['teams']; // hide teams relation in JSON output
protected $appends = ['team_names']; // add custom attribute to JSON output
public function getTeamNamesAttribute(){
return $this->teams->lists('name');
}
To change hidden and appends dynamically you can use the setter methods:
$data = User::with('teams')->find(2);
$data->setHidden(['teams']);
Filter out the columns you want in your first build.
$data = User::with(['teams' => function($query){
return $query->select('name');
}])->find(2);
Will output:
{
...
"teams": [
{
"name": "Helpdesk medewerker"
},
{
"name": "Retentie"
}
]
}
You can also use the lists method.
$data = User::with(['teams' => function($query){
return $query->lists('name');
}])->find(2);
Will output:
{
...
"teams": ["Helpdesk medewerker", "Retentie"]
}

Resources