How can I change the URL in laravel - laravel

I have a blog list. When I click on a blog I want to make the URL as the blog name like : www.domain.com/blog/my-blog-name.
In my blog list I have the link as blog/blogid(2/3/4) ex : www.domain.com/blog/1
When someone visit www.domain.com/blog/1 then the URL should be www.domain.com/blog/my-blog-name { the blog name will change as per the blog Id }
I did so many research on this but no luck. It would be great if anyone help me to get out of this.
I am using laravel 5.4. I am new to laravel also.

You need to create a slug field in your database and you will find a post using slug instead of id
Define route:
Route::get('post/{slug}', 'PostsControler#findBySlug');
Example http://example.com/post/my-awesome-blog-post
and in your controller
//PostsController.php
public function findBySlug($slug)
{
$post = Post::where('slug', $slug)->firstOrFail();
// return view
}
I suggest you use Eloquent-Sluggable to auto create slug value from your title field
$post = new Post([
'title' => 'My Awesome Blog Post',
]);
$post->save();
// $post->slug is "my-awesome-blog-post"

You can create a unique slug or name for your blog , but since names can be duplicate and for the user it is difficult to manually create a unique slug, then I would advise you to do so
Route::get('/blog/{id}/{name}', 'BlogController#show');
this it will look nice in url, as here for example in stackoverflow!

You can just override the function getRouteKeyName
public function getRouteKeyName()
{
return 'slug';
}

Try with following one!
In your routes file:
Route::get('blog/{slug}', 'BlogController#show'); // make sure not conflict with resource routes define
And then your BlogController:
public function show($slug)
{
$id = explode($slug, '-')[0]; //get id of post
// your logic
}
Hope this helps you!

you can simply take your title from database and use it as a slug like below :
$slug = str_replace(' ','-',$yourtitle);

You can use Laravel mutators setSlugAttribute in your model:
public function setSlugAttribute($title){
$this->attributes['slug'] = str_replace(' ','-',$title);
}
and write this sample code in your web.php :
Route::get('/blog/{slug}', 'BlogController#show');
You can use slug in your method.
public function findBySlug($slug){
$post = Post::whereSlug($slug)->firstOrFail();
}

Related

Why this Implicit Binding is not working? - Laravel

I'm using Laravel 9. I have a problem, i wil appreciate any help.
I Have a Model named Entity, a controller EntityControler, and a FormRequest UpdateEntityRequest.
My API Routes looks like:
Route::apiResource('entities', EntityController::class);
so i have show, create, store, update, delete... routes.
This is muy update method in EntityController (without the code/not important now)
public function update(UpdateEntityRequest $request, Entity $entity)
{
return $entity;
}
the update method works perfect. But I want another update method for only a section and here starts the problem.
This is my new API Routes:
Route::apiResource('entities', EntityController::class);
Route::patch('/entities/{id}/{section}',[EntityController::class, 'updateSection' ]);
And this is the new method in the controller(without code yet):
public function updateSection( UpdateEntityRequest $request,Entity $entity, $section)
{
return $entity;
}
But this last method return [] insted of the Entity and the update method works. WHY?
I change de uri in Postman for update PUT {{baseUrl}}/entities/1 and for updateSection {{baseUrl}}/entities/1/1 .
Why does work in update and not in updateSection?
PD:
This method work, and give the id, and I can create a Entity from this:
public function updateSection( UpdateEntityRequest $request, $entity, $section)
{
return $entity;
}
But this is not what I want. Any idea why this happen?
please make sure your uri segment is same as the variable name in the controller, in your case replace id with entity
Route::patch('/entities/{entity}/{section}',[EntityController::class, 'updateSection' ]);
for more please see documentation
Make the route param name consistent in your route api.php and your function updateSection in EntityController
Route::patch('/entities/{entity}/{section}',[EntityController::class, 'updateSection' ]);
and
public function updateSection( UpdateEntityRequest $request,Entity $entity, $section)
{
return $entity;
}

Laravel API routes and Controller variable

