Namespaced routes not working in Laravel 5 - php

I'm building an international website, therefore I managed to have URLs looking like /{language}/{other_stuff} thank to some manipulation in RouteServiceProvider
/**
* Define the routes for the application.
*
* #param \Illuminate\Routing\Router $router
* #return void
*/
public function map(Router $router, Request $request)
{
$locale = $request->segment(1);
$this->app->setLocale($locale);
/**
* Internationalization routing system
*/
$router->group(['namespace' => $this->namespace, 'prefix' => $locale], function($router) use ($locale) {
if ($locale == 'en') require app_path('Http/routes_en.php');
elseif ($locale == 'el') require app_path('Http/routes_el.php');
});
}
Works like a charm. Every language will have his own route file, it's a choice.
Let's say we go to /en/ and you're an admin, I created another namespace within Http/route_en.php to focus on the admin section :
Route::group(['namespace' => 'Admin', 'prefix' => 'admin'], function() {
Route::controller('', 'DashboardController');
Route::controller('brands', 'BrandsController');
Route::controller('contents', 'ContentsController');
Route::controller('downloads', 'DownloadsController');
Route::controller('news', 'NewsController');
Route::controller('products', 'ProductsController');
Route::controller('settings', 'SettingsController');
Route::controller('users', 'UsersController');
});
So now I should access easily sections such as /en/admin/brands but it fails. I generate all my links dynamically thanks to the HTML class
{!! HTML::linkAction('Admin\BrandsController#getIndex', 'Brands') !!}
The generation works fine when I go to /en/admin which means Admin\BrandsController#getIndex is detected by this package, but when you click on it
Sorry, the page you are looking for could not be found.
I tested some stuff and when I just simply set the route outside group() it works fine.
Route::controller('admin/brands', 'Admin\BrandsController');
What am I missing here ? Shouldn't the HTML class and the routing system agree with each others ? Is there any mistake I made ? Maybe there's an issue ?
EDIT : I opened an issue for this problem on GitHub

So nobody tried to help me.
After a few days, an issue and many tests I understood the problem by myself : you have to put the DashboardController route at the end otherwise the routing system will take it first and ignore the other ones.
/**
* Admin
*/
Route::group(['namespace' => 'Admin', 'prefix' => 'admin', 'middleware' => 'is.admin'], function() {
Route::controller('news', 'NewsController');
Route::controller('brands', 'BrandsController');
Route::controller('products', 'ProductsController');
Route::controller('users', 'UsersController');
Route::controller('downloads', 'DownloadsController');
Route::controller('settings', 'SettingsController');
Route::controller('contents', 'ContentsController');
Route::controller('', 'DashboardController');
});
NOTE : Everything will seem alright in the route listing, and even in the HTML/Form packages, but it's not.
I let it here for anybody that would have similar problems.

Related

Load backend and frontend routes separately without interfering

