Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Console route improvements #4449

Merged
merged 13 commits into from

4 participants

@mtymek

This PR attempts to finish missing features in console routes. It also extracts code responsible for parsing command line arguments into separate class under Zend\Console namespace. This allows using console commands without full MVC stack (even in non ZF2-based projects), for instance:

use Zend\Console\ConsoleRouteMatcher;

array_shift($argv);
$matcher = new ConsoleRouteMatcher("action [--verbose|-v] <param>");
$matches = $matcher->match($argv);
print_r($matches);

ConsoleRouteMatcher is now used internally by Zend\Mvc\Router\Console\Simple.

library/Zend/Console/ConsoleRouteMatcher.php
((27 lines not shown))
+
+ /**
+ * Parameters' name aliases.
+ *
+ * @var array
+ */
+ protected $aliases;
+
+ /**
+ * Class constructor
+ *
+ * @param string $route
+ * @param array $constraints
+ * @param array $defaults
+ * @param array $aliases
+ * @return \Zend\Console\ConsoleRouteMatcher
@weierophinney Owner

@return self will work here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
library/Zend/Console/ConsoleRouteMatcher.php
((42 lines not shown))
+ * @return \Zend\Console\ConsoleRouteMatcher
+ */
+ public function __construct(
+ $route,
+ array $constraints = array(),
+ array $defaults = array(),
+ array $aliases = array()
+ ) {
+ $this->defaults = $defaults;
+ $this->constraints = $constraints;
+ $this->aliases = $aliases;
+ $this->parts = $this->parseDefinition($route);
+ }
+
+
+ /** Parse a route definition.
@weierophinney Owner

Move description down one line in the docblock.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
library/Zend/Console/ConsoleRouteMatcher.php
((392 lines not shown))
+ 'hasValue' => false,
+ );
+ } else {
+ throw new Exception\InvalidArgumentException(
+ 'Cannot understand Console route at "' . substr($def, $pos) . '"'
+ );
+ }
+
+ $pos += strlen($m[0]);
+ $parts[] = $item;
+ }
+
+ return $parts;
+ }
+
+ public function match($params)
@weierophinney Owner

Add a docblock here, please.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
library/Zend/Console/ConsoleRouteMatcher.php
((396 lines not shown))
+ 'Cannot understand Console route at "' . substr($def, $pos) . '"'
+ );
+ }
+
+ $pos += strlen($m[0]);
+ $parts[] = $item;
+ }
+
+ return $parts;
+ }
+
+ public function match($params)
+ {
+ $matches = array();
+
+ /**
@weierophinney Owner

This is an inline comment - remove the second *.

@weierophinney Owner

(Do this throughout the code base where comments exist inside methods.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
library/Zend/Mvc/Router/Console/Simple.php
((6 lines not shown))
*/
- protected $validators;
-
- /**
- * @var \Zend\Filter\FilterChain
- */
- protected $filters;
+ private $matcher;
@weierophinney Owner

Protected visibility, please.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@weierophinney

I like this approach! :) Scheduling for 2.3.0.

@mtymek

Updated!

library/Zend/Mvc/Router/Console/Simple.php
@@ -97,9 +73,7 @@ public function __construct(
$filters = null,
$validators = null
) {
- $this->defaults = $defaults;
- $this->constraints = $constraints;
- $this->aliases = $aliases;
+ $this->matcher = new ConsoleRouteMatcher($route, $constraints, $defaults, $aliases);
@prolic
prolic added a note

Perhabs we should add an interface for the console route matcher class. Add typehint on the constructor and allow passing the route matcher. If null is provided, we can still use the default implementation always.

@mtymek
mtymek added a note

I was considering about making it replaceable, but then I didn't think it would be useful (that's also why $matcher property was initially private).
If you think otherwise - sure, I can update it :-) But I have one concern here: constructor accepts filters and validators, but it looks like they are not used anywhere. Can I remove them before adding new parameter (in order to clear the code), or would you consider it as BC break?

@prolic
prolic added a note

Well, removing parameters is of course a BC break. I guess that nearly nobody instantiates this class manually, so this could be perhabs a possible BC, you should better ask @Thinkscape about it. He can give you much better feedback on that topic.

If you can say for sure, that there is no usecase in replacing the matcher with an alternative implementation, i'm good with your implementation.
For extendability reasons I always prefer to code against an interface and be able to replace every single implementation, but could be, that it's not needed in this case.

Those are missing features that did not make it into "2.0 final".

The best solution would be to implement those:

  • $constraints should work the same as in http routes - copy-paste would most likely work fine + tests.
  • $defaults would need to be implemented in the "matcher" same as in the route object.
  • $aliases are self-explanatory.
  • $filters is just an array of Zend\Filter\FilterInterface instance (i.e. filter chain)
  • $validators is an array of instances of Zend\Validator\ValidatorInterface.

Filters go through captured param values, then validators are invoked. If any validator fails, this equals to route mismatch (return false).

