Laravel 5 ModelNotFoundException in Builder.php for Routing - laravel

I have a Model Class with name Article.php
and use below rout:
Route::get('articles/create','ArticlesController#create');
when input in browser http://localhost:8000/articles/create
i see this error :
ModelNotFoundException in Builder.php line 125: No query results for model [App\Article].
but when i user below every think is ok:(article insted articles)
Route::get('article/create','ArticlesController#create');
this is my controller :
class ArticlesController extends Controller {
public function index()
{
$articles = Article::all();
return view('articles.index',compact('articles'));
}
public function show($id)
{
$article = Article::findOrFail($id);
return view('articles.show',compact('article'));
}
public function create()
{
return view('articles.create');
}
}
what happened really ?!!!

The problem with your code is that in your routes.php your route priority is like this :
Route::get('articles/{id}','ArticlesController#show');
Route::get('articles/create','ArticlesController#create');
and when you go to http://localhost:8000/articles/create in your browser laravel catches create as a variable with {id} request in articles/{id} before articles/create gets an opportunity to resolve the route. To solve your problem you must consider the route priority and make the following changes to your route.php file :
Route::get('articles/create','ArticlesController#create');
Route::get('articles/{id}/edit','ArticlesController#show');
Route::get('articles/{id}','ArticlesController#show');
But if you have a bunch of these in your routes.php file you should really consider using this instead:
Route::resource('articles', 'ArticlesController');
This single line will take care of all 4 get routes (index, create, edit, show) as well as all three post/put/delete routes of (store, update, delete).
But to each their own.

You should include your controller code.
Most likely there's some code there that tries a findOrFail() on the Eloquent model, triggering this error.

Related

How can I redirect from a controller with a value to another controller in laravel?