I have two kind of routes, admin routes and frontend routes.
The frontend routes
Route::get('{locale?}/', ['uses' => '\App\Http\Controllers\loadViewController#home']);
Route::get('{locale?}/{page}', ['uses' => '\App\Http\Controllers\loadViewController#index']);
Route::get('{locale?}/{template?}/{page}', ['uses' => '\App\Http\Controllers\loadViewController#detail']);
The backend routes
Route::prefix('admin/dashboard')->group(function () {
Route::get('/', 'DashboardController#index')->name('dashboard');
});
Now when i type admin/dashboard or api/admin, laravel uses the frontend routes to load the views, while i want the backend views to be loaded.
So to filter out the backend routes i tried this
Route::group(['where' => ['page' => '^(?!admin|api)$', 'template' => '^(?!admin|api)$']], function ({
Route::get('{locale?}/', ['uses' => '\App\Http\Controllers\loadViewController#home']);
Route::get('{locale?}/{page}', ['uses' => '\App\Http\Controllers\loadViewController#index']);
Route::get('{locale?}/{template?}/{page}', ['uses' => '\App\Http\Controllers\loadViewController#detail']);
});
which obviously did not work
Also the frontend routes should not have something like /website, they should all start with /
My question is: How can i load the backend and frontend routes separately without interfering when called, even if they have the same url length in terms of parameters, keep in mind that the admin routes always start with /admin or /api.
Note: i can't put the backend routes before the frontend routes
Thanks in advance!
If you want to you could put a constraint on the locale route parameter:
Route::pattern('locale', '^(?!(api|admin)$)(\w*)');
You can put this in the boot method of you RouteServiceProvider and it will now not allow the locale route parameter to match for 'api' or 'admin'.
You can register seperate routes in RouteServiceProvider. Following is how you can do it.
Inside RouteServiceProvider.php do:
public function map()
{
$this->mapFrontendRoutes();
$this->mapAdminRoutes();
}
Definition of mapFrontendRoutes():
protected function mapFrontendRoutes()
{
Route::prefix('{locales?}')
->middleware('frontend')
->namespace($this->namespace.'\Frontend')
->group(base_path('routes/frontend.php'));
}
Definition of mapAdminRoutes():
protected function mapAdminRoutes()
{
Route::prefix('admin')
->middleware('admin')
->namespace($this->namespace.'\Admin')
->group(base_path('routes/admin.php'));
}
I personally find this very useful, helps to declare interference free and logical routes. Open to feedback.
The simple way is to group both url's as separate groups. Example as follows :
Route::group(['prefix' => 'admin', 'as' => 'admin'], function () {
Route::post('/dashboard', 'AdminController#dashboard');
});
Route::group(['prefix' => 'home', 'as' => 'home'], function () {
Route::get('/record/{id}', 'HomeController#getRecord');
});

how change order of route files defined in RouteServiceProvider - Laravel 5.3

As it was presented here, I have defined two route files in my app/Providers/RouteServiceProvider.
public function map()
{
$this->mapWebRoutes();
$this->mapProjectRoutes();
$this->mapApiRoutes();
//
}
below I have defined
protected function mapProjectRoutes()
{
Route::group([
'middleware' => 'web',
'namespace' => $this->namespace,
], function ($router) {
require base_path('project/routes/project.php');
});
}
problem:
I want the routes in project.php to be parsed first, then the web.php.
I have checked all four possible positions of the above definitions, e. putting the mapProjectRoutes above and below mapWebRoutes.
Whatever the order of the functions was, the routes in web.php took precedence.
The only way to make the routes in project.php work is to comment out the $this->mapWebRoutes();
my question
How to control the order of the route files.
Just to prevent simple mistakes, after every change of order I was doing php artisan cache:clear - didn't help
Thx

Laravel post route controller method not getting called

I'm building an app in Laravel and I already had my user registration working fine, I now want to modify how the registration works so I modified my route to call a different method.
Originally the route was defined like so:
Route::post('register', 'Auth\AuthController#postRegister');
And this worked fine. I then changed it to:
Route::post('register', 'Auth\AuthController#someOtherMethod');
This method is defined as follows:
public function someOtherMethod(Request $request)
{
die('If the method is called you should see this');
}
However, it doesn't get called (the message doesn't show). Instead it redirects me to the root of the site.
Note that I have a cache-busting script on my server that I run every time I have weird issues like this which runs the following commands:
php artisan route:clear
php artisan cache:clear
service php5-fpm restart
service nginx restart
I also run the page in an incognito/private window every time I make a change.
Now for the interesting part; I tried undoing the changes I made so that it calls postRegister again, I fully expected this to make it revert to the default behaviour but it still redirects me to the root of the site! So now I don't even have a registration page that functions at all.
Does anyone have any idea what's going on?
Thanks in advance for your help.
Edit:
Here's my full routes.php:
use Illuminate\Http\Request;
Route::group(['middleware' => 'web'], function () {
/** Public routes **/
Route::get('', 'HomepageController#index');
Route::get('/', 'HomepageController#index');
Route::get('terms', function() {
return view('terms');
});
Route::get('privacy', function() {
return view('privacy');
});
/** Public auth routes **/
Route::get('register', 'RegistrationController#index');
Route::post('register', 'Auth\AuthController#postRegister');
Route::get('login', function() {
return view('auth.login');
});
Route::post('login', 'Auth\AuthController#postLogin');
Route::get('logout', 'Auth\AuthController#getLogout');
Route::get('dashboard/login', function() {
return view('admin.login');
});
Route::post('dashboard/login', 'AdminAuth\AuthController#postLogin');
Route::get('dashboard/logout', 'AdminAuth\AuthController#getLogout');
/** Admin routes **/
Route::get('dashboard', [
'middleware' => 'admin',
'uses' => 'Admin\DashboardController#index'
]);
Route::get('dashboard/users', [
'middleware' => 'admin',
'uses' => 'Admin\DashboardController#showUsers'
]);
Route::get('dashboard/search', [
'middleware' => 'admin',
'as' => 'adminSearch',
'uses' => 'Admin\DashboardController#query'
]);
/** Admin auth routes **/
Route::get('dashboard/staff/create', [
'middleware' => 'admin',
function () {
return view('admin.register');
}
]);
Route::post('dashboard/staff/create', [
'middleware' => 'admin',
'uses' => 'AdminAuth\AuthController#postRegister'
]);
/** Controllers **/
Route::controllers([
'password' => 'Auth\PasswordController',
]);
});
make sure that you config/auth.php is calling proper Auth guard. Also redirectsTo is by default set to '/' which is route of site. What is in your middleware? the default RedirectIfAuthenticated middleware has by default entry to point to root of the site. Only these 3 scenarios possibly acting other than expected.

