Eloquent Showing pivot - laravel

for some weird reason building this model with Eloquent is hiding the Pivot that I am requiring explicitly in the relation (This Model is called Match):
public function scorers()
{
return $this->belongsToMany(
Player::class,
'match_players',
'match_id'
)->withPivot(
'goals'
)->where(
'goals', '>', 0
);
}
public function scopeComplete($query)
{
return $query->with(
'homeTeam',
'awayTeam',
'scorers'
);
}
The problem is the json result of scorers is as follows
"scorers": [
{
"id": 196,
"name": "Tino",
"surname": "Heck",
"age": 24
},...
And is hiding the pivot (goals) team_id and goals which should appear on each object inside a nested object called pivot, did anyone came across some problem like this? I cat find anything around here. Something like
"scorers": [
{
"id": 196,
"name": "Tino",
"surname": "Heck",
"age": 24,
"pivot": {
"goals": 3
}
},...
Db structure is
Match
- id
- ..
Players
- id
- ...
MatchPlayer
- player_id
- match_id
- goals
The result inside scorers is correct, so I get the actual player where goals > 0, but not the pivot I am looking for
Thanks in advance.

Silly me, I found the error, the problem was that Iwas hiding pivots on Player Model :(
So the lesson here is the $hidden array property that counts is the one on the relation model rather than the one on the Parent (Match in this case)

Related

Laravel 'hasMany' relationship not working, no idea why

I'm having trouble retrieving data through relationships.
My database structure (simplified):
orders:
id
user_id
product_id
order_items:
order_id
product_id
I need to get using relationships, all orders along with the items in the array.
Order model:
public function items()
{
return $this->hasMany(OrderItem::class, 'order_id', 'id');
}
Test controller:
public function test()
{
return Order::with('items')->get();
}
Result I got when accessing test():
[
{
"id": "d7baaae9-b925-4ff0-8bba-13e8e88d429b",
"user_id": "fa2a5f73-379d-4ab7-9bc5-81cdbd47f3b0",
"subtotal": "0.00",
"discount": "0.00",
"coupon_code": "0",
"total": "0.00",
"paid": false,
"refunded": false,
"created_at": "2022-07-26T16:41:50.000000Z",
"updated_at": "2022-07-26T17:51:45.000000Z",
"items": [
]
}
]
The "items" array does not exist in the orders table, it is coming through the relationship, but it comes empty. There is a record in the database relating orders with order_items, the OrderItem model is correctly accessing the database when I test. I don't know what the problem could be.
[EDIT_01]: I just found out that the problem is in the id I'm using, I'm using type Uuid (Ramsey\Uuid\Uuid\Uuid::uuid4()) for the keys of my tables, somehow it's not working, but when I testo with conventional ID works. Help-me.
I have the same issue, my fix is I add
protected $keyType = 'string';
to the table which has string id (uuid). Hope it can help
hope you found a solution, if not testing out your code sample here, and everything works fine for me,
public function items()
{
return $this->hasMany(OrderItem::class);
}
use this instead, should give you a better result
Try removing the third parameter and just use this:
return $this->hasMany(OrderItem::class, 'order_id');
This should work given your Database setup example, make sure you actually have items in your database that belong to that order you are debugging as well.

Laravel attribute not working as expected

In the current application, there is a model Part and a model Supplier. Every Part has a Supplier.
public function supplier()
{
return $this->belongsTo(Supplier::class);
}
I added an accessor to get the name of the supplier.
If i return the whole dataset, i get the supplier:
public function getSupplierNameAttribute()
{
return $this->supplier;
}
"supplierName": {
"id": 1,
"uuid": "37e3a715-09d3-4fac-ae88-8f12e63fe79c",
"name": "Laserteam",
"street": "8602 Dessie Tunnel",
"zip": "15869",
"city": "New Clementview",
"email_send_type": null,
"active": 0,
"created_at": "2020-01-09 09:46:02",
"updated_at": "2020-01-09 09:46:02",
"deleted_at": null,
"action": "",
"activeLabel": "<span class='badge badge-secondary'>Inaktiv<\/span>"
},
If i try to get only the name (what I need finally), there is an error:
public function getSupplierNameAttribute()
{
return $this->supplier->name;
}
ErrorException: Trying to get property 'name' of non-object in file /gopanel/sites/7industry_net/public/7time/app/Models/Part/PartAttribute.php on line 48
If i try in this way, it works:
public function getSupplierNameAttribute()
{
return $this->supplier['name'];
}
Why does return $this->supplier->name; not work?
It's hard to say what could be the problem here, but:
Make sure you don't have supplier in casts for your model
Make sure you don't use supplier for database column name or you don't make somewhere something this
$this->supplier = $this->supplier->toArray();
It seems supplier property somewhere becomes array that's why one notation works but the other doesn't.
I’m not really sure what’s going on there; if you have a supplier relation then accessing the property should lazy-load the relationship.
Alternatively, you could try this syntax:
public function getSupplierNameAttribute()
{
$this->loadMissing('supplier');
return $this->getRelation('supplier')->name;
}
However, I’d avoid defining accessors like this. It can lead to N+1 problems if you say, retrieve a collection of parts and then call $part->supplier_name on each one without eager-loading the supplier relationship.
Personally, if I’m accessing attributing on relations that I prefer to do it through the relation (i.e. $part->supplier->name) so any relations I need to eager load are shown to me.
Try this code
public function getSupplierNameAttribute()
{
return $this->supplier->name ?? 'supplier not exists';
}

How to get random row in object variable in Laravel?

Sorry for my bad english, I want to get a single row in my object. And I want that in random order. Im using array_rand() and it only return errors as stated below:
ErrorException: array_rand() expects parameter 1 to be array, object given in file C:\xampp\htdocs\user\TestProject\app\Http\Controllers\TestController.php on line
Here is my object.
"my_list": [
{
"id": 1,
"name": "My Name Test",
"address": [
{
"id": 1,
"city": "Manila",
"country": "Philippines"
}
]
},
{
"id": 2,
"name": "Your Name Test",
"address": [
{
"id": 2,
"city": "Cebu",
"country": "Philippines",
}
]
}
]
The problem is I want only to get a single row to the my_list which is object and not an array.
Here is my code.
$course = Course::where('id', 1)->with('my_list')->first();
$random_list = array_rand($course->my_list);
return $random_list;
I also try adding number of row in the array_rand like this.
$random_list = array_rand($course->my_list, 1);
But still not working.
What did I missed?
Any Eloquent query returns, by default, a Collection, even for the underlying relationships. Since you are working with one, this should work:
$course->my_list->random();
This will return only one item. If you want more, you could pass an argument to the random() method specifying the count of items you want.
For more information, check the documentation.
This Object is a Laravel collection. Please refer to the collection documentation.
https://laravel.com/docs/5.7/collections#method-random
You can try $course->my_list->random()
If you still wanna do this with your approach, can you try get_object_vars function to cast object into array.
$array = get_object_vars($object);
so that you can use them as an array in array_rand.
You might get an error, hence that it's an multi-dimensional array. Let me know so i may update.
Update for multidimensional:
Please refer to this.
// The second parameter of json_decode forces parsing into an associative array
$array = json_decode(json_encode($object), true);
try this:
$course = Course::where('id', 1)
->with(['my_list' => function($query) {
$query->inRandomOrder();
}])->first();
return $course->my_list;
Try this method:
$course = Course::where('id', 1)
->with(['my_list' => function($query) {
$query->inRandomOrder()->first();
}])->first();
return $course->my_list;
this method is more efficient since you will only get 1 row from my_list not like when you use $course->my_list->random() which retrieves all data and from there select a random row.
$random_list = $course['my_list']->random(number);
ps: number = number of element you want to get ,

Laravel 5 / Eloquent - Return a Date Based on the created_on Column Plus Variable Hours

I have two tables: statuses and status_logs.
The statuses table has 3 columns: id, name, duration
The status_logs table has 3 columns: id, status_id, created_at
I have two models that look like this:
class Status extends Model{
// Name of our database table
protected $table = 'statuses';
// Defines the relationship between this table and the status_logs table
public function status_logs(){
return $this->hasMany('App\Models\Status', 'status_id');
}
}
class StatusLog extends Model{
// Name of our database table
protected $table = 'status_logs';
// Defines the relationship between this table and the statuses table
public function statuses(){
return $this->belongsTo('App\Models\Status', 'status_id');
}
}
I can get data from both tables by using:
StatusLog::with('status')->get();
The result would look something like:
"status_logs": [{
"id": 1,
"status_id": 1,
"created_at": "02:34:53 10/5/2017",
"statuses": {
"id": 1,
"name": "started"
"duration": 48
}
}]
I would like to add a column called finish_at to each object inside of the status_logs array. This datetime will be the created_at value plus whatever the integer value of duration is. Duration is the number of hours that we need to add to created_at to get the value of finish_at.
The result should look like:
"status_logs": [{
"id": 1,
"status_id": 1,
"created_at": "02:34:53 10/5/2017",
"finish_at": "02:34:53 10/7/2017",
"statuses": {
"id": 1,
"name": "started"
"duration": 48
}
}]
How would I do this?
Use Eloquent appends would solve this.
Add additional attribute and define the value. It would be look something like below.
class StatusLog extends Model
{
protected $appends = ['finish_at'];
public function getFinishedAtAttribute()
{
// carbon to add hours
$dt = Carbon::instance($this->attributes['created_at']);
$dt->addHours($this->statuses->duration);
return $dt->toDateTimeString(); // change to your desire format
}
}
Using Carbon (http://carbon.nesbot.com/docs/#api-addsub), does something like this work for you:
$log->finished_at = $log->created_at->addHours($log->statuses()->duration);
First step is devide the duration in 24.
then add the devided duration in created_at value using using carbon
like this one.
$log->finished_at = $log->created_at->addDays($log->statuses()->duration/24);
$log->save();

Hide specific columns from pivot key

I have 2 tables say abc and xyz with ManyToMany relationship built over another table say abc_xyz (whose data will be returned as pivot key). However, pivot key upon retrieval has abc_id and xyz_id in return. I am able to access other columns in from abc_xyz table using method withPivot('dummy')
But, I want to hide the abc_id and xyz_id from the response. How do I do that?
I can hide the entire pivot key by using $hidden array but I want to hide only specific columns not the entire key.
Current Response
{
"abc_uuid": "some uuid",
"xyz" : [
{
"xyz_uuid": "some uuid",
"pivot": {
"abc_id": 1,
"xyz_id": 1,
"dummy" : "dummy value"
}
},
{
"xyz_uuid": "some uuid",
"pivot": {
"abc_id": 1,
"xyz_id": 2,
"dummy" : "dummy value"
}
}
]
}
So, I need only dummy from the pivot key, and hide abc_id and xyz_id. How do I do that?
Found a crude way to get this done. Found this answer in laravel issues unable to find the link now. However, it asks me to just add a method in my model and unset the keys I do not want.
public function toArray()
{
$attributes = $this->attributesToArray();
$attributes = array_merge($attributes, $this->relationsToArray());
foreach($attributes['xyz'] as $key => $value) {
unset($value['pivot']['abc_id']);
unset($value['pivot']['xyz_id']);
$attributes['xyz'][$key] = $value;
}
return $attributes;
}
this unsets the unwanted keys from my response. I hope laravel gives out an easy way for this.

Resources