Showing slug instead of id for crud in Laravel 8 - laravel

im making an edit section on my laravel crud project. that when i press edit, it will redirect to the edit.blade.php which will call the slug instead their id. i have worked on it and it shows the error that Too few arguments to function App\Http\Controllers\ProductController::edit(), 1 passed and exactly 2 expected
my Route
Route::get('edit/{slug}', $url. '\productController#update');
Route::get('edit', $url. '\productController#edit');
my ProductController::edit()
public function edit(Product $product, $slug)
{
return view('edit', compact('product'));
}
my ProductController::update()
public function update(Request $request, Product $product, $slug)
{
Product::where('product_slug',$request->$slug)->update([
'product_title' => $request->title,
'product_slug' => $request->slug,
'product_image' => $request->image
]);
// redirect
return redirect('edit');
}
any helps would be greatly appreciated,thanks in advance

You do not need to worry about anything. Just add below code to your Product model:
public function getRouteKeyName()
{
return 'slug';
}
and Laravel will take care of the rest. For more information, visit below link, they have a very good explanation there:
https://laravel.com/docs/8.x/routing#customizing-the-default-key-name

You're getting this error because you have 2 parameters in your methods: Product $product and $slug. To solve this error you should remove one of them.
You also need to add slug parameter to your edit route in order to access it in your controller. And your update route should be PUT or PATCH.
Something like this:
Route::get('products/{slug}/edit', [ProductController::class, 'edit'])
Route::patch('products/{slug}', [ProductController::class, 'update'])
So, you can either remove the Product $product and use the $slug to get the product:
public function edit($slug)
{
$product = Product::where('product_slug', $slug);
return view('edit', compact('product'));
}
public function update(Request $request, $slug)
{
Product::where('product_slug', $slug)->update([
'product_title' => $request->title,
'product_slug' => $request->slug,
'product_image' => $request->image
]);
// redirect
return redirect('edit');
}
Or you can remove the $slug and use the Product $product by setting slug as your route key and changing the route param to product.
// Product model
public function getRouteKeyName()
{
return 'slug'
}
// Product controller
public function edit(Product $product)
{
return view('edit', compact('product'));
}
public function update(Request $request, Product $product)
{
$product->update([
'product_title' => $request->title,
'product_slug' => $request->slug,
'product_image' => $request->image
]);
// redirect
return redirect('edit');
}
// Route
Route::get('products/{product}/edit', [ProductController::class, 'edit'])
Route::patch('products/{product}', [ProductController::class, 'update'])

pass id in your edit button instead of slug
<a href="{{url('edit/'$id'')}}" class="btn btn-info btn-sm" />Edit</a>
and change your update function
public function update(Request $request, Product $product, $id)
{
Product::where('id_column_name', $id)->update([
'product_title' => $request->title,
'product_slug' => $request->slug,
'product_image' => $request->image
]);
// redirect
return redirect('edit');
}

Related

Can't pass Request from controller to another controller's view

