yii active record relations - php

I have 2 tables, categories(id, name) and products(id, categoryId, title, content) and my models look like this
class Category extends CActiveRecord {
public $id;
public $name;
public function tableName() { return 'categories'; }
public function relations() {
return array('products' => array(self::HAS_MANY, 'Product', 'categoryId'));
}
}
class Product extends CActiveRecord {
public $id;
public $title;
public $content;
public function tableName() { return 'products'; }
}
The problem is when I try to access the products like this
Category::model()->with('products')->findAll()
The relation "products" in active record class "Category" is specified with an invalid foreign key "categoryId". There is no such column in the table "categories".
I looked at the documentation with the User / Post example and don't understand why my example is not working. Can someone clear things up please? Thank you.

Make sure that product table has field called categoryId in order to save the primary key of category table

Try specifing categoryid instead of categoryId. The reason can be in lower_case_table_names mysql directive.

Related

Laravel Comment System with Polymorphic relation

My comment system is working well with polymorphic relation. But i need to explain something clearly to help me to solve this problem first.
There is a brand page and that brand page have comments, also brand has customer support and comments for it. I couldn't mind how to make this relationship with eloquent. Some brands don't have customer support so i need to return boolean to confirm this but i couldn't even prepare database for this relation.
Brand -> customerSupport -> Comments ( How to make this relationship and the database structure )
Do i need to add some extra columns to comments table to do that properly ? Or just need to make new modal as 'CustomerSupport' and import this to commentable_type while adding or listing comments ?
Table Structures
//Brands Table
id - name - slug - img - timestamps
//Comments Table
id - parent_id - user_id(fk) - commentable_id - commentable_type - timestamps
Brand Modal
class Brand extends Model
{
// Table Name
protected $table = 'brands';
// Primary Key
public $primaryKey = 'id';
public function comments()
{
return $this->morphMany('App\Comment', 'commentable')->whereNull('parent_id');
}
}
Comment Modal
class Comment extends Model
{
//Table Name
protected $table = 'comments';
// Primary Key
public $primaryKey = 'id';
//Fillables ...
public function commentable()
{
return $this->morphTo();
}
//Comment belongs to user
public function user()
{
return $this->belongsTo('App\User');
}
//Comment belongs to brand
public function brands()
{
return $this->belongsTo('App\Brand');
}
//Comment have many replies
public function replies()
{
return $this->hasMany('App\Comment', 'parent_id');
}
}
I added a customer_support column to the brand and comments table. With this way, I'm checking if the brand has customer support or not and then get the comments for each brand's customer support. I'm not sure this is the best way to do that relation.
Brand Modal
public function customerSupport()
{
return $this->morphMany('App\Comment', 'commentable')->whereNull('parent_id')
->whereCustomerSupport(true);
}

Retrieving collection from linked eloquent models laravel

I am using laravel 5.3 and need a bit of help with Eloquent model queries. I have three models (UserDetails, Categories, Articles). I have a relationship between UserDetails->Categories (belongstoMany), and a relationship between Categories->Articles (belongstoMany) which work well. However how would I go about getting the relationship data between Userdetails->Categories->Articles.
Each individual relationship is working fine i.e. Userdetails::find(1)->categories and Categories::find(1)->Articles.
I have a feeling that scopes may be the answer but they don't seem to work when I've attempted it.
Relationships in models
UserDetails.php
public function Categories(){
return $this->belongstoMany('App\Categories', 'users_cats', 'user_id','cat_id');
}
Categories.php
public function articles(){
return $this->belongsToMany('App\Article', 'article_categories', 'categoryID', 'articleID');
}
Ive looked into HasManyThrough function but again, I'm having issues implementing it, as far as I can see it should be
return $this->hasManyThrough('App\Article', 'App\Categories', TertiaryForeignKey, FinalForeignKey, LocalForeignKey);
My tables are set up as
articles_categories pivot table
articleID – primary key of the article
categoryID – primary key of the category
users_cats pivot table
user_id – primary key of the userdetails
cat_id – primary key of the categories
Based on this it the hasManyThrough should look like this?
public function articles(){
return $this->hasManyThrough('App\Article', 'App\Categories', 'user_id', 'articleID', 'id');
}
however this returns the error
Column not found: 1054 Unknown column 'categories.user_id' in 'field list'
update
So if you want to have this kind of relationship
userdetails->categories->articles
then you need to make this:
Userdetail model:
public function categories()
{
return $this->hasMany(Category::class);
}
public function articles()
{
return $this->hasManyThrough(Article::class, Categories::class);
}
Category model:
public function userdetails()
{
return $this->belongsTo(Userdetails::class);
}
public function categories()
{
return $this->hasMany(Category::class);
}
Article model:
public function categories()
{
return $this->belongsToMany(Category::class);
}
Then you can call UserDetails::find(1)->articles->get(); directly
You just need to declare the relationship like this in the
UserDetails.php model:
public function categories()
{
return $this->hasMany(Categories::class);
}
in Categories.php model:
public function articles()
{
return $this->hasMany(Articles::class);
}
Then you can retrieve the collection of categories in your controller:
$userdetails = UserDetails::get();
pass that $categories variable into your View and display each record with an foreach loop (where the articles is the function in your model)
#foreach($userdetails->categories as $usercategories )
<div> {{$usercategories->name}} </div>
#foreach($usercategories->articles as $categoryarticles )
<div> {{$categoryarticles->name}} </div>
#endforeach
#endforeach
with the second foreach you will access the articles of the categories that belongs to the user.