OrderController.php
if (request('payment_method') == 'online') {
return redirect(route('payments.pay', $order->id));
}
web.php
Route::POST('/pay/{orderId}', 'PublicSslCommerzPaymentController#index')->name('payments.pay');
PublicSslCommerzPaymentController.php
session_start();
class PublicSslCommerzPaymentController extends Controller
{
public function index(Request $request, $ordId)
{
//code...
}
}
Here in index function I need the order id from `OrderController.
But the Error I am getting
Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException
The GET method is not supported for this route. Supported methods: POST.
if you want to redirect to named route you can use this:
return redirect()->route('payments.pay', ['orderId' => $order->id]);
if you want generate redirect to controller action you can try this:
return redirect()->action(
'PublicSslCommerzPaymentController#index', ['ordId' => $order->id]]
);
Just change in your web.php from POST method to GET method
Something like this
Route::GET('/pay/{orderId}', 'PublicSslCommerzPaymentController#index')->name('payments.pay');

Inconsistency with 'show' function

I've been working on a project for a few months now and I feel like I am seeing some inconsistency with how the public function show is working
I have a model and controller for a Location that has
public function show(Location $Location)
{
$Loc = Location::with('company:id,name')->findOrFail($Location);
return response()->json($Loc,200);
}
and that works just fine. Note the parameters.
I just made a new model and controller for Asset and it has this:
public function show(Asset $asset)
{
$AssetReturn = Asset::with('location:id,name,address')->findOrFail($asset);
return response()->json($AssetReturn,200);
}
but that does not work. it just returns empty. If i remove the class name from the parameters so its just
public function show($asset)
then it works as intended.
relation from asset model to location:
public function location()
{
return $this->belongsTo(Location::class);
}
According to the documentation, Laravel automatically resolves Eloquent models defined in routes or controller actions whose type-hinted variable names match a route segment name. For example:
Route::get('/assets/{asset}', function (App\Asset $asset) {
$asset->load('location:id,name,address');
return response()->json($asset);
});
Since the $asset variable is type-hinted as the App\Asset Eloquent model and the variable name matches the {asset} URI segment, Laravel will automatically inject the model instance that has an ID matching the corresponding value from the request URI. If a matching model instance is not found in the database, a 404 HTTP response will automatically be generated.
If you don't want this behavior and want to use findOrFail manually:
Route::get('/assets/{asset}', function ($assetId) {
$asset = App\Asset::with('location:id,name,address')->findOrFail($assetId);
return response()->json($asset);
});

Laravel blade file can't view

I created CustomerController in Http, later, I fixed-route get customers, but getting an error in a single action Controller.
I tried to show off CustomerController view for displaying customers logged in page
Here is my error message:
Use of undefined constant view - assumed 'view' (this will throw an Error in a future version of PHP)
Looks like you're trying to access the old ways to render blade file look at this :-
return View::make('customers.index', $customersList);
To use view() method
return view('admin.pages.customers.index',compact('someVaiable'));
OR
// You can define constant for your controller get methods
private $layout;
public function __construct()
{
$this->layout = 'admin.pages.customers.';
}
public function index(){
return view($this->layout.'index');
}
Take a look a this for Single Action Controllers example
https://laravel.com/docs/5.8/controllers#single-action-controllers
The first argument of the view method in the controller should be the name of the view.
Routes/web.php
Route::get('/', 'CustomerController');
app/Http/Controllers/CustomerController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class CustomerController extends Controller
{
public function __invoke(Request $request)
{
return view('customers');
}
}
resources/views/customers.blade.php
<h1>Customers</h1>

How do I handle a not found case when using Laravel Dependency Injection?

I am using a route /news/{news} and the controller public function show(News $news). When I supply the route with a valid ID, it all works fine and dandy. However, when the ID isn't found, Laravel returns a 404-page. I would rather handle that case myself, since I am using it as an API.
My question resembles this one, but I want to use Dependency Injection, if at all possible. I know I can do a normal News::where(), but that is not how I'd like to solve this. The question, therefor, is; How do I handle a not found case when using Laravel Dependency Injection?
I am building a private API so what I'd like to achieve is to return a JSON value when the news isn't found.
veNuker's option 2 is a way to go if you would like to customize the resolution logic of your Route Model Binding.
But for a 4th option, why not give Middlewares a try? Let's say you have a
class NewsIsExist
{
public function handle($request, Closure $next) {
$news_id = $request->route('news_id');
$news = News::find($news_id);
if($news) {
$request->merge(['news' => $news]);
return $next($request);
} else {
return response()->json([
'error' => "News not found."
], 404);
}
}
}
Tweek your routes to use the middleware
Route::get('news/{news_id}', [
'uses' => "NewsController#show",
'middleware' => 'news-exists'
]);
Then you can easily access your News instance in your controller
use Illuminate\Http\Request;
public function show(Request $request) {
$news = $request->get('news');
}
New answer
So after updating your question, now we know, you want to simply return JSON value when the news is not found. In this case, I would use route fallback method, which is executed when Laravel catches 404 exceptions. Good thing is, you need to implement this only once, and it will work for news/comments/users and all other things you have in your API. Add this code to your routes file:
Route::fallback(function(){
return response()->json(['message' => 'Not Found!'], 404);
});
More info - https://themsaid.com/laravel-55-better-404-response-20170921
===========================================================
Previous answer
Since you didn't specify what exactly you want to do, here are a couple of options:
Option 1 - custom error page
https://laravel.com/docs/5.5/errors#custom-http-error-pages
Option 2 - display default item
It will pass another object of News type to your controller
<?php
namespace App\Providers;
use App\News;
use Illuminate\Support\Facades\Route;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
// 'news' comes from your route param name
Route::bind('news', function ($value) {
$news = News::where('id', $value)->first();
if ( ! $news) {
//assuming here the first item is the default one
$news = News::first();
}
return $news;
});
}
}
Option 3 - catch all 404s
You can catch all 404 errors and return whatever you want as described here How do I catch exceptions / missing pages in Laravel 5?

laravel Controller error when using Request in function

I make controller by using php artisan make:controller newsController --resource
And after that when I go to my controller in function index, I want to add Request $request
public function index(Request $request)
{
}
It's return error:
Declaration of
App\Http\Controllers\Admin\NewsController::index(Illuminate\Http\Request
$request) should be compatible with
App\Http\Controllers\Controller::index()
How to fix it? I try many way but it still didn't work!
EDIT — Controller
namespace App\Http\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
UPDATED — Routes
Route::post('admin/news', 'Admin\NewsController#store');
Route::resource('admin/news', 'Admin\NewsController');
It's quite simple, just create your Resource controller without the index route Or Create new get route, like this:
Route::resource('admin/news', 'Admin\NewsController', ['except' => ['index']]);
Then add your route before the resource declaration, something like this:
Route::post('admin/news', 'Admin\NewsController#index');
Route::resource('admin/news', 'Admin\NewsController', ['except' => ['index']]);
Hope this helps you!!
This doesn't require any Laravel work arounds.
Fix:
a) Remove the index method from the base controller
or
b) Make the index method in the base controller take a Illuminate\Http\Request as an argument and use that same method signature in every controller's index method that inherited from the base in the entire application.
or
c) Figure out why there is an index method defined in the base in the first place and, if needed, move it to a trait to use in child classes instead. (allows you to override the method completely)
b is not a good option, it is just to illustrate a point
Issue demonstrated:
class Foo
{
public function index()
{
//
}
}
class Bar extends Foo
{
public function index(\Illuminate\Http\Request $request)
{
}
}
Declaration of Bar::index(Illuminate\Http\Request $request) should be compatible with Foo::index()
You want to override the index action.
You also want to pass parameters into this index action.
The App\Http\Controllers\Controller::index() does not take parameters.
So they are not "compatible".
Try this "helper-funtion" way:
public function index() {
$request = request() // use the helper function
// ...you code here...
}
You can disable index from resources and define route with different method name before or after resource:
Route::get('resources', 'ResourceController#getResources');
Route::resource('resources', 'ResourceController', $restResource)->except(['index']);

Resources