I have relation like this:
DB relation
I have a code in my model that retrieves me just one parent:
public function AllParents()
{
return $this->belongsToMany($this, 'parent', 'product_id', 'parent_id')
->select('parent', 'name');
}
I get it in my controller like this:
private function product(Product $product)
{
return $product->Product()
->with('AllParents')
->get();
}
Finally I need data like this:
Product1/Product_2/Product_3
I think I need a loop, but how to do it in Eloquent?
Just change relationship. You have mentioned pivot table name wrong one.
public function AllParents()
{
return $this->belongsToMany(Product::class, 'Product_parent', 'product_id', 'parent_id') ->select('parent', 'name');
}
and then you can access
\App\Models\Product::with('AllParents')->get()
In your Product Model. You have define relationship like this.
public function allParents()
{
return $this->belongsToMany(Product::class, 'product_parents', 'product_id', 'parent_id')->select('name');
}
And, In Controller you can get all the parents with eager loading.
Product::with('allParents')->find($productId);
And, In View you can use foreach loop to iterate every parent object.
#foreach ($product->allParents as $parentProduct)
{{ $parentProduct->name }}
#endforeach
I did like this:
I modified my controller
private function product(Product $product)
{
$allParents = [];
$parent = null;
$parent->$product->Product()->with('AllParents')->first()->id;
while ($parent != null) {
array_push($allParents, Product::all->find($parent));
$parent = Product::all()->find($parent) - first();
}
}
Related
I define the relation in Company table (where I added the plural):
protected $table = 'companies';
public function country() {
return $this->belongsTo(Country::class, "country_id")->withDefault(['country' => 'unknown']);
}
I also did the same in the Country model.
When I use the following code in the controller show function it works:
public function show (Company $company) {
$company->country = $company->country()->pluck('country');
But if I use the same code in the index function in a loop, I get an error "Call to undefined method stdClass::country()":
public function index (Company $company) {
if (request('tag')) {
$companies = Tag::where('name',request('tag'))->firstOrFail()->companies;
$companies->page_title = "Businesses matching tag '".request('tag')."'";
} else {
$companies = DB::table('companies')
->where([['is_active', '=', '1']])
->orderBy('company')
->get();
}
foreach($companies as $key => $thisCompany) {
...
$thisCompany->country = $company->country()->pluck('country');
}
I guess it is due to the fact that $company is created in the loop and not passed through the function like in show(Company $company)... but I could not find how to solve this issue... so help will be appreciated.
I have added the model in the argument of the function and change the name of the $company variable in the loop by $thisCompany to avoid confusion with the $company model.
No error but the field $country->country does not contain the name of the country but "Illuminate\Support\Collection {#443 …1}"
Why is it so complicated? Please help...
Paul, sorry, I think I didn't explain myself well in the comments.
What I meant by "What about if you change DB::table('companies') by Company?", is to stop using DB Query Builder to use the Eloquent Company model.
Specifically in this segment of code:
$companies = DB::table('companies')
->where([['is_active', '=', '1']])
->orderBy('company')
->get();
So, it could be:
$companies = Company::where([['is_active', '=', '1']])
->orderBy('company')
->get();
The explanation is that in the first way (with DB Query Builder), the query will return a collection of generic objects (the PHP stdClass object) that do not know anything about the Company and its relationships.
On the other hand, if you use the Eloquent model Company, it will return a collection of Company objects, which do know about relationships, and specifically the relationship that you have defined as country.
Then, when you loop over the collection, you will be able to access the country relation of each Company object:
foreach($companies as $key => $company) {
//...
$company->country = $company->country()->pluck('country');
}
Finally, your code could looks like:
public function index () {
if (request('tag')) {
$companies = Tag::where('name',request('tag'))->firstOrFail()->companies;
$companies->page_title = "Businesses matching tag '".request('tag')."'";
} else {
$companies = Company::where([['is_active', '=', '1']])
->orderBy('company')
->get();
}
foreach($companies as $key => $company) {
//...
$company->country = $company->country()->pluck('country');
}
//...
}
I'm returing a model with all the related models.
My problem is that perhaps some models don't have records so they are returned in my $property variable as empty and I have to evaluate their existence in blade (not done yet)
Is there any way in controller or parent model to return only the child relationships which have records? Or any blade directive to evaluate these cases?
All relationships are 1:M.
Regards!
Controller Code
class PropertyController extends Controller
{
public function details($id)
{
$property = Property::with('attributes', 'addons', 'distributions', 'images', 'attributes_2', 'services')
->where('prop_id', $id)
->first();
// dd($property);
return view('pages.processes.offerdemand.matchs.propertymodal', compact('property'));
}
}
Sir u have the same result with this code?? (just trying to help, im new in this world)
return view('pages.processes.offerdemand.matchs.propertymodal', compact(array('property')));
class PropertyController extends Controller
{
public function details($id)
{
$relations = ['attributes', 'addons', 'distributions', 'images', 'attributes_2', 'services']
$property = Property::with($relations)->whereHas($relations)
->where('prop_id', $id)
->first();
// dd($property);
return view('pages.processes.offerdemand.matchs.propertymodal', compact('property'));
}
}
SOLUTION
I changed code as follows and recieved the expected result:
public function details($id)
{
$property = Property::with(['attributes' => function ($builder) {
$builder->where('pa_value', '!=', '');
}])
->with('addons', 'distributions', 'images', 'attributes_2', 'services')
->where('prop_id', $id)
->withCount('attributes', 'addons', 'distributions', 'images', 'attributes_2', 'services')
->first();
dd($property);
return view('pages.processes.offerdemand.matchs.propertymodal', compact('property'));
}
I'm trying to get all categories of restaurants.
My models:
Restaurant
public function categories()
{
return $this->belongsToMany(Category::class,'restaurant_categories_relation','restaurant_id');
}
Category
public function restaurants()
{
return $this->belongsToMany(Restaurant::class,'restaurant_categories_relation', 'category_id');
}
In my controller:
$restaurants = Restaurant::where('district_id', $request->district)->paginate(8);
$categories = $restaurants-> ????;
Please help me do this, thanks!
You could use has() like :
Category::has('restaurants')->get();
That will return the categories who are related with the restaurants.
Try also the use of whereHas like :
$users = Category::whereHas('restaurants', function($q){
$q->->where('district_id', $request->district)->paginate(8);
})->get();
Since you've already a Collection we can't query the categories so I suggest adding a function to scope that inside the Restaurant model like :
public static function getCategoriesOfRestaurants($restaurants)
$categories = [];
foreach($restaurants as $restaurant){
array_push( $categories, $restaurant->categories->pluck('id')->toArray());
}
return Category::WhereIn('id', array_unique($categories))->get();
}
Then just call it when you get the $restaurants collection :
$restaurants = Restaurant::with("categories")->where('district_id', $request->district)->paginate(8);
$categories = Restaurant::getCategoriesOfRestaurants($restaurants);
Note: The use of with("categories") when getting the collection will query All the related categories in the first query so the foreach loop will not generate any extra query just looping through the already fetched data, and finally we will get the collection of categories in the return statement.
use with() method for eagerloading, that provides you get all categories in a single query
$restaurants = Restaurant::with("categories")->where('district_id', $request->district)->paginate(8);
foreach($restaurants as $restaurant){
foreach($restaurant->categories as $category)
{{$category}}
}
}
if you want to use categories outside of the loop, then assign these categories to a variable
foreach($restaurants as $restaurant){
$categories = $restaurant->categories;
}
// do something with $categories
Your relation should be
Restruant.php
public function categories() {
return $this->belongsToMany(Category::class,'restaurant_categories_relation','restaurant_id','category_id');
}
then in you controller method just wirte
$restruants = Restruant::with('categories')->get();
It should return you collection of all restruants with all related categories.
This is my models structure:
class Family extends Eloquent
{
public function members()
{
return $this->hasMany('App\Person');
}
}
class Person extends Eloquent
{
public function family()
{
return $this->belongsTo('App\Family');
}
public function school()
{
return $this->belongsTo('App\School');
}
}
class School extends Eloquent
{
public function students()
{
return $this->hasMany('App\Person');
}
}
So, a Person belongs to both Family and School.
I fetch a Family:
$family = Family::find(1);
And list the members:
foreach ($family->members AS $member) {
$member->name;
foreach ($member->school AS $school) {
$school->name;
}
}
How can I order the schools by name in ASC order?
EDIT
How to make this list ordered:
foreach ($family->members AS $member) {
$member->school->name;
}
EDIT 2
Very sorry. I've got mixed up.
What I'm trying to achieve is to sort the members of the family by the name of the school that they're attending.
A Person can attend only one school.
Try
$family = Family::with(['members.school'=>function($q){
$q->orderBy('name', 'ASC');
}])->find(1);
The with function will eagerload your records preventing the N + 1 query problem and also make your application run faster.
foreach ($family->members AS $member) {
$member->name;
foreach ($member->school AS $school) {
$school->name;
}
}
hope it helps
I think you need to eager load the relationship then order the relationship:
$family = Family::with(['members.school' => function($query) {
$query->orderBy('name', 'asc');
}])->find(1);
Edit
In response to your comment:
What if every person belongs to only one school, and I want to list
members ordered by the school name, without the second loop? Will
update question with the code in a second
I'm pretty sure you can go ahead and use the same query above with the eager loading as the school() relation on Person is belongsTo so it will return one eloquent record not many. You'd only need another for loop if it was returning an eloquent collection. So you should be able to run the loop like so:
foreach ($family->members AS $member) {
$member->name;
$member->school->name;
}
Unless I'm missing something?
I'll just point out as well that if you always want them sorted by name, you can define a relation on your Person object for school and order it like this:
public function schoolOrderedByName() // you could just call it school()
{
return $this->belongsTo('App\School')->orderBy('name', 'asc');
}
Then you don't have to write the constraint every time you use the relation:
$family = Family::with(members.schoolOrderedByName')->find(1);
Before the second foreach, add this statement
$schools = $member->school->orderBy('name', 'ASC')->get();
Like this
foreach ($family->members AS $member) {
$member->name;
$schools = $member->school->orderBy('name', 'ASC')->get();
foreach ($schools AS $school) {
$school->name;
}
}
I am getting an error
Trying to get property of non-object (View: C:\xampp\htdocs\laravel\proj\resources\views\mycases.blade.php)
I have defined a relationship between two models Ccase and Hiring.
public function hirings()
{
return $this -> hasMany('App\Hiring', 'case_ID')->orderBy('id','desc');
}
and paginating the results using a method below
public function getHiringsPaginateAttribute($perPage)
{
return $this->hirings()->paginate($perPage);
}
The other model 'Hiring' has a method to define relationship with Ccase as follows:
public function ccase()
{
return $this->belongsTo('App\Ccase', 'id');
}
In my controller, I have following code:
if(isset($search_term))
{
$search_term = preg_replace('/\s+/', ' ', $search_term);
$search_term = trim($search_term);
if (strlen($search_term) > 0 && strlen(trim($search_term)) == 0)
$search_term = NULL;
$search_terms = explode(' ',$search_term);
$fields = array('id', 'title', 'case');
$hirings = $hirings->whereHas('ccase', function($q) use ($search_terms, $fields){
foreach ($search_terms as $term)
{
foreach ($fields as $field)
{
$q->orWhere($field, 'LIKE', '%'. $term .'%');
}
}
});
}
$hirings = $hirings->getHiringsPaginateAttribute($results_per_page);
In mycases.blade.php, my code is
{{$hiring->ccase->id}}
This line is throwing the above said error while the output of {{$hiring->ccase}} is:
{"id":1,"case":"HI this is a sample case i am putting just for test.","created_at":"2015-02-22 11:54:09","updated_at":"2015-02-22 11:54:09"}
What might be wrong with the code?
Unfortunately, you can't use related models in views. Here's the detailed explanation why.
Your case can be solved by specifying the name of the associated column on the parent table:
return $this->belongsTo('App\Ccase', 'ccaseId', 'id');
In model Hiring, it will be like
public function ccase()
{
return $this->belongsTo('App\Ccase', 'case_ID', 'id');
}
And now in view use it like this:
{{ $hiring->ccase->id }}
Not sure, but i think that you could use relations in view, you should use an eager loading in controller where you are quering for $hirings, just add a:
with(['hirings.ccase'])
Could you please provide a peace of code from controller where you make a query to Hiring model for clear?