Model users has onetomany relation with category
public function getCategory()
{
return $this->hasMany(Category::className(), ['user_id' => 'user_id']);
}
I am not being able to access the fields of category using this relation.
public function actionGetResults()
{
$results = users::find()->where(['user_id' =>8])
->with('category')
->all();
echo "<pre>"; print_r($results);
}
$results here shows an array with fields of category. i.e category_name, category_id etc. but if i do this:
echo "<pre>"; print_r($results->category_name);
it fails.
First of all, since relation type is has many, category name is misleading and it's better to use categories.
Second, you are accessing related field wrong. $results is an array of User models and categories property of each model contains an array of related Category models to that user.
Use nested foreach loop:
foreach ($results as $user) {
foreach ($user->categories as $category) {
var_dump($category->name);
}
}
Or to get the name of the first user's first category:
$results[0]->categories[0]->name
Note that the second approach is only for demonstration purposes and can fail with Undefined index error if user or / and category does not exist.
Read Working with Relational Data for more info.
Related
I have a problem with laravel. I have created relationships between tables and relationships at the model level in laravel but if I want to display data to the view, I get an error: Property [category] does not exist on this collection instance.
the table with the films is called: videos
the table with the categories is called: categories
the pivot table is called: category_video
Video model code:
public function categories()
{
return $this->belongsToMany('App\Category');
}
Categories model code:
public function videos()
{
return $this->belongsToMany('App\Video');
}
In controller i have this:
$slider_videos = Video::->orderBy('rating','desc')
->limit(5)
->get();
In view i try this:
#foreach($slider_videos as $slider_video)
{{$slider_video->category->name}}
#endforeach
I will add that when I use this: {{$slider_video->category}} it's displaying all contents of single row
By the way, how can I specify the name of the pivot table in the model?
Categories are a collection you need to loop over it :
#foreach($slider_videos as $slider_video)
{{ $slider_videos->name }} categories are :
#foreach($slider_video->categories as $category)
{{$category->name}}
#endforeach
#endforeach
belongsToMany returns a collection even if there is only a single record linked with the relationship.
You need to access it in a foreach loop.
Like so.
#foreach($slider_video->categories as $category)
{{$category->>field_name}}
#endforeach
I have 4 models: posts, users, categories, userCategories.
posts-users have one-to-many relationship (one post belongs to a user).
posts-categories have one-to-many relationship (one post belongs to a category).
users-userCategories have one-to-many relationship (one user has many userCategories). userCategory has a rank field which holds the performance of the user for the specific category.
I query some posts with this:
$posts = Post::with(array('user.userCategories')
)
->where('category_id', '=', $category_id)
->get();
After evaluating posts, I try to get the user's the userCategory rank for the post's category.
$rank_of_the_post_owners = array();
foreach($posts as $post)
foreach($post->user->userCatergories as $userCategory)
if($userCategory->id == $post->category_id) {
$rank_of_the_post_owners [$post->id] = $userCategory->rank;
break;
}
}
}
To get rid of the code above, I want to query only related userCategory (for the post's category). So that, I want to access the rank information like user.userCategory->rank instead of the loop.
How can I do that?
When using with() you can constrain the relationship by using a closure as the value and since you already have the $category_id you could do something like:
$posts = Post::with(['user.userCategories' => function ($query) use ($category_id) {
$query->where('userCategories.id', $category_id);
}])
->where('category_id', '=', $category_id)
->get();
Then if you wanted to you could add an accessor to get the ranks for the posts:
public function getRankAttribute()
{
return $this->user->userCategories->sum('rank');
}
So to access the rank you would just need to:
$posts->first()->rank;
https://laravel.com/docs/5.4/eloquent-mutators#accessors-and-mutators
Hope this helps!
Context :
I make an Json api with laravel 5.1 to fetch all of categories and sub categories
and the relationship between categories table and subcategories table is ManyToMany
Code :
Categories model :
public function subcategory() {
return $this->belongsToMany(Subcategory::class);
}
Subcategory model :
public function category() {
return $this->belongsToMany(Categories::class);
}
Api Controller :
$response = Categories::with('subcategory')->first();
return $response
Problem :
I want loop $response to get all data not only the first one
The answer is
$response = Categories::with('subcategory')->take(-1)->get();
You are calling the first method which retrieve only the first model from Categories. In order to get all the records, you should use the get method like so:
$response = Categories::with('subcategory')->get();
Now the $response object will be a Collection of Eloquent models.
The get method is usually the last method of your queries, that acts like: run the query now please Eloquent
Take a look of the documentation about Eloquent Collection
I am looking for a way to retrieve all models in a database. Then loop through all of the models and read out the values for name, firstname and phonenumber.
So far I've gotten this and failed to go past it:
$searchModel = new EmployeeSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
I am then looking to implement those three values in a simple HTML table:
<tr><td>$firstname</td><td>$name</td><td>$phone</td></tr>
The table should be part of a PDF output, so ideally I would save it to a variable:
$html_table = '<tr><td>$firstname</td><td>$name</td><td>$phone</td></tr>';
I would need to get this for every model that fulfills the criteria of status = 'active' in the database.
So far I've only been able to get tables via gridView and not in a HTML template either.
You don't really need a data provider to achieve this, you could simply try :
$models = Employee::find()->where(['status'=>'active'])->orderBy('name ASC')->all();
foreach ($models as $model) {
echo "<tr><td>{$model->firstname}</td><td>{$model->name}</td><td>{$model->phone}</td></tr>";
}
Read more : http://www.yiiframework.com/doc-2.0/guide-db-active-record.html#querying-data
You can get all models like this:
$employees = Employee::find()
->select('firstname, name, phone')
->asArray()
->where(['status'=>'active'])
->all();
This way you will get an array of arrays containing the 3 selected fields, so now you only need to use a foreach to loop through them and create the table:
$html = '<table>';
foreach($employees as $employee) {
$html .= '<tr><td>'.$employee['firstname'].'</td><td>'.$employee['name'].'</td><td>'.$employee['phone'].'</td></tr>';
}
$html .= '</table>'
How I can return object with all relations(ans sub objects relations?).
Now I use EJsonBehavior but it returns only first level relations, not sub related objects.
My source code:
$order = Order::model()->findByPk($_GET['id']);
echo $order->toJSON();
Yii::app()->end();
The eager loading approach retrieves the related AR instances together with the main AR instance(s). This is accomplished by using the with() method together with one of the find or findAll methods in AR. For example,
$posts=Post::model()->with('author')->findAll();
The above code will return an array of Post instances. Unlike the lazy approach, the author property in each Post instance is already populated with the related User instance before we access the property. Instead of executing a join query for each post, the eager loading approach brings back all posts together with their authors in a single join query!
We can specify multiple relationship names in the with() method and the eager loading approach will bring them back all in one shot. For example, the following code will bring back posts together with their authors and categories:
$posts=Post::model()->with('author','categories')->findAll();
We can also do nested eager loading. Instead of a list of relationship names, we pass in a hierarchical representation of relationship names to the with() method, like the following,
$posts=Post::model()->with(
'author.profile',
'author.posts',
'categories')->findAll();
The above example will bring back all posts together with their author and categories. It will also bring back each author's profile and posts.
Eager loading may also be executed by specifying the CDbCriteria::with property, like the following:
$criteria=new CDbCriteria;
$criteria->with=array(
'author.profile',
'author.posts',
'categories',
);
$posts=Post::model()->findAll($criteria);
or
$posts=Post::model()->findAll(array(
'with'=>array(
'author.profile',
'author.posts',
'categories',
)
);
I found the solution for that. you can use $row->attributes to create data
$magazines = Magazines::model()->with('articles')->findAll();
$arr = array();
$i = 0;
foreach($magazines as $mag)
{
$arr[$i] = $mag->attributes;
$arr[$i]['articles']=array();
$j=0;
foreach($mag->articles as $article){
$arr[$i]['articles'][$j]=$article->attributes;
$j++;
}
$i++;
}
print CJSON::encode(array(
'code' => 1001,
'magazines' => $arr,
));
This is the best piece of code I found after a long time search to meet this requirement.
This will work like Charm.
protected function renderJson($o) {
//header('Content-type: application/json');
// if it's an array, call getAttributesDeep for each record
if (is_array($o)) {
$data = array();
foreach ($o as $record) {
array_push($data, $this->getAttributes($record));
}
echo CJSON::encode($data);
} else {
// otherwise just do it on the passed-in object
echo CJSON::encode($this->getAttributes($o));
}
// this just prevents any other Yii code from being output
foreach (Yii::app()->log->routes as $route) {
if ($route instanceof CWebLogRoute) {
$route->enabled = false; // disable any weblogroutes
}
}
Yii::app()->end();
}
protected function getAttributes($o) {
// get the attributes and relations
$data = $o->attributes;
$relations = $o->relations();
foreach (array_keys($relations) as $r) {
// for each relation, if it has the data and it isn't nul/
if ($o->hasRelated($r) && $o->getRelated($r) != null) {
// add this to the attributes structure, recursively calling
// this function to get any of the child's relations
$data[$r] = $this->getAttributes($o->getRelated($r));
}
}
return $data;
}