Laravel 4.2 - Update a pivot by its own id - laravel

I'm having some trouble with my pivot table. I've recognized too late, that it is possible, that some pivot rows doesn't have unique values in my project, means I've to add an auto_increment ID field to my pivot table.
This is my structure:
Order.php
public function items()
{
return $this->belongsToMany('Item', 'orders_items', 'order_id', 'item_id')->withPivot(['single_price', 'hours', 'prov', 'nanny_id', 'vat', 'vat_perc', 'invoice_id','id']);
}
orders_items
id, order_id, item_id, nanny_id, hours
I've conntected Orders and Items through a pivot table ('orders_items)'. It is possible, that one order has 2 or more same items in the pivot table. So I've to add an unique ID to identify and update them.
Now I try to update a pivot row. Problem is, if I have 2 or more items, he updates them all, not only one. This is my update command:
$order = Order::find($orderId);
$items = $order->items()->whereNull('nanny_id');
$free_item = $items->first();
$free_item->pivot->nanny_id = 123;
$free_item->pivot->save();
With this command, he updates all pivot rows from the order. I know the problem: Laravel uses here the wrong identifiers (it uses order_id and item_id as defined in my belongsToMany relationship - and they aren't unique). For example, Laravel tries to execute this code on save():
UPDATE orders_items SET [...] WHERE order_id = 123 AND item_id = 2;
I want, that Laravel changes the query to this one:
UPDATE orders_items SET [...] WHERE order_id = 123 AND item_id = 2 AND id = 45;
// Edit
Okay, this solution works:
$free_item->pivot->where('id',$free_item->pivot->id)->update('nanny_id',123);
But is there an easier way, f.e. adding a custom pivot model that adds the id automatically to save() and update() methods?

Related

SQLSTATE[42S22]: (SQL: select * from `categories` where `categories`.`departement_id` = 1 and `categories`.`departement_id` is not null)

I'm trying to select all categories of a specific departement.
class Test extends Controller
{
public function test(){
$depts=Departement::find(1)->categories;
foreach ($depts as $dept){
echo $dept->name;
}
return view('test');
}
}
A quick google search tells me SQLSTATE[42S22] is the code for 'Column not found'.
When you call Departement::find(1)->categories, Eloquent makes 2 queries
Get THE Department whe primary key is equal to 1
Get ALL the Categories where their 'departement_id' attribute is equal to 1
Given the query in your error
select * from `categories` where `categories`.`departement_id` = 1 and `categories`.`departement_id` is not null)
It's clear there is no departement_id column in your categories table.
If there's no departement_id column in your categories table
Either:
Add it in a migration.
Add it directly in the db if you do not work with migrations
If you want to make another column act as the foreign key
update your relationship method to reflect that.
https://laravel.com/docs/5.8/eloquent-relationships

Query on eloquent relationship

I have Book and Store models which have belongsToMany relationship.
In Book.php
public function stores(){
return $this->belongsToMany('App\Store')->withPivot('qty');
}
In Store.php
public function books(){
return $this->belongsToMany('App\Book')->withPivot('qty');
}
Now I just want to know the total number of books in store A and B together. How can I do it with eloquent ORM? I can get all books belonging to store A and B using whereHas but cannot go further to aggregate the qty field in the pivot table.
So you want the total qty of books by combination of store id and book id
The way you've described your DB structure, it looks like your pivot table has exactly these columns: book_id, store_id and qty
So all you really need to do is:
DB::table('book_stores')->get()

Laravel Eloquent select function cause empty relation

Following is my query
$user = User::select(['uuid','name','about'])->with(['education','work'])->first();
this returns empty data for relationship education and work,
but if I remove select function from query I am getting data in relationship and it also returns all columns of user table which I don't want.
how can solve this problem
The problem is that relationships (with(...)) execute an additional query to get the related results. Let's say you have one to many relationship where users have many works. User::with('work')->find(1) will then execute these 2 queries:
select user where id = 1 and select works where user_id = 1.
So basically in order to be able to execute the second query (fetch relationship data) you need to include id (or whichever column you're referencing) in you select statement.
Fix:
$user = User::select(['uuid','name','about', 'id'])->with(['education','work'])->first();
Same principle in different forms applies to all relationships. For example in the inverse of hasMany which is belongsTo you would need to select the foreign key (for example user_id).

Newest items and GROUP By with Eloquent

I have the following prices-table:
shop_id (int)
product_id (int)
price (float)
created (DateTime)
Every hour a cronjob checks the shops and inserts new entries (current prices) into these price-table.
Now I want to display the newest price for a product. I have to GROUP BY the shop_id because I only want one price per shop but I only want the newest entry (created).
Can I solve this with Eloquent Query-Builder or do I have to use raw SQL? Is it possible to pass the result of a raw SQL-query into a model if the columns are the same?
You can try it as:
Price::select('*', DB::raw('MAX(created_at) as max_created_at'))
->groupBy('shop_id')
->get()
Assuming model name is Price
Eloquent (purist) approach:
Price::orderBy('created', 'desc')->groupBy('shop_id')
->get('shop_id', 'price');
References:
https://laravel.com/api/5.3/Illuminate/Database/Query/Builder.html#method_orderBy
https://laravel.com/api/5.3/Illuminate/Database/Query/Builder.html#method_groupBy
https://laravel.com/api/5.3/Illuminate/Database/Query/Builder.html#method_get
*untested though
Q: Is it possible to pass the result of a raw SQL-query into a model if the columns are the same?
A: you could pass it to Model's contructor - but it might need model's field to be fillable - or hydrate a model. Alternatively, just access it like an keyed-array, ie. $something[0]['price'] <-- assuming an array of prices with price column.
I solved the problem without QueryBuilder. Instead I use a raw SQL-statement and generating the models with the hydrateRaw()-function of the Model-class.
$prices = Price::hydrateRaw( 'SELECT p.*
FROM prices p
INNER JOIN (
SELECT shop_id, max(created_at) AS max_ca
FROM prices p1
GROUP BY shop_id
) m ON p.shop_id = m.shop_id AND p.created_at = m.max_ca');

Laravel query builder updating field based on select count from another table

I have a Post and for each post there are multiple Likes in the likes table. I have created a total_likes field in the Posts table and I want to update it with the total number of likes from the likes table, in one statement. I current have this:
DB::table('posts as p')
->update(['total_likes' => function($query) {
$query->select(DB::raw('COUNT(*)'))
->from('likes as l')
->where(DB::raw('p.id = l.post_id'))
->groupBy('l.post_id');
}]);
But I am getting an error:
Object of class Closure could not be converted to string
I'm essentially trying to run:
UPDATE posts SET total_likes = (SELECT COUNT(id) FROM likes WHERE likes.post_id = posts.id GROUP BY id);

Resources