How do I get a field from a sub-relation in Laravel? - php

Objective:
Include category_name field in $posts attributes. The corresponding FK - category_id is currently included in my return.
Controller returns all Posts with their PostChilds
return $posts = Post::with('postchildren')->get();
Post Model hasMany PostChild
public function postchildren() {
$this->hasMany('App\PostChild')
}
PostChild Model hasOne Category
(This table has a category_id field which is a FK for id in the Category model.)
public function category() {
$this->hasOne('App\Category');
}
Category Model
This table has a category_name field

You should be able to get all the categories associated with the children via the HasManyThrough relationship e.g.
class Post
{
public function categories()
{
return $this->hasManyThrough(PostChild::class, Category::class);
}
}
Then you can access the categories directly on the post object e.g.
$categories = Post::first()->categories;
or if you're wanting an array of them something like
$posts = Post::with('categories')->get();
If you always want the categories loaded on the Post class you can define
class Post
{
protected $with = ['categories'];

Related

How to get relation of relation Count in laravel?

i have laravel models
Category: id,name
public function posts(){
return $this->hasMany(PostCategory::class,'category_id','id');
}
PostCategory : post_id, category_id
public function post(){
return $this->belongsTo(Post::class,'post_id');
}
POST: id, ..so on
public function solutions(){
return $this->hasMany(PostSolution::class,'post_id','id');
}
I need to get count of all posts fall under a category and also solutions under one category.. there is no direct relation of category and solution so how to get count of solutions in one category.
$categories = Category::withCount('posts')->get();
I think use hasManyThrough relation
// Category Class
public function solutions()
{
return $this->hasManyThrough(PostSolution::class, Post::class);
}
// Then get the data in the same old manner
$categories = Category::->withCount('posts')->get();
I hope this will help

Create conditional in Model methods

Hi guys i wish to create a custom method on my Category Model but i need to create some conditionals with it.
table post:
- id;
- category_id
-name...
table Category:
- id
- parent_id
- name
Imagin that i have a post, and in this post there is a category called SomeSubcategoryName, i my posts table i have a column called category_id.
When i call the post record i have a relation with the Category Model, but i wish to have in my Category Model a method called masterCategory, where i give the mster category by checking if the parent_id is null or not, in case that the record have a parent_id of null great, i return the record but if is not i need to use the parent_id value and search on the Model category column id for the record and return the result.
Imagine this scenario:
$post = Post::find(2);
//this call should return the main category and not the subcategory info.
$post->masterCategory();
In your category model define a relationship on its self:
public function masterCategory()
{
return $this->belongsTo(App\Category::class, 'parent_id', 'id');
}
Eager load the relationships on your Post when you query it:
$post = Post::with(['category', 'category.masterCategory'])->firstOrFail($id);
Access it like this:
$post->category->masterCategory; // will be the mastery category or null
Otherwise us:
$post->category;
Don't over complicate it.
In your Category model you should have something like this
public function master()
{
return $this->belongsTo(Category::class, 'parent_id');
}
public function isMaster()
{
if($this->parent_id)
return false;
else
return true;
}
Now you can check that post's category is master or not :
if($post->category->isMaster())
....
The second way is using relations and eloquent
$post = Post::with(['category', 'category.master'])->first($id);

Laravel.get one related record

There is two models: Category and Post.
class Category extends Model
{
public function posts()
{
return $this->hasMany('App\Post','category_id');
}
}
class Post extends Model
{
public function category()
{
return $this->belongsTo('App\Category');
}
}
//Get data
$data = Category::with(['posts' => function($query){
$query->orderBy('id','desc')->first();
}])->get();
In this case, all categories are displayed and only one post. I need to get from each category the one record post.
Example:
Category 1 - Post1
Category 2 - Post2
Category 3 - Post5
Category 4 - Post15
One category - one last post this category.
You have a Category with many Posts, but you just want to get the most recent post so you would add another relationship.
// Category.php
class Category extends Model
{
// This gets ALL posts
public function posts()
{
return $this->hasMany('App\Post','category_id');
}
// This gets the most recent post
// I am ordering by created_at instead of ID, but you can use ID
// if it makes sense for your application)
public function mostRecentPost()
{
return $this->hasOne('App\Post','category_id') // hasOne is the key here
->orderBy('created_at', 'DESC');
}
}
Then when you want to use it...
$data = Category::with('mostRecentPost')->get();

Getting all objects from hasMany relation and paginate

In my Laravel application, I have a category listing page. When the user clicks on a certain subcategory, I'd like to list all the products and use pagination on that result. I'm already listing all the products related to that subcategory, for now, with the help of a subcategory ID:
public function subcategoryListing($slug){
$products = Subcategory::find($idofSubcat)->products;
return view('pages.subcategorylisting')
->with(array(
'products' => $products,
));
}
There are three classes involved in this structure: Category, Subcategory and Products. They were declared as follows:
Category
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
use App\Subcategory;
class Category extends Model
{
protected $table = 'category';
public $timestamps = false;
public function subCategory(){
return $this->hasMany('App\Subcategory', 'category_id');
}
}
Subcategory
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Subcategory extends Model
{
protected $table = 'subcategory';
public $timestamps = false;
public function products(){
return $this->hasMany('App\Products');
}
}
Products
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Products extends Model
{
protected $table = 'products';
}
For each model class I have one table, with this structure:
Category
- id
- category_name
SubCategory
- id
- category_id
- subcategory_name
Products
- id
- subcategory_id
- product_title
- description
- price
What I want is to paginate the results retrieved from the query in my page. Is there any better way to fetch the products associated to the subcategory and paginate them?
In Eloquent (Laravel's ORM) when you call a relation as a property ($subCategory->products), it returns the related object or a collection of objects depending on the relation type (belongs to, has many, ...). Instead, if you call it as a function ($subCategory->products()), you get a QueryBuilder instance.
Refer to http://laravel.com/docs/5.1/eloquent-relationships#querying-relations, under section Relationship Methods Vs. Dynamic Properties for more details on that.
Anyway, using the relationship method, you can call paginate() for your collection. Then, with that in mind, you can change your code slightly to get what you want:
public function subcategoryListing($slug) {
// I'm supposing here that in somewhere before
// run the query, you set the value to $idofSubcat
// variable
$products = Subcategory::find($idofSubcat)->products()->paginate();
return view('pages.subcategorylisting')
->with(array(
'products' => $products,
));
}
I think, that create two categories table not so correctly, it will be better to use next:
table categories
id category_name parent_id(nullable)
and Products
id category_id product_title description price
It's more usefull, you can remove one Subcategory model and do all in Category.
namespace App;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
protected $table = 'category';
public $timestamps = false;
public function subCategory(){
return $this->belongsToMany('App\Category', 'categories', 'id', 'parent_id');
}
public function products(){
return $this->hasMany('App\Products');
}
}
and products model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Products extends Model
{
protected $table = 'products';
public function category() {
return $this->belongsTo('App\Category')
}
}
then, you can get the query result
public function subcategoryListing($slug){
$products = Category::find($idofSubcat)->products;
return view('pages.subcategorylisting')
->withProducts($products); // it's a magic))
}
But, existing one not pretty thing. Do you really sure, that products will be only in one category?)
I couldn't really understand some of your initial function:
// $slug is not being used anywhere within the function
public function subcategoryListing($slug){
// $idOfSubcat isn't passed to this function so will throw an error
$products = Subcategory::find($idofSubcat)->products;
return view('pages.subcategorylisting')
->with(array(
'products' => $products,
));
}
If all you're trying to do is paginate the Products that belong to a specific subcategory_id, given you have the subcategory_id then the following code will work:
$products = Product::where('subcategory_id', $idofSubcat)->paginate();
Then you can return this paginated collection to your view as you're already doing:
return view('pages.subcategorylisting')
->with(compact('products'));

