Calling child relations from model in laravel - eloquent

I want to fetch the categories with products and images. I have following relation:
Product Model
class Product extends Model
{
public function productCategory() {
return $this->belongsToMany('ProductCategory');
}
public function addtionalImages() {
return $this->hasMany('ProductImage');
}
}
Product Category Model
class ProductCategory extends Model
{
public function product() {
return $this->hasMany('Bazar\Models\Product', 'product_catid')
->orderBy('id', 'DESC')->limit(10);
}
}
This is how i am using eager loading:
$categories = ProductCategory::select('product_categories.*')
->with(['product'])->Paginate(20);
This returns the category and products not the additionalImage, images are related to products not with the categories, I tried ->with(['product', 'addtionalImages']) but no success, can anyone let me know what i missed? or how do i achieve?
SOLVED

I solved it, and posting the answer so it helps to others.
$categories = ProductCategory::select('product_categories.*')
->with(['product', 'product.addtionalImages'])->Paginate(20);
With use of product.addtionalImages i can access the methods of related relation.

Portfolio Model:
public function getCats(){
return $this->hasMany(RelPortfolioCategory::class,'portfolioID','id');
}
controller:
public function portfolioDetail($slug){
$db = Portfolio::where('slug' , $slug)->with('getCats')->firstOrFail();
$dbRelated = RelPortfolioCategory::whereIn('categoryID' , $db->getCats->pluck('categoryID'))->whereNot('portfolioID' , $db->id)
->with('getPortfolioDetail')->get();
return view('portfolioDetail' , compact('db' , 'dbRelated'));
}

Related

Using "With" and BelongsTo on a model which has a defined table name causes a NULL to be returned

What I am finding is that the "picker" data does not get returned when using "with" but does if I use the default lazy loading query. It seems it might be down to the fact that the "picker" table uses a table name of "users".
So I have the following tables.
USERS [id, name]
PRODUCTS [id, name, picker_id]
I have created the following models.
class User extends BaseModel {
protected $hidden = array('pivot');
public function roles() : \Illuminate\Database\Eloquent\Relations\BelongsToMany {
return $this->belongsToMany(Role::class);
}
}
class Product extends BaseModel {
public function picker() : \Illuminate\Database\Eloquent\Relations\BelongsTo {
return $this->belongsTo(Picker::class);
}
}
class Picker extends User {
protected $table = 'users';
public function products() : \Illuminate\Database\Eloquent\Relations\HasMany {
return $this->hasMany(Product::class, 'picker_id');
}
public function pickingSequence() : \Illuminate\Database\Eloquent\Relations\HasOne {
return $this->hasOne(PickingSequence::class);
}
protected static function boot() {
parent::boot();
static::addGlobalScope('status', function (\Illuminate\Database\Eloquent\Builder $builder) {
$builder->join('role_user', 'role_user.user_id', '=', 'users.id')
->where('role_user.role_id', '=', Role::PICKER);
});
}
}
The picker and user models are using the same table (users), however the picker model filters out users so only those that have the correct role of "picker" are found. Working great so far.
What I want to do is to get all products and their relevant pickers (a product has one picker, a picker has multiple products).
Product::with('picker')->get()
This returns NULL for "picker", yet if I do:
Product::first()->picker
This works so the relationship seems fine and returns:
array(6) { ["id"]=> int(5) ["name"]=> string(8) "Picker B"
["created_at"]=> NULL ["updated_at"]=> NULL ["user_id"]=>
int(3) ["role_id"]=> int(1) }
If I change the "product" model to add a debug message It shows the relationship is working:
class Product extends BaseModel {
public function picker() : \Illuminate\Database\Eloquent\Relations\BelongsTo {
debug($this->belongsTo(Picker::class)->first());
return $this->belongsTo(Picker::class);
}
}
I am using the same syntax using "with" on other queries without a problem just can't seem to see the issue.
By changing the "belongsTo" inside the "Product" class to the following:
return $this->belongsTo(User::class, 'picker_id');
This now works and returns the picker data but I am using the wrong model, the "picker" model extends the user model.

Flutter access method of ViewModel into another ViewModel

