Laravel - parameters in filter and routes - php

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);
});

Related

Conditional routing based on Middleware

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.

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() {
...
}

How to pass extra parameters to controller from Laravel route

I'm trying to handle basic validation of my API calls in the Laravel's routes. Here is what I want to achieve:
Route::group(['prefix' => 'api/v1/properties/'], function () {
Route::get('purchased', 'PropertiesController#getPropertyByProgressStatus', function () {
//pass variable x = 1 to the controller
});
Route::get('waiting', 'PropertiesController#getPropertyByProgressStatus', function () {
//pass variable x = 2 to the controller
});
});
Long story short, depending on the segment of the URI after api/v1/properties/ I want to pass a different parameter to the controller. Is there a way to do that?
I was able to get it to work with the following route.php file:
Route::group(['prefix' => 'api/v1/properties/'], function () {
Route::get('purchased', [
'uses' => 'PropertiesController#getPropertyByProgressStatus', 'progressStatusId' => 1
]);
Route::get('remodeled', [
'uses' => 'PropertiesController#getPropertyByProgressStatus', 'progressStatusId' => 1
]);
Route::get('pending', [
'uses' => 'PropertiesController#getPropertyByProgressStatus', 'progressStatusId' => 3
]);
Route::get('available', [
'uses' => 'PropertiesController#getPropertyByProgressStatus', 'progressStatusId' => 4
]);
Route::get('unavailable', [
'uses' => 'PropertiesController#getPropertyByProgressStatus', 'progressStatusId' => 5
]);
});
and the following code in the controller:
public function getPropertyByProgressStatus(\Illuminate\Http\Request $request) {
$action = $request->route()->getAction();
print_r($action);
Pretty much the $action variable is going to let me access the extra parameter that I passed from the route.
I think that you can do it directly in the controller and receiving the value as a parameter of your route:
First you need to specify the name of the parameter in the controller.
Route::group(['prefix' => 'api/v1/properties/'], function ()
{
Route::get('{parameter}', PropertiesController#getPropertyByProgressStatus');
In this way, the getPropertyByProgressStatus method is going to receive this value, so in the controller:
class PropertiesController{
....
public function getPropertyByProgressStatus($parameter)
{
if($parameter === 'purchased')
{
//do what you need
}
elseif($parameter === 'waiting')
{
//Do another stuff
}
....
}
I hope it helps to solve your issue.
Take a view for this courses: Learn Laravel or Create a RESTful API with Laravel
Best wishes.
----------- Edited ---------------
You can redirect to the route that you want:
Route::group(['prefix' => 'api/v1/properties/'], function () {
Route::get('purchased', function () {
return redirect('/api/v1/properties/purchased/valueToSend');
});
Route::get('waiting', function () {
return redirect('/api/v1/properties/waiting/valueToSend');
});
Route::get('purchased/{valueToSend}', PropertiesController#getPropertyByProgressStatus);
});
Route::get('waiting/{valueToSend}', PropertiesController#getPropertyByProgressStatus);
});
});
The last two routes response to the redirections and send that value to the controller as a parameter, is the most near that I think to do this directly from the routes.

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 - 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