Retrieving data from belongsToMany relationship in Laravel - laravel

I have some problems with getting data from my relationship. I need the tags of some domains.
$domains = Domains::where('customer_id', Auth::user()->customers_id)->get();
There are all the domains I need. On my Domains model I have this belongsToMany relation to my pivot table.
public function tags() {
return $this->belongsToMany('App\Models\Tags_Domains', 'domain_tag', 'domains_id', 'tags_id');
}
I was able to get all the datas from my relation with this:
dd($domains[0]->tags);
That gave me all the data I wanted but only for the very first domain. But I want this for every domain, to pass this new array to my Blade template. I tried many things out but couldn't make it work. ( $collection error, trying to get properly of non-object ... )
Can someone help me there?
Controller Code:
$domains = Domains::where('customer_id', Auth::user()->customers_id)->get();
return view('defaultLayout.domains.tagsdelete', [
'domains' => $domains
]);

This is because you use $domains[0] and you get the first domain.
You must loop through them:
foreach($domains as $domain) {
foreach($domain->tags as $tag) {
var_dump($tag);
}
}
Edit:
If you need the tags in your view here is how:
#foreach($domains as $domain)
<p>{{ $domain->name }}</p> //where name could be any field that $domain has
#foreach($domain->tags as $tag)
<p>{{ $tag->name }}</p> //where name could be any field that $tag has
#endforeach
#endforeach
Glad I was helpful :)

Related

Laravel Nested Foreach for FAQ Views Trying to get property of non-object