i've a problem related to view models.
I need to access the method of this viewModel:
class TheacerViewModel{
Teacher _teacherX;
TeacherViewModel(Teacher teacherX): _teacherX = teacherX;
String get name{
return _teacherX.name;
}
String get surname{
return _teacherX.surname;
}
int get age{
return _teacherX.age;
}
}
into this viewModel:
class CourseViewModel{
Course _courseX;
CourseViewModel(Course courseX): _courseX = courseX;
String get subject{
return _courseX.subject;
}
/*
my solution (not working)
Teacher get teacher{
return _courseX.theacer;
}
*/
}
My solution not working.
It is possible to do this thing ?
I've already create Teacher and Course model.
Thanks.
for #towhid comment
now i have to update this part of code(maybe only the last line)and add "teacher: teacher" to CourseViewModel(...), but how ?
because courses.map does not allow me to add 2 parameters.
List<CourseViewModel> coursesL = List<CourseViewModel>();
void courses() async {
List<Course> courses = await WebService().fetchCourses();
notifyListeners();
this.coursesL = courses.map((courseX) => CourseViewModel(courseX: courseX)).toList();
An ideal approach would be creating the independent ViewModel first and then pass that instance to the dependent ViewModels constructor to use its method and properties. This way, you can avoid of creating any unnecessary instances.
class CourseViewModel{
Course _courseX;
Teacher _teacher;
CourseViewModel(Course courseX, Teacher teacher): _courseX = courseX, _teacher = teacher;
String get subject{
return _courseX.subject;
}
Teacher get teacher => _teacher;
}

Eloquent filter on method

I have 2 tables items and naws.
With
Item::where( 'items.item_type' , '=' , $pagetype)->get();
I retrieve the object perfect, but now i wan t to filter on area in the naws table.
How can i achieve that?
Model Item:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Item extends Model
{
protected $table = 'items';
public function naw()
{
return $this->hasOne('App\Naw');
}
}
Awnser:
return Item::with([
'naw' => function($query) use ($slug)
{
$query->whereArea($slug);
}
])->where( 'items.item_type' , '=' , $pagetype)->get();

EF: Partial class - acces to the adapter?

let's say that I have a table TabA
namespace MyProject.Models.Database //<-- the same namespace as the EF's dbmx file
{
public partial class TabA
{
public void Foo()
{
//
}
}
}
Inside the Foo method, I need to perform some operations on the other table which isn't asosiated with the TabA In the other words, I need to access to the Entity Framework adapter inside that method. Is it possible ?
Edit
the answer is here https://stackoverflow.com/a/11135157/106616
If I understand the problem correctly, I assume you have your reasons for wanting to work on another entity from the TabA entity. If this is true, I can see two ways of doing this.
A) If you want your changes to be applied at the same time as other potential changes to the TabA Entity, then you can always pass in the context as a parameter:
namespace MyProject.Models.Database //<-- the same namespace as the EF's dbmx file
{
public partial class TabA
{
public void Foo(YourDbContext context)
{
var otherTableQuery = from x in context.SecondTable
where ...
select x;
foreach (var item in otherTableQuery)
{
item.Column1 = "A certain value";
}
}
}
}
Your calling method might look like:
public void DoChangesToTabA()
{
using ( YourDbContext context = new YourDbContext())
{
var tabAquery = from x in context.TabA
where ...
select x;
foreach( var item in tabAQuery)
{
item.LastModified = DateTime.Now;
if(???)
{
}
}
}
}
Now your changes will be applied the next time you call context.SaveChanges() from the calling method.

Stuffing an anonymous type in ViewBag causing model binder issues

can someone tell me what I'm doing wrong? :-)
I have this simple query:
var sample = from training in _db.Trainings
where training.InstructorID == 10
select new { Something = training.Instructor.UserName };
And I pass this to ViewBag.
ViewBag.Sample = sample;
Then I want to access it in my view like this:
#foreach (var item in ViewBag.Sample) {
#item.Something
}
And I get error message 'object' does not contain a definition for 'Something'. If I put there just #item, I get result { Something = SomeUserName }
Thanks for help.
This cannot be done. ViewBag is dynamic and the problem is that the anonymous type is generated as internal. I would recommend you using a view model:
public class Instructor
{
public string Name { get; set; }
}
and then:
public ActionResult Index()
{
var mdoel = from training in _db.Trainings
where training.InstructorID == 10
select new Instructor {
Name = training.Instructor.UserName
};
return View(model);
}
and in the view:
#model IEnumerable<Instructor>
#foreach (var item in ViewBag.Sample) {
#item.Something
}
If you want to send in ViewData For example and don't want to send in model
you could use the same could as in the upper answer
and in the Controller
enter code here
ViewData[Instractor] = from training in _db.Trainings
where training.InstructorID == 10
select new Instructor {
Name = training.Instructor.UserName
};
and in the view you need to cast this to
`IEnumerable<Instructor>`
but to do this you should use
#model IEnumerable<Instructor>
Then you could do something like this
IEnumerable<instructors> Instructors =(IEnumerable<Instructor>)ViewData[Instractor];
then go with foreach
#foreach (var item in Instructors ) {
#item.Something
}