Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Added filter possibility #3359

Merged
merged 14 commits into from

3 participants

@iwalz

I often came around with the ClassMethods hydrator, that there are parts in the hydration that shouldn't be there. Or related to #3352 that the method definition does not match.
Those few lines will give you the possibility, to easily ignore the "has" methods in your hydration e.g:

$hydrator = new ClassMethods(false);
$hydrator->removeFilter('has');
$hydrator->extract($myObject);

Or you can easily add custom filters:

$hydrator = new ClassMethods(false);
$hydrator->addFilter('serviceLocator',
    function($property) {
        list($class, $method) = explode('::', $property);
        // do not hydrate getServiceLocator
        if ($method === 'getServiceLocator') {
            return false;
        }
        return true;
    }, FilterComposite::CONDITION_AND
);
$hydrator->extract($myObject);

Heavily tested code may have more getters and setters than necessary, but if you want to transform your objects to the userland, you may want to strip some getters and setters.

Internally, there are 2 arrays, where the composition is working on. The "OR", where only 1 method from that collection has to return true and on the other hand, the "AND" condition, where all filters has to return true to get hydrated. With this implementation, #3352 can be easily implemented as another filter. If you want me to do so, close #3352 and give me a hint here. What do you think about the idea/use-case/implementation? If you like the idea behind, I can make it work the abstract-hydrator too.

@weierophinney

I asked @iwalz on IRC for more details on this, specifically how this differs from Zend\Stdlib\Hydrator\Strategy. Here is the conversation we had:

14:42:58 < waly> weierophinney: the problem is, the strategy can be used to manipulate stuff afterwards
14:43:18 < waly> weierophinney: that one will not even add it to the internal stuff that can be manipulated by the filter
14:43:26 < weierophinney> waly: what would be awesome is if you could update the description to show what you were trying to do with strategy, and either couldn't (or using it opened up your objects to incorrect manipulation), and then show how this solves that shortcoming.
14:43:28 < waly> s/filter/strategy/
14:44:34 < waly> weierophinney: the problem was this match:
14:44:37 < waly> if (!preg_match('/^(get|has|is)[A-Z]\w*/', $method))
14:44:58 < waly> weierophinney: if that matches, even if you don't want to use it, it's getting extracted
14:45:51 < weierophinney> waly: aha, I see.
14:46:03 < weierophinney> so for things like composed event managers, input filters, etc, that raises a problem.
14:46:15 < waly> weierophinney: same with something like hasFoo($bar). It will get executed without a parameter and break (there is another pr, linked there)
14:47:11 < waly> weierophinney: If you decide to merge, I'll add a "NoneParameterFilter" to fix this. But if not, the other one simply fix that issue
library/Zend/Stdlib/Hydrator/ClassMethods.php
@@ -10,7 +10,11 @@
namespace Zend\Stdlib\Hydrator;
-use Zend\Stdlib\Exception;
+use Zend\Stdlib\Exception,
+ Zend\Stdlib\Hydrator\Filter\FilterComposite,
+ Zend\Stdlib\Hydrator\Filter\IsFilter,
+ Zend\Stdlib\Hydrator\Filter\GetFilter,
+ Zend\Stdlib\Hydrator\Filter\HasFilter;
@weierophinney Owner

