Laravel nova - redirect from Dashboard - laravel

I would like to remove dashboard from my Laravel Nova app.
I found it easy to remove it from sidebar-menu - simply comment /views/dashboard/navigation.blade.php code.
However, I want to add a redirection logic (landing page depends on user role) so when navigating to / user will be redirected to a resource or tool which corresponds him.
(I have already implemented a redirection after login (https://stackoverflow.com/a/54345123/1039488)
I tried to do it with cards, but looks like this is not the right solution.
Any idea where can I place the redirection logic?

Nova 4; You can override the initialPath like so:
class NovaServiceProvider extends NovaApplicationServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
parent::boot();
Nova::initialPath('/resources/users');
}
// ...
}
This way, you get redirected to the Users resource upon logging in.

Pre nova 4 method:
To NovaServiceProvider.php add to boot method:
Nova::script('menuFix', __DIR__.'/../../resources/js/fixMenu.js');
Create file fixMenu.js with following:
if (location.pathname == '/' || location.pathname == '/dashboards/main'){
location.href = '/whereToRedirect'
}

A cleaner and safe way for Nova 3.x or below:
Copy vendor/laravel/nova/resources/views/layout.blade.php to resources/views/vendor/nova/
Now open resources/views/vendor/nova/layout.blade.php and edit it
Replace this line with the code below window.Nova = new CreateNova(config);
window.Nova = new CreateNova(config);
window.Nova.booting((Vue, router, store) => {
/** This fixes showing an empty dashboard. */
router.beforeEach((to, from, next) => {
if (to.name === 'dashboard.custom') {
next({ name: 'index', params: { resourceName: 'users'}});
}
next();
});
});
Replace users with your entity name's plural like products
Now save the file and refresh the nova dashboard and you should see the new page.
The solution was taken from here with clear steps.
The solution may also work for 4.x, but I haven't checked it yet.
Happy Coding :)

Just figured this out myself. In your Routes/web.php file, add a redirect route:
Route::redirect('/','/resources/{resource_name}');
where {resource_name} is the plural form of the resource. For example, '/resources/posts'.
In your case, you may want to redirect to your own control file, where the redirect logic can be placed.
Route::get('/', 'YourController#rootRedirectLogic');
Then in the controller YourController, add the method:
public function rootRedirectLogic(Request $request) {
// some logic here
return redirect()->route('YourRoute');
}
where 'YourRoute' is the name of the route you want to send the user to.
(Found clues to this solution in a comment by dillingham here: https://github.com/laravel/nova-issues/issues/393)

i came across this link : Laravel Nova - Point Nova path to resource page
Not sure it's a permanent solution but editing LoginController.php will do.
public function redirectPath()
{
return Nova::path().'/resources/***<resource_name>***;
}
**change to your own resource name

Related

"ReflectionException Function () does not exist" when trying to setup authentication in Laravel

I'm having some trouble getting authentication working 100% in Laravel (all views seem to work so far except for "home") and was hoping to get some assistance from the Laravel experts out there.
A bit of background info:
PHP Version: 7.3.11
Laravel Version: 8.13.0
Used Composer to build the ui scaffolding (composer require laravel/ui)
Used the Bootstrap ui option (php artisan ui bootstrap --auth)
The issue
As mentioned above, I seem to be able to access all of the generated authentication views so far (login, register & the password reset views), however after registering with a dummy account I get the following error when trying to access the "home" view:
ReflectionException
Function () does not exist
The Stack trace is pointing to the following file:
"vendor/laravel/framework/src/Illuminate/Routing/RouteSignatureParameters.php:23":
<?php
namespace Illuminate\Routing;
use Illuminate\Support\Reflector;
use Illuminate\Support\Str;
use ReflectionFunction;
use ReflectionMethod;
class RouteSignatureParameters
{
/**
* Extract the route action's signature parameters.
*
* #param array $action
* #param string|null $subClass
* #return array
*/
public static function fromAction(array $action, $subClass = null)
{
$parameters = is_string($action['uses'])
? static::fromClassMethodString($action['uses'])
: (new ReflectionFunction($action['uses']))->getParameters();
return is_null($subClass) ? $parameters : array_filter($parameters, function ($p) use ($subClass) {
return Reflector::isParameterSubclassOf($p, $subClass);
});
}
/**
* Get the parameters for the given class / method by string.
*
* #param string $uses
* #return array
*/
protected static function fromClassMethodString($uses)
{
[$class, $method] = Str::parseCallback($uses);
if (! method_exists($class, $method) && Reflector::isCallable($class, $method)) {
return [];
}
return (new ReflectionMethod($class, $method))->getParameters();
}
}
With the following line (line 23) being highlighted as the error:
: (new ReflectionFunction($action['uses']))->getParameters();
And here are the routes used in the "web.php" file:
<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('welcome', ['pageTitle' => 'Home']);
});
Route::get('/services', function () {
return view('services', ['pageTitle' => 'Services']);
});
Route::get('/contact', function () {
return view('contact', ['pageTitle' => 'Contact']);
});
Auth::routes();
Route::get('/home', ['pageTitle' => 'Client Dashboard'], [App\Http\Controllers\HomeController::class, 'index'])->name('home');
After a bit of googling I've learnt that the method I'm trying to use to setup authentication has been deprecated and it is now advised to use Jetstream or Fortify, however I also found a few examples of people still managing to use this old method in their projects:
https://www.youtube.com/watch?v=NuGBzmHlINQ
As this is my first ever Laravel project I was really trying to just stick with the basics and not over complicate things for myself which is why I chose not to use Jetstream or Fortify and tried to stick to this older approach of setting up authentication. However I've been stuck on this for a couple of hours now and have not been able to figure out what's going wrong which is why I'm now seeking some help with it.
Happy to provide extra details/project code if needed - any help I can get with this would be really appreciated.
Btw, this also happens to be my first ever post on StackOverflow so any feedback on my question or advice on how I can improve it would also be greatly appreciated.
Cheers,
adb
Adjust your last route to include some type of 'action', by removing that second argument (as it only takes 2 arguments):
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
I have changed the web.php file.
I was getting the same error when using the following route:
Route::post('/delete/{id}',[AdminController::class],'destroyProduct');
Changing the route using this code fixed the problem:
Route::post('/delete/{id}','App\Http\Controllers\AdminController#destroyProduct');
I was getting the same error when making a simple route.
Route::get("/test", [ListPagesController::class, "index"]);
This was my code in the web.php file and I was routing my blade file in views via the controller.
When I later redirected it directly to web.php this way without using a controller, the problem was resolved.
Route::get("/test", function () {return view("main");});
I don't quite understand why but the problem is solved.
You Should add it in line 2 web.php
use App\Http\Controllers\YourControllerName;
For me, I changed:
Route::get('/branch/', [Controller::class, 'get_branch_list'])->name('branch');
To:
Route::get('/branch/', 'Controller#get_branch_list')->name('branch');

