Git Product home page Git Product logo

altorouter's Introduction

AltoRouter PHP status Latest Stable Version License

AltoRouter is a small but powerful routing class, heavily inspired by klein.php.

$router = new AltoRouter();

// map homepage
$router->map('GET', '/', function() {
    require __DIR__ . '/views/home.php';
});

// dynamic named route
$router->map('GET|POST', '/users/[i:id]/', function($id) {
  $user = .....
  require __DIR__ . '/views/user/details.php';
}, 'user-details');

// echo URL to user-details page for ID 5
echo $router->generate('user-details', ['id' => 5]); // Output: "/users/5"

Features

  • Can be used with all HTTP Methods
  • Dynamic routing with named route parameters
  • Reversed routing
  • Flexible regular expression routing (inspired by Sinatra)
  • Custom regexes

Getting started

You need PHP >= 7.3 to use AltoRouter, although we highly recommend you use an officially supported PHP version that is not EOL.

Contributors

License

MIT License

Copyright (c) 2012 Danny van Kooten [email protected]

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

altorouter's People

Contributors

adduc avatar aliazizi avatar dannyvankooten avatar frosso avatar koenpunt avatar mathb avatar nyholm avatar sebastianpoell avatar sergey-nagaytsev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

altorouter's Issues

router seems dead. class is loading fine

hi people!

Please enlighten me on something:

ini_set('display_startup_errors',1);
ini_set('display_errors',1);
error_reporting(-1);

$router = new AltoRouter();
$router->map("GET","*", function() {
    echo "BOOM!";
});

I am not getting any BOOM...nor any errors!
Why?

generate url with params

hi

for generate url there is method generate() which have route name as param, and return url.

That work fine.

but how to generate an url with params, like:

/users/[i:page]?

Thanks

php 5.3 bug

if (false !== strpos($requestUrl, '?')) {
        $requestUrl = strstr($requestUrl, '?', true);
    }

throws an error regarding params count (php lower 5.3)

a cleaner way (and the possibility to use this script on lower php)
if (($sp = strpos($requestUrl, '?')) !== false) {
$requestUrl = substr($requestUrl, $sp +1);
}

Param for language

Hi

As suggested here: #38
I have implement language string on url in this way:

      $router->addMatchTypes(array('lang' => '[a-z]{2}'));
      $router->setBasePath($config->get('base_folder'));
      $routes = include BASEDIR . '/private/config/routes.php';

      foreach($routes as $key => $route)
      {
        $router->map($route[0], '/[lang:language]?'.$route[1], $route[2], $key, isset($route[3])? $route[3] : null);
      }

      $match = $router->match();

      $this->controller = $match['target']['c'];
      $this->action = $match['target']['a'];
      $this->params = $match['params'];
      $this->language_from_url = isset($this->params['language'])? $this->params['language'] : false;
      $this->name = $match['name'];

Everything work fine, however, when I try to generate an URL using method generate() then the URL returned its without language string.

Example if you open www.example/en/login then I want when generate URL to return /en/login, and not /login.

Any help is much appreciated.

Thanks

infinitescroll route

Hi

I have an url which work fine if I type on address bar, example:

www.domain.com/users/2

when I try to use this with infinitescroll plugin, which make an ajax call using GET, then the route is not found.

I define in this way:

'/users/[i:page]?'

any suggestion?

Why not optional http method?

Do we really need to repeatedly map to GET POST or GET|POST methods in map function?

Why just not make a default value that matches any http method?

I will say it is a suggestion then.

Anchors are matched as regular parameter

So if i have this code:

$router->map('GET','/[:page]', 'page', 'page');

If i open /index in a browser, it works fine. But if i want to view an anchor, e.g /index#bottom then the page parameter matches everything and does not stop at the #. Is this intended behavior? Is there a workaround?

$router->map('GET','/[:page]#[*]', 'page', 'page_anchor');

If i do this then the routing is fine, but the anchoring itself still doesn't work.

Example for post form

Hello,

is it possible to give me a working example for a post form?

This is what I have so far.

Routes (and a few more):

$router->map('GET', '/profil', 'profile', 'profil_route');
$router->map('POST', '/login', 'login', 'login_route');

