Overriding routeKeyName to slug not working - laravel

Here is my show method in my PostController and when I dd($slug) I get my slug from the database but when I try to search the post associated with that slug I get a 404 | Not Found. I've override my routeKeyName in my model but it seems like it'still fetching using id column since when I replace $slug with a hard coded id of 2 in this line $post = Post::findOrFail($slug); then I get the post from the database. I can't figure out what it is that I'm missing.
public function show($slug)
{
//dd($slug);
$post = Post::findOrFail($slug);
return view('single-blog', compact('post'));
}
My Model Post.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
public function getRouteKeyName()
{
return 'slug';
}
}

Even using a different database field, you're still using route model binding.
From the docs:
Laravel automatically resolves Eloquent models defined in routes or controller actions whose type-hinted variable names match a route segment name.
So your route variable and the field you pass to your controller method need to match, and you need to type hint it:
Route:
Route::get('/posts/{post}', [PostController::class, 'show']);
Controller:
public function show(Post $post) {

Related

How to get result in Laravel with where clause while passing model in controller method

I have a route to get a single post item by slug.
Route
Route::get('post/{post}', 'PostController#details')->name('post.details');
While I want to pass the model in the controller method for the route.
Controller
public function details(Post $post)
{
// how to get the post by slug
}
My question is how can I get the post by slug passing in the route
instead of post ID?
I am aware that I can pass the slug and get the post using where clause.
//Route
Route::get('post/{slug}', 'PostController#details')->name('post.details');
//Controller method
public function details($slug)
{
$post = Post::with('slug', $slug)->first();
}
But I want to learn to do the same by passing the Model in the method.
set route key name to your model class
//Post.php
public function getRouteKeyName()
{
return 'slug';
}
This will inform Laravel injector/resolver to look the variable passed in slug column while fetching the object instance.
What you want to do is implicit route model binding
What you can do is in your Post model define getRouteKeyName like below
<?php
class Post extends Model
{
/**
* Get the route key for the model.
*
* #return string
*/
public function getRouteKeyName()
{
return 'slug';
}
}
and define your route like this:
Route::get('post/{post:slug}', 'PostController#details')->name('post.details');
and then in your controller
public function details(Post $post)
{
// it will return post with slug name
return $post;
}
Hope it helps.
Thanks

Define a variable not explained

Sorry for the dumb question but can anyone please tell me how to define a variable in very simple terms? I have struggled for several months with "undefined variable" errors. Are variables stored in config? Or maybe in routes?
I have a database with a customers table. When I put this on my view home page {{$customers->name}} I get Undefined variable: customers.
Fine. So how and where do I define a variable. I would have thought it WAS defined given that the database table is literally called customers. Ugh!
My model file Customer.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Customer extends Model
{
protected $fillable = ['name', 'phone'];
public function address()
{
return $this->hasOne(CustomerAddress::class);
}
public function purchases()
{
return $this->hasMany(CustomerPurchase::class);
}
}
Undefined variable means the variable does not exist and the reasons for your case is, you did not pass it in the view.
Usually, to get the customers records from the database to your views, you can do it in several ways:
Query it prior to loading your view then pass it to your views:
//doing it in the controller
//create a controller: php artisan make:controller CustomerController
<?php
namespace App\Http\Controllers;
use Illuminate\Routing\Controller as BaseController;
use App\Customer; //Dont forget to import your Customer model
class CustomerController extends BaseController
{
public function index()
{
$customers = Customer::get(); //this will fetch the customer using your mdoel
return view('customer', ['customers' => $customers]); //this will pass the records to the view
}
}
//then in your routes/web.php:
Route::get('/customers', 'CustomerController#index'); //when you go to your application/customers in the browser, it will go to the controller and return the view with the records.
//OR you can skip the controllers and do it in the routes/web.php directly as what #jitesh jose mentioned.
Query straight into your view (Not really recommended, but sometimes you just need to make it work)
In your customer.blade.php
#php
$customers = \App\Customer::get();
#endphp
<ul>
#foreach($customers as $customer)
<li>{{$customer->name}}</li>
#endforeach
</ul>
My advice, try to watch a few basic Laravel videos so that you will understand the flow of the request and response.
If your model name is Customer,laravel automatically pick the table name as customers.Otherwise you have to use your desired table name in Model as follows.
protected $table = 'customers_table';
In your web.php
Route::get('/home',function () {
$customers = DB::table('customers_table')->get();
OR
$customers = Customer::get();
return view('welcome')->with('customers',$customers);
});
You can use$customers in welcome.blade.php as
#foreach($customers as $customer)
{{$customer->name}}
#endforeach

Laravel: a simple MVC example

I'm new to Laravel and the documentation's basic task list returns Views from the Route(web.php) but I want to use a Controller to return an image file.
So I have for my route:
Route::get('/products', 'ProductController#index');
Then my ProductController action (please ignore comments as I'm using index to simplify things):
<?php
namespace App\Http\Controllers;
use App\Product;
use Illuminate\Http\Request;
class ProductController extends Controller
{
/**
* Display a listing of the resource.
*
#return \Illuminate\Http\Response
Fetch and return all product records.
*/
public function index()
{
//
//return response()->json(Product::all(), 200);
return view('/pages/product', compact('product'));
}
And my product.blade.php (nested in views/pages/product):
<img src="/images/product/Frozen_Ophelia_800x.png">
I keep getting a ReflectionException Class App\Product does not exist.
I got this working when I just returned a view from the route. I'm getting a ReflectionException
Class App\Product does not exist so I think it's something at the top, ie. use App\Product; that is wrong.
Edit (below is my App\Product nested in app/Providers):
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Product extends Model
{
//
use SoftDeletes
protected $fillable = [
'name', 'price', 'units', 'description', 'image'
];
public function orders(){
return $this->hasMany(Order::class);
}
}
Assuming App\Product model exists, correct code should be:
public function index() {
$product = Product::all();
return view('pages.product', compact('product'));
}
Check the docs.
PS did you call a $ composer dumpautoload? ReflectionException Class error is often related to new class autoloading (eg. new classes in a packages)
view function should have any view template not any url or route. Of you have file views/pages/product.blade.php then use
view('pages.product',compact('product'));

How can i get result from model in laravel 5

Good day, i'm trying to get the result from my model that called with Mainmodel through my controller, my controller is MainController.
Here is my controller
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use app\Mainmodel;
class MainController extends Controller
{
function index(){
echo "Kok, direct akses sih?";
}
function get_menu(){
$menu = app\Mainmodel::request_menu();
dd($menu);
}
}
Here is my model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Mainmodel extends Model
{
function request_menu(){
$menu = DB::table('menu')
->orderBy('[order]', 'desc')
->get();
return $menu;
}
}
my routes
Route::get('menu','MainController#get_menu');
with my script above i get this
FatalErrorException in MainController.php line 17: Class
'App\Http\Controllers\app\Mainmodel' not found
how can i fix this ? thanks in advance.
Note: I'm bit confuse with laravel. I'm using codeigniter before. And i have a simple question. In laravel for request to database should i use model ? or can i just use my controller for my request to database.
sorry for my bad english.
I would imagine it's because your using app rather than App for the namespace.
Try changing:
app\Mainmodel
To:
App\Mainmodel
Alternatively, you can add a use statement to the top of the class and then just reference the class i.e.:
use App\Mainmodel;
Then you can just do something like:
Mainmodel::request_menu();
The way you're currently using you models is not the way Eloquent should be used. As I mentioned in my comment you should create a model for each table in your database (or at least for the majority of use cases).
To do this run:
php artisan make:model Menu
Then in the newly created Menu model add:
protected $table = 'menu';
This is because Laravel's default naming convention is singular for the class name and plural for the table name. Since your table name is menu and not menus you just need to tell Laravel to use a different table name.
Then your controller would look something like:
<?php
namespace App\Http\Controllers;
use App\Menu;
class MainController extends Controller
{
public function index()
{
echo "Kok, direct akses sih?";
}
public function get_menu()
{
$menu = Menu::orderBy('order', 'desc')->get();
dd($menu);
}
}
Hope this helps!
You can solve it by different solution. The solution is you don't have to call request_menu(); you can get it in your controller.
MainController
use use Illuminate\Support\Facades\DB;
public function get_menu(){
$menu = DB::table('menu')
->orderBy('Your_Field_Name', 'DESC')
->get();
dd($menu);
}

How to access my model in laravel?

I can't seem to figure out what's wrong with this code. I'm running laravel 5.4.
The error:
https://www.dropbox.com/s/64ioxdf4mv6ps1w/Screenshot%202017-02-28%2020.11.33.png?dl=0
The Controller function:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Thread;
class ThreadController extends Controller
{
public function show($id) {
return Thread::where('id', '=', $id)->messages();
}
}
The Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Thread extends Model
{
public function messages()
{
return $this->hasMany(Message::class)->get();
}
}
I suggest adding your error code instead of linking to image (right now AWS is down, thus I'm unable to view the image).
Regardless, the messages method is defining a relationship and as such, is an instance of the query builder. Rather than chaining the get method there, I suggest a slightly different approach:
In your controller
public function show($id)
{
// Use first() instead of get() since you're returning a
// specific model by its primary key (I assume)
return Thread::where('id', $id)->with('messages')->first();
}
And in your model
public function messages()
{
// This returns a query builder instance, which is what you want.
// It defines the relationship between Thread and Message
return $this->hasMany(Message::class);
}
This will eager load your messages along with your Thread model.
Hope it helps!
Regarding Joel's question in the comments...
User::find(1)->messages->create($request->only('body'));
Is not calling the 'messages function' you mentioned and not returning the relationship. Instead, it is calling the messages property, which is something different.

Resources