I'm making shop online with Laravel. I made Cart with records user_id and product_id with relations hasMany to products. My problem is that I can't get for example product's name or price, I can only get whole array with products and cart data. Can someone tell me how to get it? Maybe there is a problem with a query or just view syntax.
My migration:
public function up()
{
Schema::create('carts', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->unsignedBigInteger('product_id');
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users');
$table->foreign('product_id')->references('id')->on('products');
});
Here is my controller function:
public function index(Request $request)
{
$query = Cart::with('product')->where('carts.user_id', $request->user()->id);
$query = $query->get();
return view('cart.index', ['cart' => $query]);
}
And view to show cart
#extends('app')
#section('content')
#foreach ($cart as $item)
<form method="" action="{{ route('destroycart', ['id' => $item->id]) }}">
{{ $item['product'] }}
<button class="btn btn-outline-dark">X</button>
</form>
#endforeach
#endsection
Model:
class Cart extends Model
{
use HasFactory;
public function product() {
return $this->hasMany(Product::class, 'id', 'product_id');
}
}
Is there another option for $item['product'] to get only product data?
Forgot to paste what view returns:
[{"id":10,"name":"lklkl","description":"klklkk","img":"przyklad.mo.jpg","price":50,"count":9,"created_at":"2022-05-24T13:13:03.000000Z","updated_at":"2022-05-24T13:13:03.000000Z"}]
I would like to get for example product's name.
You should then also access products, so:
#foreach ($cart as $item)
// Cart stuff here.
#foreach ($item->product as $prod)
// Product stuff here
#endforeach
#endforeach
You can get a single cart in the controller method if you want to display only one cart at a time
public function index(Request $request)
{
return view('cart.index', [
'cart' => Cart::with('product')
->where('user_id', $request->user()->id)
->latest()
->first()
]);
}
Then in your view you can loop over the products in the cart
#extends('app')
#section('content')
<form method="" action="{{ route('destroycart', ['id' => $cart->id]) }}">
#foreach ($cart->product as $product)
<p>{{ $product->name }}</p>
#endforeach
<button class="btn btn-outline-dark">X</button>
</form>
#endsection
Or if you want to show all carts for the currently logged in user then you can do it as
public function index(Request $request)
{
return view('cart.index', [
'carts' => Cart::with('product')
->where('user_id', $request->user()->id)
->latest()
->get()
]);
}
The in the view loop over the carts and with each iteration - loop over the products
#extends('app')
#section('content')
#foreach($carts as $cart)
<form method="" action="{{ route('destroycart', ['id' => $cart->id]) }}">
#foreach ($cart->product as $product)
<p>{{ $product->name }}</p>
#endforeach
<button class="btn btn-outline-dark">X</button>
</form>
#endforeach
#endsection
Related
I'm new to laravel. I want to access the products belongs to the category. There is One-to-Many relation between them. To get this data I created a function inside ProductsController named getCtgProducts() to do just that.
I know it a bad practice to query a database straight from views, hence I am writing the database query in the controller and trying to access it inside the blade.
Can someone tell me what I'm doing wrong?
What is the proper way to access the controller function inside the blade view? I'm using Laravel Framework v9.7.0
#foreach ($ctgs as $ctg)
<h1> $ctg->name </h1> // -- It is working. Showing the correct ctgs names
<div class=container>
#if (isset($products))
#foreach ({{ App\Http\Controllers\ProductsController::getCtgProducts($ctg->id) }} as $product)
<h1> $product->name </h1>
#endforeach
#endif
</div>
#endforeach
ProductsController class
<?php
namespace App\Http\Controllers;
use App\Models\Ctg;
use App\Models\Product;
class ProductsController extends Controller
{
public function index(Request $request)
{
$products = Product::all();
$ctgs = Ctg::all();
return view('ui\welcome', compact('products', 'ctgs'));
}
public static function getCtgProducts(){
$ctgProducts = DB::table('products')->where('ctg_id', $ctgId);
return $ctgProducts;
}
}
Calling controller from blade is bad practice
move your getCtgProducts() method logic to Category Model:
public function getCtgProducts(){
$ctgProducts = DB::table('products')
->where('ctg_id', $this->id)->get();
return $ctgProducts;
}
Blade file:
#foreach ($ctgs as $ctg)
<h1> $ctg->name </h1> // -- It is working. Showing the correct ctgs names
<div class=container>
#foreach ($ctg->getCtgProducts() as $product)
<h1> $product->name </h1>
#endforeach
</div>
#endforeach
Better way:
Since there's one-to-many relationship
in Category Model you should have a relationship method:
public function products() {
return $this->hasMany(Product::class);
}
Blade:
#foreach ($ctgs as $ctg)
<h1> $ctg->name </h1> // -- It
is working. Showing the correct ctgs
names
<div class=container>
#foreach ($ctg->products as
$product)
<h1> $product->name </h1>
#endforeach
</div>
#endforeach
I use L8 And I have a category table ,it has parent_id for my subcategories
categories table
Category model
categoryController
SubCategoryController
categories.blade
sub_categories.blade
In my subcategory-index.blade.php I want to show categories but I just can show them with their id (parent id)
I don't know how to show categories title instead of their id.
I have this migration for categories table :
public function up()
{
Schema::dropIfExists('categories');
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('parent_id')->default(123);
$table->string('title');
$table->longText('description');
$table->tinyInteger('status')->comment('status is 1 when a category is active and it is 0 otherwise.')->nullable();
$table->rememberToken();
$table->softDeletes();
$table->timestamps();
});
}
and this is my category model :
class Category extends Model
{
use HasFactory;
protected $fillable = [
'parent_id','title' , 'description', 'status',
];
public function children(){
return $this->hasMany(Category::class , 'parent_id');
}
public function post(){
return $this->hasMany(Post::class);
}
}
And my subcategory controller :
...
public function index()
{
$parent_id = Category::with('parent_id')->get();
$subcategories = Category::where('parent_id' ,'!=', 123)->get();
return view('admin.subcategories.subcategories-index' , compact('subcategories'));
}
...
And the part for show subcategory title in category-index.blade.php :
<table class="table table-bordered">
<tr>
<th>#</th>
<th>id</th>
<th>title</th>
<th>category</th>
<th>status</th>
<th>operation</th>
</tr>
#foreach($subcategories as $subcategory )
<tr>
<td>{{ $loop->iteration }}</td>
<td>{{ $subcategory['id'] }}</td>
<td>{{ $subcategory['title'] }}</td>
<td>{{ $subcategory['parent_id']}}</td>
<td>
#if($subcategory['status']==0 or $subcategory['status']==NULL)
inactive
#else
active
#endif
</td>
<td>
<form method="POST" action="{{ route('subcategory.destroy',$subcategory->id) }}">
<a class="btn btn-info" href="{{ route('subcategory.show' , $subcategory->id) }}">show</a>
<a class="btn btn-primary" href="{{ route('subcategory.edit' , $subcategory->id) }}">edit</a>
#csrf
#method('DELETE')
<button type="submit" class="btn btn-danger"> delete</button>
</form>
</td>
</tr>
#endforeach
</table>
Thanks for telling me what to do :>
To get subcategories
$sub_categories = Category::whereNotNull('parent_id')->get();
To get sub-categories with parent
$sub_categories_with_parent = Category::with('parent')->whereNotNull('parent_id')->get();
To fetch categories
$categories = Category::whereNull('parent_id')->get();
To fetch categories with children
$categories_with_childern = Category::with('children')->whereNull('parent_id')->get();
You might have to redefine your relations as well:
public function parent()
{
return $this->belongsTo(Category::class);
}
public function children()
{
return $this->hasMany(Category::class , 'parent_id');
}
In migration define relation as well
$table->foreign('parent_id')->references('id')->on('categories')->onUpdate('cascade')->onDelete('cascade');
Make parent field nullable
$table->unsignedBigInteger('parent_id')->nullable()->default(123);
The line down below is incorrect. Because with() is used to get relational data and parent_id is not a relation name.
$parent_id = Category::with('parent_id')->get();
If your route contains the id or slug of the category, you can use it, but I think it doesn't, because your index function doesn't accept any route parameter. So I assume you are trying to fetch all categories and subcategories. But in this case, the second line of the index function doesn't make sense at all.
If you want to all categories:
$categories = Category::where('parent_id', null)->with('children')->get();
I see you use 123 for top-level categories, and it looks high enough. But nullable is a better practice for that purpose.
If you need a specific category and its subcategories:
// web.php
Route::get('category/{slug}', [CategoryController::class, 'index']);
// CategoryConteroller.php
public function index($slug)
{
$category = Category::where('slug', $slug)->with('children')->get();
}
When I click on a particular product on the products page, it directed me to the single product page. Particular product ID also showing in the URL. But data won't be passed. My single product page doesn't show the particular product data.
This is my Controller.
SingleProductController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Product;
use App\Category;
class SingleProductController extends Controller
{
public function index(Product $product)
{
$arr['product'] = $product;
return view('singleproducts')->with($arr);
}
public function create()
{
//
}
public function store(Request $request)
{
//
}
public function show($id)
{
$product = Product::find($id);
return view ('singleproducts')->with(['product'=>$product]);
}
public function edit($id)
{
//
}
public function update(Request $request, $id)
{
//
}
public function destroy($id)
{
//
}
}
This is my blade file.
singleproducts.blade
#extends('layouts.singleproducts')
#section('content')
<h2 class="font-size-25 text-lh-1dot2">{{ $product ['prod_name'] }} </h2>
<div class="mb-4">
<div class="d-flex align-items-baseline">
<ins class="font-size-36 text-decoration-none">{{ $product ['prod_price'] }}</ins>
<del class="font-size-20 ml-2 text-gray-6">$2,299.00</del>
</div>
</div>
#endsection
This is my route.
web.php
Route::get('/singleproducts', 'SingleProductController#index')->name('singleproducts');
Route::get('/singleproducts/{id}', 'SingleProductController#show')->name('eachproduct');
Why my show function is not working?
route.php
Route::get('/singleproducts', 'SingleProductController#index')->name('singleproducts');
Route::get('/eachproduct/{id}', 'SingleProductController#show')->name('eachproduct');
Product List Page
#if (isset($products) && count($products) > 0)
#foreach ($products as $product)
<div class="blog_box_inner" style="cursor: pointer;" >
<h1 class="blog_inner_heading">
<a href="/eachproduct/{{$product['id']}}" class="blog_readmore_link">
{{$product['prod_name']}}
</a>
</h1>
</div>
#endforeach
#endif
Single page
<h2 class="font-size-25 text-lh-1dot2">{{ $product['prod_name']}} </h2>
Controller
public function index() {
$products = Product::orderBy('id', 'DESC')->get();
return view('')->with(compact('products'));
}
public function show($id) {
$product = Product::find($id);
return view('')->with(compact('product'));
}
Hope fully it will help to you easily.
Use like this
return view('singleproducts',compact('product'));
In your view use like this
<h2 class="font-size-25 text-lh-1dot2">{{ $product->prod_name }} </h2>
<ins class="font-size-36 text-decoration-none">{{ $product->prod_price }}</ins>
Try this
public function show(Product $product)
{
return view ('singleproducts', compact('product'));
}
and pass in route
Route::get('/eachproduct/{product}', 'SingleProductController#show')->name('eachproduct');
and in your view page get product data as
singleproducts.blade
#extends('layouts.singleproducts')
#section('content')
<h2 class="font-size-25 text-lh-1dot2">{{ $product->prod_name }} </h2>
<div class="mb-4">
<div class="d-flex align-items-baseline">
<ins class="font-size-36 text-decoration-none">{{ $product->prod_price }}</ins>
<del class="font-size-20 ml-2 text-gray-6">$2,299.00</del>
</div>
</div>
#endsection
It will auto find your product on base of id.
I am quite new to laravel so this might be silly mistake but I just can't figure out why it gives me this error. Right so on my website users can create posts and other users can like those posts. However, my implementation of the like system throws the following error:
ErrorException (E_ERROR)
Method Illuminate\Database\Eloquent\Collection::likes does not exist. (View: C:\xampp\htdocs\eventcw\resources\views\eventspage.blade.php)
This is my post controller method in charge of the likes:
public function postLikePost($post_id){
$loggedin_user = Auth::user()->id;
$like_user = Like::where(['user_id' => $loggedin_user, 'post_id' => $post_id])->first();
if(empty($like_user->user_id)){
$user_id = Auth::user()->id;
$post_id = $post_id;
$like = new Like;
$like->user_id = $user_id;
$like->post_id = $post_id;
$like->save();
return redirect()->route('events');
}else{
return redirect()->route('events');
}
}
My database relations seem fine,
here is my Like model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Like extends Model
{
public function user(){
return $this->belongsTo('App\User');
}
public function post(){
return $this->belongsTo('App\Post');
}
}
Here is my likes table migration:
Schema::create('likes', function (Blueprint $table) {
$table->increments('id');
$table->integer('post_id');
$table->integer('user_id');
$table->timestamps();
});
Here is my post view:
<section class="row posts">
#foreach($posts as $post)
<div class="col-md-2 col-md-offset-3">
<article class="post">
<p>{{ $post->body }}</p>
<div class="info">Posted by {{ $post->user->first_name }} {{ $post->user->last_name }} on {{ $post->created_at }}</div>
<p>This post has {{ $posts->likes()->count() }} likes </p>
Like|
</article>
</div>
#endforeach
</section>
The error indicates you are calling likes() directly on a Collection.
$posts is the collection, which you are iterating over in your blade template.
Change {{ $posts->likes()->count() }} to {{ $post->likes()->count() }}
Right now I am trying to do a Laravel url with slug. I have my main page where I show all categories:
<div class="panel-body">
#foreach($categories as $category)
<p>{{ $category->name }}</p>
#endforeach
</div>
And now I want to go to a certain category page. I created routes:
Route::get('/test', 'FuelAccountingController#index')->name('fuel_accounting');
Route::get('/test/{slug}', 'FuelAccountingController#element');
And functions in controller:
public function index()
{
$categories = DB::table('fuel_accounting_categories')
->select('id', 'name', 'slug')
->get();
return view('pages.fuel_accounting')->with('categories', $categories);
}
public function element($slug)
{
$category = DB::table('fuel_accounting_categories')
->select('slug')
->where('slug', '=', $slug)
->first();
return view('pages.fuel_accounting_element')->with('category', $category);
}
And when I am trying to reach a page (for example: laravel.dev/test/current_category) it does not work. Can someone explain me how to do that?
Error: Sorry, the page you are looking for could not be found. (1/1) NotFoundHttpException
FIXED
<div class="panel-body">
#foreach($categories as $category)
<p>{{ $category->name }}</p>
#endforeach
</div>