I am trying to get a products list using Laravel 4.2 query builder.
The tables are related as follows
PRODUCTS
products.product_category_id
PRODUCT CATEGORIES
products.product_category_id = product_categories.id
PRODUCT CATEGORY TRANSLATIONS
product_categories.id = product_category_translations.product_category_id
What I am doing now is...
$products = DB::table('products')->join('product_categories', function($join){
$join->on('products.product_category_id','=','product_categories.id');
});
And I can get the contents of the product categories related table. But how can I nest another join and get the related data from the product categories translations table?
I would advise you to take a look at the laravel documentation to find a proper way to make relationship with models.
http://laravel.com/docs/4.2/eloquent#relationships
You would then create models like
class Product extends Eloquent {
public function category()
{
return $this->hasOne('ProductCategory');
}
}
class ProductCategory extends Eloquent {
public function product()
{
return $this->hasOne('Product');
}
public function translation()
{
return $this->hasOne('Translation');
}
...
Then to fetch the last table it would be as simple as something like :
$category = Category::find($categoryId);
$translation= $category ->translation;
Or if the id you have, is the productId, you can make it similar from the product table.
Related
I'm facing a problem with name conventions for mysql's tables in laravel, expecially for categories name.
I found out to have a lot of category-like tables to identify a Model category.
In some cases I managed to rename them avoiding the prefix 'category'. For example the model UserCategory has become Role, and the table has become roles. With this trick I can have a readable role_user pivot table.
In other cases I can't find a proper name: ProductCategory, CarCategory, StyleCategory and so on. What is the best approach in this case? And what is the best name could I assign to the model and to the table?
Furthermore, if a model has multiple categories of his type I should have something like product_productcategory pivot table and that's orrible. That's why I always prefer to avoid the word category in a model/table, but I'm afraid there are no other ways in these cases.
What is your approach? Are there some best practices?
If your category tables have columns in common, I would suggest using many-to-many polymorphic relation:
product
id - integer
name- string
car
id - integer
manufacturer - string
model - string
categories
id - integer
name - string
categorizable
category_id - integer
categorizable_id - integer
categorizable_type - string
The Product and Car models will both have a categories method that calls the morphToMany method on the base Eloquent class:
class Product extends Model
{
/**
* Get all of the categories for the product.
*/
public function categories()
{
return $this->morphToMany('App\Category', 'categorizable');
}
}
Inverse of the relationship:
class Category extends Model
{
/**
* Get all of the products that are assigned this category.
*/
public function products()
{
return $this->morphedByMany('App\Product', 'categorizable');
}
/**
* Get all of the cars that are assigned this category.
*/
public function cars()
{
return $this->morphedByMany('App\Video', 'categorizable');
}
}
Have three tables / models:
Clients:
id - client
Brands:
id - brand
BrandModels:
id - model - brand_id
BrandModelClients:
id - brandmodel_id - client_id
I would like to get a "group by" clients list based on the brands in the cleanest way. Right now, I'm doing it in a dirty way.
So the point is that if I have a client who has three different cars of the same brand, get just one client element.
I not getting a proper structure of your database, but you should use eloquent relation like below: for more read eloquent-relationships
Class Brand extends Model{
public function models(){
return $this->hasMany('App\BrandModel', 'brand_id');
}
}
Class BrandModel extends Model{
public function clients(){
return $this->hasMany('App\BrandModelClient', 'brandmodel_id');
}
}
Class BrandModelClient extends Model{
public function client(){
return $this->hasOne('App\Client', 'client_id');
}
}
$brands = Brand::with('models.clients.client')->get();
Fixed with two queries this way:
//One to get all models
$models_list = BrandModel::whereIn('brand_id', $list_fav_brands)->get()->pluck('id','model');
//Second to get the clients
$client_list = BrandModelsClient::whereIn('brands_model_id', $models_list)->with('client')->get()->pluck('client.id','client.name');
When I try to access articles vie category it works properly here is category.php model
public function articles(){
return $this->belongsToMany('App\Article');
}
but when I try to access category name view article it doesn't work as it's supposed to, I made I mistake there and trying to fix it, but no luck so far. here is the Article model
public function category(){
return $this->hasOne('App\category');
}
and there is a table for relation those two to each others it's called article_category in page where I get all articles for the given tag, I want to do something like $article->category->name there is something sound very wrong to me but I can't figure it out.
The error I'm receiving is
Column not found: 1054 Unknown column 'category.article_id' in 'where clause' (SQL: select * from category where category.article_id = 1 and category.article_id is not null limit 1) (View: C:\wamp64\www\loremipsum\bluhbluhbluh\articleByTag.blade.php)
Btw the way I save the relationship for the article_category when an article is created is
$article->category()->sync($request->category, false);
You've said that article might have only one category. In this case, delete pivot table and add category_id into the articles table.
Then in the Article model define this relationship:
public function category()
{
return $this->belongsTo(Category::class);
}
And in the Category model:
public function articles()
{
return $this->hasMany(Article::class);
}
When you'll do that, you'll be able to access article's category with:
$article->category->name
You have the relationship established incorrectly. Remove the intermediate table and add category_id to the articles table.
Relationships are not set correctly
Category model should be like :
class Category extends Model
{
protected $table='category';
//give me all articles associated with the given category
public function articles()
{
return $this->hasMany('App\Article');
}
}
And Article model
class Article extends Model
{
protected $table='article';
//get the category associated with the given article
public function category()
{
return $this->belongsTo('App\Category');
}
}
for attaching articles to a category:
$article->category()->associate($category)->save();
Sometimes we use MySql Views to organize related tables to make it easier to search and sort. For example if you have Posts with a Status, and a Source.
Post
subject
body
source_id
status_id
Status
id
label
other_field
Source
id
label
other_field
View
create view read_only_posts as
SELECT statuses.label as status, sources.label as source, posts.*
from posts
left join statuses on statuses.id = posts.status_id
left join sources on sources.id = posts.source_id
Then we have the Post model and an extra model:
// Post.php
class Post extends Model
{
//
}
// ReadOnlyPost.php
class ReadOnlyPost extends Post
{
protected $table = 'read_only_posts';
}
This is nice because now you can directly sort or filter on Status or Source as a string not the id's. You can also include the 'other_field'.
But we have a problem that I need help with. If you have a polymorphic many-to-many relationship on Posts, I can't get it to work on the read only version. For example if you have polymorphic tags:
// Post.php Model
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
The problem is when you filter a post (using the read only model) with a specific tag you get sql like this:
select count(*) as aggregate from read_only_posts where exists (select * from tags inner join taggables on tags.id = taggables.taggable_id where read_only_posts.id = taggables.taggable_type and taggables.taggable_type = 'read_only_posts' and label = 'test')
As you can see the problem is the taggables.taggable_type = 'read_only_posts'.
I can't find a way to override the morph type for a model. (I am on laravel 5.4 and the MorphClass isn't there anymore). The morph map is an associative array so you can't do this:
// AppServiceProvider
public function boot()
{
Relation::morphMap([
'posts' => Post::class,
'posts' => ReadOnlyPost::class, <--- Can't do this
My stupid fix is when I attach a tag to a post I also attach it to ready_only_posts, which is kind of a mess.
Anyone else uses Views for read only models? Anyone have a better way to overriding the many to many polymorphic type for a specific model?
Looking at the code, I believe this might work.
class ReadOnlyPost extends Posts
{
public function getMorphClass() {
return 'posts';
}
}
In theory you should need to have the Posts model/table listed in the morph map, since the system will auto generate the type of "posts" for it based on naming.
I have the following tables
products table
product_id
name
desc
with a has many relation to
suggested products table
id
product_id
suggested_product_id
Quantity
required (boolean)
What I am trying to accomplish is being able to access the name of a suggested product id in my view.
Products Controller
public function show($id)
{
$product = Product::with('stockitems','suggestedproducts.product')->find($id);
return view('backend.products.show', compact('product'));
}
I know the issue is at "suggestedproducts.product" just not sure how i specify the key(suggested_product_id) for the eager load is a product_id.
You should define the following relationship in your Product model:
public function suggestedProducts()
{
return $this->belongsToMany(Product::class, 'suggestedproducts', 'product_id', 'suggested_product_id')
->withPivot(['quantity', 'required']);
}
This would allow you to get all related products as Eloquent models by doing the following:
$product = Product::with('suggestedProducts')->find($id);
$product->suggestedProducts; // This accesses the suggested products
To access the name of each suggested product, just do the following:
foreach ($product->suggestedProducts as $suggestedProduct)
echo $suggestedProduct->name;
To access the data in the pivot table, you have to use the following:
foreach ($product->suggestedProducts as $suggestedProduct)
echo $suggestedProduct->pivot->quantity;