show name instead of id in a url using laravel routing - laravel

I have defined a route in laravel 4 that looks like so :
Route::get('/books/{id}', 'HomeController#showBook');
in the url It shows /books/1 for example , now i'm asking is there a way to show the name of the book instead but to keep also the id as a parameter in the route for SEO purposes
thanks in advance

You could also do something like this:
Route::get('books/{name}', function($name){
$url = explode("-", $name);
$id = $url[0];
return "Book #$id";
});
So you can get book by id if you pass an url like: http://website.url/books/1-book-name

if your using laravel 8, this may be helpfull.
In your Controller add this
public function show(Blog $blog)
{
return view('dashboard.Blog.show',compact('blog'));
}
In your web.php add this
Route::get('blog/{blog}', [\App\Http\Controllers\BlogController::class,'show'])->name('show');
Then add this to your model (am using Blog as my Model)
public function getRouteKeyName()
{
return 'title'; // db column name you would like to appear in the url.
}
Note: Please let your column name be unique(good practice).
Result: http://127.0.0.1:8000/blog/HelloWorld .....url for a single blog
So no more http://127.0.0.1:8000/blog/1
You are welcome.

You can add as many parameters to the url as you like, like this:
Route::get('/books/{id}/{name}', 'HomeController#showBook');
Now when you want to create an url to this page you can do the following:
URL::action('HomeController#showBook', ['id' => 1, 'name' => 'My awesome book']);
Update:
If you are certain that there will never be two books with the same title, you can just use the name of the book in the url. You just need to do this:
Route::get('/books/{name}', 'HomeControllers#showBook');
In your showBook function you need to get the book from the database using the name instead of the id. I do strongly encourage to use both the id and the name though because otherwise you can get in trouble because I don't think the book name will always be unique.

You can also use model binding check more on laravel docs
For example
Route::get('book/{book:name}',[BookController::class,'getBook'])->name('book');
The name attribute in "book/{book:name}" should be unique.

Related

Laravel route difference between {id} vs {tag}

I am new in Laravel pardon me if question is silly. I have seen a doc where they used
For get request
Route::get("tags/{id}","TagsController#show");
For put request
Route::put("tags/{tag}","TagsController#update");
What is the difference and benefit between this ? I understood 1st one, confusion on put route.
There’s no real difference as it’s just a parameter name, but you’d need some way to differential parameters if you had more than one in a route, i.e. a nested resource controller:
Route::get('articles/{article}/comments/{comment}', 'ArticleCommentController#show');
Obviously you couldn’t use just {id} for both the article and comment parameters. For this reason, it’s best to use the “slug” version of a model for a parameter name, even if there’s just one in your route:
Route::get('articles/{article}', 'ArticleController#show');
You can also use route model binding. If you add a type-hint to your controller action for the parameter name, Laravel will attempt to look up an instance of the given class with the primary key in the URL.
Given the route in the second code example, if you had a controller that looked like this…
class ArticleController extends Controller
{
public function show(Article $article)
{
//
}
}
…and you requested /articles/123, then Laravel would attempt to look for an Article instance with the primary key of 123.
Route model binding is great as it removes a lot of find / findOrFail method calls in your controller. In most instances, you can reduce your controller actions to be one-liners:
class ArticleController extends Controller
{
public function show(Article $article)
{
return view('article.show', compact('article'));
}
}
Generally there's no practical difference unless you define a custom binding for a route parameter. Typically these bindings are defined in RouteServiceProvider as shown in the example in the docs
public function boot()
{
parent::boot();
Route::model('tag', App\Tag::class);
}
When you bind tag this way then your controller action can use the variable via model resultion:
public function update(Tag $tag) {
// $tag is resolved based on the identifier passed in the url
}
Usually models are automatically bound so doing it manually doesn't really need to be done however you can customise resolution logic if you do it manually
Normal way
Route::get("tags/{id}","TagsController#show");
function($id)
{
$tag = Tag::find($id);
dd($tag); // tag
}
With route model bindings
Route::put("tags/{tag}","TagsController#update");
function(Tag $tag) // Tag model binding
{
dd($tag); // tags
}
ref link https://laravel.com/docs/5.8/routing#implicit-binding
It's just a convention. You can call it all you want. Usually, and {id} refers to the id in your table. A tag, or similarly, a slug, is a string value. A tag could be 'entertainment' for video categories, while 'my-trip-to-spain' is a slug for the description of a video.
You have to chose the words what you are comfortable with. The value will be used to find in your database what record is needed to show the correct request in the view. Likewise you can use video/view/{id}/{slug} or any combination thereof.
Just make sure your URLs don't get too long. Because search engines won't show your website nicely in search results if you do. Find the balance between the unambiguous (for your database) and logic (for your visitors).
Check this out: Route model bindings
Use id, Laravel will get the id from route, and it will be the tag's id, it is integer.
function show($id) {
$tag = Tag::find($id);
}
Use tag, Laravel automatically resolves Eloquent models defined in routes or controller actions whose type-hinted variable names match a route segment name.
In URL, your tag parameter is integer, however in your controller action $tag will be a model object:
function action(Tag $tag) {
$tag->name;
}
So you don't need to get the $tag by eloquent in your controller action. You just need to specify it is From model Tag $tag
It will do it automatically.

