Laravel 8 route not found using jetstream nav menu - php

Fairly new to laravel 8 with some experience with laravel 7. I'm trying to add some additional pages to the default dashboard nav menu. however after adding the code, as I expect it to be, I get this error:
Symfony\Component\Routing\Exception\RouteNotFoundException
Route [accounts.index] not defined. (View: /home/some/path/resources/views/navigation-menu.blade.php)
So here is what I have done code wise:
in web.php i have the following route:
Route::middleware(['auth:sanctum', 'verified'])
->get('/accounts', [AccountController::class, 'index'])
->name('accounts');
I have a controller /app/Http/Controllers/AccountController.php as follows:
<?php
namespace App\Http\Controllers;
use App\Models\Account;
use Illuminate\Support\Facades\View;
class AccountController extends Controller
{
//
public function index() {
$accounts = Account::all();
return View::make('pages.accounts.index')->with('accounts', $accounts);
}
/**
* Show the form for creating a new resource.
*
* #return Response
*/
public function create()
{
return View::make('pages.accounts.create');
}
/**
* Store a newly created resource in storage.
*
* #return Response
*/
public function store()
{
//
}
/**
* Display the specified resource.
*
* #param int $id
* #return Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param int $id
* #return Response
*/
public function update($id)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return Response
*/
public function destroy($id)
{
//
}
}
I have a Model /app/Models/Account.php:
<?php
namespace App\Models;
use Eloquent;
class Account extends Eloquent
{
}
I also have blade templates for this page which i wont list for brevity as don't think this matters with the issue and at this point if I navigate to {url}/accounts the accounts index page is shown as intended.
However now I want to move this functionality into the jetstream dashboard so I can cut down on some development time and theme it similar to the default laravel concept.
The first thing I need is to add a new nav item next to Dashboard so I amended the default navigation-menu.blade.php file (/resources/views/navigation-menu.blade.php) by copying what it uses for dashboard and updating:
...
<!-- Navigation Links -->
<div class="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex">
<x-jet-nav-link href="{{ route('dashboard') }}" :active="request()->routeIs('dashboard')">
{{ __('Dashboard') }}
</x-jet-nav-link>
</div>
<div class="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex">
<x-jet-nav-link href="{{ route('accounts.index') }}" :active="request()->routeIs('accounts.index')">
{{ __('Accounts') }}
</x-jet-nav-link>
</div>
</div>
...
It is at this point when reloading the page throws the error. Anyone know what is causing this? I initially tried without using .index as this is the default anyway right?
I have also tried to follow a few tuts on doing this ((https://eheidi.dev/blog/creating-a-multi-user-to-do-application-with-laravel-jetstream-2p1k)) but I get the same error when i reload my page after editing the navigation-manu.blade.php file so I'm at a loss. I'm developing this on ubuntu 20.04
thanks
Craig
*** EDIT ***
I have updated my route to be a resource for better use moving forward.
Route::middleware(['auth:sanctum', 'verified'])
->resource('/accounts', [AccountController::class, 'index'])
->name('accounts.index');
Tested this without the amend in navigation-menu.blade.php and all still worked added back the amends and same error.
*** EDIT 2 ***
I have I think narrowed this down to what should be in the navigation-menu file and the web routes file. I have further amended my web.php code as per point 2 of an answer below by Chadrack:
Route::middleware(['auth:sanctum', 'verified'])
->resource('/accounts', AccountController::class)
->only( ['index', 'create', 'store', 'update'])
->name('index', 'accounts');
The snippet I added to the navigation-menu.blade.php is:
<div class="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex">
<x-jet-nav-link href="{{ route('accounts') }}" :active="request()->routeIs('accounts')">
{{ __('Accounts') }}
</x-jet-nav-link>
</div>
This is still throwing the error, also if i add .index to route function ( route('accounts.index') ) I still get an error (either Route [accounts.index] not defined or Route [accounts] not defined
*** EDIT 3 ***
I repeated the initial tutorial I had tried and failed with (https://eheidi.dev/blog/creating-a-multi-user-to-do-application-with-laravel-jetstream-2p1k) but as with my issue here after i have added the x-jet nav-link section to the blade template and added the route, when i reload i get the same error (with the new defined route) Route [dashboard-todo] not defined. So if the issue I get is the same for both options then I must be missing something here? As pointed out before I have tried every combination of route type. It works using the url [url]/accounts until I add the link into the nav-bar. The Dashboard does work when no changes are made to the navigation-menu.blade.php

you need to call your route using it's name.
in your definition you are define the route with the name accounts while you are calling a route named by accounts.index
replace your route
Route::middleware(['auth:sanctum', 'verified'])
->get('/accounts', [AccountController::class, 'index'])
->name('accounts');
By
Route::middleware(['auth:sanctum', 'verified'])
->get('/accounts', [AccountController::class, 'index'])
->name('accounts.index');
// note this

Your route name is accounts and you called accounts.index, it will not work, you have two possibilities to fix them.
replace :
Route::middleware(['auth:sanctum', 'verified'])->get('/accounts', [AccountController::class, 'index'])->name('accounts')
by :
Route::middleware(['auth:sanctum', 'verified'])
->get('/accounts', [AccountController::class, 'index'])
->name('accounts.index')
You can also use resources as method :
Route::middleware(['auth:sanctum', 'verified'])->resource('/accounts', AccountController::class)->only(['index', 'create','store',update]);

So just in case anyone else had this issue, I managed to fix it as follows:
First i used the following in web.php:
Route::middleware(['auth:sanctum', 'verified'])->resource('/accounts', \App\Http\Controllers\AccountController::class);
Note no name element and the full path to the controller (in addition to it being in a use at the top of web.api.
I then ran the following to clear my routes:
php artisan route:clear
I was then able to use the following in navigation-menu.blade.php:
<x-jet-nav-link href="{{ route('accounts.index') }}" :active="request()->routeIs('accounts.index')">
{{ __('Accounts') }}
</x-jet-nav-link>
Note I call accounts.index here. Now when i go onto my dashboard I see the new menu item and can visit the page as required. I am now also able to add the other pages from this resource (ie create, edit, destroy).
Of note I'm not sure if i need the full path in the route, found this on another post on SO and now it is working as I expected I don't wish to upset the apple-cart.
thanks
Craig

Related

Laravel language switcher, pass additional parameters to a route

I really can't think of an elegant solution to fix this problem so here it is:
I followed this tutorial https://www.youtube.com/watch?v=KqzGKg8IxE4 to create a localization option for my website. However, integrating the auth was cancer and now I'm faced with an even greater issue regarding the routing for pages that require a get parameter.
Here is my blade code inside the app.blade.php for the language switcher:
<language-switcher
locale="{{ app()->getLocale() }}"
link-en="{{ route(Route::currentRouteName(), 'en') }}"
link-bg="{{ route(Route::currentRouteName(), 'bg') }}"
></language-switcher>
And here are some of my routes
Route::redirect('/', '/en');
Route::get('email/verify', 'Auth\VerificationController#show')->name('verification.notice');
Route::get('email/verify/{id}/{hash}', 'Auth\VerificationController#verify')->name('verification.verify');
Route::get('email/resend', 'Auth\VerificationController#resend')->name('verification.resend');
Route::group([
"prefix" => '{language}',
'where' => ['language' => '(en||bg)'],
], function () {
//Auth routes
Auth::routes();
//Returns to home
Route::get('/', 'HomeController#index')->name('home');
//Handles the faq routes
Route::resource('faq', 'FaqController');
});
Route::get('password/reset/{token}', 'Auth\ResetPasswordController#showResetForm')->name('password.reset');
Route::post('password/reset', 'Auth\ResetPasswordController#reset')->name('password.update');
});
It works well for pages that don't require any get parameters to work with ex: Login / Register / Home page, however if i use something that requires like, faq.edit, which takes an {id} parameters - the language switcher will throw an error because I haven't passed an {id} parameter to it.
The only solution I can think of is adding the language-switcher inside the child blade view and from there I pass the required parameters, however that implies that I have to add the language-switcher to every child view instead of only once at the parent.
You can achieve it with the following steps:
Implement a URL generator macro which will make much easier to generate your URLs which must be identical except language
Get the current route's parameters
Merge the chosen language into them
<?php
namespace App\Providers;
use Illuminate\Routing\UrlGenerator;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
UrlGenerator::macro('toLanguage', function (string $language) {
$currentRoute = app('router')->current();
$newRouteParameters = array_merge(
$currentRoute->parameters(), compact('language')
);
return $this->route($currentRoute->getName(), $newRouteParameters);
});
}
}
And in your Blade file
#inject('app', 'Illuminate\Contracts\Foundation\Application')
#inject('urlGenerator', 'Illuminate\Routing\UrlGenerator')
<language-switcher
locale="{{ $app->getLocale() }}"
link-en="{{ $urlGenerator->toLanguage('en') }}"
link-bg="{{ $urlGenerator->toLanguage('bg') }}"
></language-switcher>
You'll notice I used contracts injection instead of using facades. More informations here https://laravel.com/docs/7.x/contracts#contracts-vs-facades
And if you don't known Laravel macros, more informations here https://tighten.co/blog/the-magic-of-laravel-macros

Laravel change language via URL/Route

Fairly new to Laravel and I'm trying to add a functionality that allows the user to switch between two languages by clicking a button in a header.blade.php file. So far I've got it so there's a test.php file in the respective lang directories with test strings and have managed to get <p>{{__('test.test')}}</p> to display the correct language when manually set. At the moment I'm not sure if this is actually calling the route to update the language or if the logic I have for updating it is wrong since I get no errors and I'm using barryvdh/laravel-debugbar to debug.
My logic for the button:
<button href="{{ url('language', config('app.locale') == 'en' ? 'fr' : 'en') }}">{{ config('app.locale') }}</button>
In routes/web.php:
Route::get('/language', 'LanguageController#show');
Route::post('/language/{lang}', 'LanguageController#update');
LanguageController.php, created via php artisan make:controller --api
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class LanguageController extends Controller
{
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
return App::getLocale();
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//Tried the following
config(['app.locale' => $id]);
App::setlocale($id);
}
}
Questions:
Is this the correct way to update the language at runtime?
How can I tell if my api calls are being made?
How can I achieve this inside of a template .vue file?
Is making a Controller for the language redundant?
Would the inner HTML of my button change if the locale was changed?
Is affecting config files at runtime bad practice?
--Edit--
I should also mention that the only reason I made a controller for this is because I had the route calls in web.php use a function instead however, they stated they were Closure running php artisan route:list and with the research I found I couldn't tell if that was correct
You are on the right way, but there is something missing.
You can't use the configuration to edit at runtime the language.
Save local language in user Session and create a new middleware to set on each request the language saved in session.
I found this article that can help you, localization-laravel

