Calling controllers dynamically - laravel

I'm attempting to create dynamic routing in Laravel for my controllers - I know this can be done in Kohana, but I've been unsuccessful trying to get it working with Laravel.
This is what I have right now:
Route::get('/{controller}/{action?}/{id?}'...
So I would like to call controller/method($id) with that.
Ideally this is what I would like to do:
Route::get('/{controller}/{action?}/{id?}', $controller . '#' . $action);
And have it dynamically call $controller::$action.
I've tried doing this:
Route::get('/{controller}/{action?}/{id?}', function($controller, $action = null, $id = null)
{
$controller = new $controller();
$controller->$action();
});
But I get an error message: Class Controller does not exist.
So it appears that Laravel is not including all the necessary files when the controller extends the BaseController.
If I use $controller::$action() it tells me I can't call a non-static function statically.
Any ideas for how to make this work?

You can auto register all controllers in one fell swoop:
Route::controller( Controller::detect() );
If you're using Laravel 4 (as your tag implies), you can't use Controller::detect() anymore. You'll have to manually register all the controllers you want to use.

After reading that Laravel doesn’t support this anymore, I came up with this solution:
$uri = $_SERVER['REQUEST_URI'];
$results = array();
preg_match('#^\/(\w+)?\/?(\w+)?\/?(\w+)?\/?#', $_SERVER['REQUEST_URI'], $results);
// set the default controller to landing
$controller = (empty($results[1])) ? 'landing' : $results[1];
// set the default method to index
$method = (empty($results[2])) ? 'index' : $results[2];
Route::get('{controller?}/{action?}/{id?}', $controller . '#' . $method);
// now we just need to catch and process the error if no controller#method exists.

Related

Error 404 WP Ajax Request

I was working on creating a WP plugin that will load other plugins only on specific URL. These plugins are deactivate in WP admin plugins, and are only loaded when a specific page is accessed.
Within my plugin's Class construct function:
$uri = $_SERVER['REQUEST_URI'];
$exp = explode('/', $uri);
$uri = $exp[2];
$options = get_option( $this->plugin_name );
$key = array_search( '/'.$uri.'/', array_column($options, 'url') );
$plugin_dir = $options[$key]['plugin']; // this prints plugin file directory ex. /MyPlugin/myplugin.php
include( WP_PLUGIN_DIR . $plugin_dir);
Above code loads the plugin on specific URL/page. Meaning the variable $plugin_dir grabbed the correct directory. BUT, problem occur when there's an AJAX request from that plugin. Ex. when i try to delete an item using ajax request, it returns Error 404 Bad request.
Weird part is, almost same code above, but this time, i manually assign the plugin directory to a variable: ex.
$uri = $_SERVER['REQUEST_URI'];
$exp = explode('/', $uri);
$uri = $exp[2];
$options = get_option( $this->plugin_name );
$key = array_search( '/'.$uri.'/', array_column($options, 'url') );
$plugin_dir = '/MyPlugin/myplugin.php'; // manually place the plugin file dir
//same output as $plugin_dir = $options[$key]['plugin'];
include( WP_PLUGIN_DIR . $plugin_dir);
But this time, plugin works really well. No Ajax bad request error.
What could be the possible explanation for this? Is there any solution about this issue, so that i can dynamically get the plugin file directory from wp options based on the Request URI.
Also, another issue. Instead of REQUEST URI, i wanted to get the POST/PAGE ID instead, but everything returns NULL/empty. Still inside the construct function, i tried different approach to get the page ID:
global $post;
var_dump($post->ID); //returns NULL
global $wp_query;
var_dump($wp_query->post->ID); //returns NULL
echo get_the_ID(); //returns empty/NULL
Is there a way how to properly get the POST/PAGE details, or even just the ID?
Thank you.

configuring dynamic url's in router

I'm using Codeigniter. Basically what I want is to remove the Controller name (Home) from the url.
Those urls look like:
http://localhost/mechanicly/Home
http://localhost/mechanicly/Home/about
http://localhost/mechanicly/Home/contactus
now there are two ways I can remove the Home controller:
static definition of every url inside route:
$route['about'] = "Home/about";
$route['contactus'] = "Home/contactus";
I can use call backs in routes in Codeigniter:
$route['(.+)'] = function ( $param ) {
if( strpos( $param, "Admin" ) !== false ) {
echo $param;
return "Admin/".$param;
}
else{
echo $param;
return "Home/".$param;
}
};
this logic is much better as it is generic and I don't have to create new routes every time for new method inside the controller.
It is working fine for the client controller which is Home but I have another controller named as Admin and I want to redirect Admin requests to the Admin controller and Home request to the Home Controller.
Why does above code work fine for the Home controller but returns
not found
when I validate for the Admin controller?
I am using CI version 3.x
If you really want to get crazy, you could parse the methods from the controller file and programatically create the "static" approach.
Pseudo code here
$controller_file_contents = file_get_contents('path/to/controller.php');
$controller_methods = function_that_parses_methods_from_file($controller_file_contents);
foreach ($controller_methods as $controller_method) {
$route[$controller_method] = "Home/" . $controller_method;
}
How function_that_parses_methods_from_file works is probably gonna involve a regex, something like function \w+. If you go with this approach, try to keep the controller as small as possible by offloading as much logic as possible into models, which is often a good idea anyways. That way the performance impact in the router is as small as possible.
Alternatively, you may be able to parse the controller using get_class_methods if you can figure out how to load the controller into memory inside the router without conflicting when you need to load the controller using the router or causing too much performance issues.
Pretty goofy, but every method you create in that controller will automatically create a route.
you can create your menu(url´s) from db like
tbl_menu tbl_level
---------- -------------
id id
fk_level level
name dateUP
dateUP active
active
In your controllers you need to call the correct menu by session or wherever you want
then you can has this in your route.php
$route['(.+)'] = 'int_rout/routing/' . json_encode($1);
in your controller Int_rout.php
public function routing ( $param ) {
$routing = json_decode($param);
$routing = explode('/', $routing);
//$menu -> get menu from model
foreach($menu as $item){
if($routing[0] === $item->name){
//$level -> get level from model
$redirect = $level->level;
}
}
//the final redirect will be like
//admin/user or admin/user/12
//public/us
$params = ( empty($routing[1])) ? '' : '/' . $routing[1];
redirect($redirect . '/' . $routing[0] . $params, 'refresh');
}

Laravel 5.3 dynamic routing to multiple controllers

I'm using Laravel 5.3. I have a bunch of urls that I'd like to handle with a single route, to multiple controllers.
e.g.
GET /admin/foo => FooController#index
GET /admin/foo/edit/1 => FooController#edit($id)
GET /admin/bar => BarController#index
GET /admin/bar/edit/1 => BarController#item($id)
GET /admin/baz => BazController#index
GET /admin/baz/edit/1 => BazController#item($id)
etc.
I want to be able to detect if the controller exists, and if not throw a 404 or route to a default controller (which may throw a 404).
Below is what I've got so far, but I'm not sure what I'm doing. Shouldn't I be instantiating the controller using the service container? I don't think I should be hardcoding namespaces like this. And my handling of the id parameter is sketchy. Perhaps I should have two routes for these two patterns or something?
Route::get('/admin/{entityType}/{action?}/{id?}', function ($entityType, $action = 'index', $id = null) {
$controllerClass = 'App\Http\Controllers\\' . ucfirst($entityType) . 'Controller';
$controller = new $controllerClass;
$route = app(\Illuminate\Routing\Route::class);
$container = app(\Illuminate\Container\Container::class);
return (new Illuminate\Routing\ControllerDispatcher($container))->dispatch($route, $controller, $action);
abort(404);
});
I'd recommend you to define a route for every controller explicitly. This is the best way to build a maintainable app.
Also, if using one route and one method is an option (with right architecure it is) use one route:
Route::get('/admin/{entityType}/{action?}/{id?}', 'Controller#method');
And one entry point:
public function method($entity, $action = null, $id = null)
{
// Handle request here.
https://laravel.com/docs/5.3/routing#parameters-optional-parameters

Load view by current URL last segment in Codeigniter

I'm trying to load view content page when url last segment matched. When click a link which get link in url like http://192.168.20.2/vtp/attendance/rawAttendance then load the rawAttendance view and when I click other link which last segment is getAttendance then it's also load the same same view not getAttendance. How do get this done?
$last = $this->uri->total_segments();
$lastSegment = $this->uri->segment($last);
if ($this->input->post("fromAjax")) {
if($lastSegment == "rawAttendance"){
$this->load->view('attendance/rawAttendance', $data);
}else if($lastSegment == "getAttendance"){
$this->load->view('attendance/getAttendance', $data);
}else {
}
}
CI has its inbuilt helper for knowing controller name and method name.
$classname = $this->router->fetch_class();
$methodname = $this->router->fetch_method();
if ($this->input->post("fromAjax")) {
if($classname == "attendance" && $methodname == "rawAttendance"){
$this->load->view('attendance/rawAttendance', $data);
}else if($classname == "attendance" && $methodname == "getAttendance"){
$this->load->view('attendance/getAttendance', $data);
} else {
}
}
CodeIgniter is a basic MVC framework - so everything starts with the controller. From the code you've written, I assume you already have your routes, etc configured to point at the method you've placed in your question.
You can simplify things quite a bit from the way you have them. Using the CI helper for controller/method is a bit helpful, but I think you're looking for something a little more elastic in your approach to dynamically load a view based on your last URI segment.
Try something like this:
// Get your last URI segment
$last = $this->uri->total_segments();
$lastSegment = $this->uri->segment($last);
/**
* Do whatever logic you need to do to calculate your data
*/
// ...
/**
* Load the view
*/
$this->load->view( 'attendance/' . $lastSegment, $data );
This could probably be better architected using the CI routes capability though. For instance, if you have several view folders and view files within, it would be best practice to organize those and better cement your URI structures so that each URI segment plays a specific role:
CI routes.php
$route["vtp/(:any)/(:any)"] = "path_to_method";
Method
$dir = $this->uri->segment(2);
$view = $this->uri->segment(3);
$this->load->view( $dir . "/" . $view, $data );

Specify controller & method to use in anonymous function of a route parameter?

I'm checking out Laravel. Trying to make use of a wildcard route. The 2nd parameter is an anonymous function. Ideally I'd like to do a little bit of validation to determine if it's a valid wildcard option & then specify the controller & method to use.
Route::get('lodging/{entrance}', function($entrance){
// validate if entrance is 'north','south','east','west'
// send to controller & specific method
return "entrance is $entrance";
});
Is this an appropriate place to do this?
Or should this validation just be taken care of in the controller and use this format for the route:
Route::get('lodging/{entrance}', 'Lodging#chooseEntrance');
You can add simple validation to your route
Route::get('lodging/{entrance}', function(){ ... })->where('entrance', 'north|south|east|west');
See Routing#parameters-regular-expression-constraints
Route::get('lodging/{entrance}', function($entrance){
$app = app();
$controller = $app->make('ExampleController');
if($entrance=="north"){
return $controller->callAction('index', $parameters = array());
}else{
return $controller->callAction2('index', $parameters = array());
}
})->name('lodging');
hope it helps it helps someone.

Resources