I'm trying to pass a Request from a controller, but for reasons I don't understand the data simply isn't being passed through to the view and I get Undefined variable: request. I have confirmed that right up until the redirect to the action the request is populated with all the additional variables, so the issue must be after that.
ManufacturerController
public function decode(Manufacturer $manufacturer, Request $request) {
$validated = $request->validate([
"id" => ["required","min:5","max:30", "alpha_num"],
"email" => ["email","required","max:255"]
]);
$request->merge([
"manufacturer" => $manufacturer
]);
// Pass the Request to the Manufacturer model and return a modified version of it
$request = $manufacturer->oneplus($request);
return redirect()->action([TransactionController::class, "index"])->with($request);
}
abort(404);
}
Manufacturer model:
public function oneplus($request) {
$id = $request->id;
/* BUSINESS LOGIC THAT GENERATES $new FROM $id... */
$request->merge([
'new' => $new
]);
return $request;
}
Route in web.php
Route::get('/payment', [TransactionController::class, "index"]);
TransactionController:
public function index()
{
return view('payment');
}
payment.blade.php
{{ dd($request->new) }}
The problem when using redirects is that the redirect will cause a brand new request to happen. When using redirect()->with('variable', 'value') you need to then access that variable using:
session('variable')`
the reason being that the variable is "flashed" to the next request via the session (in practice it's not sent to the next request, it's just available for the next request through the session and then disappears).
While this may be an easy solution to your problem a better solution is to not use a redirect if possible. Here's a simplification of an alternative:
ManufacturerController:
public function decode(Manufacturer $manufacturer, Request $request) {
$validated = $request->validate([
"id" => ["required","min:5","max:30", "alpha_num"],
"email" => ["email","required","max:255"]
]);
$request->merge([
"manufacturer" => $manufacturer
]);
// Pass the Request to the Manufacturer model and return a modified version of it
$request = $manufacturer->oneplus($request);
$transactionController = app()->make(TransactionController::class);
return $transactionController->index($request);
}
TransactionController:
public function index(Request $request)
{
return view('payment')->with("request", $request);
}
This will call the other controller method within the same request.
You need to make few changes in TransactionController and ManufacturerController to make it work
TransactionController:
public function index(Request $request)
{
return view('payment', [
'request' => $request->session()->get('request')
]);
}
ManufacturerController:
public function decode(Manufacturer $manufacturer, Request $request) {
$validated = $request->validate([
"id" => ["required","min:5","max:30", "alpha_num"],
"email" => ["email","required","max:255"]
]);
$request->merge([
"manufacturer" => $manufacturer
]);
// Pass the Request to the Manufacturer model and return a modified version of it
$request = $manufacturer->oneplus($request);
return redirect()->action([TransactionController::class, "index"])->with('request', $request->all());
}
abort(404);
}
You can pass like this
ManufacturerController :
return redirect()->action(
[TransactionController::class, "index"],
['data' => $request]
);
Route in web.php
// ? = Optional
Route::get('/payment/{data?}', [TransactionController::class, "index"]);
TransactionController:
public function index($data)
{
return view('payment');
}

Problem with "Route" resource in laravel 8

My app was working fine until I wanted to replace my "get" routes with a single "resource" to be able to include a delete function. I remind you that I am a beginner in laravel so it is surely due to the fact that I can not be able to make a "resource" route.
This is my code :
Route::get('/', function(){
return view('front.pages.homepage');
})->name('homepage');
Route::get('/garages', [GarageController::class, 'index'])->name('garage.index');
Route::get('/garages/{garage}', [GarageController::class, 'show'])->name('garage.show');
Route::get('/garages_create', [GarageController::class, 'create'])->name('garage.create');
Route::post('/garages_create', [GarageController::class, 'garage_create'])->name('garage_create');
Route::resource('cars', [CarController::class]);
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Car;
use App\Models\Garage;
class CarController extends Controller
{
public function index()
{
$list = Car::paginate(10);
return view('cars', [
'list' => $list
]);
}
public function store()
{
$garages = Garage::orderBy('name')->get();
return view('carCreate/carCreate', [
'garages' => $garages,
]);
}
public function create(Request $request)
{
{
$request->validate([
'name' => 'required',
'release_year' => 'required',
'garage_id' => 'required', 'exists:garage_id'
]);
$car = new Car();
$car->name = $request->name;
$car->release_year = $request->release_year;
$car->garage_id = $request->garage_id;
$car->save();
return redirect('/cars');
}
}
public function show(Car $car)
{
return view('carShow/carShow', compact('car'));
}
public function edit($id)
{
//
}
public function update(Request $request, $id)
{
//
}
public function destroy($id)
{
//
}
}
And my error is : ErrorException
Array to string conversion

Method SendMoneyController::index does not exist

I am using Laravel 8, and my application is working fine locally. Now I upload the app to a dedicated server and I'm getting the error below:
BadMethodCallException Method
App\Http\Controllers\User\SendMoneyController::index does not exist.
However, this method exists and it's working fine on the local server.
Controller
class SendMoneyController extends Controller
{
use AmlRulesVerification;
protected $sendMoneyInterface, $transactionInterface, $recipientInterface, $cardInterface, $homeInterface;
public function __construct(
SendMoneyInterface $sendMoneyInterface,
TransactionInterface $transactionInterface,
RecipientInterface $recipientInterface,
CardInterface $cardInterface,
HomeInterface $homeInterface
) {
$this->sendMoneyInterface = $sendMoneyInterface;
$this->transactionInterface = $transactionInterface;
$this->recipientInterface = $recipientInterface;
$this->cardInterface = $cardInterface;
$this->homeInterface = $homeInterface;
}
public function index(Request $request, $id = null)
{
$transaction = $this->sendMoneyInterface->getTransaction($request, $id);
if (isset($transaction['transaction']->card) && $transaction['transaction']->card) {
return redirect()->route('send.money.confirmation', ['id' => $id]);
}
return view('customers.send_money.index',
[
'data' => $transaction,
'countries' => $this->homeInterface->landingViewData($request)
]);
}
}
web.php
Route::group(['middleware'=>'languageSwitcher'],function () {
Auth::routes(['verify' => true]);
Route::get('/', [HomeController::class, 'landingView'])->name('landing.view');
Route::get('users/registration', [UserController::class, 'showRegisterForm'])->name('user.registration');
Route::get('localization/change/language', [LanguageSwitcher::class, 'changeLanguage'])->name('LangChange');
Route::post('/set/email/session', [UserController::class, 'setEmailInSession']);
Route::group(['middleware'=>'auth'],function () {
Route::get('/home', [HomeController::class, 'index'])->name('home');
Route::get('/send/money', [UserSendMoneyController::class, 'index'])->name('send.money.index');
)};
)};
Please Verify the namespace in the UserSendMoneyController
Route::get('/send/money', [User\UserSendMoneyController::class, 'index'])->name('send.money.index');
try these changes if commented this line then uncomment too In "app\provider\RouteServiceProvider"
protected $namespace = 'App\\Http\\Controllers';
Why are you using a variable whose value you have already set to null?
public function index(Request $request)
{
$transaction = $this->sendMoneyInterface->getTransaction($request);
if (isset($transaction['transaction']->card) && $transaction['transaction']->card) {
return redirect()->route('send.money.confirmation');
}
return view('customers.send_money.index',
[
'data' => $transaction,
'countries' => $this->homeInterface->landingViewData($request)
]);
}

Lavarel & Vue e-commerce: how to post an order as array of products instead of single product

I am kinda new to both Laravel and Vue and I am working on a school project. I have been following a guide and trying to develop the product but I have the following problem: in the guide was only possible to do an order with a single product. Using LocalStorage a created a Cart component where you can add several products instead. How do I use axios.post to correctly post the order in the database now?
app/Http/Controllers/OrderController.php:
<?php
namespace App\Http\Controllers;
use App\Models\Order;
use Auth;
use Illuminate\Http\Request;
class OrderController extends Controller
{
public function index()
{
return response()->json(Order::with(['product'])->get(),200);
}
public function store(Request $request)
{
$order = Order::create([
'product_id' => $request->product_id,
'user_id' => Auth::id(),
'quantity' => $request->quantity,
'address' => $request->address
]);
return response()->json([
'status' => (bool) $order,
'data' => $order,
'message' => $order ? 'Order Created!' : 'Error Creating Order'
]);
}
public function show(Order $order)
{
return response()->json($order,200);
}
Resources/JS/views/Checkout.vue (between < script > tag):
placeOrder(e) {
e.preventDefault()
let address = this.address
let product_id = this.product.id
let quantity = this.quantity
axios.post('api/orders/', {address, quantity, product_id})
.then(response => this.$router.push('/confirmation'))
},
App/Http/Models/Order.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Order extends Model
{
use SoftDeletes;
protected $fillable = [
'product_id', 'user_id', 'quantity', 'address'
];
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
public function product()
{
return $this->belongsTo(Product::class, 'product_id');
}
}
Actually, You can achieve your goal by changing many lines of code instead of using your current code at backend (laravel Model-Controller) and frontend (Vue). I will show you how to do by adding hasMany relationship in your User model structure, then changing saving method at controller, and axios request payload. This method has limitation, you have to post an array of products of the same user ID.
Add hasMany relationship in your User Model. Read this
class User extends Model
{
//add this line
public function order()
{
return $this->hasMany(Order::class);
}
Use createMany function to save multiple rows in your controller. Read this
public function store(Request $request)
{
//use this lines to store array of orders
$user = Auth::user();
$orderStored = $user->order()->createMany($request->data);
//return your response after this line
}
Change your axios payload from vue method
data(){
return {
//add new key data to store array of order
arrayOfOrders:[];
};
},
methods:{
placeOrder(e) {
e.preventDefault()
let address = this.address
let product_id = this.product.id
let quantity = this.quantity
//remark these lines, change with storing to arrayOfOrders data instead of doing post request
//axios.post('api/orders/', {address, quantity, product_id})
//.then(response => this.$router.push('/confirmation'))
this.arrayOfOrders.push({
product_id:product_id,
quantity:quantity,
address:address
});
},
//create new function to make post request and call it from your button
postData(){
let instance = this;
axios.post('api/orders/', {
data:instance.arrayOfOrders
}).then(response => this.$router.push('/confirmation'))
}
}
Thank you for your answer! Just one thing is not so clear.. in my OrderController.php should the final code look something like this?
public function store(Request $request)
{
$user = Auth::user();
$order = $user->order()->createMany([
'product_id' => $request->product_id,
'user_id' => Auth::id(),
'quantity' => $request->quantity,
'address' => $request->address
]);
return response()->json([
'status' => (bool) $order,``
'data' => $order,
'message' => $order ? 'Order Created!' : 'Error Creating Order'
]);
}

Getting all posts from a user

I'm really new to Laravel and ran it some problems. I have a /user/USERNAME view, which obviously, shows the users profile. But now I want to get ALL posts the user posted to be shown on his profile.
My web.php
Route::group(['middleware' => 'auth'], function() {
Route::any('/user/{username}', [
'as' => 'user',
'uses' => 'UserController#view_user'
]);
});
My User model
public function posts() {
return $this->hasMany(Post::class);
}
My Post model
public function user() {
return $this->belongsTo(User::class);
}
My UserController
public function view_user($username = null) {
$user = null;
$user = User::where('name', $username)->firstOrFail();
$posts = Post::where('creator', $username)->get();
return view('/user', [
'user' => $user,
'posts' => $posts
]);
}
public function index() {
$posts = Post::all();
return view('user', compact('posts'));
}
When I'm trying to get the posts with for example {{ $posts->title }} it gives me: Property [title] does not exist on this collection instance.
How am I supposed to do this the correct way?
$posts returns a collection, so in order to retrieve the title of a post you need to loop through the single items of the collection. Then you can use $post->title.

Resources