I'm a new user of Laravel, and i'm a bit confused with Laravel route API and the name of variable in the controller.
Here an example to explain :
An API route
Route::middleware('auth:sanctum')->group( function () {
Route::resource('cepage', CepageController::class);
});
For a PUT or PATCH, i have this function in the CepageController :
public function update(Request $request, Cepage $cepage)
{
$input = $request->all();
$validator = Validator::make($input, [
'libelle' => 'required',
'abrege' => 'required'
]);
if($validator->fails()){
return $this->sendError($validator->errors());
}
$cepage->libelle = $input['libelle'];
$cepage->abrege = $input['abrege'];
$cepage->save();
return $this->sendResponse(new CepageResource($cepage), 'Cépage mis à jour');
}
If you see my route name "cepage" have the same name of the $cepage variable of the function declaration in the controller, Laravel update the record in the database.
If they are no identical, Laravel create a new record in the database.
Why they need to be exactly the same ?
I think i miss something in the documenation of Laravel.
Thanks for your explanations.
It needs to be the same, for laravel to know what object does he needs to create for us.
Route::resource does a few routes for you, with the base url give into it (https://laravel.com/docs/8.x/controllers#actions-handled-by-resource-controller)
So once you have defined Route::resource('cepage', CepageController::class)
You will have the following routes defined:
Verb URI Action Route Name
GET /cepage CepageController#index cepage.index
GET /cepage/create CepageController#create cepage.create
POST /cepage CepageController#store cepage.store
GET /cepage/{cepage_id} CepageController#show cepage.show
GET /cepage/{cepage_id}/edit CepageController#edit cepage.edit
PUT/PATCH /cepage/{cepage_id} CepageController#update cepage.update
DELETE /cepage/{cepage_id} CepageController#destroy cepage.destroy
And in the controller you need to follow the naming, because in the url you have only ids of the object. But if you follow the naming, laravel will fetch the object for you by its id. See:
public function update(Request $request, $cepage_id)
{
$cepage = Cepage::find($cepage_id);
//here you have to fetch the object for yourself to access it
}
public function update(Request $request, Cepage $cepage)
{
//here you can already access $cepage variable
}

how to hide id from url in Laravel 6?

hide id from url
https://wallpaperaccess.in/photo/162/download-wallpaper
i want url like this
https://wallpaperaccess.in/photo/download-wallpaper
ImagesController.php
public function show($id, $slug = null ) {
$response = Images::findOrFail($id);
$uri = $this->request->path();
if( str_slug( $response->title ) == '' ) {
$slugUrl = '';
} else {
$slugUrl = '/'.str_slug( $response->title );
}
$url_image = 'photo/'.$response->id.$slugUrl;
//<<<-- * Redirect the user real page * -->>>
$uriImage = $this->request->path();
$uriCanonical = $url_image;
if( $uriImage != $uriCanonical ) {
return redirect($uriCanonical);
}
Route
// Photo Details
Route::get('photo/{id}/{slug?}','ImagesController#show');
NOTE: i don't have any slug column in database, so can we use title as slug?
You should add a column field slug and auto-generate it from title
use Illuminate\Support\Str;
$slug = Str::slug($request->input('title'), '-');
In Models\Image.php
public function getRouteKeyName()
{
return 'slug';
}
In routes\web.php
Route::get('photo/{image:slug}','ImagesController#show');
In app\Http\Controllers\ImagesController.php
use app\Models\Image.php;
...
public function show(Image $image)
{
// controller will automatically find $image with slug in url
// $image_id = $image->id;
return view('your.view', ['image' => $image]);
}
In order to use a slug in the URL instead of an id, you'll need to...
Create a column in your table where you store the slug. A good way to make a slug unique is to append the actual id at the end. If you really don't want to see the id anywhere, you have no choice, you'll have to ensure the slug is unique yourself (there are a lot of ways to achieve this).
This is one way to automatically create an unique slug:
Make sure the slug column is nullable, then open your model and add these methods.
They are called "model events".
created is called when the model is, well, created.
updating is called when you are updating the model but before it's actually updated.
Using created and updating should automatically create the slug when you create or update a Images instance.
protected static function booted()
{
parent::booted();
static::created(function (Images $images) {
$images->slug = Str::slug($images->title.'-'.$images->id);
$images->save();
});
static::updating(function (Images $images) {
$images->slug = Str::slug($images->title.'-'.$images->id);
});
}
From a SEO point of view, updating the slug when the title change is arguably not a good practice, so you might want to omit this part (static::updating...), it's up to you.
Go to your model and add the following method:
/**
* Get the route key for the model.
*
* #return string
*/
public function getRouteKeyName()
{
return 'slug'; //or whatever you call the slug column
}
This way, the router will resolve your model by the slug, not the id.
In your route file, remove the id and change the name of the slug to match the name of your model:
Route::get('photo/{images}','ImagesController#show'); //here I'm assuming your model is Images from what I see in your controller
In your controller, change the declaration of your show method to this:
public function show(Images $images)
{
dd($images);
// if you did all this correctly, $images should be the Images corresponding to the slug in the url.
// if you did something wrong, $images will be an empty Images instance
//
//
// your code...
}
Images should be renamed to Image, models should not be plural. However, it should not make any difference here.

How can I display blog category name in URL instead of a static name in Laravel 7?

I'm working on my application using Laravel 7, I have done the blog section in my front-end and everything is working well except that I would like to display the URL having name of the category followed by the slug (name of the blog) For example in my URL I would like to have:
www.domain.com/plumbing/best-plumbing-tips-for-your-home instead of www.domain.com/post/best-plumbing-tips-for-your-home
In the second link, "post" is the URL in my web routes file.
"plumbing" is the category "best-plumbing-tips-for-your-home" is the title of the blog and I would like the URL to dynamically pick the name of the Category where the blog post belongs to. Please help.
In my Controller:
public function post($slug){
$post = Post::with('category', 'user')->where('slug', $slug)->first();
$posts = Post::with('category', 'user')->inRandomOrder()->limit(3)->get();
$categories = BlogCategory::all();
if($post){
return view('blog.front-end.post', compact(['post', 'posts', 'categories']));
}else {
return redirect('/');
}
}
public function category($slug){
$category = BlogCategory::where('slug', $slug)->first();
if($category){
$posts = Post::with('category', 'user')->where('category_id', $category->id)->get();
return view('blog.front-end.category', compact(['category', 'posts']));
}else {
return redirect()->route('front-end.home');
}
}
In my Web Routes file:
Route::get('/post/{slug}', 'Blog\FrontEndController#post')->name('front-end.post');
Route::get('/category/{slug}', 'Blog\FrontEndController#category')->name('front-end.category');
Route::get('/blog', 'Blog\FrontEndController#postsForBlogPage')->name('front-end.blog-page');

recover the slug of a category linked to another category Laravel

I would like to recover the slug of 2 categories from my routes but can’t write the Controller.
My Route
Route::get('technicians/o/{occupation}/c/{city}', 'User\TechnicianController#viewoccupationcity');
My Controller
public function viewoccupationcity($slug)
{
$technicians = TechnicianResource::collection(occupation::where('slug',$slug)->firstOrFail()->technicians()
->with('city','occupation')
->latest()->get());
return $technicians;
}
Route::get('technicians/o/{occupation}/c/{city}', 'User\TechnicianController#viewoccupationcity');
Your controller will accept the parameters from your route as variables by order
public function viewoccupationcity($ocupation, $city)
{
...
}
Example:
URL: technicians/o/foo/c/bar
public function viewoccupationcity($ocupation, $city)
{
// $ocupation will be 'foo'
// $city will be 'bar
}
Ok, you would need to retrieve 2 variables as that is what you are passing
public function viewoccupationcity($occupation, $city)
If you want the whole slug to do another search then you would use the $request object. So like so
public function viewoccupationcity(Request $request, $occupation, $city){ // You also need to include the Request decleration
$slug = $request->path();
$technicians = TechnicianResource::collection(occupation::where('slug',$slug)->firstOrFail()->technicians()
->with('city','occupation')
->latest()->get());
return $technicians;
}
EDIT: We are having to do a lot of guesswork as your question isn't very clear. I think what you are trying to achieve is probably this
public function viewoccupationcity($occupation, $city){
$technicians = TechnicianResource::collection(occupation::where('city',$city)->where('occupation',$occupation)->firstOrFail()->technicians()
->with('city','occupation')
->latest()->get());
return $technicians;
}
If you need something more then you need to give more details

Resources