Yii2 join relations for multiple tables

I am new to yii2. I have read the documentation and some answers on sof but still I cant get to work with relations in yii2. I am able to create raw mysql query for the problem but I dont know how to create the same query using yii2 relations. I am confused with via, joinWith and some key concepts. I will make the problem as descriptive as possible.
I have four models.
Category, CategoryNews, NewsTags, Tags
category table - cat_id, cat_name
news_category table - nc_id, nc_cat_id, nc_news_id
news_tags table - nt_id, nt_news_id, nt_tag_id
tags table - tag_id, tag_name
What I need is tags model object for each category, that is for each category i need all news tags belonging to that category. Request is from gridview.
The generated relations are:
Category Model:
public function getNewsCategory()
{
return $this->hasMany(NewsCategory::className(), ['nc_cat_id' => 'cat_id']);
}
NewsCategory Model:
public function getNcNews()
{
return $this->hasOne(News::className(), ['news_id' => 'nc_news_id']);
}
public function getNcCat()
{
return $this->hasOne(Category::className(), ['cat_id' => 'nc_cat_id']);
}
NewsTags Model:
public function getNtNews()
{
return $this->hasOne(News::className(), ['news_id' => 'nt_news_id']);
}
public function getNtTag()
{
return $this->hasOne(Tags::className(), ['tag_id' => 'nt_tag_id']);
}
News Model:
public function getNewsCategory()
{
return $this->hasMany(NewsCategory::className(), ['nc_news_id' => 'news_id']);
}
public function getNewsTags()
{
return $this->hasMany(NewsTags::className(), ['nt_news_id' => 'news_id']);
}
Tags Model:
public function getNewsTags()
{
return $this->hasMany(NewsTags::className(), ['nt_tag_id' => 'tag_id']);
}
ie. each category contains multiple news and each news contain mutiple tags and I need all tags related to each category.
More precisely, on the gridview I need all categories and a column displaying all tags related to these categories.
Please help!!
You can avoid declaration of models for junction tables, using viaTable syntax for many-to-many relations. Then your code will contain only three models (Category, News and Tag) and everything will be much simplier.
Your code for AR models and relations could looks as follows:
public class Category extends ActiveRecord
{
public function getNews()
{
return $this->hasMany(News::className(), ['id' => 'news_id'])
->viaTable('news_category_table', ['category_id' => 'id']);
}
}
public class News extends ActiveRecord
{
public function getCategories()
{
return $this->hasMany(Category::className(), ['id' => 'category_id'])
->viaTable('news_category_table', ['news_id' => 'id']);
}
public function getTags()
{
return $this->hasMany(Tags::className(), ['id' => 'tag_id'])
->viaTable('news_tags_table', ['news_id' => 'id']);
}
}
public class Tag extends ActiveRecord
{
public function getNews()
{
return $this->hasMany(News::className(), ['id' => 'news_id'])
->viaTable('news_tags_table', ['tag_id' => 'id']);
}
}
These relations you can use in link and unlink functions (rows in junction tables will be managed by Yii in backround). But keep in mind that you should use TRUE as second param in unlink() to remove row in junction table:
$article = new News();
$tag = new Tag();
$tag->save();
$article->link('tags', $tag);
$article->link('caterories', $category);
OR vice versa
$tag->link('news', $article);
$category->link('news', $article);
To get all tags in given category you can declare following function in Category class:
public function getTags()
{
return Tags::find()
->joinWith(['news', 'news.categories C'])
->where(['C.id' => $this->id])
->distinct();
}
This will work as relation query and you can use it as $category->tags or as $category->getTags()->count() or any other way (but not in link and unlink functions).
P.S. To use provided example in your code You should first change names, because I used singular form for AR classes names (Tag) and short notation for primary and foreign keys (id, tag_id etc). And I'd recommend you also to use such naming approach in your code and DB structure.
P.P.S. This example code wasn't tested so be careful :)

