Laravel modify route parameter to name column instead of id - php

In my web.php file, I specify the following route:
Route::get('/{project}', 'ProjectsController#index');
In my ProjectsController, I define the public function index as follows:
use App\Project;
// ... Here is the class declaration etc.
public function index(Project $project) {
dd($project->name);
}
Currently, I have one entry in my projects table, which I can call without any problems over my eloquent model. This is my entry:
Name: sampleproject
Description: This is a test.
ID: 1
// And the timestamps...
When calling /sampleproject, it returns a 404 error page.
[...]
UPDATE: When calling /1, which is the project id, everything works as expected. How can I modify my code so I can call my Controller over the project name, not the id?

in your model:
public function getRouteKeyName()
{
return 'yourcolumn';
}

Related

Laravel apiResource to fetch record by field other than id

I am using Laravel to fetch records from the database for which I have created an apiResource controller. I have setup the following code inside routes.
Route::apiResource('/MyController',MyController::class)->middleware('auth:api');
In MyController.php my code to display a specific data is:
/**
* Display the specified resource.
*
* #param \App\Models\ContentType $contentType
* #return \Illuminate\Http\Response
*/
public function show(MyModel $Model)
{
// show content type info
return response([
'data' => new MyControllerResource($Model)
],200);
}
I get the data when I place an api call like this:
http://localhost:8000/api/MyController/1
What I want is a record getting fetched by passing other field value instead of id in the route. For example.
http://localhost:8000/api/MyController/mypost
Any idea how can I achieve this?
The route key name defaults to id for all models. You will want to update this to name or whatever field "mypost" is by adding a getRouteKeyName() method.
<?php
namespace App;
...
class Post extends Model
{
public function getRouteKeyName()
{
return 'name';
}
...
}
You are using route model binding. And in laravel its default behaviour is to find model with id and return collection. It will not search for any other field. Of course you can change this behaviour but it can only search data by one field. To change this behaviour use getRouteKeyName method in model like:
public function getRouteKeyName()
{
return 'another_field_in_my_table';
}
You can also use explicit binding like:
Route::bind('MyController', function($value) {
return \App\MyModel::where('id', $value)->orWhere('another_field_in_my_table', $value)->first();
});
To learn more about explicit binding check docs.
You'll have to define route separately. You can group the routes by controller and middleware though. And once done, then, Inside your route, you need to change to this:
Route::get('/show/{post:columnName}', [ MyController::class, 'show' ])->middleware('auth:api');
Now your data will be fetched on the basis of your column name defined in the route.

How to change Route Model Binding finding data from id to slug

I have a route like the following.
Route::get('/articles/{articleSlug}' ,
[App\Http\Controllers\ArticleController::class, 'single']);
And the method of single() at ArticleController class goes here:
public function single($slug)
{
$article = Article::where('slug',$slug)->first();
$article->increment('viewCount');
return view('home.article',compact('article'));
}
Now I wish to use Route Model Binding for finding this data from the articles table based on the column slug. But as I know, Route Model Binding finds data based on the id. So how to change Route Model Binding finding data from id to slug ONLY for ArticleController.php (meaning that the other Controller classes can work with id as route model binding)?
In case you want to use other model field as the biding attribute instead of id you can define a getRouteKeyName which return the name of the field which must be use
class Article extends Model {
// other methods goes here
public function getRouteKeyName() {
return 'slug';
}
}
Or you can pass the field name directly when you define the route like this
Route::get('/articles/{article:slug}' , [App\Http\Controllers\ArticleController::class, 'single']);
With this code inside of your controller you must ensure that the name provide as parameter in the route definition match the name of the controller argument
public function single(Article $article)
{
$article->increment('viewCount');
return view('home.article',compact('article'));
}
Your controller is already set up, all you need to do is change your variable name to $slug in the route, and I believe that should be enough:
Route::get('/articles/{slug}' , [App\Http\Controllers\ArticleController::class, 'single']);
change your route to this:
Route::get('/articles/{article:slug}' , [App\Http\Controllers\ArticleController::class, 'single']);
and then inject the Article model to your controller function and let laravel do the rest for you:
public function single(Article $article)
{
$article->increment('viewCount');
return view('home.article',compact('article'));
}
you can customize route model bindings directly in the route definition:
past given code in app/model/Article.php:
public function getRouteKeyName()
{
return 'slug';
}
2.when you use slug change route to
Route::get('/articles/{article:slug}' , [App\Http\Controllers\ArticleController::class, 'single']);
to use id sample change slug to id
Route::get('/articles/{article:id}' , [App\Http\Controllers\ArticleController::class, 'single']);
you can add bind method to your model boot() like this
public function boot()
{
Route::bind('article', function ($value) {
return Article::where('slug', $value)->firstOrFail();
});
}
to learn more about it read this section in the Laravel docs
https://laravel.com/docs/9.x/routing#customizing-the-resolution-logic

