Skip to content
This repository has been archived by the owner on Jan 8, 2020. It is now read-only.

Commit

Permalink
Merge branch 'hotfix/4496'
Browse files Browse the repository at this point in the history
Close #4496
  • Loading branch information
weierophinney committed May 24, 2013
2 parents 3d609f8 + 266ce83 commit 5758f25
Show file tree
Hide file tree
Showing 5 changed files with 268 additions and 4 deletions.
14 changes: 10 additions & 4 deletions library/Zend/Stdlib/Hydrator/ClassMethods.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
use Zend\Stdlib\Hydrator\Filter\HasFilter;
use Zend\Stdlib\Hydrator\Filter\IsFilter;
use Zend\Stdlib\Hydrator\Filter\MethodMatchFilter;
use Zend\Stdlib\Hydrator\Filter\NumberOfParameterFilter;
use Zend\Stdlib\Hydrator\Filter\OptionalParametersFilter;

class ClassMethods extends AbstractHydrator implements HydratorOptionsInterface
{
Expand All @@ -29,6 +29,11 @@ class ClassMethods extends AbstractHydrator implements HydratorOptionsInterface
*/
protected $underscoreSeparatedKeys = true;

/**
* @var \Zend\Stdlib\Hydrator\Filter\FilterInterface
*/
private $callableMethodFilter;

/**
* Define if extract values will use camel case or name with underscore
* @param bool|array $underscoreSeparatedKeys
Expand All @@ -38,10 +43,12 @@ public function __construct($underscoreSeparatedKeys = true)
parent::__construct();
$this->setUnderscoreSeparatedKeys($underscoreSeparatedKeys);

$this->callableMethodFilter = new OptionalParametersFilter();

$this->filterComposite->addFilter("is", new IsFilter());
$this->filterComposite->addFilter("has", new HasFilter());
$this->filterComposite->addFilter("get", new GetFilter());
$this->filterComposite->addFilter("parameter", new NumberOfParameterFilter(), FilterComposite::CONDITION_AND);
$this->filterComposite->addFilter("parameter", new OptionalParametersFilter(), FilterComposite::CONDITION_AND);
}

/**
Expand Down Expand Up @@ -128,8 +135,7 @@ public function extract($object)
continue;
}

$reflectionMethod = new ReflectionMethod(get_class($object) . '::' . $method);
if ($reflectionMethod->getNumberOfParameters() > 0) {
if (!$this->callableMethodFilter->filter(get_class($object) . '::' . $method)) {
continue;
}

Expand Down
54 changes: 54 additions & 0 deletions library/Zend/Stdlib/Hydrator/Filter/OptionalParametersFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Stdlib\Hydrator\Filter;

use InvalidArgumentException;
use ReflectionException;
use ReflectionMethod;
use ReflectionParameter;

/**
* Filter that includes methods which have no parameters or only optional parameters
*/
class OptionalParametersFilter implements FilterInterface
{
/**
* Map of methods already analyzed
* by {@see \Zend\Stdlib\Hydrator\Filter\OptionalParametersFilter::filter()},
* cached for performance reasons
*
* @var bool[]
*/
private static $propertiesCache = array();

/**
* {@inheritDoc}
*/
public function filter($property)
{
if (isset(self::$propertiesCache[$property])) {
return self::$propertiesCache[$property];
}

try {
$reflectionMethod = new ReflectionMethod($property);
} catch (ReflectionException $exception) {
throw new InvalidArgumentException(sprintf('Method %s doesn\'t exist', $property));
}

$mandatoryParameters = array_filter(
$reflectionMethod->getParameters(),
function (ReflectionParameter $parameter) {
return ! $parameter->isOptional();
}
);

return self::$propertiesCache[$property] = empty($mandatoryParameters);
}
}
43 changes: 43 additions & 0 deletions tests/ZendTest/Stdlib/Hydrator/ClassMethodsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/

namespace ZendTest\Stdlib\Hydrator;

use Zend\Stdlib\Hydrator\ClassMethods;
use ZendTest\Stdlib\TestAsset\ClassMethodsOptionalParameters;

/**
* Unit tests for {@see \Zend\Stdlib\Hydrator\ClassMethods}
*
* @covers \Zend\Stdlib\Hydrator\ClassMethods
* @group Zend_Stdlib
*/
class ClassMethodsTest extends \PHPUnit_Framework_TestCase
{
/**
* @var ClassMethods
*/
protected $hydrator;

/**
* {@inheritDoc}
*/
public function setUp()
{
$this->hydrator = new ClassMethods();
}

/**
* Verifies that extraction can happen even when a getter has parameters if those are all optional
*/
public function testCanExtractFromMethodsWithOptionalParameters()
{
$this->assertSame(array('foo' => 'bar'), $this->hydrator->extract(new ClassMethodsOptionalParameters()));
}
}
120 changes: 120 additions & 0 deletions tests/ZendTest/Stdlib/Hydrator/Filter/OptionalParametersFilterTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/

namespace ZendTest\Stdlib\Hydrator\Filter;

use Zend\Stdlib\Hydrator\Filter\OptionalParametersFilter;

/**
* Unit tests for {@see \Zend\Stdlib\Hydrator\Filter\OptionalParametersFilter}
*
* @covers \Zend\Stdlib\Hydrator\Filter\OptionalParametersFilter
* @group Zend_Stdlib
*/
class OptionalParametersFilterTest extends \PHPUnit_Framework_TestCase
{
/**
* @var OptionalParametersFilter
*/
protected $filter;

/**
* {@inheritDoc}
*/
public function setUp()
{
$this->filter = new OptionalParametersFilter();
}

/**
* Verifies a list of methods against expected results
*
* @param string $method
* @param bool $expectedResult
*
* @dataProvider methodProvider
*/
public function testMethods($method, $expectedResult)
{
$this->assertSame($expectedResult, $this->filter->filter($method));
}

/**
* Verifies a list of methods against expected results over subsequent calls, checking
* that the filter behaves consistently regardless of cache optimizations
*
* @param string $method
* @param bool $expectedResult
*
* @dataProvider methodProvider
*/
public function testMethodsOnSubsequentCalls($method, $expectedResult)
{
for ($i = 0; $i < 5; $i += 1) {
$this->assertSame($expectedResult, $this->filter->filter($method));
}
}

public function testTriggersExceptionOnUnknownMethod()
{
$this->setExpectedException('InvalidArgumentException');
$this->filter->filter(__CLASS__ . '::' . 'nonExistingMethod');
}

/**
* Provides a list of methods to be checked against the filter
*
* @return array
*/
public function methodProvider()
{
return array(
array(__CLASS__ . '::' . 'methodWithoutParameters', true),
array(__CLASS__ . '::' . 'methodWithSingleMandatoryParameter', false),
array(__CLASS__ . '::' . 'methodWithSingleOptionalParameter', true),
array(__CLASS__ . '::' . 'methodWithMultipleMandatoryParameters', false),
array(__CLASS__ . '::' . 'methodWithMultipleOptionalParameters', true),
);
}

/**
* Test asset method
*/
public function methodWithoutParameters()
{
}

/**
* Test asset method
*/
public function methodWithSingleMandatoryParameter($parameter)
{
}

/**
* Test asset method
*/
public function methodWithSingleOptionalParameter($parameter = null)
{
}

/**
* Test asset method
*/
public function methodWithMultipleMandatoryParameters($parameter, $otherParameter)
{
}

/**
* Test asset method
*/
public function methodWithMultipleOptionalParameters($parameter = null, $otherParameter = null)
{
}
}
41 changes: 41 additions & 0 deletions tests/ZendTest/Stdlib/TestAsset/ClassMethodsOptionalParameters.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @package Zend_Stdlib
*/

namespace ZendTest\Stdlib\TestAsset;

/**
* Test asset to check how optional parameters of are treated methods
*/
class ClassMethodsOptionalParameters
{
/**
* @var string
*/
public $foo = 'bar';

/**
* @param mixed $optional
*
* @return string
*/
public function getFoo($optional = null)
{
return $this->foo;
}

/**
* @param string $foo
* @param mixed $optional
*/
public function setFoo($foo, $optional = null)
{
$this->foo = (string) $foo;
}
}

0 comments on commit 5758f25

Please sign in to comment.