Laravel 5 can't find class for custom namespace

In my Laravel app I'm splitting the front end and back end code into folder. These are app/Http/Controllers/BackEnd and app/Http/Controllers/FrontEnd. Rather than type all that out on every file I thought it would be easier to define two namespaces, BackEnd and FrontEnd. I've edited my composer file to this:
"autoload": {
"classmap": [
"app/Models",
"database"
],
"psr-4": {
"App\\": "app/",
"BackEnd\\": "app/Http/Controllers/BackEnd",
"FrontEnd\\": "app/Http/Controllers/FrontEnd"
}
},
I then ran composer autodump and set up my route file like this:
Route::group(['prefix' => 'webman', 'middleware' => 'auth', 'namespace' => 'BackEnd'], function()
{
Route::get('/', ['as' => 'webmanHome', 'uses' => 'HomeController#index']);
});
But when I browse to localhost:8000/webman/ I just get an error, Class App\Http\Controllers\BackEnd\HomeController does not exist. The controller does exist, this is the file:
<?php namespace BackEnd;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class HomeController extends Controller {
/**
* Display the admin home page, showing the front-end menu and "apps" as links to other sections of the ACP.
*
* #param Reqeust $request
*
* #return View
*/
public function index(Request $request)
{
return view('backend.index');
}
}
I've checked vendor/composer/autoload_psr4.php to make sure that the namespace is being defined and it is, this is in the array returned 'BackEnd\\' => array($baseDir . '/app/Http/Controllers/BackEnd'),.
Strangely if I use <?php namespace App\Http\Controllers\BackEnd; at the top of HomeController.php then everything works, why? What am I missing? Why can't autoload find the file with just BackEnd?
When setting namespace in Route::group() it is actually appending that to App\Http\Controllers. What you could do is remove it and reference the full path like so:
Route::group(['prefix' => 'webman', 'middleware' => 'auth'], function()
{
Route::get('/', ['as' => 'webmanHome', 'uses' => '\BackEnd\HomeController#index']);
});
Try changing/commenting the below line in RouteServiceProvider.php
protected $namespace = 'App\Http\Controllers';
There's an interesting and easy way to get around this... Service Providers.
When the route file is loaded via a provider, the 'App\Http...' is not enforced.
public function boot()
{
$this->loadRoutesFrom(app_path('Your/Model/routes.php'));
}
Keep in mind no middleware is attached either. Your route group will have to specify a 'web' middleware or you'll go nuts wondering why validation, etc, isn't working anymore....(been there!)
It's a cool way to go about it anyway, using providers leads to more modular code and re-use.

Laravel 4: Can I tell which route is calling the controller function?

I have a laravel app with 2 groups of routes:
Route::group(array('prefix' => 'api'), function()
{
Route::post('/login', ['uses' => 'AuthenticationController#apiLogin']);
}
Route::group(array('prefix' => 'admin'), function()
{
Route::post('/login', ['uses' => 'AuthenticationController#adminLogin']);
}
In an effort to save time and prevent writing double code I'd like to condense the apiLogin() and adminLogin() function to one function: login(). I'd also like to return different things based on the route that is calling the function.
If the request is coming from /api/login I want to return Response::json($apiResponse). If the request is coming /admin/login I want to return Redirect::('route.to.redirect.to')
Is there a way I can tell where the controller function is being called from? (preferable without parsing the URL)
You can check the route in your controller. (I'm not saying this is the best solution for your problem, but you can)
The best way to do this is by naming your routes. Laravel Docs
Route::post('/login', ['as' => 'apiLogin', 'uses' => 'AuthenticationController#apiLogin']);
Route::post('/login', ['as' => 'adminLogin', 'uses' => 'AuthenticationController#adminLogin']);
And then you just do
Route::currentRouteName();
If for some reason you can't name your routes you can still get the path of the route (that's not the full url but the segment that's defined in the route. groups included)
So Route::getCurrentRoute()->getPath() should return either api/login or admin/login
You can check URL in controller, but the better solution in this case would be probably leaving routes as they are, create login method with parameter:
public function login($from) {
}
and define apiLogin and adminLogin functions this way:
public function apiLogin() {
return $this->login('api');
}
public function adminLogin() {
return $this->login('admin');
}
this way, if you will decide in future to change the code you will change the code only of those methods, leaving routes without a change.

Categories