I'm trying to make a mini CMS-type component and I have three models:
Page.php
class Page extends Eloquent {
protected $table = 'pages';
public function content() {
return $this->hasManyThrough('Content', 'PageGroup');
}
public function groups() {
return $this->hasMany('PageGroup');
}
}
PageGroup.php
class PageGroup extends Eloquent {
protected $table = 'page_groups'
public function group() {
return $this->hasMany("Content");
}
}
Content.php
class Content extends Eloquent {
protected $table = 'content';
public function content() {
return $this->hasMany("Content");
}
}
Edit:
I've set up my relationship models with the correct relationships.
$page = Page::find(1);
$page_group = $page->groups()->where('id', '=', 1)->get();
Returns the PageGroup collection belonging to the Page. I guess my new question is if it's possible to get a collection from that collection... Something like:
$content = $page_group->content;
Because that returns:
Undefined property: Illuminate\Database\Eloquent\Collection::$content
Does this make any sense? I apologize for the newbie question; I'm just getting into Laravel!
I feel like an idiot.
The method chain $page->groups()->where("id", "=", 1)->get()->content; will not work because $page->groups()->where("id", "=", 1); returns a list of rows!
$page->groups()->where("id", "=", 1)->first()->content will work.
Related
I have a scenario where User has a belongsToMany relation with PortalBreakdown, PortalBreakdown has a belongsTo relation with Portal. Portal has order column in it. I have a method listing_quota($id) in UserController which returns all breakdowns of the user. I want to sort these breakdowns based on order column of the portal. Below are the code of classes and a method I have tried.
class User extends Model {
protected $table = 'user';
public function listing_quota() {
return $this->belongsToMany('App\PortalBreakdown', 'user_listing_quota')->withPivot(['quota']);
}
}
class PortalBreakdown extends Model {
protected $table = 'portal_breakdown';
public function portal() {
return $this->belongsTo('App\Portal');
}
}
class Portal extends Model {
protected $table = "portal";
protected $fillable = ['name', 'description', 'order'];
}
Below is the method where I am trying to return sorted by order. I tried few things some of which can be seen in commented code but not working.
class UserController extends Controller {
public function listing_quota($id)
{
$user = User::with(['listing_quota' => function ($query) use ($id) {
// $query->sortBy(function ($query) {
// return $query->portal->order;
// });
}, 'listing_quota.portal:id,name,order'])->findOrFail($id);
// $user = User::with(['listing_quota.portal' => function ($q) {
// $q->select(['id', 'name',order']);
// $q->orderBy('order');
// }])->findOrFail($id);
return $this->success($user->listing_quota);
}
}
I also tried chaining orderBy directly after relation in Model class but that's also not working from me. Thank you in advance.
NOTE: I am using Laravel Framework Lumen (5.7.8) (Laravel Components 5.7.*)
i trying to load all rows from a model without the relationship.
The attributes $with it not event set on my Event model but when i do
$events = Event::all();
all my relationship are loaded, and i can see all the query with the dbquerylog.
i don't understand why theses relationship are loaded,
Please help me !
Thanks you.
I'm using Laravel 8.
here's an example.
class Event extends Model {
public function items() {
return $this->hasMany(Item::class);
}
public function items2() {
return $this->hasMany(Item2::class);
}
public function items3() {
return $this->hasMany(Item3::class);
}
public function items4() {
return $this->hasOne(Item4::class);
}
}
$events = Event::all();
If you have a single instance of a model object, you can do:
$obj->withoutRelations();
As laravel documentations says you can use without: https://laravel.com/docs/8.x/eloquent-relationships
Model
protected $with = ['item1','item2','item3','item4'];
Controller
$events = Event::without(['item1','item2','item3','item4'])->get();
I met this problem one day, and it turned out that I was using relation in scope method. Because of this relation values were added to response.
Check out this example:
class Event extends Model {
public function items() {
return $this->hasMany(Item::class);
}
[...]
public function scopeItemsGreen() {
return $this->items->every(function ($item) {
return $item->color == 'green';
});
}
I can't return $parent->child() | I get null;
Parent Model
class PrinterSetting extends Model
{
protected $table = 'printer_settings';
//fillables here
protected $with = ['copies'];
public function copies(){
return $this->hasMany(\App\DB\PrinterCopy\PrinterCopy::class, 'printer_id');
}
}
Child Model
class PrinterCopy extends Model
{
protected $table = 'printer_copies';
public function printer(){
return $this->belongsTo(\App\DB\PrinterSetting\PrinterSetting::class, 'id', 'printer_id');
}
}
Code in Controller:
$availablePrinters = $this->printerSetting->where('is_active', 1)->get();
foreach($availablePrinters as $availablePrinter)
{
//working
foreach($availablePrinter->copies() as $copy)
{
//Not working
}
}
I can't find the reason why it's not working.
I Tried to dump $availablePrinter->copies and it work, but ofcourse I can't insert it on foreach() loop.
Please help.
$availablePrinter->copies() return Query builder, you have to use $availablePrinter->copies which is Collection that you can add in loop, Try this
$availablePrinters = $this->printerSetting->where('is_active', 1)->get();
foreach($availablePrinters as $availablePrinter)
{
//working
foreach($availablePrinter->copies as $copy)
{
dd($copy)
}
}
Side note, also fix your belongsTo relation in PrinterCopy model, it should be like this
public function printer(){
return $this->belongsTo(\App\DB\PrinterSetting\PrinterSetting::class,'printer_id');
}
Problem: I have accessor in Size.php model which is called in relationship with Item.php Model, in API i need the accessor to work, but in other controllers i want to disable the accessor. I have removed unnecessary/unrelated code from all files.
What i want to do:
In ItemControllerAPI i need accessor to work, but i want to disable accessor in other controllers.
I have already seen:
I have already seen these links but didn't work for me.
1: https://laracasts.com/discuss/channels/eloquent/accessor-on-demand-but-not-on-every-results
2: Create dynamic Laravel accessor
3: https://laracasts.com/discuss/channels/general-discussion/eager-load-accessors
Size.php (Model)
class Size extends Model
{
protected $appends = ['addons'];
public function items()
{
return $this->belongsToMany('App\Item', 'items_sizes')->withPivot('price');//->withTimestamps();
}
public function getAddonsAttribute($value)
{
$addon = Addon::where('addons.category_id', $this->category_id)
->where('size_id', $this->id)
->get();
return $addon;
}
}
Item.php (Model)
class Item extends Model
{
public function options()
{
return $this->belongsToMany('App\Option', 'items_options')->withTimestamps();
}
public function sizes()
{
return $this->belongsToMany('App\Size', 'items_sizes')->withPivot('price');//->withTimestamps();
}
}
ItemControllerAPI.php (Controller)
class ItemControllerAPI extends BaseControllerAPI
{
public function show($id)
{
// If i call the Size model directly by using setAppends([]) its working fine,
// its removing the appended array from Size model
// $size = Size::all();
// $size->each->setAppends([]);
// return $size;
// If i use it with relationship it won't work.
// $itemSingleQuery = Item::with(['sizes' => function($query)
// {
// Doesn't work
// $query->setAppends([]);
// Doesn't work
// $query->each->setAppends([]);
// }])
// ->with('options')
// ->where('id', $id)
// ->get();
// query for getting data with relationships
$itemSingleQuery = Item::with('sizes')
->with('options')
->where('id', $id)
->get();
return $this->respondSuccess('content found', $itemSingleQuery);
}
}
I've found out how to do this:
After getting the entire collection we need to call setAppends() in each model, which contains appends, to add or remove them before serialization to array or JSON.
$itemSingleQuery = Item::with('sizes')->get();
$itemSingleQuery->each(function ($item) {
$item->sizes->each->setAppends(['addons']);
});
I would suggest that you set $appends when you need it:
$itemSingleQuery->pluck('sizes')->collapse()->each->setAppends(['addons']);
there are the following models:
class Page extends Model {
protected $with = ['blocks'];
public function blocks() {
return $this->belongsToMany('\App\Block');
}
}
class Block extends Model {
protected $with = ['fields'];
public function fields() {
return $this->hasMany('\App\Fields');
}
}
class Field extends Model {
protected $with = ['data'];
public function data() {
return $this->hasOne('\App\Data');
}
}
And there is a controller in which I get the data:
public function get() {
$page_id = 1;
$data = Page::find($page_id);
}
The result is the following structure:
Page
- Block 1
- field 1
- Some data
- field 2
- More data
- Block 2
- Field 1
- Other data
The block may belong to multiple pages.
The field belongs to the block.
But the data stored in this field belong to both the field and the page at the same time.
So, I need to pass the variable $page_id to the data() function of the Field model. To get something like this:
public function data() {
return $this->hasOne('\App\Data')->where('page_id', '=', $page_id);
}
Tell me, please, how to do this?
I solved this problem by removing $with from models and selecting the data with this code:
Page::with(['blocks.fields.data'=> function($query) use ($page_id){
$query->where('page_id', $page_id);
}])->find($page_id);
But it's not beautiful. I just want to write Page::find($page_id);
Thanks!
I like force loading relation but in your case maybe this what you looking for :
https://laravel.com/docs/master/eloquent-resources#conditional-relationships
you can do this as the following :
Page::whereHas('blocks.fields.data', function($query) use ($page_id){
$query->where('page_id', $page_id);
})->find($page_id);