Laravel 3 - set routes dyncamically - laravel

I am using Laravel 3 with two sets of login controllers - the main domain goes to login, all subdomains should route to portal/login#index
I am using the following code in my routes.php:
Route::filter('before', function()
{
$server = explode('.', Request::server('HTTP_HOST'));
if (count($server) == 3)
{
$account = Account::where('subdomain', '=', $server[0])->first();
Session::put('account_id', $account->id);
Route::get('login', 'portal.login#index');
Route::post('login', 'portal.login#index');
Route::get('logout/(:any)', 'portal.login#logout');
}
else
{
// some other stuff - no routing calls in here
}
}
This code works fine for capturing the subdomain & doing the other tasks (such as setting the $account_id), but seem to have no affect on the routing
test.mydomain.com/login should go to portal/login, but instead goes to the main login controller.
I've searched through to be sure there are no filters affecting this (it is an inherited app)
Is this the correct way to set this up, and if so, what else might be affecting this?
TIA!

It's because when you are inside
if (count($server) == 3)
{
// Here
}
The registering of new routes using get/post is not going to respond because the system has already done the route matching, in this case you can forward the request to a new route using
Route::forward($method, $uri);
Which is in laravel/routing/route.php file as given nelow
/**
* Calls the specified route and returns its response.
*
* #param string $method
* #param string $uri
* #return Response
*/
public static function forward($method, $uri)
{
return Router::route(strtoupper($method), $uri)->call();
}
So, if you want to create a request similar to Route::get('login', 'portal.login#index'); then you can do it as
Route::forward('GET', 'login');
In this case, you have keep this route registered just normally you register a route. So, register/add the requests in the routes.php that you want to create dynamically and use Route::forward() method inside
if (count($server) == 3)
{
Route::forward('GET', 'login'); // for a get request
Route::forward('POST', 'login'); // for a post request
}
That's it.

Related

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

Laravel 5.7: Where can I register the allowed GET parameters and block others?

I have simple Laravel application and I have custom allowed GET parameters for my app:
$allowedGetParameters = [
'user',
'event',
'action'
]
How can I block all other GET parameters except the specified parameters in the array?
For example possible URL addresses:
- https://app.com/?user=16
- https://app.com/?event=242&user=16
- https://app.com/?user=16&event=242&action=like
URL with other GET parameters must return response 404. Here example URLs:
- https://app.com/?user=16&post=43&like=true
- https://app.com/?guru=242&set=superguru&action=true
Note:
If the URLs contain one or more unallowed GET parameters with or without allowed GET parameters in this case, the result should also be returned 404.
Create middleware https://laravel.com/docs/5.7/middleware
implement handle method, where you are make your checks:
$params = array_keys($request->all());
$is_valid_params = count(array_diff($params, $allowedGetParameters)) == 0;
$is_get_request = $request->method() == 'GET';
if ($is_valid_params && $is_get_request) {
return $next($request);
};
return abort(404);
Also I would move $allowedGetParameters to config folder in somefile.php, and would access like that: count(array_diff($params, config('somefile.allowedGetParameters')) == 0;
Don't forget to:
1) register your middleware in app\Http\Kernel.php in protected $routeMiddleware
2) wrap your routes in web.php with:
Route::group(['middleware' => ['name_of_your_widdleware']], function () {

How do I access non id property of request inside form requests?

I want to access route request parameters inside laravel form requests authorize. I cant find an example describing this.
// Works fine when you want id
dd($this->route('myResourceName'));
// How to do when I want something else???
dd($this->route('anotherAttribute'));
// Above give null probably because it is a resourceful controller
On a side note, I dont understand this design, whats the point?
$this->route('anyAttribute') would be the easiest, right?
Edit: more extensive example
class UpdateSlotAPIRequest extends APIRequest
{
public function __construct(){
parent::__construct();
$this->slot = Slot::find($this->route('slot'));
$this->access_token = $this->route('access_token'); // this is not working!
}
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// If administrator is logged in all is good.
// If slot is free its ok.
// If its not free but you provide good access_token its also fine.
return Auth::check() || $this->slot->isAvailable() || $this->slot->isValidAccessToken($this->access_token);
}
...
```
$access_token = request()->input('access_token');
Found it in https://laravel.com/docs/5.4/helpers

Laravel 5.0 custom 404 does not use middleware

I'm using a middleware to parse the output of the templates. This is working fine for all pages.
However when I want to show a 404 (got a custom page for that) it doesn't treat it as a http request (that's what I think) since it doesn't go through the middleware.
My question is, how to have ALL requests go through the middleware.
The error pages don't go through the routes.php.
In Kernel.php move your middleware from the $routeMiddleware array to $middleware array.
Middleware in this array will run on every request (tested in 5.1).
For people like me who spending hours in 2020 because of this weird behaviour...
Now in Laravel there is a new instrument «Fallback Routes».
Add this to /routes/web.php:
Route::fallback(function () {
return view("404"); // template should exists
});
After that all requests will go throught middlewares.
At Laravel 5.4 and probably some older ones you can modify the file app/exceptions/Handler.php and the function render like this:
if( is_a( $exception, \Symfony\Component\HttpKernel\Exception\NotFoundHttpException::class ) ) {
return redirect()->route( 'error_404' );
}
// ... old code in the function ...
in this way every 404 errors are redirected to certain real route that acts like other routes of site.
You may also submit any data from current request to show a reasonable error at the target.
I had a use case where api routes needs to always return json response.
All routes return json response (laravel checks through $request->expectsJson()) IF user specifically ask for it by sending accept: application/json header.
But many a times user doesn't send the header and they get an html response instead.
As for my use case, all api routes will always send json response we can force the routes to return json, by manually attaching accept: application/json header using a middleware.
App\Http\Middleware\ForceJsonOnAPIs.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Str;
class ForceJsonOnAPIs
{
/**
* Handle an incoming request.
*
* #param Request $request
* #param Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
// Force Json accept type on api routes
if ($request->is('api/*') && !Str::contains($request->header('accept'), ['/json', '+json'])) {
$request->headers->set('accept', 'application/json,' . $request->header('accept'));
}
return $next($request);
}
}
Register the middleware in App\Http\Kernel.php
// add the new middleware ForceJsonOnAPIs
protected $middleware = [
\App\Http\Middleware\ForceJsonOnAPIs::class,
// rest of the middleware,
];
Important: You can assign the middle to $middlewareGroups in Kernel like web or api, But you will get into trouble when 404 exception occurs. The issue is The error pages don't go through the routes.php (Thanks to #Björn Answer above) thus the routes middleware won't get called and the 404 will return html response.
It's the same case for validation or authentication exceptions.
In my opinion, it's best to assign the middleware in the $middleware array as it runs on each request. This way all exceptions will automatically return correct exceptions as json in all routes.

Passing variables before controller URI segment in CodeIgniter

I would like to pass some site-wide validated variables before controller segment in URL.
Example:
Default URL would be:
www.mysite.com/controller/method/variable/
Sometimes I'd like to have also URL like this to refer to user created sub-configuration of this site (theme, menus, ...), so user could share this site URL nicely and others would see the site though his custom configurations.
www.mysite.com/username/controller/method/variable
Here username is custom part of base_url. It should be validated against database and set as session variable to use it later in my controllers and change theme for example. Also all the links on the site would start to use www.mysite.com/username as base_url after website is entered with this username in the URL.
One way to solve this would be routing it like this:
controller/method/variable_name1/variable_value1/user_conf/username
...and the add the implementation to every single controller in my project. But this is not an elegant solution.
Is this what you're after:
$route['(:any)/(:any)'] = '$2/$1';
where all your function definitions have the username as the last parameter:
class Controller{function page(var1, var2, ..., varn, username){}}
Or, if you only want in on one specific page you could do something like this:
$route['(:any)/controller/page/(:any)'] = 'controller/page/$2/$1'; //This will work for the above class.
Or, if you want it for a number of functions in a controller you could do this:
$route['(:any)/controller/([func1|func2|funcn]+)/(:any)'] = 'controller/$2/$3/$1';
After messing with this problem for a day I ended up with adding custom router class to my project. I'm working in CodeIgniter 2.0, so the location of this file should be application/core/MY_Router.php
My code is following:
class MY_Router extends CI_Router {
// --------------------------------------------------------------------
/**
* OVERRIDE
*
* Validates the supplied segments. Attempts to determine the path to
* the controller.
*
* #access private
* #param array
* #return array
*/
function _validate_request($segments)
{
if (count($segments) == 0)
{
return $segments;
}
// Does the requested controller exist in the root folder?
if (file_exists(APPPATH.'controllers/'.$segments[0].EXT))
{
return $segments;
}
$users["username"] = 1;
$users["minu_pood"] = 2;
// $users[...] = ...;
// ...
// Basically here I load all the
// possbile username values from DB, memcache, filesystem, ...
if (isset($users[$segments[0]])) {
// If my segments[0] is in this set
// then do the session actions or add cookie in my cast.
setcookie('username_is', $segments[0], time() + (86400 * 7));
// After that remove this segment so
// rounter could search for controller!
array_shift($segments);
return $segments;
}
// So segments[0] was not a controller and also not a username...
// Nothing else to do at this point but show a 404
show_404($segments[0]);
}
}

Resources