Create a lists of categories and their subcatgory in Laravel 5

I have three tables as category, subcategory and subcategory_category that I use to store the foreign key of other table in
I want to show a list with category and subcategory, such as:
category1
subcategory1
subcategory2
category2
subcategory3
subcategory4
I tried this but it is not OK
in my controller:
$mycategories = SubcategoriesCategories::with('parent')->with('children2')->get();
and in model:
class SubcategoriesCategories extends Model {
protected $table = 'subcategories_to_categories';
public function parent()
{
return $this->belongsTo('App\categories', 'categories_id');
}
public function children2()
{
return $this->belongsTo('App\subcategories', 'subcategories_id');
}
}
in mysubcategories_categories table i have:
For children operations you can use nested set technique, there is a library that can help you, it is called Baum https://github.com/etrepat/baum
I think you didn't configure your modeles right..
its should be like:
class Category{
public function subcategories(){
return $this->hasMany('app\subcategory')//or whatever is your relations
}
}
and than in controller:
$categories = Category::with('subcategories')->all();

YII Active Record Join

I am looking at YII for the first day, and i'm having some problems trying to work out the relations between some tables.
my table structure is as follows:
Pets:
pet_id
pet_name
....
Pet_Owner_Link
pet_id
owner_id
Owner:
owner_id
owner_name
How would I go about getting all of the pets that belong to an owner? Really struggling to get my head around the AR relations at the moment.
Per this comment by DD.Jarod on the Yii AR documentation page: http://www.yiiframework.com/doc/guide/1.1/en/database.arr#c970
"If you declare a many to many relationship, the order of keys inside the jointable declaration must be 'my_id, other_id':
class Post extends CActiveRecord
{
public function relations()
{
return array(
'categories'=>array(self::MANY_MANY, 'Category',
'tbl_post_category(post_id, category_id)'),
);
}
}
class Category extends CActiveRecord
{
public function relations()
{
return array(
'Posts'=>array(self::MANY_MANY, 'Post',
'tbl_post_category(category_id, post_id)'),
);
}
}
So your code would look like:
class Owner extends CActiveRecord
{
public function relations()
{
return array(
'pets'=>array(self::MANY_MANY, 'Pet',
'tbl_post_category(pet_id, owner_id)'),
);
}
}
class Pet extends CActiveRecord
{
public function relations()
{
return array(
'owners'=>array(self::MANY_MANY, 'Post',
'tbl_post_category(owner_id, pet_id)'),
);
}
}
Your problem may be that your primary keys for Pet and Owner by default should be id (not pet_id / owner_id). Yii may be getting confused if you don't clarify that your primary keys don't match the default naming convention / aren't setup as primary keys in the database. You can specify what your primary key is in a model like this:
public function primaryKey()
{
return 'owner_id';
}
Finally, you would retrive the information like this:
$owner = Owner::model()->findByPk((int)$id);
foreach($owner->pets as $pet)
{
print $pet->name;
}
I know this is not exactly what you ask, but this is how I do it.
Add this item in your relations() return in Owner model :
'all_pets'=>array(self::HAS_MANY, 'Pet_Owner_Link','owner_id'),
Add this item in your relations() return in Pet_Owner_Link model :
'pet'=>array(self::BELONGS_TO, 'Pet', 'pet_id'),
Then get a pet like this
$owner->all_pets[$i]->pet;

Categories