GithubHelp home page GithubHelp logo

zendframework / zend-router Goto Github PK

View Code? Open in Web Editor NEW
32.0 19.0 20.0 3.38 MB

Standalone routing implementation for HTTP and console requests

License: BSD 3-Clause "New" or "Revised" License

PHP 100.00%

zend-router's People

Contributors

akrabat avatar bakura10 avatar blanchonvincent avatar dasprid avatar evandotpro avatar ezimuel avatar freeaqingme avatar jonathanmaron avatar localheinz avatar maks3w avatar marc-mabe avatar michalbundyra avatar mikaelkael avatar mpinkston avatar mtymek avatar mwillbanks avatar ocramius avatar padraic avatar phpboyscout avatar prolic avatar ralphschindler avatar samsonasik avatar sgehrig avatar socalnick avatar thinkscape avatar vahid-sohrabloo avatar veewee avatar wdalmut avatar weierophinney avatar xerkus 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

Watchers

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

zend-router's Issues

Slashes in route params are unescaped when passing uri option

I expect a parameter passed to a segment route to always be escaped. When I pass an uri option when assembling a route, for whatever reason slashes in the route parameters are unescaped. This causes the route to no longer match correctly.

$router = \Zend\Router\Http\TreeRouteStack::factory([
    'routes' => [
        'example-route' => [
            'type' => \Zend\Router\Http\Segment::class,
            'options' => [
                'route' => '/example/route/with/:token',
            ],
        ],
    ],
]);

var_dump($router->assemble([
    'token' => 'token/with/slashes',
], [
    'name' => 'example-route',
]));
// string(42) "/example/route/with/token%2Fwith%2Fslashes"

var_dump($router->assemble([
    'token' => 'token/with/slashes',
], [
    'name' => 'example-route',
    'uri' => new \Zend\Uri\Uri('/'),
]));
// string(38) "/example/route/with/token/with/slashes"

I expect the token parameter in the second case to also become encoded. For some reason passing an uri without normalize_path: false normalizes the path, unescaping the passed parameters.

Undesired normalization happens by default in these places:

if (! isset($options['normalize_path']) || $options['normalize_path']) {
$uri->normalize();
}

if (! isset($options['normalize_path']) || $options['normalize_path']) {
$uri->normalize();
}

Advanced Routing

I want to achieve this routing.

I want to achieve this kind of routing:

ParentRouteController
GET domain.com/parent-route
GET domain.com/parent-route/:value
POST domain.com/parent-route
UPDATE domain.com/parent-route/:value

ChildRoute1Controller
GET domain.com/parent-route/:value/child-route-1
GET domain.com/parent-route/:value/child-route-1/:child1value
POST domain.com/parent-route/:value/child-route-1
UPDATE domain.com/parent-route/:value/child-route-1/:child1value

ChildRoute2Controller
GET domain.com/parent-route/:value/child-route-1/:child1value/child-route-2
GET domain.com/parent-route/:value/child-route-1/:child1value/child-route-2/:childRoute2Value
POST domain.com/parent-route/:value/child-route-1/:child1value/child-route-2
UPDATE domain.com/parent-route/:value/child-route-1/:child1value/child-route-2/:childRoute2Value

I'm using ZF 2.5.2, thanks!

wrong dispatch

// ./module/Editor/config/module.config.php
return [
 'router' => [
        'routes' => [
            'editor' => [
                'type'    => 'Segment',
                'options' => [
                    // Change this to something specific to your module
                    'route'    => '/editor[/:action][/][:id]',      // <-  notice it's 'editor'  here 
                    'defaults' => [
                        'controller'    => Controller\EditorController::class,
                        'action'        => 'index',
                    ],
                ],
                'may_terminate' => true,
                'child_routes' => [
                    // You can place additional routes that match under the
                    // route defined above here.
                ],
            ],
        ],
    ],
]
// ./module/Editorvote/config/module.config.php