Laravel - 404 | Not Found upon "/{id}" entry

I am getting a "404 | Not Found" error when i try to access a specific item from my database. The items with the specific ID's do exist in the database, but i am not even sure if that even has any influence on the problem.
My routing looks likes this:
Route::prefix('departments')->group(function() {
Route::get('/{id}', [DepartmentController::class, 'showDepartment']);
});
And the related controller looks like this:
public function showDepartment() {
return '';
}
}
I haven't yet finished the function. I just wanted to check if the routing even worked by returning an empty string.
So what am i doing wrong? Is it the routing or the controller?
According to the Laravel documentation, you have to define the parameter in the route then use it in the controller as a parameter.
in your controller:
public function showDepartment($id) {
return 'Hello';
}
The id is not bound to any model to fetch from the database to do that you can use Laravel route model binding
for example when you have a model named Department you write your route like this:
Route::get('/{department}', [DepartmentController::class, 'showDepartment']);
and in the controller:
public function showDepartment(Department $department) {
return 'Hello from depratment';
}
When your department exists it returns the response otherwise return 404.
You may need a Department model class. Then you can find the item from database by id $department = Department::findOrFail($id);
you are send parameter in route and this function without any parameter
route :
Route::prefix('departments')->group(function() {
Route::get('/{id}', [DepartmentController::class, 'showDepartment']);
});
your function in controller should be
public function showDepartment($id) {
$department = Department::findOrFail($id);
}
}

Page 404 if page isn't found in Laravel

I have a project on Laravel 5.8. It's internet-market with categories, brands and products. I used in my controllers a variable from model:
route:
Route::prefix('categories')->get('/{category}', 'ProductsController#openCategory')->name('openCategory');
model:
class Category extends Model
{
public function products()
{
return $this->hasMany(Product::class);
}
public function getRouteKeyName()
{
return 'category_alias';
}
}
controller-method:
public function openCategory(Category $category = null)
{
$allInfo = $this->getAllInfo();
$categories = $this->getCategories();
$brands = $this->getBrands();
return view("pages.category", compact('allInfo','category', 'categories', 'brands'));
}
I don't use relation by ID, I use relation by 'category_alias'. But if I write category name with error, I get message - OPPS! We Couldn’t Find this Page
Uh... So it looks like you brock something. The page you are looking for has up and Vanished. Why? But if I use relation by ID, I get page 404 - it's success for me.
By defining the route with ->get('/{category}' and typehinting on the controller, Category $category you are telling Laravel that you want it to resolve the category for you.
This is handled by the service container as described at https://laravel.com/docs/master/container#introduction
If you provide a value which doesn't resolve to the id for a category in the database, the service container will be be unable to load anything. Laravel responds to those scenarios by returning the 404.

Model connections is not working properly - Laravel

I'm trying to display a tag that is selected by the user. The tag name is in the tags table. The tagpost table has the mapping between the tag and the user.
The following is the User model, where the primary key in users table is id, and var_id can be many types and 2 is for users (not sure if the below where condition is correct):
public function tagpost()
{
return $this->hasMany('App\tagpost', 'var_id')->where('type',2);
}
The following is the tagpost model:
public function tags()
{
return $this->belongsToMany('App\tag','id');
}
public function users()
{
return $this->belongsToMany('App\User');
}
The following is the tag model :
public function tagposts()
{
return $this->hasMany('App\tagpost', 'var_id');
}
The following query is not working in the blade :
<option>{{ Auth::user()->tagpost()->tags()->select('t_name')->first()->t_name}} </option>
Error in blade :
Call to undefined method Illuminate\Database\Query\Builder::tags()
You are calling the relations as method whereas they should be called as property like this. Also i suggest you the laravel documentation
<option>{{ Auth::user()->tagpost->tags->select('t_name')->first()->t_name}} </option>
If tagpost is just the relation table why don’t you define a method tags() on the User model, using the tagposts table as the pivot so you can just do Auth::user()->tags()?
Your code won’t work because ->tagpost() returns the Relation itself and not the tagpost models...

Categories