i have 2 models. PostModel and CategoriesModel.
class PostModel extends Model
{
protected $table='posts';
protected $primaryKey = 'id';
protected $guarded=['id'];
public function categories()
{
return $this->belongsTo(CategoriesModel::class);
}
}
class CategoriesModelextends Model
{
protected $table='categories';
protected $primaryKey = 'id';
protected $guarded=['id'];
public function posts()
{
return $this->hasMany(PostModel::class);
}
}
I want to get 6 categories with 10 posts.
I used this code in my controller
$categories = CategoriesModel::with(['pages' => function($query) {
$query->limit('10');
}])->take("6")->get();
but this code is wrong. it applies to all records. But the truth is that this query applies per one categories. please help me.thanks
there is a laravel package specialized in this called Eloquent Eager Limit:
after installing it:
composer require staudenmeir/eloquent-eager-limit:"^1.0"
you should use it inside the models that would apply limited eager loading:
class PostModel extends Model
{
use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
// ........
}
class CategoriesModel
extends Model
{
use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
// ........
}
now this query will get the result you want:
$categories = CategoriesModel::with(['pages' => function($query) {
$query->limit('10');
}])->take("6")->get();
For eager loading you can do like this with map operation :
$categories = CategoriesModel::with('pages')->take(6)->get()
->map(function($q)
{ $q->pages = $q->pages->take(10); // take only 10 query
return $q;
}
);
The reason the above approach is necessary is because the constrained eager loading query roughly translates to SQL like:
Query to select Categories:
select * from `categories`
limit 6;
Query to fetch relation
select * from `categories`
inner join `posts` on `categories`.`id` = `posts`.`category_id`
where `posts`.`category_id` in (id's from categories query)
limit 10;
First of all your relation name is wrong in your controller. Update your category model by the following code:
public function ten_posts()
{
return $this->hasMany(PostModel::class)->take(10);
}
then update your controller with the following code:
$categories = CategoriesModel::with('ten_posts')->take(6)->get();
Try like this -
$categories = CategoriesModel::with(['pages' => function($query) {
$query->take('10');
}])->take("6")->get();
Related
My Model looks like this
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class appraisaltask extends Model
{
//
protected $table = 'empappraisaltask';
/*
* An invoice can has many payments
*
*/
public function ratings(){
return $this->hasMany('App\appraisalrating','empappraisaltask_id')->select(array('comment', 'rating'));
}
}
and I am doing a query in my function like this
public function getUserbasictask(){
$taskwithcomments = appraisaltask::select(array('id','taskname','description','status'))->with( array('ratings' => function($query)
{
// the condition that will be apply on the with relation
$query->where('emp_id','=',Auth::user()->empid);
}))->where('type','=','basic')->get();
return json_encode($taskwithcomments);
}
But I am getting Empty Rating object . ANy suggestion how to do that
If I remove the select() from the rating function in the model I get all the details
Any help would be appreciated
i got your issue,update your ratings function in appraisaltask model
public function ratings()
{
return $this->hasMany('App\appraisalrating','empappraisaltask_id')->select(array('emp_id','comment', 'rating'));
}
and also update query
public function getUserbasictask(){
$taskwithcomments = appraisaltask::select(array('id','taskname','description','status'))
->with(['ratings' => function($query)
{
// the condition that will be apply on the with relation
$query->where('emp_id','=',Auth::user()->empid);
}])->where('type','=','basic')->get();
return json_encode($taskwithcomments);
}
hope it will work.
I am trying to paginate a Eloquent relationship like this:
$query = Product::find(1)->options()->paginate();
But I get the following error:
Fatal error: Call to a member function getCurrentPage() on a non-object
I have confirmed that the code $query = Product::find(1)->options() returns a collection of options. The $query object seems to be of type hasMany. Below are the model classes I am using.
class Product extends Eloquent
{
protected $table = 'products';
public function options ()
{
return $this->hasMany('ProductOption', 'product_id');
}
}
class ProductOption extends Eloquent
{
protected $table = 'product_options';
public function product()
{
return $this->belongsTo('Product', 'product_id');
}
}
Does eloquent not return paginated results for relationships?
You can not lazy load relational pagination like that, instead in your Product Model put the following function below your options has many relationship
public function getOptionsPaginatedAttribute()
{
return $this->options()->paginate(10);
}
This will allow you to call the pagination on your relational data by
$product->options_paginated
Create a custom length-aware paginator.
$options = new LengthAwarePaginator(Product::find(1)->options()->
->skip(($request->input('page', 1) - 1) * 10)->take(10)->get(),
Product::find(1)->options()->count(),
10, $request->input('page', 1),
[
// paginator options here
]);
$query = Product::find(1)->get()->options()->paginate();
Try adding get
Hi there i'm trying to sort a collection by attribute of the relation.
This is my model
class Song extends \Eloquent {
protected $fillable = ['title', 'year'];
public function artist(){
return $this->hasOne('Artist','id', 'artist_id');
}
}
class SongDance extends \Eloquent {
protected $table = 'song_dances';
protected $fillable = ['rating'];
public function dance(){
return $this->belongsTo('Dance', 'dance_id');
}
public function song(){
return $this->belongsTo('Song', 'song_id');
}
}
class Dance extends \Eloquent {
protected $fillable = ['name'];
public function song_dances(){
return $this->hasMany('SongDance','dance_id','id');
}
public function songs(){
return $this->belongsToMany('Song', 'song_dances', 'dance_id', 'song_id');
}
}
this is how far i'm by now:
$dance = Dance::find(1);
$songs = $dance->songs()
->with('artist')->whereHas('artist', function ($query) {
$query->where('urlName','LIKE','%robbie%');})
->where('song_dances.rating', '=', $rating)
->orderBy('songs.title','asc')
->where('songs.year', '=', 2012)
->get();
Yeah i just could add a ->sortBy('artist.name'); to the query, but he result-collection can be quite big (about 6000 items) therefore i would prefer a databased sorting.
is there a possibility to do this?
Since Eloquent's relations are all queried separately (not with JOINs), there's no way to achieve what you want in the database layer. The only thing you can do is sort the collection in your app code, which you've already dismissed.
If you feel you must sort it in the database then you should write your own join queries instead of relying on Eloquent's relations.
Now I have news category,news, and news image table structure like :
and i want to make a list like :
how i make list like that with eloquent relationship ( whereHas or Has ) ?
PS: Sometimes news have'nt an image
Assuming that your model is called Category and has a relationship called news which further has a relationship called image, you'd simply do the following.
$categories = Category::with(['news', 'news.image'])->all();
That would grab all categories with their news, and the image relationship if they have one.
if you don't have the relationships setup, it'd look something like this.
Category model:
<?php
class Category extends Eloquent
{
protected $table = 'category';
public function news()
{
return $this->hasMany('News');
}
}
News model:
<?php
class News extends Eloquent
{
protected $table = 'news_main';
public function category()
{
return $this->belongsTo('Category');
}
public function image()
{
return $this->hasOne('NewsImage');
}
}
News Image model:
<?php
class NewsImage extends Eloquent
{
protected $table = 'news_img';
public function news()
{
return $this->belongsTo('News', 'id_news');
}
}
NOTE
It may be worth changing the names of the tables and some of the fields to have a more uniform and sensible feel to the naming structure.
categories category_id
news news_id
news_images
Hi i thought i can handle this myself, but actually i don't know how to bite it.
I am trying to categorise my programs. There will be only 2 levels of categories:
1 CATEGORY
2 |-Subcategory
I want it to be as simple as possible.
- program can belong to only one subcategory,
- categories can have many subcategories,
- subcategories can have many programs,
Of course i would like to list all programs from subcategories, when someone choose a main category.
I am also not sure about my current database tables structure and relationship in models.
Tables in database:
programs: id, title, description, program_subcategory_id
programs_categories: id, name
programs_subcategories: id, name, program_category_id
Models:
Program.php
class Program extends Eloquent {
protected $table = 'programs';
public function user()
{
return $this->belongsTo('User');
}
public function subcategory()
{
return $this->belongsTo('ProgramSubcategory', 'program_subcategory_id');
}
}
ProgramCategory.php
class ProgramCategory extends Eloquent {
protected $table = 'programs_categories';
public function subcategories()
{
return $this->hasMany('ProgramSubcategory');
}
}
ProgramSubcategory.php
class ProgramSubcategory extends Eloquent {
protected $table = 'programs_subcategories';
public function programs()
{
return $this->hasMany('Program');
}
public function category()
{
return $this->belongsTo('ProgramCategory');
}
}
Actual controllers:
ProgramsController.php
class ProgramsController extends BaseController {
public function index()
{
$programs = Program::with('subcategory')->orderBy('programs.id', 'desc')->paginate(5);
$acategories = ArticleCategory::All();
$pcategories = ProgramCategory::All();
return View::make('programs.index', compact('programs', 'acategories', 'pcategories'));
}
}
ProgramsSubcatecories.php
class ProgramsSubcategories extends BaseController {
public function index($cname)
{
$programs = ProgramSubcategory::whereAlias($cname)->first()->programs()->orderBy('id', 'DESC')->paginate(10);
$pcategories = ProgramCategory::All();
$scategories = ProgramSubcategory::All();
$acategories = ArticleCategory::All();
return View::make('programs.index', compact('programs', 'pcategories', 'scategories ', 'acategories'));
}
public function show($cname, $id)
{
$category = ProgramSubcategory::whereAlias($cname)->first();
$program = $category->programs()->findOrFail($id);
$pcategories = ProgramCategory::All();
$acategories = ArticleCategory::All();
return View::make('programs.show', compact('program', 'category', 'pcategories', 'scategories ', 'acategories'));
}
}
It is not a problem for me to list all items from one category with eager loading. But i have problem how to do it with 2-levels categories.
Please advise how to start it.
You are not looking for eager loading, you need to solve how to manage hierarchical data in your database.
Nested sets model serves this purpose very well. You should read some theory on Wiki: http://en.wikipedia.org/wiki/Nested_set_model
Fortunately, there are Eloquent implementations already.
To mention some:
- Baum (the best free, imho), https://github.com/etrepat/baum
- Laravel Nested Set, https://github.com/atrauzzi/laravel-nested-set
- Laravel4-nestedset, https://github.com/lazychaser/laravel4-nestedset
and the paid one (surely highest quality as well)
from Cartalyst company - https://cartalyst.com/manual/nested-sets