Create generic route-based authorization in Laravel

I'm coming from conventional PHP background and trying to create my first big project in Laravel.
I usually user User/Role/Permission to manage user permissions in my applications. It works like follows:
User has many Roles
Role has many Permissions
to make things simple, I actually used the page names as permissions, so that I check the current page name against user permissions.
That was all easy in PHP, now I am trying to implement a similar approach in Laravel. I have User, Role, Permission models, and I check if user has permission using a method in User model as follows (inspired from a Laracasts tutorial):
public function permissions()
{
return $this->roles->map->permissions->flatten()->pluck('name')->unique();
}
And in my AuthServiceProvider I added the following code:
Gate::before(function ($user, $permission){
return $user->permissions()->contains($permission);
});
So if I add some permission (for example 'add_user') to the user, I can simply do the following in the route, and it works just fine:
Route::get('/test', function () {
return 'You are authorized';
})->name('add_user')->middleware('can:add_user');
Now since I have a lot of pages, I wouldn't like to pass specific permission name to the middleware, rather find a better and more generic way.
The only way I could come up with is to use the permission name same as the route name, and create a new middleware to take care of authorization.
So In my solution I added the following middleware class:
class BeforeMiddleware
{
public function handle($request, Closure $next)
{
$route_name = $request->route()->getName();
if(!Auth::user()->permissions()->contains($route_name)) {
throw new \Exception('Not Authorized');
}
return $next($request);
}
}
Added it to Kernel.php:
protected $routeMiddleware = [
'before' => \App\Http\Middleware\BeforeMiddleware::class,
...
];
And finally changed the route to be as follows:
Route::middleware(['before'])->group(function () {
Route::get('/test', function () {
return 'You are authorized';
})->name('add_user');
});
This way I don't actually have to pass the permission name when I check the permission, and directly get it from the route name.
I have many questions about my solution: is it really a good approach? Does it have any drawbacks? Is there a better approach?
Also I preferred to use AuthServiceProvider instead of the new middleware, but I couldn't retrieve the route name from ServiceProvider scope. Can I somehow use AuthServiceProvider for a similar case?
Sorry if I made the post somehow long, but I needed to be as clear as I could.

Laravel - Add Route Wildcard to every Route