return [
  'router' => [
        'routes' => [
            'editorvote' => [
                'type'    => 'Segment',
                'options' => [
                    // Change this to something specific to your module
                    'route'    => '/editorvote[/:action][/][:id]',   //<- start with  editor***
                    'defaults' => [
                        'controller'    => Controller\EditorvoteController::class,
                        'action'        => 'index',
                    ],
                ],
                'may_terminate' => true,
                'child_routes' => [
                    // You can place additional routes that match under the
                    // route defined above here.
                ],
            ],
        ],
    ],
]

open http://localhost/editorvote with browser, the request was dispatched to editor module( $routeMatch->getMatchedRouteName() produce editor) , but if we change ./module/Editor/config/module.config.php:

return [
 'router' => [
        'routes' => [
            'editor' => [
                'type'    => 'Segment',
                'options' => [
                    // Change this to something specific to your module
                    'route'    => '/editorX[/:action][/][:id]',   //<-change 'editor'  to  'editorX'
                    'defaults' => [
                        'controller'    => Controller\EditorController::class,
                        'action'        => 'index',
                    ],
                ],
                'may_terminate' => true,
                'child_routes' => [
                    // You can place additional routes that match under the
                    // route defined above here.
                ],
            ],
        ],
    ],
]

open http://localhost/editorvote , the dispatch works perfectly.

php -v
PHP 7.1.5 (cli) (built: Jun  8 2017 22:55:53) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies

composer.lock:

 {
            "name": "zendframework/zend-router",
            "version": "3.0.2",
            "source": {
                "type": "git",
                "url": "https://github.com/zendframework/zend-router.git",
                "reference": "03763610632a9022aff22a0e8f340852e68392a1"
            },
            "dist": {
                "type": "zip",
                "url": "https://files.phpcomposer.com/files/zendframework/zend-router/03763610632a9022aff22a0e8f340852e68392a1.zip",
                "reference": "03763610632a9022aff22a0e8f340852e68392a1",
                "shasum": ""
            }, 

Segment routing and controller constraint

In version 3.0.2
If I have the following Segment route

'application' => [
    'type'    => Segment::class,
    'options' => [
        'route'    => '/app[/:controller][/:action]',
        'constraints' => [
            'controller' => '[a-zA-Z][a-zA-Z0-9_-]+',
            'action'     => '[a-zA-Z][a-zA-Z0-9_-]+',
        ],
        'defaults' => [
            'controller'    => Controller\IndexController::class,
            'action'        => 'index',
        ],
    ],
],

And use the the new InvokableFactory for the IndexController like this

    'controllers' => [
        'factories' => [
            Controller\IndexController::class => InvokableFactory::class,
        ],
    ],

Following the url /app/index/index will result in a

The requested controller could not be mapped to an existing controller class.
Controller:
index(resolves to invalid controller class or alias: index) 

If I add this to the controllers part of the configuration

'invokables' => [
    'index' => Controller\IndexController::class,
],

the url will be matched correctly (So basically the controller constraint is expecting the full namespace to the controller).
But this doesn't look like a solution, because the 'index' key will be overwritten by another Module's Index controller invokable.

Multilingual site in ZF3

When i set the locale parameter to another value than the default value that has been defined in
module.config.php, the routing does not take this into account and uses the default value of locale instead.

Code to reproduce the issue

route definition of module.config.php:

'router' => [
        'router_class' => TranslatorAwareTreeRouteStack::class,
        'routes' => [
            'home' => [
                'type' => Segment::class,
                'options' => [
                    'route'    => '/',
                    'constraints' => [
                        'amp' => 'amp'
                    ],
                    'defaults' => [
                        'locale' => 'nl',
                        'controller' => WebsiteController::class,
                        'action'     => 'index',
                    ],
                ],
            ],
            'website' => [
                'type' => Segment::class,
                'options' => [
                    'route'    => '/:locale/{home}[/:amp]',
                    'constraints' => [
                        'amp' => 'amp'
                    ],
                    'defaults' => [
                        'locale' => 'nl',
                        'controller' => WebsiteController::class,
                        'action'     => 'index',
                    ],
                ],
            ],

            'faq' => [
                'type' => Segment::class,
                'options' => [
                    'route'    => '/:locale/{faq}[/:amp]',
                    'constraints' => [
                        'amp' => 'amp'
                    ],
                    'defaults' => [
                        'locale' => 'nl',
                        'controller' => WebsiteController::class,
                        'action'     => 'faq',
                    ],
                ],
            ],

layout in which you can choose another language: website.phml I have hard coded the value to 'en':

<li>
<a href="<?= $this->url('home', ['locale' => 'en']); ?>"<?= ($this->plugin('translate')->getTranslator()->getLocale() == 'en') ? ' class="active"' : null; ?>>
<img src="<?= $this->basepath($language['data'][11]); ?>" alt="<?= $language['data'][3]; ?>" width="54" height="37" />
</a>
</li>

Expected results

I should expect that ZF knows that locale should be set to 'en' without having to send the 'locale' parameter with every link you create on the website.
When I go to the faq, i would expect that te site goes to http://mydomain.com/**en**/faq

Actual results

When I switch to en, the routing uses the default value 'nl' instead
So when I go to the faq now, the site goes to http://mydomain.com/**nl**/faq , when I have switched the language to en.

Config option to set TreeRouteStack::baseUri

In every project I see people working around the Url ViewHelper not working in console context.

If there was a config option like below we could have one standardized way of solving this.

<?php // config/autoload/server-url.local.php

return [
    'server_url' => 'https://example.com'
]

Example of my latest workaround: https://stackoverflow.com/a/52248041/1899162

Secondarily we could then also use this option to make the ServerUrl ViewHelper work in console context.

@weierophinney do you want this PR for this repository or for Zend\View?

Combination of MVC+Middleware+Wildcard Route give the error

I was inspired by Middleware and try it using with Zend MVC as described here.
All worked well until I tried using Wildcard route.
When a route has 'middleware' config key with an array of Middleware applied it arise error rawurlencode() expects parameter 1 to be string, array given in Wildcard::assemble().

Minimal routes configuration to get error

return [
    'routes' => [
        'default' => [
            'type' => 'Segment',
            'options' => [
                'route' => '/[:controller[/[:action]]]',
                'constraints' => [
                    'controller' => '[a-zA-Z]?[a-zA-Z0-9_-]*',
                    'action' => '[a-zA-Z]?[a-zA-Z0-9_-]*',
                ],
                'defaults' => [
                    'middleware' => [Page\ConnectivePage::class, Page\RendererMiddleware::class],
                    'controller' => 'index',
                    'action' => 'index',
                ],
            ],
            'may_terminate' => true,
            'child_routes' => [
                'wildcard' => [
                    'type' => 'Wildcard',
                    'priority' => 10,
                    'options' => [],
                ],
            ],
        ],
    ],
];

image

Action key always returns index, problematic for RESTful controllers

The RESTful controller of MVC knows two different behaviours:

  • Analyse the request method and dispatch to one of the REST methods
  • Analyse the action returned by the router and dispatch to this

For me, using the latest and greatest versions of both components, this is a problem. For some reason, the router always sets the action key of the RouteMatch, so RESTful actions are never executed.

This it the RouteMatch I get for http://somedomain/:

object(Zend\Router\Http\RouteMatch)#128 (3) {
    ["length":protected]=> int(1)
    ["params":protected]=> array(2) {
        ["controller"]=> string(38) "Application\Controller\IndexController"
        ["action"]=> string(5) "index"
    }
    ["matchedRouteName":protected]=> string(4) "home"
}

The respective config is this:

return [
    'router' => [
        'routes' => [
            'home' => [
                'type' => Literal::class,
                'options' => [
                    'route'    => '/',
                    'defaults' => [
                        'controller' => Controller\IndexController::class,
                    ],
                ],
            ],
        ],
    ],

I also tried to overwrite the index key deliberately by setting it to

                    'defaults' => [
                        'controller' => Controller\IndexController::class,
                        'action' => 'getList',
                    ],

but the RouteMatch always stays the same. Why? Is it me or the code?

Any help is very welcome.

Translation issue with Router

Based on the idea of this:

<?= $this->translate(sprintf('My name is %s', 'Bruno')) ?>

I wanted to create a Url segment, for example:

'/{:param1-somelabelhere-:param2}'

Now, let say using array translation I do like this:

<?php
return array(
    ':param1-somelabelhere-:param2' => ':param1-somelabelisnowtranslated-:param2',
);

The issue comes here, when I am in the view, if I do:

Url: <?= $this->url('myroutename', array('param1'=>11, 'param2'=>22)) ?>

It renders as:

Url: /:param1-somelabelisnowtranslated-:param2

Instead of expecting behaviour:

Url: /11-somelabelisnowtranslated-22

Any ideas? It seems to be like a bug. For example in Spanish and English the position of the words is usually different, so it wouldn't make any sense for me to translate something like: english-schools-new-york as ingles-escuelas-nueva-york, that phrase should be translated as escuelas-ingles-nueva-york.

Empty route type

I've been trying to produce a module which has flexible routing which an end user of the module can adapt to fit it into their site. I have hit an impasse being able to fully support the following use cases:

1a. Deploy the module as a stand alone application with the module based at the root of the domain.
1b. Deploy the module as a part of another application with the module based at the root of the domain.
2. Deploy the module as part of another application with the module based in a "subdirectory" eg prefix the url with a fixed string.
3. Deploy the module as part of another application with the module based on a different sub domain (at it's root)

For all the cases, the routing structure as used by the module cannot change as it needs to be able to perform redirects and render urls based on the routing. At best I've managed to produce a configuration which solves 2 of the 3.

My attempts to solve it provide a tree of routes anchored by a single route. For customisation, the intention is that the user can replace this route configuration (using standard ZF2 module config) with their own configuration which enables one of the three behaviours. However at present there does not seem to be a way to provide a placeholder route which will allow for (1) which can be replaced to enable (2) + (3) without also changing the child route structure (and thus breaking rendering and redirects)

The solution that I'm proposing is to create a new "Empty" route type which will always return true when asked if it matches and when composed into a route will render as an empty string. This will act as the placeholder route in the above situation and can be swapped to either a segment or domain route type depending on the user needs.

See conferencetools/tickets-module#100 for more info

filterable routes

Hey,

First of all, either I'm really stupid and did a bunch of work for nothing or this might be a useful request.

I am making a rest-api like application and wanted my routes to be filterable, as in 'allowed' based on a boolean condition. I know this is possible by listening to the dispatch event but I really wanted the config to be at the routes them self. Unless I missed a clue it is not possible to set extra data in the routes config. So I implemented my own router that extends this module.

To sum it up:

  • Did I miss a clue and is this already possible?
  • If not, are you interested in integrating my extension into this module?

Link to my extension: zf3-filterableRouter

Strange behaviour with constraints and segment child routes.

I want to create routes with an optional [lang] parameter that would be used to set the application language as follows:

Example with default lang param(EN for example)

domain.tld/
domain.tld/users
domain.tld/contacts
etc.

Example witt new lang param(DE for examle)

domain.tld/de
domain.tld/de/users
domain.tld/de/contacts
etc.

This is my route configuration:

 'router' => [
        'routes' => [
            'site' => [
                'type' => Segment::class,
                'options' => [
                    'route' => '[/:lang]',
                    'constraints' => [
                        'lang' => '[a-z]{2}',
                    ],
                    'defaults' => [
                        'controller' => Controller\IndexController::class,
                        'action' => 'index',
                        'lang' => 'en',
                    ],
                ],
                'may_terminate' => true,
                'child_routes' => [
                    'home' => [
                        'type' => Literal::class,
                        'options' => [
                            'route' => '/',
                            'defaults' => [
                                'controller' => Controller\IndexController::class,
                                'action' => 'index',
                            ],
                        ],
                        'may_terminate' => true,
                    ],
                    'application' => [
                        'type' => Segment::class,
                        'options' => [
                            'route' => '/application[/:action]',
                            'defaults' => [
                                'controller' => Controller\IndexController::class,
                                'action' => 'index',
                            ],
                        ],
                        'may_terminate' => true,
                    ],
                ],
            ],
        ],
    ],

When I have lang param in the url everything is fine. But when I try to open "default" lang without specifying it into the path (ex. example.tld/application/test) it gives me 404 error.

What I found is that the final regex after transformation from Segment class is (\G(?:/(?P<param1>([a-z]{2})))?) and path is /application/test. When preg_match is executed on Segment.php:385 it return match with following values:

[
     '0' => '/ad',
     'param1' => 'ad',
     '1' => 'ad',
],

which is obviously the wrong behavior. My language is set to "ad" instead of open application/test action. I tested around 10 more regex but without success... (ex. ^[a-z]{2}$).

Question on assemble() with TreeRouteStack + method routes

given the following setup:

//# composer require zendframework/zend-router

require __DIR__ . '/vendor/autoload.php';

use Zend\Http\Request;
use Zend\Router\Http\TreeRouteStack;

$router = new TreeRouteStack();

$routes = [
    'post' => [
        'type'    => 'literal',
        'options' => [
            'route'    => '/blog/post',
            'constraints' => [
                'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
                'page'   => '[0-9]+',
                'id'     => '[0-9]+',
            ],
            'defaults' => [
                'controller' => 'Blog\Controller\PostController',
                'action'     => 'index',
            ],
        ],
        'may_terminate' => false,
        'child_routes' => [
            'index' => [
                'type' => 'segment',
                'options' => [
                    'route' => '[/index[/:page]]',
                    'defaults' => [
                        'page' => 1,
                    ],
                ],
                'may_terminate' => false,
                'child_routes'  => [
                    'GET' => [
                        'type'    => 'method',
                        'options' => [
                            'verb' => 'GET',
                        ],
                    ],
                ],
            ],
            'read' => [
                'type' => 'segment',
                'options' => [
                    'route' => '/:id',
                    'defaults' => [
                        'action' => 'read',
                    ],
                ],
                'may_terminate' => false,
                'child_routes'  => [
                    'GET' => [
                        'type'    => 'method',
                        'options' => [
                            'verb' => 'GET',
                        ],
                    ],
                ],
            ],
            'update' => [
                'type' => 'segment',
                'options' => [
                    'route' => '/:id/update',
                    'defaults' => [
                        'action' => 'update',
                    ],
                ],
                'may_terminate' => false,
                'child_routes'  => [
                    'GET:POST' => [
                        'type'    => 'method',
                        'options' => [
                            'verb' => 'GET,POST',
                        ],
                    ],
                ],
            ],
        ],
    ],
];

$router->addRoutes($routes);

$name = 'post/index/GET';
echo $name . ' => ' . $router->assemble(['page' => 42], [
    'name'   => $name,
]) . PHP_EOL;
// /blog/post/index/42


$name = 'post/read/GET';
echo $name . ' => ' . $router->assemble(['id' => 123], [
    'name'   => $name,
]) . PHP_EOL;
// /blog/post/123

$name = 'post/update/GET:POST';
echo $name . ' => ' . $router->assemble(['id' => 123], [
    'name'   => $name,
]) . PHP_EOL;
// /blog/post/123/update

is it possible to avoid using the method route name (i.e. using just post/index, post/update) when assembling paths / generating URIs? Since we need to use may_terminate => false it would seem that is not possible. The only thing i was able to do was using an empty string for the route name and utilize ugly name assemble params like post/index/

When we are assembling urls we usually don't care about the method, the router will determine if the request method is accepted for the requested url.

...or am I missing something very basic/trivial? (my apologies in this case)

thanks and kind regards

Working with different locales fix proposal

Hello! I work on translatable route segment with 3 locales ['en' => 'en_US', 'lv' => 'lv_LV', 'ru' => 'ru_RU']. However, I need to encode lv & ru translations with rawurlencode() in php array. That is because /Zend/Router/Http/Segment.php method, which performs match against the HTTP request, do not match given url path with generated regex within translation keys loop.

So my proposal is: Encode each translated string before generating regex.

proposal

Slim 2 redirect is not working

Redirect is not working in slim 2 & it returns below error for this line
$application->redirect($application->urlFor('details', array(
'slug' => $slug,
)));

Error

Slim_Exception_Stop Object

(
[message:protected] =>
[string:Exception:private] =>
[code:protected] => 0
[file:protected] => /usr/local/test/enduser/vendors/Slim/Slim.php
[line:protected] => 810
[trace:Exception:private] => Array
)

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.