Conditional routing based on Middleware - php

I need to call different controller for the same url based on a middleware. The url has to be the same, so redirecting in the middleware is not an option. The code below is sample, controllers for dozens for routes are already finished, so checking the session value there is not an option either.
Tried to create two different middleware (has/hasnt the session value), but the latter route group overwrites the previous anyway. Any clue? Maybe a different approach needed?
route.php looks like this:
Route::group(array('namespace' => 'Admin', 'prefix' => 'admin', 'middleware' => 'auth'), function () {
// set of default routes
Route::get('/', array('as' => 'admin', 'uses' => 'FirstController#index'))->middleware('admin');
Route::get('/profile', array('as' => 'profile', 'uses' => 'FirstController#profile'))->middleware('admin');
Route::group(array('middleware' => 'sessionhassomething'), function () {
// set of the same routes like above but overwritten if middleware validates
Route::get('/', array('as' => 'admin', 'uses' => 'SecondController#index'))->middleware('admin');
Route::get('/profile', array('as' => 'profile', 'uses' => 'SecondController#profile'))->middleware('admin');
});
});
SessionHasSomething middleware:
class sessionHasSomething {
public function handle($request, Closure $next)
{
if(session()->has("something_i_need_to_be_set")) {
return $next($request);
}
// return what if not set, or ...?
}
}
Thanks in advance!

If you are only checking if session()->has('something'), it is possible to use route closures to add a condition within the route which needs to be dynamic.
Below is an example:
Route::get('/', function() {
$controller = session()->has('something')) ? 'SecondController' : 'FirstController';
app('app\Http\Controllers\' . $controller)->index();
});
->index() being the method within the controller class.

We almost have the same issue and here's what I did. (I didn't use middleware).
In my blade.php, I used #if, #else and #endif
<?php
use App\Models\User;
$check = User::all()->count();
?>
#if ($check == '0')
// my html/php codes for admin
#else
// my html/php codes for users
#endif
you can also do that in your controller, use if,else.

Related

Laravel $id return 'en' instead of id

My route:
Route::group([
'prefix' => '{locale}',
'where' => ['locale' => '[a-zA-Z]{2}'],
'middleware' => 'setlocale'],
function () {
// GROUP FOR AUTHENTICATION
Route::group([
'middleware' => 'auth:sanctum', 'verified',
], function () {
// GROUP FOR ADMIN
Route::group([
'prefix' => 'admin',
'as' => 'admin.',
], function () {
Route::resource('partner', PartnerFormController::class);
});
});
});
My view that when I click, it shows the details page:
Edit
My controller:
public function show(PartnerForm $partnerForm, $id)
{
$details = DB::table('partner_forms')->where('id', $id)
->first();
return view('admin.partner-details', compact('details'));
}
I tried to call $details->name or $details->in my view details page but it didnt work. The URL is working properly by displaying http://127.0.0.1:8000/en/admin/partner/1 but when i dd() my $id in controller it returns en, which I believe is the en from the URL.
Instead of sending the ID along with the route, send all the variables and enter the information into the new page in the control without the need to connect to the database and using route model binding.
Example :
view A
Foo
route
Route::get('.../{partner}', [Controller::class, 'Bar'])->name('admin.partner.show');
controller
public function Bar(Partner_MODEL $partner){
return view('view_name', compact('partner'));
}
view B : use $partner.
Important note : in (route, controller method, compact meethod) The variable name must be similar

Laravel 5.4 routing for same prefix group but different middleware giving error

I need all the route under same prefix manager with one middleware for guest manager_guest and another for logged in user manager_auth.
This code bellow is my route web.php file.
Is there any other way ?
My routes:
Route::prefix('manager')->group(['middleware' => 'manager_guest'], function () {
Route::get('/register', 'Manager\RegisterController#showRegister')->name('manager.register.create');
Route::post('/register', 'Manager\RegisterController#register')->name('manager.register.store');
Route::get('/login', 'Manager\LoginController#showLogin')->name('manager.login.create');
Route::post('/login', 'Manager\LoginController#login')->name('manager.login');
});
Route::prefix('manager')->group(['middleware' => 'manager_auth'], function () {
Route::post('/logout', 'Manager\LoginController#logout')->name('manager.logout');
Route::get('/profile', 'Manager\PageController#profile')->name('manager.profile');
});
Error after executing php artisan route:list
PHP Warning: Uncaught ErrorException: Array to string conversion in E:\laragon\www\laraveladmin\vendor\laravel\framework\src\Illuminate\Routing\Router.php:329
Stack trace:
#0 E:\laragon\www\laraveladmin\vendor\laravel\framework\src\Illuminate\Routing\Router.php(329): Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(8, 'Array to string...', 'E:\\laragon\\www\\...', 3
29, Array)
#1 E:\laragon\www\laraveladmin\vendor\laravel\framework\src\Illuminate\Routing\Router.php(329): require()
#2 E:\laragon\www\laraveladmin\vendor\laravel\framework\src\Illuminate\Routing\Router.php(285): Illuminate\Routing\Router->loadRoutes(Array)
#3 E:\laragon\www\laraveladmin\vendor\laravel\framework\src\Illuminate\Routing\RouteRegistrar.php(104): Illuminate\Routing\Router->group(Array, Array)
#4 E:\laragon\www\laraveladmin\routes\web.php(30): Illuminate\Routing\RouteRegistrar->group(Array, Object(Closure))
#5 E:\laragon\www\laraveladmin\vendor\laravel\framework\src\Illuminate\Routing\Router.php(329): require('E:\\laragon\\www\\...')
#6 in E:\laragon\www\laraveladmin\vendor\laravel\framework\src\Illuminate\Routing\Router.php on line 329
PHP Fatal error:  Illuminate\Routing\Router::loadRoutes(): Failed opening required 'Array' (include_path='E:\Developer\Wbserver\php\PEAR') in E:\laragon\www\laraveladmin\vendor\laravel\framework\src\Illuminate
\Routing\Router.php on line 329
 