I have created a multilanguage application in laravel and for every route (because i want to see in the url what my language is) i need
www.example.com/{locale}/home
for example, whereas {locale} is the set language and home well, is home. but for every route i need to declare that locale wildcard. is there any way to get this done with middleware or something, to add this before route is executed?
Thanks!
You can use prefix for it.
Route::group(['prefix' => '{locale}'], function () {
Route::get('home','Controller#method');
Route::get('otherurl','Controller#method');
});
And here how you can access it now.
www.example.com/{locale}/home
www.example.com/{locale}/otherurl
For more info.
https://laravel.com/docs/5.8/routing#route-group-prefixes
Not sure if I am understanding your request right, but I believe this is the scope you are looking for:
A generalized route which can receive the "locale" based on which you can serve the page in the appropriate language.
If that's the case, I would define a route like this:
Route::get({locale}/home, 'HomeController#index');
and then in your HomeController#index, you will have $locale variable based on which you can implement your language logic:
class HomeController extends Controller
{
/**
* Show the application homepage.
*
* #return mixed (View or Redirect)
*/
public function index(Request $request, $locale)
{
switch ($locale) {
case 'en':
//do english logic
break;
so on...
}
}
I hope it helps

How to render a cms page with default theme AND variables from controllers in OctoberCMS?

I'm wondering how I can render a view, or display a page with my default theme in OctoberCMS, via a route that executes a function in a controller.
If I have the following route:
Route::get('bransje', [
'uses' => 'Ekstremedia\Cityportal\CPController#bransje'
]);
And in my controller CPController ive tried several things, like I used to with Laravel:
public function bransje() {
$stuff = Stuff::with('info');
return View::make('cms::bransje')->with('stuff',$stuff);
}
But I cannot seem to get it to work, and I've tried to search the web, but it's hard to find answers. I have found a workaround, and that is to make a plugin component, then I can include that component and do:
public function onRun()
{
$this->eventen = $this->page['stuff'] = $this->stuff();
}
protected function stuff()
{
return ...
}
Is there any way so I can make pages without using the Cms, and that are wrapped in my default theme? I've tried
return View::make('my-theme-name::page');
and a lot of variants but no luck.
I know I can also do a:
==
public function onRun()
{
}
in the start of my page in the cms, but I'm not sure how to call a function from my plugin controller via there.
You can bypass frontend routing by using routes.php file in your plugin.
Full example in this video turotial.
If this answer can still be useful (Worked for October v434).
I have almost the same scenerio.
What I want to achieve is a type of routing like facebook page and profile.
facebook.com/myprofile is the same url structure as facebook.com/mypage
First I create a page in the CMS for each scenario (say catchpage.htm)
Then a created a catchall route at the buttom of routes.php in my plugin that will also not disturb the internal working of octobercms.
if (!Request::is('combine/*') && !Request::is('backend/*') && !Request::is('backend')) {
// Last fail over for looking up slug from the database
Route::get('{slug}/{slug2?}', function ($slug, $slug2 = null) {
//Pretend this are our routes and we can check them against the database
$routes = ["bola", "sade", "bisi", "ade", "tayo"];
if(in_array($slug, $routes)) {
$cmsController = new Cms\Classes\Controller;
return $cmsController->render("/catchpage", ['slug' => $slug]);
}
// Some fallback to 404
return Response::make(View::make('cms::404'), 404);
});
}
The if Request::is check is a list of all the resource that october uses under the hood, please dont remove the combine as it is the combiner route. Remove it and the style and script will not render. Also the backend is the url to the backend, make sure to supply the backend and the backend/*.
Finally don't forget to return Response::make(View::make('cms::404'), 404); if the resource is useless.
You may put all these in a controller though.
If anyone has a better workaround, please let us know.

How to catch any link that came from upload/ in laravel 5?

im new in laravel 5.2, I just want to ask how you can catch a link that came from uploads like: http://sitename.com/uploads/59128.txt? I want to redirect them to login page if they tried to access any of route or link that came from uploads/{any filename}.
Yes you can achieve by protecting your route with auth middleware,
make a small FileController
class FileController extends Controller {
public function __construct()
{
$this->middleware('auth');
}
public function getFile($filename)
{
return response()->download(storage_path($filename), null, [], null);
}
}
and then in routes.php
Route::get('file/{filename}', 'FileController#getFile')->where('filename', '^[^/]+$');
And that's it. Now, your authenticated users can download files from storage folder (but not its subfolders) by calling http://yoursite.com/file/secret.jpg. Add you can use this URL in src attribute of an image tag.
answer's original source!
#xerwudjohn simple you can't.
When this file is in the public folder, everyone can access it whitout being logged in.
One method I tried for some minutes, create a new route:
Route::group(['middleware' => ['web', 'auth']], function () {
Route::get('/download/{id}', 'DownloadController#showFile');
});
create the function showFile in the DonwloadController
public function showFile($id)
{
return redirect('/image/'.$id.'.txt');
}
or use a Model to read uniqueIds out of any table and get the realfile name.
Cheers

Resources