i have a problem with my FAQ views. i want to display FAQ by categories like this:
Category1
FAQ1
FAQ2
FAQ3
Category2
FAQ1
FAQ2
FAQ3
Here is my Controller
public function faq()
{
$faq_category_vendor = DB::table('faq_categories')->where('categories_for','1')->get();
$faq_vendor = DB::table('faqs')
->join('faq_categories', 'faq_categories.id', '=', 'faqs.category')
->select('faqs.*','faq_categories.*', 'faq_categories.id as idcategory', 'faqs.id as id')
->where('faq_for','1')->get();
return view('owner.faq',['faq_category_vendor' => $faq_category_vendor,'faq_vendor' => $faq_vendor]);
}
Here is my Views :
#foreach($faq_category_vendor as $item)
For ({{$item->name}}) :
#foreach($faq_vendor as $item2)
#if ($item->id == $item2->category)
- {{$item2->ask}} : {{$item2->answer}}<br>
#else
#endif
#endforeach
<br>
#endforeach
The output is :
Facade\Ignition\Exceptions\ViewException
Trying to get property 'category' of non-object (View: C:\xampp\htdocs\weddinc\weddinc\weddinc_beta\resources\views\owner\faq.blade.php)
Can anyone help me?
Check if your faq_categories has id in faqs,becouse if don't you will get empty join so trying get
$item2->category
will throw exception.My proposition is do something like this in .blade
#php
try{
$testData=$item2->category;
} throw (\Exception $e) {
dd($item2);
}
#endphp
That will give you dd in blade so you will see if all records has joins
So there's a couple of points here which will help you out.
Your controller implies that you don't have relationships set up. Having relationships between your data will help you out massively; from what I can make out, you have a 1 to many relationship between faq_categories and faq (one faq_category has many faqs).
So, in your FaqCategory model:
public function faqs()
{
return $this->hasMany('app\faq');
}
In your Faq model:
public function category()
{
return $this->belongsTo('app\faq_category`);
}
Okay, so you said that you want to display each category, and then each FAQ under every category. In your controller, you can get all categories like so:
$categories = FaqCategory::all();
And in your blade, you can do this:
#foreach($categories as $category)
#foreach($category->faqs as $faq)
{{ $faq }}
#endforeach
#enforeach

Merge two collections in Laravel and access it

Ok, so here is my problem : I have'nt found a proper solution to 'merge' (not sure if it is the right word for it) two collections in laravel. I'll show you my code, it'll explains itself.
So here is my crappy way-arround code, but I'm pretty sure there is a better way to do it :
Here is my controller :
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Product;
use App\ProductPhoto;
class ProductController extends Controller
{
public function index() {
$products = Product::all();
$photos = ProductPhoto::all();
return view('/products')->with([
'products' => $products,
'photos' => $photos
]);
}
}
and my view looks like this ;
#foreach($products as $product)
#foreach($photos as $photo)
#if($photo->product_id = $product->id)
<img src="/products/{{ $product->id }}/{{ $photo->filename }}">
#endif
#endforeach
#endforeach
But I'd like to have all the photos related to the product in the product collection. I'd like to have a simple view as :
#foreach($products as $product)
#foreach($product->photos as $photo)
<img src="/products/{{ $product->id }}/{{ $photo->filename }}"
#endforeach
#endforeach
Or another way simpler than that. I've been trying merge, but I don't think this is the one I need, I don't know. Or maybe the way I do it is the correct one, but I doubt it.
Thanks for reading !
I'd recommend using eloquent relationships for this. To do this you would want to create a relationship on the product class called photos. This would look something like this:
class Product extends Model
{
...
public function photos()
{
return $this->hasMany(ProductPhoto::class);
}
...
}
Once you have done this, you can update your controller as you no longer need to fetch the photos from the model. For performance, you could eager load the photos.
public function index() {
$products = Product::with('photos')->get();
return view('/products')->with([
'products' => $products
]);
}
Finally, you can update your view to use the photos relationship instead.
#foreach($products as $product)
#foreach($product->photos as $photo)
<img src="/products/{{ $product->id }}/{{ $photo->filename }}"
#endforeach
#endforeach
I hope that helps.
I don't usually like when people ignore the proposed example and tell you that there's a better way to do that... but there is a better way to do that:
for the Products Eloquent add a method called photos
Class Products extends Model{
...
public function photos(){
return $this->hasMany(Photos::class);
}
}
for the Photos Eloquent add a method called product
Class Photos extends Model{
...
public function product(){
return $this->belongsTo(Product::class);
}
}
now for the photos migration you need to add a column called product_id in case you're using this photos table only for products and not anything else like users.
if you want to be able to assign photos to multiple models like Users can have photos, then you need to consider using Morphs Polymorphic Relationships
when you want to add photos to the product you can then do
Product::find(1)->photos()->create(['filename'=>'....']);
That should add photos row assigned with the product.
Then in your view you can do something like:
#foreach(Products::all() as $_product)
<div>
{{$_product->title}
<div class="product_photos">
#foreach($_product->photos as $_photo)
<img .../>
#endforeach
</div>
</div>
#endforeach
I'm just showing you the correct way to achieve that instead of comparing photos with id and so on, your way will make it much slower.
Look up Laravel Relationships. That will take a bit of time like few minutes to convert your models to use Relationships but will save you days of coding later.

How to pass variable from foreach to view in laravel 5.4?

I want to count each location in my Job table by using location_id in my job table with id in location table. below code, I can count result correctly but I don't know how to pass this variable to the view. Please help?
//my code
public function index(){
$location = Location::all();
$count_location = [];
foreach ($location as $locations){
$count_location = Job::where('location_id', $locations->id)->count();
}
}
Use withCount() and view() to pass location with counted jobs to the view:
public function index(){
return view('view.name', [
'locations' => Location::withCount('jobs')->get()
]);
}
In the view:
#foreach ($locations as $location)
{{ $location->name }} has {{ $location->jobs_count }} jobs
#endforeach
You can return the collection of locations to the view and then loop through each object in the collection like so:
return view('index', [
'locations'=> $locations,
]);
Then in your index.blade.php you can use something like a #foreach or #forelse loop
#foreach ($locations as $location)
{{ $location->id }}
#endfoeach
EDIT
From the looks of it you would be better off defining a relationship between locations and jobs (i.e. a "many to many" or "one to many" relationship). this would allow you to get the counts for jobs at given locations very easily like so:
$location->jobs->count()
Eloquent relationships are explained in the documentation here
https://laravel.com/docs/5.5/eloquent-relationships
It would be more efficient if construct your query to fetch the count of related models instead of looping through all the results.
Have a look at Counting Related Models in the documentations.
For example, to get the count of all jobs related to a location, you could do:
$locations = App\Location::withCount('jobs')->get();
foreach ($locations as $location) {
echo $location->jobs_count;
}
You need to adjust the code according to your models structure.
Do this
public function index(){
$locations = Location::all();
return view('index', compact('locations'));
}
In your Location model make a relationship by adding this
public function jobs(){
return $this->hasMany(Job::class);
}
In your index view do this
#foreach ($locations as $location)
{{$location->jobs->count}}
#endforeach
Please note that Job should be there in your your model

laravel passing data to view blade

//model
return $this->hasMany('App\Model\Order', 'customer_id')->select('name');
//controller
$customer = Model\customer::find($id);
return view('customer', array('data' => $customer));
//view (blade)
{{ $data }} //{"id":1,"name":"Tony"}
{{ $data->orders }} //[{"name":"T-shirt"},{"name":"Macbook"}]
i'm new in laravel
I have a question about passing data to view.blade
I used hasMany to join 2 table together and pass $data to view
when I try to output $data, I could not see order object inside of data object
but when I did $data->orders, it shows object
can anyone tell me how it works?
The behavior you are seeing is because Laravel lazy loads relations when they are accessed. If the relation has not been loaded, Laravel will send another query and add it to your $data object behind the scenes. That's why when you dump the $data variable, you are not seeing the orders.
To demonstrate, run the following snippet.
{{ $data }} //{"id":1,"name":"Tony"}
// Laravel will lazy load the orders relation
{{ $data->orders }} //[{"name":"T-shirt"},{"name":"Macbook"}]
// Now the $data object has the orders property.
{{ $data }} //{"id":1,"name":"Tony", "orders": [{"name":"T-shirt"},{"name":"Macbook"}]}
Solution
You have a couple options here. Here are 2.
1. Eager load relation when querying model.
$customer = Model\customer::with('orders')->find($id);
This is the preferred method as it prevents n+1 querying.
2. Load relation after model has been queried.
$customer = Model\customer::find($id);
$customer->load('orders');
Now when you dump the model, you will see the orders property.
In your model,
public function orders(){
return $this->hasMany('App\Model\Order', 'customer_id');
}
In view
{{ $data->orders->order_name }}
I hope it will works
You have defined hasMany relationship in your model. So, for a particular customer there can be multiple orders. So, it shows in array. You have to loop through:
foreach($data->orders as $order)
{
$order->name
}
to get the orders.

htmlentities() expects parameter 1 to be string, array given? Laravel

I've found many question realated to my problem but couldn't found an answer yet. It's about my foreach loop in my blade.
I want to print all product-names in my blade but I couln't figure out how to do that.
thats how I'm getting the products:
--- current code:
// controller
$id_array = Input::get('id');
$products= Products::whereIn('id', $id_array)->get();
$product_name = [];
foreach($products as $arr)
{
$product_name= $arr->lists('name');
}
returning $product_name gives me this as a output:
["football","cola","idontknow","freshunicorn","dummy-data"]
In my blade is just a simple:
#foreach($products as $product)
{{ $product}}
#endforeach
Error: htmlentities() expects parameter 1 to be string, array given
Thanks for your help and time.
It seems you are getting an object in an array in an array.
Like this:
array(
array(
object
)
)
It happens because you use the get() function to retrieve you model. The get() function always "wants" to retrieve multiple models. Instead you will have to use the first() function.
Like this:
foreach($id_array as $arr)
{
$want2editarray[] = Product::where('id', $arr)->first();
}
Hope it helps :)
Edit after #Wellno comment
That's probably because Product::where('id', $arr)->first(); returns null because it did not find anything.
I forgot to add a check after the retrieving of the product.
This can be done like this:
foreach($id_array as $arr)
{
// First try to get model from database
$product = Product::where('id', $arr)->first();
// If $product insert into array
if ($product) $want2editarray[] = $product;
}
Why do you use loop with IDs? You can find all products by IDs:
$products = Product::whereIn('id', $id_array)->get();
And then use $products in the blade template
#foreach($products as $product)
{{ $product->name }}
#endforeach
try to use Model/Eloquent to fetch data.
View should only display the data and not fetching directly from DB or do heavy calculations.

Resources