0

We have standart route from sample

            array(
                'type'    => 'Literal',
                'options' => array(
                    'route'    => '/application',
                    'defaults' => array(
                        '__NAMESPACE__' => 'Application\Controller',
                        'controller'    => 'Index',
                        'action'        => 'index',
                    ),
                ),
                'may_terminate' => true,
                'child_routes' => array(
                    'default' => array(
                        'type'    => 'Segment',
                        'options' => array(
                            'route'    => '/[:controller[/:action]]',
                            'constraints' => array(
                                'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
                                'action'     => '[a-zA-Z][a-zA-Z0-9_-]*',
                            ),
                            'defaults' => array(
                            ),
                        ),
                    ),
                ),
                'priority' => -1000,
            ),

It understands URLs like

/application
/application/some
/application/index/about

But it not understands URLs like

/application/index/about/param1/val1/param2/val2/...

In Zend1 was *, we could add it to route like this

 'route'    => '/:controller/:action/*',

And all parameters after * tried to split by slash. Question: is there way in zend 2 to create routes with unknown parameter-names? One solution is create own route type, but may be exists built-in solutions?

UPD:

I have wrote myself Route class, that parses * on roure-end , and non-required parameters will parse in ZF1 style.

<?php

namespace Engine\Mvc\Router\Http;

use Zend\I18n\Translator\TranslatorInterface as Translator;
use Zend\Mvc\Router\Exception;
use Zend\Stdlib\RequestInterface as Request;

class Segment extends \Zend\Mvc\Router\Http\Segment
{
    protected $unknownParameterParse = false;
    protected $route = null;
    public function __construct($route, array $constraints = [], array $defaults = [])
    {
        if ($route{mb_strlen($route)-1} == '*'){
            $route = mb_substr($route, 0, mb_strlen($route)-1);
            $this->unknownParameterParse = true;
        }
        $this->route = $route;
        parent::__construct($route, $constraints, $defaults);
    }

    public function assemble(array $params = [], array $options = []) {
        $path = parent::assemble($params, $options);
        if ($this->unknownParameterParse){
            $unknowns = [];

            foreach($params as $key=>$value){
                if (strpos($this->route, ':'.$key)===false ){
                    $unknowns[] = $this->encode($key) . '/'. $this->encode($value);
                }
            }
            if ($unknowns){
                $path = rtrim($path, '/').'/'.implode('/', $unknowns);
            }
        }
        return $path;
    }

    public function match(Request $request, $pathOffset = null, array $options = [])
    {
        if (!method_exists($request, 'getUri')) {
            return;
        }

        $uri  = $request->getUri();
        $path = $uri->getPath();

        $regex = $this->regex;

        if ($this->translationKeys) {
            if (!isset($options['translator']) || !$options['translator'] instanceof Translator) {
                throw new Exception\RuntimeException('No translator provided');
            }

            $translator = $options['translator'];
            $textDomain = (isset($options['text_domain']) ? $options['text_domain'] : 'default');
            $locale     = (isset($options['locale']) ? $options['locale'] : null);

            foreach ($this->translationKeys as $key) {
                $regex = str_replace('#' . $key . '#', $translator->translate($key, $textDomain, $locale), $regex);
            }
        }

        if ($pathOffset !== null) {
            $result = preg_match('(\G' . $regex . ')', $path, $matches, null, $pathOffset);
        } else {
            $result = preg_match('(^' . $regex . ($this->unknownParameterParse ? '' : '$') . ')', $path, $matches);
        }


        if (!$result) {
            return;
        }
        $matchedLength = strlen($matches[0]);
        $params        = [];

        foreach ($this->paramMap as $index => $name) {
            if (isset($matches[$index]) && $matches[$index] !== '') {
                $params[$this->decode($name)] = $this->decode($matches[$index]);
            }
        }

        /*ENGINE get not defined params*/
        if ($this->unknownParameterParse){
            $otherParams = explode("/", trim(substr($path, strlen($matches[0])), "/") );
            foreach($otherParams as $i=>$param){
                if ($i%2 == 0){
                    $pairKey = $param;
                }else{
                    $params[$pairKey] = $param;
                }
            }
        }
        /* endof get not defined params */
        return new \Zend\Mvc\Router\Http\RouteMatch(array_merge($this->defaults, $params), $matchedLength);
    }
}

How said chaoss88 it perfectly does Wildcard route: we can make parent-route with Segment type, and child route with Wildcard type. But class above some more proger-friendly. Routes like this:

'route'    => '/core/:controller[/:action]*'

Working good. But Wildcard router has security issues if you are using ZF2 router as grant of request filtration - thats why it's deprecated. But I think router is for url parse/assemble, not for filtration: for filtration/validation ZF2 has much better solutions.

Alexander Goncharov
  • 1,572
  • 17
  • 20
  • I actually don't know if it can works but you can maybe try [Regex routing](http://framework.zend.com/manual/current/en/modules/zend.mvc.routing.html#zend-mvc-router-http-regex) – jbrtrnd Jun 17 '16 at 07:19
  • Regexp have no dynamic parametrization. But I have already solved problem with my router, extends \Zend\Mvc\Router\Http\Segment . – Alexander Goncharov Jun 20 '16 at 09:51

2 Answers2

0

I think Wildcard is that you're looking for:

            'child_routes' => array(
                'default' => array(
                    'type'    => 'Wildcard',
                    'options' => array(
                            'key_value_delimiter' => '/',
                            'param_delimiter' => '/'
                            )
                    ),
              ),
chaoss88
  • 146
  • 2
  • 11
  • 1
    Wildcard route type is deprecated a long time ago due to security issues. http://framework.zend.com/manual/current/en/modules/zend.mvc.routing.html#zend-mvc-router-http-wildcard-deprecated – edigu Jun 18 '16 at 23:18
  • Good solution, thanks! About security - I think, potential unsecure request parameters must to validate manualy in controoller. It is old web-developing rule - any data can be in input. – Alexander Goncharov Jun 20 '16 at 09:48
0

I am not sure what those parameters are supposed to represent but from your example it looks like you could/should use query parameters for those parameters instead of route params. You could send the request as follows:

application/index/about?param1=val1&param2=val2&...

With such url you can do the following in your controller to get your query params:

$param1 = $this->params()->fromQuery('param1');  // val1
$param1 = $this->params()->fromQuery('param2');  // val2

And you can get the controller and action like this:

$controller = $this->params()->fromRoute('controller');  // index
$action = $this->params()->fromRoute('action');  // about

You don't have to change anything in your route config for this to work.
Check also this answer here.

Community
  • 1
  • 1
Wilt
  • 41,477
  • 12
  • 152
  • 203