To follow PSR-1/2, we need one use per import (i.e., do not use the "comma" notation with imports).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
library/Zend/Stdlib/Hydrator/Filter/FilterComposite.php
((9 lines not shown))
+ */
+namespace Zend\Stdlib\Hydrator\Filter;
+
+use Zend\Stdlib\Exception\InvalidArgumentException;
+
+/**
+ * @category Zend
+ * @package Zend_Stdlib
+ * @subpackage Hydrator
+ */
+class FilterComposite implements FilterInterface
+{
+ /**
+ * @var \ArrayObject
+ */
+ protected $orFilter;
@weierophinney Owner

Please add an empty line after each property declaration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
library/Zend/Stdlib/Hydrator/Filter/FilterComposite.php
((35 lines not shown))
+ * Constant to add with "and" conditition
+ */
+ const CONDITION_AND = 2;
+
+ /**
+ * Define default Filter
+ *
+ * @throws InvalidArgumentException
+ */
+ public function __construct($orFilter = array(), $andFilter = array())
+ {
+ array_walk($orFilter,
+ function($value, $key) {
+ if(
+ !is_callable($value) &&
+ !$value instanceof FilterInterface
@weierophinney Owner

Move the "&&" to the next line (should prefix the line, not suffix, per ZF CS).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
library/Zend/Stdlib/Hydrator/Filter/FilterComposite.php
((48 lines not shown))
+ if(
+ !is_callable($value) &&
+ !$value instanceof FilterInterface
+ ) {
+ throw new InvalidArgumentException(
+ 'The value of ' . $key . ' should be either a callable or ' .
+ 'an instance of Zend\Stdlib\Hydrator\Filter\FilterInterface'
+ );
+ }
+ }
+ );
+
+ array_walk($andFilter,
+ function($value, $key) {
+ if(
+ !is_callable($value) &&
@weierophinney Owner

Same comment as line 50

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
library/Zend/Stdlib/Hydrator/Filter/FilterComposite.php
((59 lines not shown))
+
+ array_walk($andFilter,
+ function($value, $key) {
+ if(
+ !is_callable($value) &&
+ !$value instanceof FilterInterface
+ ) {
+ throw new InvalidArgumentException(
+ 'The value of ' . $key . ' should be either a callable or ' .
+ 'an instance of Zend\Stdlib\Hydrator\Filter\FilterInterface'
+ );
+ }
+ }
+ );
+
+ $this->orFilter = new \ArrayObject($orFilter);
@weierophinney Owner

Import ArrayObject

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
library/Zend/Stdlib/Hydrator/Filter/FilterComposite.php
((87 lines not shown))
+ * return false;
+ * }
+ * return true;
+ * }, FilterComposite::CONDITION_AND
+ * );
+ * </code>
+ *
+ * @param string $name
+ * @param callable|FilterInterface $filter
+ * @param int $condition Can be either FilterComposite::CONDITION_OR or FilterComposite::CONDITION_AND
+ * @throws InvalidArgumentException
+ */
+ public function addFilter($name, $filter, $condition = self::CONDITION_OR)
+ {
+ if (
+ is_callable($filter) ||
@weierophinney Owner

Put condition onto next line

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
library/Zend/Stdlib/Hydrator/Filter/FilterComposite.php
((95 lines not shown))
+ * @param callable|FilterInterface $filter
+ * @param int $condition Can be either FilterComposite::CONDITION_OR or FilterComposite::CONDITION_AND
+ * @throws InvalidArgumentException
+ */
+ public function addFilter($name, $filter, $condition = self::CONDITION_OR)
+ {
+ if (
+ is_callable($filter) ||
+ $filter instanceof FilterInterface
+ ) {
+ if ($condition === self::CONDITION_OR) {
+ $this->orFilter[$name] = $filter;
+ } elseif ($condition === self::CONDITION_AND) {
+ $this->andFilter[$name] = $filter;
+ }
+ } else {
@weierophinney Owner

Reverse the conditional, so that the method body doesn't happen inside a conditional:

if (!is_callable($filter) && !$filter instanceof FilterInterface) {
    /* throw new ... */
}

if ($condition === self::CONDITION_OR) {
    $this->orFilter[$name] = $filter;
    return $this;
}
if ($condition === self::CONDITION_AND) {
    $this->andFilter[$name] = $filter;
    return $this;
}
return $this;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
library/Zend/Stdlib/Hydrator/Filter/FilterComposite.php
((128 lines not shown))
+
+ if( isset($this->andFilter[$name])) {
+ unset($this->andFilter[$name]);
+ }
+ }
+
+ /**
+ * Check if $name has a filter registered
+ *
+ * @param $name string Identifier for the filter
+ * @return bool
+ */
+ public function hasFilter($name)
+ {
+ return
+ isset($this->orFilter[$name]) || isset($this->andFilter[$name]);
@weierophinney Owner

Join these lines.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
library/Zend/Stdlib/Hydrator/Filter/FilterComposite.php
((158 lines not shown))
+ count($this->orFilter) === 0 &&
+ count($this->andFilter) === 0
+ ) {
+ return true;
+ }
+
+ // Check if 1 from the or filters return true
+ $returnValue = false;
+ foreach($this->orFilter as $filter) {
+ if (is_callable($filter)) {
+ if( $filter($property) === true)
+ {
+ $returnValue = true;
+ break;
+ }
+ } else {
@weierophinney Owner

Add a continue before the else, and then you can do away with the else statement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
library/Zend/Stdlib/Hydrator/Filter/FilterComposite.php
((172 lines not shown))
+ }
+ } else {
+ if ( $filter->filter($property) === true) {
+ $returnValue = true;
+ break;
+ }
+ }
+ }
+
+ // Check if all of the and condition return true
+ foreach($this->andFilter as $filter) {
+ if (is_callable($filter)) {
+ if( $filter($property) === false) {
+ return false;
+ }
+ } else {
@weierophinney Owner

Add a continue inside the conditional, and then you can do away with the else statement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
tests/ZendTest/Stdlib/HydratorTest.php
((14 lines not shown))
+ $this->assertTrue(isset($datas['isFoo']));
+ $this->assertEquals($datas['isFoo'], true);
+ $this->assertTrue(isset($datas['isBar']));
+ $this->assertEquals($datas['isBar'], true);
+ $this->assertTrue(isset($datas['hasFoo']));
+ $this->assertEquals($datas['hasFoo'], true);
+ $this->assertTrue(isset($datas['hasBar']));
+ $this->assertEquals($datas['hasBar'], true);
+
+ $hydrator->removeFilter('has');
+ $datas = $hydrator->extract($this->classMethodsCamelCase);
+ $this->assertTrue(isset($datas['hasFoo'])); //method is getHasFoo
+ $this->assertFalse(isset($datas['hasBar'])); //method is hasBar
+ }
+
+ public function testHydratorClassMethodsWithCostumFilter()
@weierophinney Owner

Small typo: s/Costum/Custom/ :)

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

@iwalz Functionality looks good -- I'd love to see you incorporate the filter functionality into the AbstractHydrator, and use it to resolve #3352 as well.

Thanks!

@weierophinney weierophinney was assigned
@iwalz

Should be done @weierophinney
I'll update the docs these days, if you want to, I can add a section about the strategies too (haven't seen one on rtd).

@iwalz

With the latest commit, you can tell your own objects how to get hydrated to the userland, providing a filterinterface.
A MethodMatchFilter has been added too.

Can you think for any use-case on hydrate()? That's all about extract() only

library/Zend/Stdlib/Hydrator/ArraySerializable.php
((12 lines not shown))
});
+ #var_dump($data);

Please remove the commented-out var_dump

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@iwalz iwalz referenced this pull request in zendframework/zf2-documentation
Merged

Added hydrator filter doc #595

@iwalz

The failed test on ZendTest/Cache seem not to be linked to the changes I made. The suite passed locally

@weierophinney weierophinney merged commit 4052748 into zendframework:develop

1 check failed

Details default The Travis build failed
@ghost Unknown referenced this pull request from a commit
@weierophinney weierophinney Merge branch 'feature/3359' into develop
Close #3359
a097ced
@weierophinney weierophinney referenced this pull request from a commit in zendframework/zend-stdlib
@weierophinney weierophinney Merge branch 'feature/3359' into develop 1c3fd99
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 6, 2013
  1. @iwalz

    Added filter possibility

    iwalz authored
  2. @iwalz
Commits on Jan 7, 2013
  1. @iwalz

    Fixed reviews

    iwalz authored
Commits on Jan 8, 2013
  1. @iwalz
  2. @iwalz

    Fixed complex composite

    iwalz authored
  3. @iwalz
  4. @iwalz
  5. @iwalz

    Fixed code style

    iwalz authored
  6. @iwalz

    Added filter to reflection

    iwalz authored
Commits on Jan 9, 2013
  1. @iwalz
Commits on Jan 11, 2013
  1. @iwalz
  2. @iwalz

    Simplified code

    iwalz authored
Commits on Jan 12, 2013
  1. @iwalz

    Removed dump

    iwalz authored
Commits on Jan 13, 2013
  1. @iwalz

    CS fixes

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