Use controller namespace from route closure - php

I want a Route::group() to use a particular namespace using a closure rather than using the laravel syntax. So instead of
Route::group(['namespace' => 'My\Namespace\For\Controllers'), function () {
// TestController found in `My\Namespace\For\Controllers`
Route::resource('resource/url', TestController#test)
}
I wonder if it is possible to have something like
Route::group(function () {
// Some logic for using the `My\Namespace\For\Controllers`
// namespace for all routes within this group
// Controller found in `My\Namespace\For\Controllers`
Route::resource('resource/url', Controller#test)
}
I want this functionality so I can decide the controller name-space dynamically depending on a parameter passed to a route.

I guess the right way to do that is to create middleware, but definetely not route.php file.
https://laravel.com/docs/5.2/middleware
Update
If you need just to set namespace for all controllers in a group, you can do it like this:
Route::group(['namespace' => 'My\Namespace\For\Controllers'], function() {
// Controllers within the "My\Namespace\For\Controllers" namespace
});
https://laravel.com/docs/5.2/routing#route-group-namespaces

Related

Laravel - passing parameters from web.php routes to controller

I am trying to pass a parameter to my UserController but i can't seem to find a method to do this. All other topics give examples where the parameter is already defined in the url but that is not what i want.
$my_var = "some data";
Route::get('/login', 'Auth\UserController#login');
I need $my_var in my UserController
class UserController extends Controller
{
public function login()
{
// Retreive $my_var somehow
return view("login");
}
}
Sorry for my bad english, it's not my native language
In some cases using hardcoded parameters might be reasonable way to go, and one such could be case where you need to get different kinds of entities from single controller.
For an example you could have restful "users/" -route, which fetches all users from UserModel. Next you wish to separate "normal" users and admin-users by having "admin-users/" -route. Now one way to go is to represent both routes to web.php, and make them point to same controller:
Route::resource('users', 'UserController');
Route::resource('admin-users', 'UserController');
One way to solve this separation is by not passing an argument, but by detecting which route was called:
$sqlFilters['user_is_admin'] = $request->is('admin-users') || $request->is('admin-users/*');
This checks whether controller was accessed via "admin-users". Asterisk is wildcard for any route under "admin-users" path.
This method has been existing at least since Laravel 6.0, probably even before that: https://laravel.com/docs/8.x/requests#inspecting-the-request-path
You are doing it wrong. That's not how you work with an MVC framework and it's better not to define a variable or constant in web.php which is for your routes and middlewares only. By the way, if you need to do it this way, you have two ways:
1) Use a trait:
web.php:
trait TestTrait {
public static $my_var = 'some data';
}
Route::get(/login', 'Auth\UserController#login');
UserConroller.php:
use TestTrait;
class UserController extends Controller
{
use TestTrait;
public function login()
{
// You can retrieve it as a variable: $my_var
echo TestTrait::$my_var;
}
}
2) Use a constant instead of a variable:
web.php:
define('MY_VAR', 'some data');
Route::get('/login', 'Auth\UserController#login');
UserConroller.php:
public function login()
{
// You can retrieve it as a constant: MY_VAR
echo MY_VAR;
}
If the variable is hardcoded, why not state it as a constant?
If no other logic is needed, the variable can be passed through the routes file.
$my_var = "some data";
Route::get('/login', function(){
Return view('login', compact('my_var')):
});

Laravel action not defined error, but action is defined in controller

I keep getting an error that the action is not defined in my controller, but it is. I can access the index action, but not the processOrder action.
Below is my controller and my routes file.
namespace App\Http\Controllers\ThirdPartyAPI;
use App\Order;
use App\ThirdPartyAPI;
use GuzzleHttp\Client;
use App\Jobs\ThirdParyOrders;
use App\ThirdParty\ThirdPartyAPI;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class OrdersController extends Controller
{
public function index ()
{
// list orders
}
public function processOrder()
{
// some logic here
}
}
If my I call the action "#index" in my routes/web.php file, it works and it returns the url, but if I change the "#index" to "#processOrder", it throws the error.
Ie. this works:
Route::get('thirdparty/process-order', function() {
return action('ThirdPartyApi\OrdersController#index');
});
But this doesn't:
Route::get('thirdparty/process-order', function() {
return action('ThirdPartyApi\OrdersController#processOrder');
});
I'm not sure where I'm missing the plot.
I've tried to quit and then re-run:
php artisan serve
I've also tried
composer dump-autoload
Still not sure what the problem was initially, but I've managed to get it working by using a different method.
Intead of using a closure, I do it like this:
Route::get('thirdparty/{thirdparty_client}/process-order/{order}', 'ThirdPartyApi\OrdersController#processOrder');
This seems to do the trick. I didn't know that I could pass multiple parameters to the controller in this way, but this is working 100%.
I think you should have to try this as route.
Route::any("thirdparty/process-order", "ThirdPartyApi\OrdersController#processOrder");

Do I need to have Controller.php in all my API subversion?

I am trying to create an API directory in my Laravel project and I'm receiving the following error...
Class 'App\Http\Controllers\Controller' not found
I have tried using use App\Http\Controllers\Controller; on top of my API controllers but no luck.
My API classes are defined like...
class SyncController extends Controller {...}
class TimecardController extends Controller {...}
I'm pretty sure the error is coming from the extends Controller portion.
in App\Http\Controllers\Controller I have Controller.php. One way I have pushed past this is to duplicate the Controller.php into App\Http\Controllers\Api\v2\ and change the namespace of that controller to match where it is located (namespace App\Http\Controllers\Api\v2;)
I don't believe this is correct, as there should be a way to reference the Controller.php from the controllers in the API subdirectory.
../Controllers/Controller.php and API is a subdirectory, ../Controllers/Api/v2/SyncController.php
Any help would be much appreciated.
Thanks
-----------Edit------------
my routes for the api look like so
Route::group(['prefix' => 'api/v2'], function () {
Route::get('sync', 'Api\v2\SyncController#sync')->middleware('auth:api');
Route::post('timecard', 'Api\v2\TimecardController#create')->middleware('auth:api');
});
The Controller class cannot be found because the API controllers are not in the default Laravel controller directory. You need to add the controller class as a use statement. Then the autoloader will be able to find it.
namespace App\Http\Controllers\Api\v2;
use App\Http\Controllers\Controller;
class SyncController extends Controller {...}
And while your at it you might also want to add the auth:api middleware to the entire group. Much safer and efficient.
Route::group(['prefix' => 'api/v2', 'middleware' => 'auth:api', 'namespace' => 'Api\v2'], function () {
Route::get('sync', 'SyncController#sync');
Route::post('timecard', 'TimecardController#create');
});

Access current route name in Slim3 controller's class constructor

With Slim I group my controllers and generally have an abstract BaseController I extend for each group. I use class based routing:
/* SLIM 2.0 */
// Users API - extends BaseApiController
$app->post('/users/insert/' , 'Controller\Api\UserApiController:insert');
.
.
// Campaigns - extends BaseAdminController
$app->get('/campaigns/', 'Controller\CampaignController:index')->name('campaigns');
and needed to password protect some routes, at other times I needed to have a slightly different configuration. BaseApiController, BaseAdminController... etc. There were times I needed to know which route I was in so I could execute a certain behavior for just that route. In those cases I would have a helper function like so:
/* SLIM 2.0 */
// returns the current route's name
function getRouteName()
{
return Slim\Slim::getInstance()->router()->getCurrentRoute()->getName();
}
This would give me the route name that is currently being used. So I could do something like...
namespace Controller;
abstract class BaseController
{
public function __construct()
{
/* SLIM 2.0 */
// Do not force to login page if in the following routes
if(!in_array(getRouteName(), ['login', 'register', 'sign-out']))
{
header('Location: ' . urlFor('login'));
}
}
}
I cannot find a way to access the route name being executed. I found this link
Slim 3 get current route in middleware
but I get NULL when I try
$request->getAttribute('routeInfo');
I have also tried the suggested:
'determineRouteBeforeAppMiddleware' => true
I've inspected every Slim3 object for properties and methods, I can't seem to find the equivalent for Slim3, or get access to the named route. It doesn't appear that Slim3 even keeps track of what route it executed, it just... executes it.
These are the following methods the router class has and where I suspect this value would be:
//get_class_methods($container->get('router'));
setBasePath
map
dispatch
setDispatcher
getRoutes
getNamedRoute
pushGroup
popGroup
lookupRoute
relativePathFor
pathFor
urlFor
I was hoping someone has done something similar. Sure, there are other hacky ways I could do this ( some I'm already contemplating now ) but I'd prefer using Slim to give me this data. Any Ideas?
NOTE: I'm aware you can do this with middleware, however I'm looking for a solution that will not require middleware. Something that I can use inside the class thats being instantiated by the triggered route. It was possible with Slim2, was hoping that Slim3 had a similar feature.
It's available via the request object, like this:
$request->getAttribute('route')->getName();
Some more details available here
The methods in your controller will all accept request and response as parameters - slim will pass them through for you, so for example in your insert() method:
use \Psr\Http\Message\ServerRequestInterface as request;
class UserApiController {
public function insert( request $request ) {
// handle request here, or pass it on to a getRouteName() method
}
}
After playing around I found a way to do it. It may not be the most efficient way but it works, and although it uses Middleware to accomplish this I think there are other applications for sharing data in the Middleware with controller classes.
First you create a middleware but you use a "Class:Method" string just like you would in a route. Name it whatever you like.
//Middleware to get route name
$app->add('\Middleware\RouteMiddleware:getName');
Then your middleware:
// RouteMiddleware.php
namespace Middleware;
class RouteMiddleware
{
protected $c; // container
public function __construct($c)
{
$this->c = $c; // store the instance as a property
}
public function getName($request, $response, $next)
{
// create a new property in the container to hold the route name
// for later use in ANY controller constructor being
// instantiated by the router
$this->c['currentRoute'] = $request->getAttribute('route')->getName();
return $next($request, $response);
}
}
Then in your routes you create a route with a route name, in this case I'll use "homePage" as the name
// routes.php
$app->get('/home/', 'Controller\HomeController:index')->setName('homePage');
And in your class controller
// HomeController.php
namespace Controller;
class HomeController
{
public function __construct($c)
{
$c->get('currentRoute'); // will give you "homePage"
}
}
This would allow you to do much more then just get a route name, you can also pass values from the middleware to your class constructors.
If anyone else has a better solution please share!
$app->getCurrentRoute()->getName();
$request->getAttribute('route')->getName();

Laravel 4, how to apply filters on Route::controller()

I know i can do this
Route::get('foo/bar', array('before' => 'filter', 'uses' => 'Controller#bar'));
to apply routes some filter. I am aware of Route::group() method too. Anyway, if i want to define a controller in this way
Route::controller('foo/{id}/bar', 'Controller');
i can not pass an array as the 2nd argument.
The question: how to apply filters to the following route?
Route::controller('foo/{id}/bar', 'Controller');
=== EDIT
I want to code this in my route.php, not inside a controller constructor.
In the constructor of your controller you may use
public function __construct()
{
$this->beforeFilter('auth');
}
Also, you can use
Route::group(array('before' => 'auth'), function() {
Route::controller(...);
});
Blockquote The controller method accepts two arguments. The first is the base URI the controller handles, while the second is the class name of the controller. Next, just add methods to your controller, prefixed with the HTTP verb they respond to.
The Route::controller is responsible of creating a group of route using REST naming conventions. Is thought for creating RESTFull services.
Blockquote Filters may be specified on controller routes similar to "regular" routes:
Because this function only allows two params, you can apply controller filters in the constructor. For example:
class RoutedController extends Controller
{
public function __construct()
{
//Apply Auth filter to all controller methods
$this->filter('before', 'auth');
}
}
You can read about the controller filters in the Laravel docs: http://laravel.com/docs/controllers#controller-filters

Categories