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.
Related
So I’m making a catalogue using Laravel 7.* and I have a problem.
I have many products and many categories. I have created a many-to-many relationship so a product can be in many categories.
Now, what I am trying to do is to show in a page each category with related products, but obviously I am doing something wrong.
Below you may see some code:
Product.php:
public function categories()
{
return $this->belongsToMany(Category::class);
}
Category.php:
public function product()
{
return $this->belongsToMany(Product::class);
}
Show.blade.php
#php
$products = \App\Product::with('categories')->find(1);
#endphp
#foreach ($products as $id)
{{ $id->name }}<br>
#endforeach
Any help please?
Fixed it.
I fetched categories in controller and send to view. Then for each category displayed each product.
Get all the categories and show products related to them.
#php
$categories= \App\Category::all();
#endphp
#foreach($categories as $category)
#foreach($category->product as $product)
{{$product->name}}
#endforeach
#endforeach
You need also Id of category that you want to show products related to it.
According To This answer
Try this:
$category_id = 1; // Desired Category Id
$products = \App\Product::whereHas('categories', function($query) use ($category_id) {
$query->where('category_id', $category_id);
})->paginate();
I also added pagination.
I have 3 models in my app Users, Sales and Plans, when I render sales for each customer (due to storing) I only get id's for other users and models related to that sale (like account manager, owner, plan), now I'm trying to use those ID's inside blade to get names or other rows based on ID and model. Here is the show function:
public function show($id) {
$user = User::find($id);
$sales = Sale::where('customer_id', '=', $id)->get();
return view('profiles.customer', ['user' => $user, 'sales' => $sales]);
}
And in blade I get all those sales like:
#foreach ($sales as $sale)
<li>
<i class="fa fa-home bg-blue"></i>
<div class="timeline-item">
<span class="time"><i class="fa fa-clock-o"></i> {{$sale->created_at->format('g:ia, M jS Y')}}</span>
<h3 class="timeline-header">{{$user->name}} became a customer</h3>
<div class="timeline-body">
<p>Date: {{$sale->sold_date}}</p>
<p>Price: {{$sale->sale_price}}</p>
</div>
</div>
</li>
#endforeach
So inside each record I have like "account_manager_id", "agent_id", "owner_id", "plan_id".
Currently I have this solved by adding public static function (this is for users, have same function for Plan model as well) in Sale model class:
public static function getUser($id) {
return User::where('id', $id)->first();
}
And I'm using it like this in Blade:
Account manager: {{$sale->getUser($sale->account_mgr_id)->name}}
Is this the safest and best way to do it? Or there is something I'm overlooking here?
You need to add relationships in your Sales Model.
class Sales extends Eloquent {
.....
.....
public function accountManager() {
return $this->hasMany('App\User', 'account_manager_id');
}
public function agents() {
return $this->hasMany('App\User', 'agent_id');
}
public function owner() {
return $this->hasOne('App\User', 'owner_id');
}
}
Now $sales->agents will give you a user with agent_id as id in User table.
Update your hasOne, hasMany relationships as your need. Laravel Documentation.
From your blade template, your access your AccountManager as
#foreach($sales->accountManager as $manager)
Name: {{ $manager->name}}
#endforeach
I think you could use Eloquent relationships. Taking your example, you should define relationship in your User model:
<?php
class User extends Eloquent {
public function sales() {
return $this->hasMany(Sale::class, 'customer_id');
}
}
Then, whenever you need to get sales of that user (entries, that relate via customer_id column), just simply do
<?php
$user = User::find($id);
$sales = $user->sales;
This is very fun when when you have to print out list of users that have sales, for example
<?php
public function showUsersWithSales() {
$users = User::with('sales')->get();
return view('users-with-sales', compact('users'));
}
users-with-sales.blade.php example:
#foreach ($users as $user)
User: {{ $user->name }}<br>
Sales:<br>
#foreach ($user->sales as $sale)
{{ $sale->amount }} {{ $sale->currency }} # {{ $sale->created_at }}<br>
#endforeach
<hr>
#endforeach
It would print all users with their sale amount and currency, followed by date when it was created.
This sample takes into account, that your User model has name attribute and your Sale model has amount, currency, created_at and customer_id fields in your database.
To reverse the action, say you have a sale and want to know who made it, just simply define a relationship!
<?php
class Sale extends Eloquent {
public function customer() {
return $this->belongsTo(User::class, 'customer_id');
}
}
Hope that helps!
Eloquent Relationship is your friend, https://laravel.com/docs/5.2/eloquent-relationships and you can solve your problem easily.
Suggestion is to remove all those function access and control from view and put it somewhere else. This will be good habit for you so you can avoid the infamous fat view.
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 :)
I have a hasmany relationship on my model and I'm trying to output just the one result, i have a product category which can display only one product image.
I have two tables.
1 = Product
2 = ProductPhotos
I've tried outputting the one photo like
#foreach($products as $product)
<img src="{{ $product->photos->first() }}">
#endforeach
I have the following relationship setup in my product model
public function photos()
{
return $this->hasMany('App\ProductPhoto', 'product_id');
}
but this doesnt work.
You're just missing the parenthesis for the method. It should be:
$product->photos()->first();
Which will allow Eloquent to access the photos method in the Product model.
I'm new to MVC and do not understand it very much at all. I have a database with one table called products
I have a Model called Productwhich looks like
<?php
class Product extends Eloquent {
// MASS ASSIGNMENT -------------------------------------------------------
// define which attributes are mass assignable (for security)
// we only want these 3 attributes able to be filled
protected $fillable = array('type', 'brand', 'image');
}
I have a Route like so
Route::get('products', function()
{
return View::make('products');
});
And my View looks like this
#extends('master')
#section('content')
PRODUCTS
#foreach($products as $product)
{{ $product->type }}
#endforeach
#stop
I see you can get all the rows like so $products = Product::all(); but I don't understand WHERE this goes. Does it go in the View? Does it go in the Model? Does it go in the Route? My current #foreach loop just results in an undefined variable: products
Can someone please clarify?
This should get you started for now:
Route::get('products', function()
{
$products = Product::all();
return View::make('products')->with('products', $products);
});