A switch for $match['target'] to match the targets, among them is:

switch($match['target']) {
  ...
  case 'profile':
    /* show_login() will return a variable with
    // the html content of a <form action="/login" method="post">
    */
    $html = show_login();
    break;
  case 'login':
    var_dump($_POST);
    break;
}

Now my question:
Is it possible to send the $_POST variables to the login_route? When I submit the form right now, $_POST is always empty. Am I doing it wrong?

I hope you can understand what I'm talking about. Any help or hints in the right direction are appreciated.

Setup Packagist package and Github service hook

I've updated the composer.json so a dedicated package can be registered on Packagist.

But I can't enable the service hook, so I ask you, @dannyvankooten, can you register AltoRouter on packagist and add the required service hook in the GitHub repository:

Enabling the Packagist service hook ensures that your package will always be updated instantly when you push to GitHub. To do so you can go to your GitHub repository, click the "Settings" button, then "Service Hooks". Pick "Packagist" in the list, and add your API token (see above), plus your Packagist username if it is not the same as on GitHub. Check the "Active" box and submit the form.

example for actually calling controller#action and passing vars?

hi there, just played a bit with AltoRouter and figured out that it leaves out to me to actually call the matched controller#action and pass the appropriate vars but i am not sure i implemented this correctly. it surely works but thought of making sure i am on the correct route :) you might want to include this in an example if this is the correct way of doing this to help others

$router = new AltoRouter();
$router->setBasePath('/demosite4.com'); 
$router->map('GET','/', 'home_controller#display_item', 'home');
$router->map('GET','/content/[:parent]/?[:child]?', 'content_controller#display_item', 'content');
$match = $router->match();

// not sure if code after this comment  is the best way to handle matched routes
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 if ($match['target']==''){
    echo 'Error: no route was matched'; 
    //possibly throw a 404 error
} else {
    echo 'Error: can not call '.$controller.'#'.$action; 
    //possibly throw a 404 error
}


// content_controller class file is autoloaded 
 <?php
class content_controller {
    public function display_item($args) {
        //echo our params to to make sure we got them
        echo 'parent: '. $args['parent'];
        echo 'child: '. $args['child'];
    }
?>

If set a basePath map '*' not work.

Hi,

If set a basePath using $router->setBasePath('/altoRouter');
and then: $router->map('*',..); not work.
Only work if basePath is empty.

Because route receive basePath + route.

And when match:

if ($_route === '*') $match = true; // Route is basePath + * and not only *

pairs of vars

Is it possible to define a route like this :

/articles/archives/rub_id/35/
/articles/archives/rub_id/35/page/3/
/articles/archives/rub_id/35/page/3/order/date/

in only 1 route ?

$router->map('GET','/articles/archives/XXXXX', 'article#archive', 'article_archive');

Something like ZendRouter with dynamic number of pairs "var_name/var_value".

Sory for my english :)

Kaimite

Language regex

Hello i want to match this url

http://localhost/en_US

the map is
$router->map('GET', '/[a:lang]/?', '', 'language');

the country code regex is [A-Za-z]{2}_[A-Za-z]{2}

it is possible to work this?

Custom regex not working with other maps

Hello custom regex not working with othet params.

Here some examples.

http://localhost/altorouting/en_US (working)
$router-&gt;map('GET', '@/(?[A-Za-z]{2}_[A-Za-z]{2})$', '', '');

http://localhost/altorouting/en_US/user (not working)
$router-&gt;map('GET', '@/(?[A-Za-z]{2}_[A-Za-z]{2})$/user', '', '');

http://localhost/altorouting/en_US/cat1/ca2/cat3 (not working)
$router-&gt;map('GET', '@/(?[A-Za-z]{2}_[A-Za-z]{2})$/[*:permalink]', '', '');

http://localhost/altorouting/home/en_US (not working)
$router-&gt;map('GET', '/home/@/(?[A-Za-z]{2}_[A-Za-z]{2})$', '', '');

Change autoload from file- to classmap- based for efficiency

Originally asked by @joegreen88 in issue #5:

How about changing the autoload section in composer.json from "files": ["AltoRouter.php"] to "classmap": ["AltoRouter.php"]?

The current implementation is including Altorouter.php every time vendor/autoload.php is included, but this is not always necessary. Using classmap means that Altorouter.php is only included when the AltoRouter class is autoloaded.

setBasePath with absolute URL

It would be great to add a "absolute url" in setBasePath.

Here a example with absolute URL

$router = new AltoRouter();
$router->setBasePath('http://localhost/app');
$router->map('GET|POST', '/users/[i:id]/', 'user');

/* http://localhost/app/user/1 */
echo $router->generate('user', array('id' => 1));

How can I define url query rout.

Hi,
First of all I would like to thank all that contribute to this project.
I have started to test this utility but have some questions and appreciate your quick response.
This is the sample route I created:
$router->map('GET|POST','/', array('c' => $CompaniesCtrl, 'a' => 'ListAction'), 'home');

$router->map('GET|PUT|DELETE','/companies/[i:id]', array('c' => $CompanyCtrl), 'company_edit');
here is the route I use to list companies
$router->map('GET|POST','/companies/', array('c' => $CompaniesCtrl));
so How can I create rout to support the following?
http://localhost:8000/api/companies/?page=0&size=5
thanks

css/js wont be loaded

Hello,

I use altorouter for my framework but I saw a problem today.
My page wont load in the css and js that needs to be loaded.

Can I make a resource map for my js and css that will load everything from "URL_TO_WEBSITE/public/{{CSS OR JS}}" ?
If possible how can I do this the best ?

Greets, Wouter.

Can't use AltoRouter, always obtains "404 Not Found"

Hi,

I've downloaded last version of AltoRouter and creates a .htaccess file like this:

RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ./index.php [L]

My index.php is:

<?php
include 'lib/AltoRouter/AltoRouter.php';

$router = new AltoRouter();
$router->setBasePath('/test/paco');
/* Setup the URL routing. This is production ready. */

// Main routes that non-customers see
$router->map('GET','/', 'home.php', 'home');
$router->map('GET','/quizs/[i:id]/', 'quizs.php', 'quiz_show');
$router->map('GET','/quizs/', 'quizs.php', 'quiz');
$router->map('GET','/members/', 'member.php', 'member');

/* Match the current request */
$match = $router->match();
?>

<h1>AltoRouter Test</h1>

<h3>Current request: </h3>
<pre>
        Target: <?php var_dump($match['target']); ?>
        Params: <?php var_dump($match['params']); ?>
        Name:   <?php var_dump($match['name']); ?>
</pre>

<h3>Try these requests: </h3>
<p><a href="<?php echo $router->generate('home'); ?>">GET <?php echo $router->generate('home'); ?></a></p>
<p><a href="<?php echo $router->generate('quiz_show', array('id' => 5)); ?>">GET <?php echo $router->generate('quiz_show', array('id' => 5)); ?></a></p
>

But whe I try to call:

https://gow.upcnet.es/test/paco/quizs/

or

https://gow.upcnet.es/test/paco/members/

I obtain this:

Not Found

The requested URL /test/paco/members was not found on this server.

I'm a bit confused... Where is the problem? Thanks in advance,

Group routes with prefix

As an enhancement, it would be great to add a "RouteGroup" which contains an array of routes and a prefix for all (e.g to avoid repeating "/admin")

Tag stable release?

Hello,

