I need help with router when i enter route in href for example
Login
Register
first link i click works
url is localhost/account/login
but second time i click link url is localhost/account/account/register
function __construct(){
$arr = require 'application/config/routes.php';
foreach ($arr as $key => $val) {
$this->add($key, $val);
}
}
public function add($route, $params) {
$route = '#^'.$route.'$#';
$this->routes[$route] = $params;
}
public function match() {
$url = trim($_SERVER['REQUEST_URI'], '/');
foreach ($this->routes as $route => $params) {
if (preg_match($route, $url, $matches)) {
$this->params = $params;
return true;
}
}
return false;
}
public function run(){
if($this->match()){
$path = 'application\controllers\\'.ucfirst($this->params['controller']).'Controller';
if(class_exists($path)){
$action = $this->params['action'].'Action';
if (method_exists($path, $action)){
$controller = new $path($this->params);
$controller->$action();
}else{
View::errorCode(404);
}
}else{
View::errorCode(404);
}
}else{
View::errorCode(404);
}
}
Your URL's don't start with /, so they are relative to the current URL. Please add a / before.
Your code now:
Register
Change it to:
Register
Related
Under htdocs folder i have created folder called PHP under that i have created file called index.php. I have written wrouting PHP code but it is not working.
index.php
<?php
echo "Welcome" . "<br>";
$routes = [];
route('/', function () {
echo "Home Page";
});
route('/login', function () {
echo "Login Page";
});
route('/about-us', function () {
echo "About Us";
});
route('/404', function () {
echo "Page not found";
});
function route(string $path, callable $callback) {
global $routes;
$routes[$path] = $callback;
}
run();
function run() {
global $routes;
$uri = $_SERVER['REQUEST_URI'];
$found = false;
foreach ($routes as $path => $callback) {
if ($path !== $uri) continue;
$found = true;
$callback();
}
if (!$found) {
$notFoundCallback = $routes['/404'];
$notFoundCallback();
}
}
http://localhost/PHP/
Welcome
Page not found
http://localhost/PHP/index.php/login/ (getting below output)
Welcome
Page not found
Expected output
Welcome
Login Page
Here wt am doing mistake, can anyone explain and update my code
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 am using php mvc and when i try to edit a specific row, it says, "no route matched" but the route is well defined.
Here is the route for match
$router->add('{controller}/{id:\d+}/{action}');
and here is Router.php.
<?php
namespace Core;
/**
*Router
*/
class Router
{
protected $routes = [];
//saves the parameter from the matched route
protected $params = [];
/**
*Below, params=[] indicates that the paramentes in the url can be empty
*/
public function add($route, $params = [])
{
// Convert the route to a regular expression: escape forward slashes
$route = preg_replace('/\//', '\\/', $route);
// Convert variables e.g. {controller}
$route = preg_replace('/\{([a-z]+)\}/', '(?P<\1>[a-z-]+)', $route);
// Convert variables with custom regular expressions e.g. {id:\d+}
$route = preg_replace('/\{([a-z]+):([^\}]+)\}/', '(?P<\1>\2)', $route);
// Add start and end delimiters, and case insensitive flag
$route = '/^' . $route . '$/i';
$this->routes[$route] = $params;
}
/**
*matches the route and sets the parameters
* $url: The route URL
* returns true is match is found else flase
*/
public function match($url)
{
//Matches to the fixed URL format /controller/action
//$reg_exp = "/^(?P<controller>[a-z-]+)\/(?P<action>[a-z-]+)$/";
foreach ($this->routes as $route => $params) {
if (preg_match($route, $url, $matches))
{
//get named capture group values
//$params = [];
foreach ($matches as $key => $match) {
if (is_string($key))
{
$params[$key] = $match;
}
}
$this->params = $params;
return true;
}
}
return false;
}
// foreach ($this->routes as $route => $params) {
// if ($url == $route) {
// $this->params = $params;
// return true;
// }
// }
// return false;
// if (preg_match($reg_exp, $url, $matches))
// {
//
//
// }
//gets the currently matched parameters
public function getParams()
{
return $this->params;
}
public function dispatch($url)
{
$url = $this->removeQueryStringVariables($url);
if($this->match($url)){
$controller = $this->params['controller'];
$controller = $this->convertToStudlyCaps($controller); //Text can easily be converted from uppercase or lowercase to sTudLYcAPs
//$controller = "App\Controllers\\$controller";
$controller = $this->getNameSpace() . $controller;
if (class_exists($controller)){
$controller_object = new $controller($this->params);
$action = $this->params['action'];
$action = $this->convertToCamelCase($action);
if (is_callable([$controller_object, $action]))
{
$controller_object->$action();
}else{
throw new \Exception("Method $action (in controller $controller) not found");
}
}else{
throw new \Exception("Controller class $controller not found");
}
}else {
throw new \Exception("No route matched");
}
}
/**
*Convert the string with hypens to StudlyCaps,
*e.g. post-authors => PostAuthors
*/
protected function convertToStudlyCaps($string)
{
return str_replace(' ', '', ucwords(str_replace('-', ' ', $string)));
}
/**
*Convert the string with hypens to camelCase,
*e.g. add-new => addNew
*/
protected function convertToCamelCase($string)
{
return lcfirst($this->convertToStudlyCaps($string));
}
/**
*This removes query string variable i.e. posts/index&page=1 => posts/index
*
*/
protected function removeQueryStringVariables($url)
{
if($url != '')
{
$parts = explode('&', $url, 2);
if(strpos($parts[0], '=') === false){
$url = $parts[0];
}
else{
$url = '';
}
}
return $url;
}
/*
*Get the namespace for the controller class. The namespace defined in the
*route parameters is added if present.
*/
protected function getNameSpace()
{
$namespace = 'App\Controllers\\';
if(array_key_exists('namespace', $this->params))
{
$namespace .= $this->params['namespace'] . '\\';
}
return $namespace;
}
}
?>
P.S. i can add values to database but cannot edit it, as it says route not matched. if it helps,here is index.php:
<?php
/**
* FIRST CONTROLLER
*
*/
/**
*Twig
*/
require_once dirname(__DIR__) . '/vendor/Twig/lib/Twig/autoload.php';
Twig_Autoloader::register();
/**
*AutoLoader
*
*/
spl_autoload_register(function ($class){
$root = dirname(__DIR__); //gets the parent directory
$file = $root . '/' . str_replace('\\', '/', $class) . '.php';
if (is_readable($file))
{
require $root . '/' . str_replace('\\', '/', $class) . '.php';
}
});
/**
*Error and Exception handling
*
*/
error_reporting(E_ALL);
set_error_handler('Core\Error::errorHandler');
set_exception_handler('Core\Error::exceptionHandler');
/**
*Routing
*
*/
//require '../Core/Router.php';
$router = new Core\Router();
//Routes
$router->add('', ['controller' => 'Home', 'action' => 'index']);
$router->add('{controller}/{action}');
$router->add('admin/{controller}/{action}', ['namespace' => 'Admin']);
$router->add('{controller}/{id:\d+}/{action}');
$router ->dispatch($_SERVER['QUERY_STRING']);
/*
// Display the routing table
echo '<pre>';
//var_dump($router->getRoutes());
echo htmlspecialchars(print_r($router->getRoutes(),true));
echo '<pre>';
//Match the requested route
$url = $_SERVER['QUERY_STRING'];
if ($router->match($url)) {
echo '<pre>';
var_dump($router->getParams());
echo '<pre>';
}else{
echo "No Route Found For URL '$url'";
}
*/
?>
I'm currently developing a router for one of my projects and I need to do the following:
For example, imagine we have this array of set routes:
$routes = [
'blog/posts' => 'Path/To/Module/Blog#posts',
'blog/view/{params} => 'Path/To/Module/Blog#view',
'api/blog/create/{params}' => 'Path/To/Module/API/Blog#create'
];
and then if we pass this URL through: http://localhost/blog/posts it will dispatch the blog/posts route - that's fine.
Now, when it comes to the routes that require parameters, all I need is a method of implementing the ability to pass the parameters through, (i.e. http://localhost/blog/posts/param1/param2/param3 and the ability to prepend api to create http://localhost/api/blog/create/ to target API calls but I'm stumped.
Here's something basic, currently routes can have a pattern, and if the application paths start with that pattern then it's a match. The rest of the path is turned into params.
<?php
class Route
{
public $name;
public $pattern;
public $class;
public $method;
public $params;
}
class Router
{
public $routes;
public function __construct(array $routes)
{
$this->routes = $routes;
}
public function resolve($app_path)
{
$matched = false;
foreach($this->routes as $route) {
if(strpos($app_path, $route->pattern) === 0) {
$matched = true;
break;
}
}
if(! $matched) throw new Exception('Could not match route.');
$param_str = str_replace($route->pattern, '', $app_path);
$params = explode('/', trim($param_str, '/'));
$params = array_filter($params);
$match = clone($route);
$match->params = $params;
return $match;
}
}
class Controller
{
public function action()
{
var_dump(func_get_args());
}
}
$route = new Route;
$route->name = 'blog-posts';
$route->pattern = '/blog/posts/';
$route->class = 'Controller';
$route->method = 'action';
$router = new Router(array($route));
$match = $router->resolve('/blog/posts/foo/bar');
// Dispatch
if($match) {
call_user_func_array(array(new $match->class, $match->method), $match->params);
}
Output:
array (size=2)
0 => string 'foo' (length=3)
1 => string 'bar' (length=3)
This is a basic version - simply just a concept version to show functionality and I wouldn't suggest using it in a production environment.
$routes = [
'blog/view' => 'Example#index',
'api/forum/create' => 'other.php'
];
$url = explode('/', $_GET['url']);
if (isset($url[0]))
{
if ($url[0] == 'api')
{
$params = array_slice($url, 3);
$url = array_slice($url, 0, 3);
}
else
{
$params = array_slice($url, 2);
$url = array_slice($url, 0, 2);
}
}
$url = implode('/', $url);
if (array_key_exists($url, $routes))
{
$path = explode('/', $routes[$url]);
unset($path[count($path)]);
$segments = end($path);
$segments = explode('#', $segments);
$controller = $segments[0];
$method = $segments[1];
require_once APP_ROOT . '/app/' . $controller . '.php';
$controller = new $controller;
call_user_func_array([$controller, $method], $params);
}
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))