"Wildcard" routing setup

Submitted by davestewart - 8 years ago

Helper function to mass-map routes to methods. I use this setup in development to quickly map all "test/*" routes to a Test controller, to test out arbitrary PHP code. Updated version also supports DI in controller methods. Updated to correctly fill optional arguments.

<?php 

// This trick has been superseded by Laravel Sketchpad
// https://github.com/davestewart/laravel-sketchpad

/**
 * Wildcard routing function
 *
 * @param   string          $route          Base route, i.e. 'test'
 * @param   string          $controller     Path to controller, i.e. 'TestController'
 * @param   string|array    $verbs          Optional Route verb(s), i.e. 'get'; defaults to ['get', 'post']

 * @usage   wildcard('test', 'TestController');
 * @usage   wildcard('test', 'TestController', ['get']);
 * @usage   wildcard('test', 'Test\TestController');
 * 
 * @example http://localhost/test/hello/world
 * @example http://localhost/test/goodbye/world
 * @example http://localhost/test/foo/1/2/3
 *
 * @author  Dave Stewart | dave@davestewart.io
 */
function wildcard($route, $controller, $verbs = ['get', 'post'])
{
	// variables
	$stack      = Route::getGroupStack();
	$namespace  = end($stack)['namespace'];
	$controller = $namespace . '\\' . $controller;

	// routing
	Route::match($verbs, rtrim($route, '/') . '/{method}/{params?}', function($method, $params = null) use ($route, $controller)
	{
		// method
		$callable = $controller . '@' . $method;

		// call
		if($params)
		{
			// variables
			$values     = explode('/', $params);
			$ref        = new ReflectionMethod($controller, $method);
			$params     = $ref->getParameters();
			$args       = [];

			// map route segments to the method's parameters
			foreach ($params as /** @var \ReflectionParameter */ $param)
			{
				// parse signature [match, optional, type, name, default]
				preg_match('/<(required|optional)> (?:([\\\\a-z\d_]+) )?(?:\\$(\w+))(?: = (\S+))?/i', (string) $param, $matches);

				// assign untyped segments
				if($matches[2] == null)
				{
					$args[$matches[3]] = array_shift($values);
				}
			}

			// append any remaining values
			$values = array_merge($args, $values);

			// call
			App::call($callable, $values);
		}
		else
		{
			App::call($callable);
		}

	})->where('params', '.*');
}