Laravel Accessor or HasManyThrough or something else? - php

I have four models: User, Product, Order, OrderItem
When a User adds an item to his cart, it creates a new Order and the item becomes a new OrderItem.
The tables:
users
id - integer
name - string
products
id - integer
name - string
orders
id - integer
user_id - integer
paid - boolean
order_items
order_id - integer
product_id - integer
quantity -integer
price - double
Relationships:
`Product` hasMany `OrderItem`
`OrderItem` belongsTo `Order`
`OrderItem` belongsTo `Product`
`Order` hasMany `OrderItem`
`User` hasMany `Order`
I want to be able to list all Product and under each, all the Users who bought that Product (Order whereNotNull 'paid').
Inversely, I'd like to show a User all the Products they have purchased.
I've tried taking it in steps with relationships. I can get {{ $product->orderItems }} to work, but not {{ $product->orderItems->orders }}
Laravel doesn't allow hasManyThrough relationships with a pivot table, which is essentially what order_items is, so that won't work.
Maybe I could do this with an Accessor with a join, but I can't wrap my head around it because I can't really set the relationship.
Maybe a custom Eloquent collection so every time I call Product it already has all the paid User and every time I call User the collection will already have all his Product?

Laravel has no native support for a direct relationship.
I've created a package for cases like this: https://github.com/staudenmeir/eloquent-has-many-deep
class Product extends Model
{
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function users()
{
return $this->hasManyDeep(
User::class,
['order_items', Order::class],
[null, null, 'id'],
[null, null, 'user_id']
)->whereNotNull('orders.paid');
}
}
$users = Product::find($id)->users;

Related

one to one relation with middle table

I have a invoice model which can belong to a product or a plan ... my database looks like this
invoices : id , type (enum:product,plan) , price
invoice_products : invoice_id , product_id
invoice_plans : invoice_id , plan_id
plans : id , title
products : id , title
when I want to show my invoices for the purchased item I have to write something like
$purachse = $invoice->invoice_plan->plan ;
Or
$purachse = $invoice->invoice_product->product ;
Is there a way to get rid of invoice_product in my relation?
I want to get the product or plan but I don't want to keep going through invoice_product I prefer laravel to handle that for me.
something like belongsToMany but for 1-1 relation .. there is hasOneThrough but it wont work as I thought.
You have to use Laravel polymorphic relations: https://laravel.com/docs/9.x/eloquent-relationships#one-to-one-polymorphic-relations

Laravel: fetch pivot relationship through another relationship

Using Laravel, I'd like to fetch an order status (order_status table) from an order (orders table) based on the
locale relationship stored in the orders table using a pivot table (order_status_locale table).
The pivot table contains the "localised" order status from the order.
Of course, I could fetch the localised order status (order_status_locale) directly from the database, but I'd like to
fetch the localised order status through a Laravel relationship.
Something like this:
$order = Order::find(123);
$order->localisedOrderStatus->label;
This is an example of the database structure:
orders:
id: int
locale_id: int
...other columns
locales:
id: int
...other columns
order_statuses:
id: int
...other columns
order_status_locale:
order_status_id: int
locale_id: int
label: varchar
its sometimes better to make model of your pivot table. like OrderStatusLocale.php
then you can make the relation through it.
lastly if you want to achieve
$order->localisedOrderStatus->label;
you can use laravel has one through. or i think its better to go through the relation like $order->order_status->locale->label

Include belongsTo and hasMany to builder in Laravel

I include the region and category language of category table in the builder. The region returns the exact output that I want, but the category language always returns empty. I copy the query and run it to Postgres and it returns some data.
Query
Relation of region and category language to category table
Output
Category Language Schema
Executed query for Category Language Table in Postgres. Working fine here
CategoryLanguageRegion Model
I think you have to add category_id in select query as follows:
'categoryLanguages' => functon($query) {
$query->select('id', 'title', 'description', 'category_id');
}
For region, you don't have to add because mapping is other way around. It's Category model that contains foreign key region_id, but for CategoryLanguage, Category model doesn't have any foreign key that's why you have to explicitly add category_id in select query.

Joining table created_at and updated_at values not being set

I have two models, Product and Attribute. There is a 'product_attributes' joining table between 'products' and 'attributes'. The relationship is defined in both models using belongsToMany(), and the key of the table is a compound one of product_id and attribute_id.
I can successfully retrieve and store records in the joining table - so, as such everything is functioning as expected, with the exception that the created_at and updated_at in product_attributes is not being set.
Is the above by design, and is there anything I can do to rectify this?
You should use the belongsToMany function with the timestamps declaration like this:
$this->belongsToMany(<entity>)->withTimestamps();

Laravel 4: How to remove `limit 1` restriction from Find() in Eloquent?

I want to retrieve all the tasks details (task_title etc) belonging to one author_id (author2 in this case).
Tests table
author_id task_id
author2 task_1
author2 task_2
Tasks table
task_id task_title
task_1 task_title_1
task_2 task_title_2
Author table
author_id author_name
author_2 authorTwo
Model test.php
public function tasks()
{
return $this->belongsTo('Task','task_id');
}
TestsController.php
public function index()
{
$test=Test::find('author2')->tasks()->get();
return View::make('tests.index', compact('tests'));
}
and the query SQL:
select * from `tests` where `author_id` = 'author2' limit 1
select * from `tasks` where `tasks`.`task_id` = 'task1'
But actually in tasks table, there are more than one value related to author 2 (in this case task 1 and task2 ) but as the sql only illustrates task1.
How can I remove the limit 1 restriction to retrieve all the tasks belonging to author 2?
There are multiple issues with that. The main ones being:
You're using the wrong relationship for a many-many, look into belongsToMany()
It looks like you're trying to look up on a composite key which is not supported
Find is intended to fetch only one record, and does not limit the result set of a relationship. As shown by your SQL, you're not limiting your tasks by one, you're limiting tests. Use get() in conjunction with where() when you need to fetch multiple records.
Here is a link to the documentation to get you started - http://four.laravel.com/docs/eloquent
Test::where("author_id","=","author2")->get()
You should not be using find for anything that is not a primary key, by the way. This is the aim of find: it fetches one item as it assumes that the key it searches for is primary auto-increment (i.e. unique)

Categories