Laravel relations

I am creating a basic forum just so I have something meaningful to do while learning Laravel.
So just like every forum is organized, on the main page i would like to have a list of categories and their subcategories, a total count of posts in every subcategory while also a link to latest post
So relationship is nested hasMany:
Category -> has Subcategories -> has Threads -> has Posts.
In controller method I have
$cat = Category::with('subcategory')->get();
return View::make('forum.index', compact('cat'));
and this works for basic list of categories and subcategories but I can't figure out the rest.
This sure doesnt work
Category::with('subcategory')->with('threads')->with('posts')->get();
since relation between them is not set. Looking at Laravel docs, there is hasManyThrough relation. Is that a solution?
class Category extends Eloquent {
public function subcategory() {
return $this->hasMany('Subcategory');
}
public function posts() { // not sure about this cause it doesnt work
return $this->hasManyThrough('Post', 'Thread');
}
}
And on top of that how do I get posts->count() for every subcategory? Is it possible to have it split? Chaining could get complicated..
EDIT
Table columns are
Categories
id | title
Subcategory
id | title | category_id
Threads
id | title | subcategory_id | user_id
Posts
id | title | body | thread_id | user_id
EDIT 2
What would be the code for grabing only latest post? This doesnt work
$data = Category::with('subcategories.threads')->with(array('posts' => function($query)
{
$query->take(1);
}))->get();
You have setup only one relation that works and that is:
class Category extends Eloquent {
public function subcategory() {
return $this->hasMany('Subcategory');
}
}
Declare other relationships in other models:
class Subcategory extends Eloquent {
public function threads() {
return $this->hasMany('Thread');
}
}
class Thread extends Eloquent {
public function posts() {
return $this->hasMany('Post');
}
}
Once you have declared relationships then you may use:
$categories = Category::with('subcategory.threads.posts')->get();
Since the one Category has many subcategories so use the plural name for subcategories instead of subcategory in your Category model, so for example, you may use:
class Category extends Eloquent {
public function subcategories() {
return $this->hasMany('Subcategory');
}
}
Then also:
$categories = Category::with('subcategories.threads.posts')->get();
All relationships will be retrieved as nested object collections. For example:
$categories->subcategories; // Will be a collection of Subcategory models
$categories->subcategories->threads // Will be a collection of Thread models
$categories->subcategories->threads->posts // Will be a collection of Post models
You may declare a hasManyThrough relationship between Subcategory and Post using something like this:
class Subcategory extends Eloquent {
public function threads() {
return $this->hasMany('Thread');
}
public function posts() {
return $this->hasManyThrough('Post', 'Thread');
}
}
Also, you may build a relationship between Category and Thread through Subcategory.
I have
QuestionCategory and Questions['category_id'] and ItemsOfQuestion['question_id']
This Code has Work for my I hope that is useful for you
$categories=ExamCategory::with(['question' => function ($query) use($exam){$query->where('exam_id','=',$exam->id)->with('Items');}])->get();

Categories