I have multiple routes with route model binding that direct users from Shop > Category > Product. The route links are working fine.
But if a user adds a garbage value to the URL, Laravel does not throw 404 error. How can force 404 error if a user adds any extra character to URL?
Route
Route::get('/{shop_url}/{category_url}/{product_url}/buy', 'Controller#buy')->name('buy')->where(['shop_url', 'category_url', 'product_url' => '[\w\d\-]+(.*)']);
Route::get('/{shop_url}/{category_url}', 'Controller#view')->name('view')->where(['shop_url','category_url' => '[\w\d\-]+(.*)']);
Route::get('/{shop_url}', 'Controller#shop')->name('shop')->where('shop_url', '[\w\d\-]+(.*)');
Controller
public function shop($shop_url)
{
$shop = Shop::where('shop_url', $shop_url)->firstorfail();
return view ('shop', compact('shop'));
}
public function view($shop_url, $category_url)
{
$shop = Shop::where('shop_url', $shop_url)->firstorfail();
$category= Category::firstorfail();
return view ('shop', compact('shop', 'category'));
}
public function buy($shop_url, $category_url, $product_url)
{
$shop = Shop::where('shop_url', $shop_url)->firstorfail();
$category= Category::where('category_url', $category_url)->firstorfail();
$product = Product::firstorfail();
return view ('shop', compact('shop', 'category', 'product'));
}
Here domain.com/shop-ca/clothing works and if user types domain.com/shop-ca/clothes, it also displays the same page. Here I want it to display 404. How would I do that?
First of all, you should check your slug, in your code I see these lines:
$category= Category::firstorfail();// it will get the first route in the database, not the needed category
So, first, try to do this:
public function view($shop_url, $category_url)
{
$shop = Shop::where('shop_url', $shop_url)->firstOrfail();
$category= Category::where('category_url', $category_url)->firstOrfail();// I actually don't know the name of your slug field, but if the category is wrong, laravel will return 404 page.
return view ('shop', compact('shop', 'category'));
}
You have check $product_url in your buy function and through 404 error manually.
Related
I am trying to change the url of my article page so instead of showing the article id I'd like to show the article title.
Currently the URL is as follows;
https://www.example.com/posts/post/32
Where 32 is just a random article id.
Instead I like it to display as follows;
https://www.example.com/posts/post/my-amazing-article
Now I have looked in the laravel documentation and different posts on stackoverflow and tried a bunch of stuff but I'm obviously making a mistake somewhere cus nothing seems to work so im pretty much back where I started.
Blade
Route
Route::get('/posts/post/{id}', [App\Http\Controllers\WelcomeController::class, 'post'])->name('post');
Controller
public function post(request $request){
$id = $request->id;
$article = Tinymce::find($id);
return view('/post')->with('articles, $articles');
}
Now the articles, which are saved in Tinymce, are actually created on a different controller on subdomain.
public function tinymce(Request $request)
{
if(request()->ajax())
{
if($request->article_id == null)
{
$tinymce = new Tinymce;
}else{
$tinymce = Tinymce::find($request->article_id);
}
$tinymce->description = $request->description;
$tinymce->content = $request->myContent;
$tinymce->title = $request->title;
$tinymce->author = $request->author;
$tinymce->publish = $request->publish;
$title = $tinymce->title;
$slug = Str::slug($title, "-");
$tinymce->slug = $slug;
$tinymce->save();
return $tinymce->id;
}
}
As you can see I've turned the title into a slug as I read somewhere that's the way to go to use custom url but I didn't get very far with it.
Any help would be greatly appreciated, thank you.
Explanation:
First, As you said you stored slug into your database. so, that's good.
From Controller to View, you can get that slug into post object.
Blade View : (you have to pass slug in route url)
Route : (make id to slug)
Route::get('/posts/post/{slug}', [App\Http\Controllers\WelcomeController::class, 'post'])->name('post');
Controller : (now you can get slug from the second parameter)
public function post(request $request, $slug = ''){
$article = Tinymce::where('slug', $slug)->first();
return view('/post', compact('article'));
}
Now, you can use access custom URLs using slug.
I Hope, it helps you. #assiemp
I don't know if I correctly formulated the question. However, I've got 2 tables - products and categories (many to many relationship) and in categories page I want to display it's products with pagination if it has any and if it doesn't - I want to display "products not found". It worked, but without pagination.
Here's the controller:
public function show($slug)
{
$category = $this->categoryRepository->findBySlug($slug);
$paginate = $category->products()->paginate(6);
return view('site.pages.category')->with(['category' => $category,
'paginate' => $paginate]);
}
What to do achieve this?
Wrap it around an if statement like if(isset($your_variable) && !empty($your_variable)){ You may only need isset OR !empty, but you can mess around and see what works. Hope that helps!
I modified the controller like this:
public function show($slug)
{
$category = $this->categoryRepository->findBySlug($slug);
$products = $category->products();
if(isset($products) && !empty($products)){
$paginate = $products->paginate(6);
return view('site.pages.category')->with(['category' => $category,
'paginate' => $paginate]);
}
else {
return view('site.pages.category', compact('category'));
}
}
However, now I get this: Call to a member function products() on null..
Try this code below. I am not a Laravel Developer but just looked at some docs and writing this answer.
You are getting Call to a member function products() on null error, because $category is null (Not have any data). So you should check whether the $category have any data before calling products().
And you can check whether the products is empty or not in blade template and print the message accordingly. No need to render another template for that.
public function show($slug)
{
$category = $this->categoryRepository->findBySlug($slug);
if ($category) {
$products = $category->products()->paginate(6);
}
return view('site.pages.category')->with(['products' => $products]);
}
And in your Blade Template, check the $products is not empty,
#if ($products)
#foreach ($products as $product)
{{ $product->name}}
#endforeach
{{ $products->links() }}
#else
products not found
#endif
And obviously, change the template to your needs.
Currently I'm working on a project where I made it so that when a user types a correct password in form field, it will give them the items from the given section.
The main problem i'm having is that to do this I need to capture the request and therefore the route has to be a post method instead of a get as such:
public function index(Request $request)
{
$id = $request->input('id');
$password = $request->input('password');
$result = DB::table('scrumboards')->find($id);
if ($result->key == $password) {
$scrumboard = $result;
$items = DB::table('backlogs')->get();
return view('scrumboard', ['items' => $items, 'scrumboard' => $scrumboard]);
} else {
$scrumboard = $result;
return redirect('home');
}
}
and the route as such:
Route::post('/scrumboard', 'ScrumboardController#index');
By doing this, request errors wont work since It wants to redirect back but can't since this is a post method.
Any way I can avoid this clash?
Routes can have multiple HTTP verbs. Define your route as
Route::match(['get', 'post'], '/scrumboard', 'ScrumboardController#index');
to make it available as GET and POST route.
For example, I have this route in my web.php :-
Route::get('products/{product}/owners', 'ProductController#showOwners');
When I try to add new 'Owner' to the product, I have to do it in the parent URL, like this :-
Route::post('products/storeOwner', 'ProductController#storeOwner');
And then I pass the product ID in a hidden field in the form, because the post request doesn't accept URL parameters. So is there anyway to do it like below ?
Route::post('products/{product}/storeOwner', 'ProductController#storeOwner');
So the POST request will be sent inside the particular 'product' URL?
UPDATE
/* ProductController Class */
public function storeOwner (AddProductOwner $request)
{
$product= Product::find($request->product);
$user = Auth::user();
if ( $user->ownerOf($product)) {
// Check if the current user is already one of the owners).
// If the current user is the owner then return to the product
// This line is not executed because in (products/show.blade.php) we have set a condition.
return redirect('products/' . $request->product);
}
$join = new Join;
$join->role = $request->join_role;
$join->product()->associate($request->product);
$join->user()->associate(Auth::user());
$join->message = $request->message;
$join->save();
// TODO: we have to make this with ajax instead of normal form
return redirect('products/'. $request->product);
}
I hope my question is clear enough..
Yes you can do as you mentioned in your last route
Route::post('products/{product}/storeOwner', 'ProductController#storeOwner');
And then get the product Id in your functions argument
public function storeOwner (AddProductOwner $request, $productId)
{
dd($productId); // TRY THIS OUT. CHECK THE 2nd ARGUMENT I SET.
$product= Product::find($productId); // PASS THE VERIABLE HERE.
$user = Auth::user();
if ( $user->ownerOf($product)) {
// Check if the current user is already one of the owners).
// If the current user is the owner then return to the product
// This line is not executed because in (products/show.blade.php) we have set a condition.
return redirect('products/' . $request->product);
}
$join = new Join;
$join->role = $request->join_role;
$join->product()->associate($request->product);
$join->user()->associate(Auth::user());
$join->message = $request->message;
$join->save();
// TODO: we have to make this with ajax instead of normal form
return redirect('products/'. $request->product);
}
You can send URL parameters to a POST request. Just make sure in your form you are sending the wildcard.
<form action="/products/{{ $productid }}/storeOwner" method="POST">
In your routes
Route::post('products/{productid}/storeOwner', 'ProductController#storeOwner');
In your controller, use it
public function storeOwner($productid)
{
dd($productid);
}
I want to pass multiple parameters from route to controller in laravel5.
ie,My route is ,
Route::get('quotations/pdf/{id}/{is_print}', 'QuotationController#generatePDF');
and My controller is,
public function generatePDF($id, $is_print = false) {
$data = array(
'invoice' => Invoice::findOrFail($id),
'company' => Company::firstOrFail()
);
$html = view('pdf_view.invoice', $data)->render();
if ($is_print) {
return $this->pdf->load($html)->show();
}
$this->pdf->filename($data['invoice']->invoice_number . ".pdf");
return $this->pdf->load($html)->download();
}
If user want to download PDF, the URL will be like this,
/invoices/pdf/26
If user want to print the PDF,the URL will be like this,
/invoices/pdf/26/print or /invoices/print/26
How it is possibly in laravel5?
First, the url in your route or in your example is invalid, in one place you use quotations and in the other invoices
Usually you don't want to duplicate urls to the same action but if you really need it, you need to create extra route:
Route::get('invoices/print/{id}', 'QuotationController#generatePDF2');
and add new method in your controller
public function generatePDF2($id) {
return $this->generatePDF($id, true);
}