Laravel routing access category and show method

To display the blog list i have using the following route
// Blog List
Route::name('blog')->get('blog', 'Front\BlogController#index');
Ex: http://www.mypropstore.com/blog/
To display the blog category,
Route::name('category')->get('blog/{category}', 'Front\PostController#category');
Ex: http://www.mypropstore.com/blog/buy-sell
To display the blog details, comments and tag details, we have using "posts" middleware
// Posts and comments
Route::prefix('posts')->namespace('Front')->group(function () {
Route::name('posts.display')->get('{slug}', 'PostController#show');
Route::name('posts.tag')->get('tag/{tag}', 'PostController#tag');
Route::name('posts.search')->get('', 'PostController#search');
Route::name('posts.comments.store')->post('{post}/comments', 'CommentController#store');
Route::name('posts.comments.comments.store')->post('{post}/comments/{comment}/comments', 'CommentController#store');
Route::name('posts.comments')->get('{post}/comments/{page}', 'CommentController#comments');
});
Ex: http://www.mypropstore.com/posts/apartment-vs-villa-which-is-the-right-choice-for-you
Now i want to change the blog details url page to
http://www.mypropstore.com/blog/apartment-vs-villa-which-is-the-right-choice-for-you-{{blogid}}
Ex: http://www.mypropstore.com/blog/apartment-vs-villa-which-is-the-right-choice-for-you-54
If i change that above format, it conflict category page. Any body knows how to set the routing for blog details page(middleware "posts")
Assuming the blogid part, at the end of your suggested route...
http://www.mypropstore.com/blog/apartment-vs-villa-which-is-the-right-choice-for-you-{{blogid}}
...is numeric, you could do something like this:
For your route definition for your post details page, use the following:
Route::name('posts.display')
->get('blog/{slug}-{id}', 'PostController#show')
->where('id', '[0-9]+');
What this does is ensures that this route is only matched by paths that follow the pattern blog/{slug}-{id} but constrains that the id part of your route must be numeric i.e. consist only of one or more numbers.
You will need to ensure that this route appears before the one matching your category route or else the category route will take precedence.
Your controller should have a show method like this:
class PostController extends Controller
{
public function show($slug, $id)
{
// $id will contain the number at the end of the route
// $slug will contain the slug before the number (without the hyphen)
// You should be able to do this to get your post.
$post = Post::findOrFail($id);
dd($post);
}
}
Since your categories aren't numbers you could solve the conflict specifying that id will always be a number like this:
Route::get('/blog/{id}', 'BlogController#show')->where('id', '[0-9]+');

Want to show name instead of id in the URL field in Laravel