Laravel two 404 styles

I have a main site and an admin control panel.
I want to have different 404 pages for each version.
How should I do this? I currently have the following code in my app/Exceptions/Handles.php file:
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Exception $exception
* #return \Illuminate\Http\Response
*/
public function render($request, Exception $exception)
{
if($exception instanceof \Symfony\Component\HttpKernel\Exception\NotFoundHttpException)
{
$view = $request->is('admin/*') ? 'acp.errors.404' : 'errors.404' ;
return response()->view($view, [], 404);
}
return parent::render($request, $exception);
}
But I use the package spatie/laravel-permission and get the following error;
Trying to get property 'role' of non-object (View: F:\Development\RPR\site\resources\views\layouts\acp.blade.php) (View: F:\Development\RPR\site\resources\views\layouts\acp.blade.php)
I use in acp.blade.php auth()->user()->role, to get the user role, which just works fine without any exception. How should I fix this?
Here are two ways to accomplish different 404 views depending on the route. Both will allow you to have these error pages:
/resources/views/acp/errors/404.blade.php
/resources/views/errors/404.blade.php
The directories will be checked in order until a view is found, which means you can selectively add custom error views and fall through to the default when none exist. If the route did not match, then it will not look for a custom error page.
Option 1
Override registerErrorViewPaths() inside app/Exceptions/Handler.php:
/**
* Register the error template hint paths.
*
* #return void
*/
protected function registerErrorViewPaths()
{
parent::registerErrorViewPaths();
if (request()->is('admin/*')) {
View::prependNamespace(
'errors',
realpath(base_path('resources/views/acp/errors'))
);
}
}
Option 2
Create a ViewServiceProvider:
php artisan make:provider ViewServiceProvider
Register your provider in config/app.php:
'providers' => [
// ...
App\Providers\ViewServiceProvider::class,
],
Edit the boot method of your provider:
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
if (request()->is('admin/*')) {
View::prependNamespace(
'errors',
realpath(base_path('resources/views/acp/errors'))
);
}
}
For the second part of the question, auth()->user() is only available when the session middleware has run. If the 404 was caused by the route not existing, then the request does not go through the web middleware and unfortunately sessions and auth information will not be available. However, if the 404 was caused by a ModelNotFoundException triggered inside a controller, then the web middleware probably did run and you can access the user.
Inside your error view you have to check if the user is signed in:
#guest
<p>Hello, guest</p>
#else
<p>Hello, {{ auth()->user()->name }}</p>
#endguest
If this is not good enough for your use case, then you might want to try Route::fallback(), which allows you to define a controller for serving 404 pages and does run web middleware.