This way we'd have both the BC and all features covered.

@weierophinney Owner
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@prolic

definitely a good approach, thanks!

@mtymek

OK. Currently route constructor works like before:

$route = new Simple('--foo=');

... or it can be injected with custom matcher:

use Zend\Console\RouteMatcher\RouteMatcherInterface;
use Zend\Mvc\Router\Console\Simple;

class CustomRouteMatcher implements RouteMatcherInterface
{
    public function match($params)
    {
    // ...
    }
}

$matcher = new CustomRouteMatcher('custom:route:definition');
$route = new Simple($matcher);

@Thinkscape: I will try to find some time to implement missing features you mentioned, and open separate PR.

@Thinkscape

@weierophinney agreed. Chain actually implements respective Interface, so it's better to hint for FilterInterface and ValidatorInterface. This means one could provide a single or a chain of filters/validators.

@mtymek forget arrays, see above. Separate PR means this PR will have BC break. It'd be best if the second one came before this one. Just watch out for merge conflicts.

@mtymek

@Thinkscape just thinking, there's still plenty of time before v2.3, so I could actually do everything in one go. Expect some questions though, here you have a few to start with :-)

  • you mentioned constraints and defaults as if they were not implemented, but after looking at the code (+ doing running some test scripts), they seem to be working. I guess it's enough to add some unit tests, right?
  • it is not clear for me how aliases should work. How are they different from alternatives ("[-v|--verbose]", etc)?
@Thinkscape

1) yes
2) -a|-b|-c is an alternative, not alias. Alias means foo == bar - allows you to map any number of aliases (keys) to any number of (named) params. This is a useful feature i.e. for keeping BC without changing controller logic.

@mtymek

I added support for aliases and tests.

As for filters and validators, if I change them from arrays to FilterInterface and ValidatorInterface, how can I validate multiple parameters? I thought they should be an array with each element representing validators/filters applied on single param.

@Thinkscape

Take a look at InputFilter for some inspiration. That might be a decent approach...

@mtymek

I don't get it. Imagine following route:

add-user <name> <email>

I need different validation rules for name and email, so I cannot pass single ValidatorInterface to route matcher. I have to use an array:

$nameValidator = new Zend\Validator\ValidatorChain();
$nameValidator->add(new Zend\Validator\StringLength());
$nameValidator->add(new Zend\I18n\Validator\Alpha());

$emailValidator = new Zend\Validator\EmailAddress();

$validators = ;
$matcher = new DefaultRouteMatcher(
    'add-user <name> <email>', 
    array(), 
    array(), 
    array(), 
    array(), 
    array(
    'email' => $emailValidator,
    'name' => $nameValidator,
    )
);

Or am I missing something here?

@Thinkscape

Yes, "array of".

@mtymek

Done - please review.

@Thinkscape

Looks clear. Great job :-)

@weierophinney weierophinney commented on the diff
library/Zend/Mvc/Router/Console/Simple.php
@@ -68,19 +50,14 @@ class Simple implements RouteInterface
protected $assembledParams = array();
/**
- * @var \Zend\Validator\ValidatorChain
+ * @var \Zend\Console\RouteMatcher\DefaultRouteMatcher
@weierophinney Owner

Shouldn't this be RouteMatcherInterface instead of DefaultRouteMatcher?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@weierophinney weierophinney referenced this pull request from a commit
@weierophinney weierophinney [#4449] docblock fixes
- Ensured docblock references were correct
0a2538c
@weierophinney weierophinney merged commit 4421715 into zendframework:develop
@weierophinney weierophinney referenced this pull request from a commit in zendframework/zend-console
@weierophinney weierophinney Merge pull request zendframework/zf2#4449 from mtymek/feature/separat…
…e_console_route_matcher

Console route improvements
a024b12
@weierophinney weierophinney referenced this pull request from a commit in zendframework/zend-console
@weierophinney weierophinney [zendframework/zf2#4449] docblock fixes
- Ensured docblock references were correct
91f70dc
@weierophinney weierophinney referenced this pull request from a commit in zendframework/zend-console
@weierophinney weierophinney Merge branch 'feature/4449' into develop fde42e0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 8, 2013
  1. @mtymek
  2. @mtymek

    refactored unit tests

    mtymek authored
  3. @mtymek
  4. @mtymek

    CS

    mtymek authored
  5. @mtymek

    protected visibility

    mtymek authored
  6. @mtymek
Commits on May 17, 2013
  1. @mtymek

    RouteMatcherInterface

    mtymek authored
  2. @mtymek
Commits on May 18, 2013
  1. @mtymek

    test constraints

    mtymek authored
  2. @mtymek

    param aliases

    mtymek authored
Commits on May 20, 2013
  1. @mtymek

    param validators

    mtymek authored
  2. @mtymek

    param filters

    mtymek authored
  3. @mtymek

    two more tests

    mtymek authored
Something went wrong with that request. Please try again.