I wanted to load AltoRouter via Composer, but since there are no tags, I have to use "niahoo/altorouter": "dev-master" (by the way, shouldn't that be dannyvankooten/AltoRouter ?), which in turn requires that I set "minimum-stability": "dev" in my composer.json file.

Long story short, could you push a git tag, something like v1.0.0 to your repo?

Hook integration

Hi

there is an example with hook integration like toro php router have?

So we can fire before and/or after a controller.

thanks

External file for routes

Hi,

Is possible add external file (example .ini file) with all routes, something like:

[routes]
home="GET|POST /home home#index"
users="GET /users users#index"

then when we create new instance we can:

$router = new AltoRouter('routes.ini');

$match = $router->match();

Thanks!!

Dot in URL not allowed?

Shouldn't both these URLs work?

map('GET', '/location/[:lat]/[:lng]', null); echo "Works ...\n"; var_dump( $router->match('/location/42/-73')['params'] ); echo "Doesn't work?\n"; var_dump( $router->match('/location/42.333/-73') ); ?>

Perhaps the dot confuses a regex somewhere?

Thanks for any help!

namespace controllers

Hi,

I have for each controller a namespace like:

namespace Controller;

I have dinamic load controller, example:

$this->controller = new $this->controller();

I have try add use \Controller; on top of page, and also:

$this->controller = new \Controller$this->controller();

But not work...

any suggestion?

Thanks

Help with Windows IIS

Is there a similar way to set up an .htaccess file for use with Alto, in a Windows Server 2008 R2 + IIS environment instead of Apache?

Thanks.

Accessing POST data with router

Hi, im not sure if im getting myself confused or not, but i was assuming using the POST method i would be able to retrieve the POST data from the returned match.

Am I wrong? If so whats the best way to get the post data after a match has been made?

Cheers

Processing HEAD requests

A general question on the usage of AltoRouter with any server (nginx in my case) and processing HEAD requests.

Now any HEAD request to my app results in a 500 Internal Server Error, because these requests are not handled by the router.
But essentially I want the result of the GET request without the body returned. Does anyone know how to do this efficiently? Preferably on the server side (nginx), so I don't have to modify all applications.

Support unicode regular expressions

i can't add this regex

/[^\x{0600}-\x{06FF}\x{FB50}-\x{FDFD}\x{FE70}-\x{FEFF}\x{0750}-\x{077F}a-zA-Z0-9\/_-\s\x{200C}]+/u

please help me for add this regex

My custom branch

edit: I'm sorry i mixed up Github accounts, i'm niahoo https://github.com/niahoo/AltoRouter/tree/named-only

Hi,

I would like too explain why i have a custom branch if someone is interested.

This branch is called "named-only" because you can only map routes that have a name :

  • the $name for the map() function is not optional
  • the function doesn't throw exceptions

As many people that use AltoRouter (i guess), i don't use a framework such as Laravel or Symphony, but a set of good libraries, such as AltoRouter (and i can still use libraries from Symfony in the end).

But as i do more websites, i want to reuse code. So, if i build a "Signup" module, i define controllers, models ... and routes. So, in the routes file of the signup module, i map several routes such as 'login', 'logout', 'signup', etc. But if i want override one of these routes in a particular website, i don't want to try/catch every map() call.

So, modules are loaded in order of priority. The website's own module comes first and map() 'login' for example. Say i want a special login page. Then, when the signup module is loaded and maps all its routes, the ones with a name which is already registered are simply ignored.

I think this is good enough since it's simple. But i would like to know what you think.

Obviously it would be more simple to me to have these changes merged to master branch, but it's not so hard to maintain that in my own branch (a few lines of codes only are different), that's why i never pulled a request and i don't mind to keep maintaining my own branch.

Thanks for reading

A getMatchedResult() method?

I suggest to have a getMatchedResult() method called in the foreach test routes loop of match() method in order to continue tests if getMatchedResult() return false. With this, we can, in user extension side, for example, check if a page exists and if it fails, check if a controller exists... until end of routes set. Because a found route's expression is not necessary the real target of this expression...

see https://github.com/flavi1/AltoRouter/commit/11033973f4f1c794249900e21cd7c4db1d302a97
(maybe code is more understandable than my explanation...)

How to match a query url?

How can I match a query url? For instance,

http://xxx/admin/page/main/list?set=1&page=2

$Router->map('GET','/[:module]/[:branch]/[:method]?set=[i:setnumber]&page=[i:pagenumber]', '/module/branch/method?set&page');

I would like to get this result,

array (size=3)
  'target' => string '/module/branch/method?set&page' (length=22)
  'params' => 
    array (size=3)
      'module' => string 'page' (length=4)
      'branch' => string 'main' (length=4)
      'method' => string 'list' (length=4)
      'setnumber' => int '1' (length=1)
      'setnumber' => int '2' (length=1)
  'name' => null

But I get falseinstead,

$match = $Router->match();
var_dump($match); \\boolean false

is it possible the result that I'm after?

Add $_GET variables to parameters?

Got this in the mail.

.....
I discovered that if I have an URL like this http://www.site.com/users/1?param1=test everything that is sent after ? is not recognized as a parameter so I changed your class and added this

if(count($_GET)>0) {
        foreach($_GET as $key => $get) {
                $params[$key] = $get;
         }
}

.....

Personally, I think request parameters should not be in the parameters outputted by the AltoRouter class as it adds some unnecessary complexity. Variables need to be checked for collision with AltoRouter parameter names, etc..

Example
Visitors adds controller=foo, AltoRouter also outputs a controller parameter.

What do you guys think?

Router cant map in class

Hello everyone,

I am creating a custom MVC framework and want to use altorouter as my router.
So I have made a bootstrap class with a _loadRouter function in it.
This function loads the router config file so that we can map the array.

Here is the function :

    private function _loadRoutes($routes) {

        require_once SYSDIR."vendor/altorouter/AltoRouter/AltoRouter.php";
        $router = new AltoRouter();
        $router->setBasePath(BASE_URL."test");

        foreach($routes as $key => $route) {
            #echo '$router->map('. $route[0] .",". $route[1] .",". $route[2] .",". $key .')<br />';
            $router->map(
                  $route[0]
                , $route[1]
                , $route[2]
                , $key
            );
        }

        $match = $router->match();

        // not sure if code after this comment  is the best way to handle matched routes
        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 if ($match['target']==''){
            echo APPPATH."controllers/$controller.php";
            echo 'Error: no route was matched'; 
            //possibly throw a 404 error
        } else {
            echo 'Error: can not call '.$controller.'#'.$action; 
            //possibly throw a 404 error
        }
    }

It keeps saying no route was mactched.
Here is the router config file :

return $routes = array(
    'home' => array("'GET'", "'/'", "'Home#index'"),
    'test' => array("'GET'", "'/test/'", array("'c'" => "'Controller'", "'a'" => "'action'"))
);

HELP: setBasePath can't be ' '

I have the altorouter on the root of the website. I assume that I set setBasePath as '/' . Problems show up when I map "/index.php" to home. It looks for //index.php not /index.php. I then make a map to "index.php". This works. Except when generating a link. It does makes a link index.php not /index.php

Help

Trailing slash issue

Hello i have this maps

map('GET', '/', '', 'home'); $router->map('GET', '@/(?[A-Za-z]{2}_[A-Za-z]{2})', '', 'language'); $router->map('GET', '/user', '', 'user'); ?>

.htaccess
Options +FollowSymLinks
RewriteEngine On
RewriteRule ^(.*)$ index.php [NC,L]

CASES
http://localhost/alto/ (working)
http://localhost/alto/en_US/ (working)
http://localhost/alto/en_US (working)
http://localhost/alto/user (working)
http://localhost/alto/user/ (not working)

why the last map not working with/without trailing slash?

Optional parameters are not working

See this code:

$router->map('GET','/popular(/page/[i:page]/?)?/?', 'popular');
echo $router->generate('popular'), array('page'=>3);

Outputs

/popular(/page/[i:pageno]/?)?/?/?

Default value Param

Hello it's possible to set in rule default value? [lang:language='en']

$router = new AltoRouter();
$router->setBasePath();
$router->addMatchTypes(array('lang' => '[A-Za-z]{2}'));

$router->map('GET', '/', '', 'home');
$router->map('GET', '/[lang:language]/rss', '', 'rss');

echo $router->generate('rss');
/*
output
[lang:language]/rss
*/

Before Filters for Routes

Is it possible in the software to add a filter to run before a route is processed? For example, I want to say:

Before you run this route, make sure the user is authenticated.

Of course I wouldn't want to do that for all routes. My site may have a few routes that don't require login, and of course the login page itself shouldn't require login.

Currently, it looks like I would need to introduce this logic at the top of every callback function for every route that needs it. It would be cleaner to write once.

If I'm mistaken, and this functionality exists, please let me know!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.