How can joins be nested in Laravel 4.2 Query Builder - mysql

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

Laravel and mysql table name conventions for categories

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');
}
}

Eloququent: relationship from relationship

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');

Category relationship is giving error when I try to acces category through post

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();

Laravel 5 Read Only View Model with polymorphic Relationship

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.

How do I connect a "related products" table

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;