[Symfony\Component\Debug\Exception\FatalErrorException] Illuminate\Routing\Router::loadRoutes(): Failed opening required 'Array' (include_path='E:\Developer\Wbserver\php\PEAR')
Try this instead
Route::group(['prefix' => 'manager', 'middleware' => 'manager_guest'], function() {
});
You could "factorize" your code like this:
Route::prefix('manager')->group(function () {
Route::middleware(['manager_guest'])->group(function () {
// These will be prefixed with "manager" and assigned the "manager_guest" middleware
});
Route::middleware(['manager_auth'])->group(function () {
// These will be prefixed with "manager" and assigned the "manager_auth" middleware
});
// These will just be prefixed with "manager"
});
I noticed all your controllers live in the sub-namespace Manager. You can chain the methods and make your routes file even cleaner. For instance:
Route::prefix('manager')->namespace('Manager')->group(function () {
Route::middleware(['manager_guest'])->group(function () {
Route::get('register', 'RegisterController#showRegister')->name('mananger.register.create');
});
Route::middleware(['manager_auth'])->group(function () {
Route::get('profile', 'PageController#profile')->name('mananger.profile');
});
});
None of the other answers worked for me as I had a lot of routes to change, and didn't want to change namespaces. The key to making this work is "as". The downside of this being that it changes the path when using "route()", but your use of name on each route here would override that anyway.
Route::group(['prefix' => 'manager', 'middleware' => ['manager_guest'], 'as' => 'manager_guest'], function() {
...
}
Route::group(['prefix' => 'manager', 'middleware' => ['manager_auth'], 'as' => 'manager_auth'], function() {
...
}

Laravel redirect to user dashboard when visiting login page if logged in

I have a basic login system setup, but I would like the user to be sent to there dashboard page if they try to access the "login" page or "create account" page.
How do I go about doing this?
I am thinking something in the routes file?:
Route::post('/login', array('uses' => 'UserController#login'));
Route::post('/create-account', array('uses' => 'UserController#createAccount'));
Route::group(array('before' => 'auth'), function () {
Route::get('/dashboard', array('uses' => 'DashboardController#index'));
Route::get('/logout', function () {
Auth::logout();
return Redirect::to('/start');
});
});
Perhaps some kind of group around the first two routes?
A before filter is perfect for this. Since it basically will do the opposite of auth let's call it no_auth:
Route::filter('no_auth', function(){
if(Auth::check()){
return Redirect::to('dashboard');
}
}
And then wrap a group around your two routes to apply the filter:
Route::group(array('before' => 'no_auth'), function(){
Route::post('/login', array('uses' => 'UserController#login'));
Route::post('/create-account', array('uses' => 'UserController#createAccount'));
});
Edit
Actually, as #afarazit points out, there's already a filter like that in app/filters.php called guest. You just have to change the redirect URL to dashboard and you're ready to go.
There's already a filter for what you want, check your filters.php for "guest"
There are many ways to do this. You can use an Event listener like so:
Event::listen('user.login', function (){
if(Auth::check()){
return Redirect::to('dashboard');
}
});
Event::listen('user.create', function (){
if(Auth::check()){
return Redirect::to('dashboard');
}
});
You need a named controller for above like so:
Route::post('/login', array(
'uses' => 'UserController#login',
'as' => 'user.login'
));
Route::post('/create-account', array(
'uses' => 'UserController#createAccount',
'as' => 'user.create'
));
You may use a constructor and include a filter in it. Here is an example; You can modify your code according to the example.
public function __construct(SignInForm $signInForm)
{
$this->signInForm = $signInForm;
$this->beforeFilter('guest', ['except' => 'destroy']);
}
If laravel version is 4.2
open your app/filters.php and add
Route::filter('no_auth', function(){
if(Auth::check()){
return Redirect::to('dashboard');
}
});
add your login and create account pages to your app/routes.php like below:
Route::group(array('before' => 'no_auth'), function(){
Route::post('/login', array('uses' => 'UserController#login'));
Route::post('/create-account', array('uses' => 'UserController#createAccount'));
});
It worked for me.

Laravel - parameters in filter and routes

I have the following code:
filters.php
Route::filter('empty_cart', function () {
if (empty(Cart::contents()) || Cart::totalItems() == 0) {
return Redirect::to('');
}
});
routes.php
Route::group(array('before' => 'csrf','before' => 'detectLang','before' => 'empty_cart'), function () {
Route::get('site/{slug}/cart', array('uses' => 'CartController#getCart'));
Route::get('site/{slug}/cart/billing', array('uses' => 'CartController#getBilling'));
Route::get('site/{slug}/login', array('uses' => 'UsersController#getLoginForm'));
});
How can I redirect the user to the "site/{$slug}" if the cart is empty? Can I use parameters in the filter.php or how can I send the "slug" to the filter?
Your issue is likely in your Route::group line. You are passing an array of filters to run but giving each individual item the same key. You should split each before filter with a pipe |:
Route::group(array('before' => 'csrf|detectLang|empty_cart'), function () {
// Your routes here
}
The routes you define within the group will only be valid when all 3 filters are passed, if any of the filters fail, you will get a 404. If you would like to implement certain action when a filter fails you can remove this filter in the routes file and implement it on the controller's constructor or elsewhere.
Alternatively, you could try adding another route after this group, that doesn't apply the filters such that any requests that don't match the filtered routes will be caught by this event. You could then put your redirect in place.
Route::group(array('before' => 'csrf|detectLang|empty_cart'), function () {
Route::get('site/{slug}/cart', array('uses' => 'CartController#getCart'));
}
Route::get('site/{slug}/cart', 'YourController#yourAction');
// OR
Route::get('site/{slug}/cart', function($slug){
return Redirect::to('/'. $slug);
});

Laravel - Subdomain localization

I want to set the localization using subdomains. I've managed to set up subdomain wildcards and it's working fine. However I'd like to set up filters.
For example I was thinking of setting up an array of available countries in the config:
<?php
return array(
'available' => array(
'uk',
'fr',
'de'
)
);
Then in my routes I need a way of filtering a group. For the moment my code is the following without any filters:
<?php
$homeController = 'MembersController#profile';
if ( ! Sentry::check())
{
$homeController = 'HomeController#index';
}
Route::group(['domain' => '{locale}.'.Config::get('app.base_address')], function() use ($homeController)
{
Route::get('/', ['as' => 'home', 'uses' => $homeController]);
Route::post('users/register', ['as' => 'register', 'uses' => 'UsersController#register']);
Route::resource('users', 'UsersController');
});
Does anyone have any ideas for filtering the group?
Also if the subdomain isn't valid how can I redirect to something like uk.domainname.com?
Thank you in advance for any help, it's much appreciated.
you could solve this in your routes with a filter, that will be executed first. it checks then for the available subdomains and if it doesn't find it, it redirects to a default subdomain.
Route::filter('subdomain', function()
{
$subdomain = current(explode('.', Request::url()));
if (!in_array($subdomain, Config::get('app.countries.available'))) {
return Redirect::to(Config::get('app.default_subdomain') . '.' . Config::get('app.base_address'));
}
});
Route::group(['before' => 'subdomain'], function()
{
...
}
In your app/filters.php I would write something like this. You will have a to create a new variable in your config called availableSubdomains with your subdomains array.
<?php
Route::filter('check_subdomain', function()
{
$subdomain = Route::getCurrentRoute()->getParameter('subdomain');
if (!in_array($subdomain, Config::get('app.availableSubdomains')))
return Redirect::home();
});
Then I will add a before filter in your group route in app/routes.php
<?php
Route::group(
['domain' => '{locale}.'.Config::get('app.base_address'),
'before' => 'check_subdomain']
, function() use ($homeController)
{
Route::get('/', ['as' => 'home', 'uses' => $homeController]);
Route::post('users/register', ['as' => 'register', 'uses' => 'UsersController#register']);
Route::resource('users', 'UsersController');
});
Sorry, I haven't tested it.
For subdomains where the language designator is the first part of the subdomain name, like: en.domain.com/section here is what I've used for laravel 5.1
this uses getHost which avoids the problem with http/https showing up first
app\Http\routes.php:
Route::filter('subdomain', function() {
$locale_url = current(explode('.', Request::getHost()));
if (!in_array($locale_url, Config::get('app.countries_available'))) {
return Redirect::to(Config::get('app.default_subdomain') . '.' . Config::get('app.base_address'));
}
App::setLocale($locale_url);
});
it is necessary to add things like:
config/app.php:
'countries_available' => ['en','es'],
to find the variable
finally, to add it to a route
app\Http\routes.php:
Route::group(['before' => 'subdomain'], function()
{
Route::get('/', 'control#func');
...
});

Categories