I don't want to show /route_name/{id} in the URL field of my Laravel project. Instead of that I want to show /route_name/{name} but pass the id in the back-end to the controller.
Suppose I have a route named departments and pass an id 3 named knee_pain as a parameter. And it is like /departments/3
But I want to to show /departments/knee_pain in my url and as well as want to pass the id 3 in my controller without showing the id in the url.
How to do that ?
In your model you can use the getRouteKeyName method to bind to another attribute than the default id in your routes :
public function getRouteKeyName()
{
return 'slug'; // Default is 'id'.
}
Rather than using the name attribute, that you could use elsewhere in your application for displaying the name of the entry, I recommend using an attribute made url friendly. You could use Str::slug() for that.
public function setNameAttribute($value) {
$this->name = $value;
$this->slug = \Str::slug($value);
}
It will 'slugify' your string, for example : \Str::slug('Knee pain') => 'knee-pain'.
Note : in Laravel 5.5, use the str_slug() helper.
You should also make sure this string is unique in your database.
First you have to garantee that the name is unique, if don't you will have more than one Id in your controller. For that i recommend you to use Purifier to remove spaces and make it URL friendly:
Purifier
Second, probably the best way to have clean controllers is creating a middleware that understand what kind of name is (what table should middleware look for). You can validate that by route name and send the correct id to controller.
Middleware docs

how can i use url encode Laravel 5.2

i am working in a project and want use the name of a post as URL, then i did this:
Routes.php
Route::get('/{nombre}',['as' => 'noticias.show', 'uses' => 'NoticiasController#show'])->where('nombre', '[A-Za-z0-9-_]+');
and i did this:
Contoller.php
public function show($nombre)
{
$Noticia = Noticias::where('nombre', $nombre)->first();
$Categorias = categoriasn::CategoriaN();
if(!$Noticia){
return 'No exite ninguna noticia';
}
return view('noticias.noticia')->with(compact('Noticia'))->with(compact('Categorias'));
}
this is the way i use to call a post, using name, but for example if the post has a space the url show me `%20, and no display the post.
if someone can help will be awesome.
Thank you so much.
Hint
Instead of passing post name of every post, you may use post-slug.
You can add a extra column on database posts table called post-slug.
Prepare every post name to post-slug by removing space and a replace dash(-) while saving post.

Laravel routing - shorten the urls upto only one URI segment.

It is said that shorter the URL, better the seo (atleast my client believes on it).
Now am creating website similar to watchtown.co.uk in laravel. I need to generate in such a way that the uri should not be more than one segment.
Requirement
I have following urls:
1.Need to change From:
localhost/laravelproj/public/brands/brandname/watches
to
localhost/laravelproj/public/brandname-watches.html
2.Need to change From:
localhost/laravelproj/public/brands/brandname/jewellery
to
localhost/laravelproj/public/brandname-jewellery.html
3.Need to change From:
localhost/laravelproj/public/categories/categoryname/watches
to
localhost/laravelproj/public/categoryname-watches.html
4.Need to change From:
localhost/laravelproj/public/categories/categoryname/jewellery
to
localhost/laravelproj/public/categoryname-jewellery.html
5.Need to change From:
localhost/laravelproj/public/products/productname
to
localhost/laravelproj/public/productname-watches.html
I hope you understood the pattern .
I can see watchtown.co.uk has done exactly the same (or is it any other way ?)
I created this function in controller for brands:
public function showProductListingByBrands($brandSlug) {
$brand = Brand::findBySlug($brandSlug)->first();
$products = "";
if($brand){
$products = $brand->products()->paginate(Misc::getSetting('paginate'));
}
$products = Product::findBySlug($brandSlug);
return View::make('store');
}
Now how do i manipulate it as my requirement? Im really new in laravel.
Thanks in advance.
Just to give you a brief idea.
On your route page
Route::get('/{product_name}/', array(
'as' => 'product_page',
'uses' => 'ProductPage#getProduct'
));
As you see when the user goes to the page like
Example: www.website.com/watch
it will go to the controller ProductPage with the method of getProduct, so the variable {product_name} will be passed on the controller.
Controller
public function getProduct($product_name = false) {
$product = Products::where('product_name', '=', $product_name);
// Do check product existing record
if ($product->count() == 0) {
return Redirect::route('some-page-error')
->with('failure', 'The hell are you doing?');
} else {
$product = $product->first();
return View::make('product_page')
->with('product_name', $product);
}
}
So on method getProduct, the parameter $product_name is watch
So, the method will check if the product exists or not, if not the user will be redirected to 404 page.
If not, it will be redirected to the template that you've made then pass all the product data and display it all there.
But it would be nice if you put the Route into /product/{product_name}, also it would be also good if it's product id instead of product name since product name can get redundant.
So yea.
edits
I don't know what you're trying to do and why it must be .html, but mmm.. Just wanna give you an idea. Well I don't know if my answer is a good way, someone might give better answer than me.

Resources