Laravel - How to pass variable to layout partial view

I have a partial view in master layout which is the navigation bar. I have a variable $userApps. This variable checks if the user has enabled apps (true), if enabled then I would like to display the link to the app in the navigation bar.
homepage extends master.layout which includes partials.navbar
My code in the navbar.blade.php is this:
#if ($userApps)
// display link
#endif
However I get an undefined variable error. If I use this in a normal view with a controller it works fine after I declare the variable and route the controller to the view. I dont think I can put a controller to a layout since I cant route a controller to a partial view, so how do I elegantly do this?
What version of Laravel you use? Should be something like this for your case:
#include('partials.navbar', ['userApps' => $userApps])
Just for a test purpose, I did it locally, and it works:
routes.php
Route::get('/', function () {
// passing variable to view
return view('welcome')->with(
['fooVar' => 'bar']
);
});
resources/views/welcome.blade.php
// extanding layout
#extends('layouts.default')
resources/views/layouts/default.blade.php
// including partial and passing variable
#include('partials.navbar', ['fooVar' => $fooVar])
resources/views/partials/navbar.blade.php
// working with variable
#if ($fooVar == 'bar')
<h1>Navbar</h1>
#endif
So the problem must be in something else. Check your paths and variable names.
The other answers did not work for me, or seem to only work for older versions. For newer versions such as Laravel 7.x, the syntax is as follows.
In the parent view:
#include('partial.sub_view', ['var1' => 'this is the value'])
In the sub view:
{{ $var1 }}
I have gone through all the answers but below is the best way to do because you can also run queries in serviceProvider.
You need to create a separate service or you can use AppServiceProvider
<?php
namespace App\Providers;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
View::composer('layouts.admin-layout', function ($view) {
$view->with('name', 'John Doe');
});
}
}
In your layout
{{$name}}
This approach is very simple:
In parent view :
#include('partial.sub_view1', ['This is value1' => $var1])
In sub view :
{{ $var1 }}
You can use view composer to send your variable to partial view.
Check the laravel documentation on laravel.com about view composer.
Also you can check the following link that will help you resolve this problem.
https://scotch.io/tutorials/sharing-data-between-views-using-laravel-view-composers

Laravel 5 Routing Calling Wrong View

I've got a simple Laravel 5 site that I am working on (learning Laravel)
I have a link on my 'users' view to add a 'new user':
Create New User
My user Routes look like the following:
Route::get('/users', 'UserController#index');
Route::get('/user/{id}', 'UserController#edit');
Route::get('/user/create', 'UserController#create');
Route::get('/user/update', 'UserController#update');
Route::get('/user/delete/{id}', 'UserController#delete');
My UsersController has the following:
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
$users = user::all();
return view('user.index',compact('users'));
}
/**
* Show the form for creating a new resource.
*
* #return Response
*/
public function create()
{
$userroles = userrole::all();
return view('user.create', compact('userroles'));
}
When I click the link - I get the following error:
Trying to get property of non-object (View: C:\xampp\htdocs\mysite\resources\views\user\edit.blade.php)
I cannot figure out why it is trying to load edit.blade.php
I have tried just putting the following in my create view and it still doesn't render.
#extends('app')
#section('content')
Test
#endsection
I'm not sure why the routing is being so bizarre.
Any ideas?
Put the create (and update) route before the edit route in your routes file. Laravel 1st stumbles on the edit route and treats the create as id.
You can test it by doing a dd($id) in your edit method in the controller.

Categories