There are few routers out there but I decided to create a very simple route for a very light site.
Here is my index.php
$route = new Route();
$route->add('/', 'Home');
$route->add('/about', 'About');
$route->add('/contact', 'Contact');
Here is my router:
<?php namespace Laws\Route;
use Laws\Controller\Home;
class Route
{
private $_uri = array();
private $_method = array();
private $_route;
public function __construct()
{
}
public function add($uri, $method = null)
{
$this->_uri[] = '/' . trim($uri, '/');
if ($method != null) {
$this->_method[] = $method;
}
}
public function submit()
{
$uriGetParam = isset($_GET['uri']) ? '/' . $_GET['uri'] : '/';
foreach ($this->_uri as $key => $value) {
if (preg_match("#^$value$#", $uriGetParam)) {
$useMethod = $this->_method[$key];
new $useMethod(); // this returns an error (cannot find Home'
new Home(); // this actually works.
}
}
}
}
new $useMethod(); does not work. returns error 'cannot find Home'
new Home(); actually works.
What am I missing here?
You can use your concurrent way for calling a class or you can use this:
call_user_func(array($classname,$methodname))
Related
I'm new to php, I would like to have access to the $router instance in my views so that I can use the route names with $router->generate() in the view but I don't know how to do it?
I use Altorouter like this:
Index.php
$router = new AltoRouter();
$router->map( 'GET', '/post/[:id]/', 'PostController#find' );
$match = $router->match();
if ($match === false) {
throw new \Exception($error->404());
} else {
list($controller, $action) = explode('#', $match['target']);
if (is_callable(array($controller, $action))) {
$obj = new $controller();
call_user_func_array(array($obj, $action), array($match['params']));
} else {
throw new \Exception($error->500());
}
}
PostController.php
public function find($args)
{
$post = $this->PostModal->find($args[id]);
// View
View::render('post/show', compact('post'));
}
My class View.php which manages the views
public static function render(string $path, array $variables = [])
{
extract($variables);
ob_start();
require 'views/' . $path . '.html.php';
$pageContent = ob_get_clean();
require 'views/layouts/layout.html.php';
}
If you have the same problem as me, I resolved by adding
global $router;
in the render
I am just starting with php and I can't create this object.
I call my object with the variable $theClass is a concatenation of a namespace and a variable from a an array.
One var_dump of $theclass show me the right path... the problem start wen I try to create a new $theClass on variable($control) the var_dump show me nothing...
<?php
namespace App\Router;
class Router {
private $routes = [];
private $url;
public function __construct($url){
$this->url = $url;
}
public function get($path, $action){
$this->routes['GET'][$path] = $action;
}
public function match(){
foreach ($this->routes as $key => $routes) {
foreach ($routes as $path => $action) {
if ($this->url === $path) {
$elements = explode('#', $action);
//$this->callController($elements);
$theClass = "App\Controller\\$elements[0]";
// I try this way to 'App\Controller\\' . $elements[0];
var_dump($theClass);
$method = $elements[1];
var_dump($method);
$control = new $theClass();
$control->$method();
}
}
header('HTTP/1.0 404 Not Found');
}
}
}
I have a string, route, and i explode it and then i have a classname. $callback = explode('#', $callback); $callback[0] is the classname. I am making a router and based on the class and methed i return this.
I want to get the full namespace and when i use this then it works but now i want to make it dynamically.
How do i concat BaseController to the ::class?
BasController::class
$fullclass = HERE I NEED THE FULL NAMESPACE$callback[0];
$class = new $fullclass;
$method = $callback[1];
$class->$method();
Exaple index.php
Router::route('/user/{id}/' , 'BaseController#show');
Router::execute($_SERVER['REQUEST_URI']);
Router:
namespace App;
class Router
{
private static $routes = array();
private function __construct()
{
}
private function __clone()
{
}
public static function route($pattern, $callback)
{
$pattern = $pattern;
self::$routes[$pattern] = $callback;
}
public static function execute($url)
{
foreach (self::$routes as $pattern => $callback) {
if ($pattern == $url) {
$callback = explode('#', $callback);
$fullclass = __NAMESPACE__ . '\\Controllers\\' . $callback[0];
$class = new $fullclass;
$method = $callback[1];
$class->$method();
}else{
echo 404;
}
}
}
}
BasController::class returns a full class name in string in that case you can simply concat any string on it. If $callback[0] is a string you can do below code.
$fullclass = BasController::class . $callback[0];
$class = new $fullclass;
$method = $callback[1];
$class->$method();
I hope you are trying to retrieve namespace
echo (new \ReflectionClass($object))->getNamespaceName() ;
If you are in that scope try
__NAMESAPCE__
See this document if you are looking for autoload
What i was looking for is giving the class as param into the route
Router::route('/user/{id}/' , App\Controllers\BaseController::class , 'show');
When i type this address:
http://localhost/gamelvl/world-of-tanks/tankguide/
I can enter the tankguide view. Now inside this folder is another folder called ussr but when I create a controller and model for ussr I can not enter it with this address:
http://localhost/gamelvl/world-of-tanks/tankguide/ussr/
Now, any one can give me instructions on whether this is the right thing or other solutions for this?
routing app
<?php
class App
{
public $controller = 'index';
public $method = 'index';
public $params = [];
function __construct()
{
if (isset($_GET['url'])) {
$url = $_GET['url'];
$url = $this->parseUrl($url);
$this->controller = $url[0];
unset($url[0]);
if (isset($url[1])) {
$this->method = $url[1];
unset($url[1]);
}
$this->params = array_values($url);
}
$controllerurl = 'controllers/' . $this->controller . '.php';
if (file_exists($controllerurl)) {
require($controllerurl);
$object = new $this->controller;
$object->model($this->controller);
if (method_exists($object, $this->method)) {
call_user_func_array([$object, $this->method], $this->params);
}
}
}
function parseUrl($url)
{
filter_var($url, FILTER_SANITIZE_URL);
$url = rtrim($url, '/');
$url = explode('/', $url);
return $url;
}
}
?>
tankguide controller
<?php
class Tankguide extends Controller
{
function index()
{
$this->view('tankguide/index');
}
}
?>
core controller
<?php
class Controller
{
function __construct()
{
}
function view($viewUrl,$data=[])
{
require('header.php');
require('views/' . $viewUrl . '.php');
require('footer.php');
}
function model($modelUrl)
{
require('models/model_' . $modelUrl . '.php');
$classname = 'model_' . $modelUrl;
$this->model = new $classname;
}
}
?>
project structure
if (method_exists($object, $this->method)) will return false for the given url, because it is looking for a method called ussr on the Tankguide class. Either create a ussr method on that class
I tried to follow the recommendations from this topic: zend framework 2 + routing database
I have a route class:
namespace Application\Router;
use Zend\Mvc\Router\Http\RouteInterface;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\Mvc\Router\RouteMatch;
class Content implements RouteInterface, ServiceLocatorAwareInterface {
protected $defaults = array();
protected $routerPluginManager = null;
public function __construct(array $defaults = array()) {
$this->defaults = $defaults;
}
public function setServiceLocator(\Zend\ServiceManager\ServiceLocatorInterface $routerPluginManager) {
$this->routerPluginManager = $routerPluginManager;
}
public function getServiceLocator() {
return $this->routerPluginManager;
}
public static function factory($options = array()) {
if ($options instanceof \Traversable) {
$options = ArrayUtils::iteratorToArray($options);
} elseif (!is_array($options)) {
throw new InvalidArgumentException(__METHOD__ . ' expects an array or Traversable set of options');
}
if (!isset($options['defaults'])) {
$options['defaults'] = array();
}
return new static($options['defaults']);
}
public function match(Request $request, $pathOffset = null) {
if (!method_exists($request, 'getUri')) {
return null;
}
$uri = $request->getUri();
$fullPath = $uri->getPath();
$path = substr($fullPath, $pathOffset);
$alias = trim($path, '/');
$options = $this->defaults;
$options = array_merge($options, array(
'path' => $alias
));
return new RouteMatch($options);
}
public function assemble(array $params = array(), array $options = array()) {
if (array_key_exists('path', $params)) {
return '/' . $params['path'];
}
return '/';
}
public function getAssembledParams() {
return array();
}
}
Pay attention that the match() function returns object of the instance of Zend\Mvc\Router\RouteMatch
However in the file Zend\Mvc\Router\Http\TreeRouteStack it checks for object to be the instance of RouteMatch (without prefix of namespace)
if (
($match = $route->match($request, $baseUrlLength, $options)) instanceof RouteMatch
&& ($pathLength === null || $match->getLength() === $pathLength)
)
And the condition fails in my case because of the namespace.
Any suggestions?
Ok, i figured out what the problem was.
Instead of returning Zend\Mvc\Router\RouteMatch I should return Zend\Mvc\Router\Http\RouteMatch
This fixed my problem