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

Commit

Permalink
Merge pull request #5364 from ronan-gloo/develop
Browse files Browse the repository at this point in the history
Add Naming strategy for Hydrators
  • Loading branch information
weierophinney committed Jan 3, 2014
2 parents dda5d78 + 2810655 commit d8e150b
Show file tree
Hide file tree
Showing 8 changed files with 262 additions and 37 deletions.
95 changes: 92 additions & 3 deletions library/Zend/Stdlib/Hydrator/AbstractHydrator.php
Expand Up @@ -12,10 +12,14 @@
use ArrayObject;
use Zend\Stdlib\Exception;
use Zend\Stdlib\Hydrator\Filter\FilterComposite;
use Zend\Stdlib\Hydrator\StrategyEnabledInterface;
use Zend\Stdlib\Hydrator\NamingStrategy\NamingStrategyInterface;
use Zend\Stdlib\Hydrator\Strategy\StrategyInterface;

abstract class AbstractHydrator implements HydratorInterface, StrategyEnabledInterface, FilterEnabledInterface
abstract class AbstractHydrator implements
HydratorInterface,
StrategyEnabledInterface,
FilterEnabledInterface,
NamingStrategyEnabledInterface
{
/**
* The list with strategies that this hydrator has.
Expand All @@ -24,8 +28,16 @@ abstract class AbstractHydrator implements HydratorInterface, StrategyEnabledInt
*/
protected $strategies;

/**
* An instance of NamingStrategyInterface
*
* @var NamingStrategyInterface
*/
protected $namingStrategy;

/**
* Composite to filter the methods, that need to be hydrated
*
* @var Filter\FilterComposite
*/
protected $filterComposite;
Expand All @@ -43,6 +55,8 @@ public function __construct()
* Gets the strategy with the given name.
*
* @param string $name The name of the strategy to get.
*
* @throws \Zend\Stdlib\Exception\InvalidArgumentException
* @return StrategyInterface
*/
public function getStrategy($name)
Expand Down Expand Up @@ -104,7 +118,7 @@ public function removeStrategy($name)
*
* @param string $name The name of the strategy to use.
* @param mixed $value The value that should be converted.
* @param array $object The object is optionally provided as context.
* @param mixed $object The object is optionally provided as context.
* @return mixed
*/
public function extractValue($name, $value, $object = null)
Expand Down Expand Up @@ -133,6 +147,36 @@ public function hydrateValue($name, $value, $data = null)
return $value;
}

/**
* Convert a name for extraction. If no naming strategy exists, the plain value is returned.
*
* @param string $name The name to convert.
* @param null $object The object is optionally provided as context.
* @return mixed
*/
public function extractName($name, $object = null)
{
if ($this->hasNamingStrategy()) {
$name = $this->getNamingStrategy()->extract($name, $object);
}
return $name;
}

/**
* Converts a value for hydration. If no naming strategy exists, the plain value is returned.
*
* @param string $name The name to convert.
* @param array $data The whole data is optionally provided as context.
* @return mixed
*/
public function hydrateName($name, $data = null)
{
if ($this->hasNamingStrategy()) {
$name = $this->getNamingStrategy()->hydrate($name, $data);
}
return $name;
}

/**
* Get the filter instance
*
Expand Down Expand Up @@ -195,4 +239,49 @@ public function removeFilter($name)
{
return $this->filterComposite->removeFilter($name);
}

/**
* Adds the given naming strategy
*
* @param NamingStrategyInterface $strategy The naming to register.
* @return self
*/
public function setNamingStrategy(NamingStrategyInterface $strategy)
{
$this->namingStrategy = $strategy;

return $this;
}

/**
* Gets the naming strategy.
*
* @return NamingStrategyInterface
*/
public function getNamingStrategy()
{
return $this->namingStrategy;
}

/**
* Checks if a naming strategy exists.
*
* @return bool
*/
public function hasNamingStrategy()
{
return isset($this->namingStrategy);
}

/**
* Removes the naming strategy
*
* @return self
*/
public function removeNamingStrategy()
{
$this->namingStrategy = null;

return $this;
}
}
25 changes: 16 additions & 9 deletions library/Zend/Stdlib/Hydrator/ArraySerializable.php
Expand Up @@ -32,14 +32,20 @@ public function extract($object)
}

$data = $object->getArrayCopy();
$filter = $this->getFilter();

foreach ($data as $name => $value) {
if (!$this->getFilter()->filter($name)) {
if (!$filter->filter($name)) {
unset($data[$name]);
continue;
}

$data[$name] = $this->extractValue($name, $value);
$extractedName = $this->extractName($name, $object);
// replace the original key with extracted, if differ
if ($extractedName !== $name) {
unset($data[$name]);
$name = $extractedName;
}
$data[$name] = $this->extractValue($name, $value, $object);
}

return $data;
Expand All @@ -58,15 +64,16 @@ public function extract($object)
*/
public function hydrate(array $data, $object)
{
$self = $this;
array_walk($data, function (&$value, $name) use ($self) {
$value = $self->hydrateValue($name, $value);
});
$replacement = array();
foreach ($data as $key => $value) {
$name = $this->hydrateName($key, $data);
$replacement[$name] = $this->hydrateValue($name, $value, $data);
}

if (is_callable(array($object, 'exchangeArray'))) {
$object->exchangeArray($data);
$object->exchangeArray($replacement);
} elseif (is_callable(array($object, 'populate'))) {
$object->populate($data);
$object->populate($replacement);
} else {
throw new Exception\BadMethodCallException(sprintf(
'%s expects the provided object to implement exchangeArray() or populate()', __METHOD__
Expand Down
32 changes: 13 additions & 19 deletions library/Zend/Stdlib/Hydrator/ClassMethods.php
Expand Up @@ -19,6 +19,8 @@
use Zend\Stdlib\Hydrator\Filter\IsFilter;
use Zend\Stdlib\Hydrator\Filter\MethodMatchFilter;
use Zend\Stdlib\Hydrator\Filter\OptionalParametersFilter;
use Zend\Stdlib\Hydrator\Naming\UnderscoreCamelCaseNaming;
use Zend\Stdlib\Hydrator\NamingStrategy\UnderscoreNamingStrategy;

class ClassMethods extends AbstractHydrator implements HydratorOptionsInterface
{
Expand Down Expand Up @@ -77,7 +79,15 @@ public function setOptions($options)
*/
public function setUnderscoreSeparatedKeys($underscoreSeparatedKeys)
{
$this->underscoreSeparatedKeys = $underscoreSeparatedKeys;
$this->underscoreSeparatedKeys = (bool) $underscoreSeparatedKeys;

if (true === $this->underscoreSeparatedKeys) {
$this->setNamingStrategy(new UnderscoreNamingStrategy);
} else {
if ($this->getNamingStrategy() instanceof UnderscoreNamingStrategy) {
$this->removeNamingStrategy();
}
}

return $this;
}
Expand Down Expand Up @@ -117,11 +127,6 @@ public function extract($object)
$filter = $this->filterComposite;
}

$transform = function ($letters) {
$letter = array_shift($letters);

return '_' . strtolower($letter);
};
$attributes = array();
$methods = get_class_methods($object);

Expand All @@ -146,9 +151,7 @@ public function extract($object)
}
}

if ($this->underscoreSeparatedKeys) {
$attribute = preg_replace_callback('/([A-Z])/', $transform, $attribute);
}
$attribute = $this->extractName($attribute, $object);
$attributes[$attribute] = $this->extractValue($attribute, $object->$method(), $object);
}

Expand All @@ -173,17 +176,8 @@ public function hydrate(array $data, $object)
));
}

$transform = function ($letters) {
$letter = substr(array_shift($letters), 1, 1);

return ucfirst($letter);
};

foreach ($data as $property => $value) {
$method = 'set' . ucfirst($property);
if ($this->underscoreSeparatedKeys) {
$method = preg_replace_callback('/(_[a-z])/i', $transform, $method);
}
$method = 'set' . ucfirst($this->hydrateName($property, $data));
if (is_callable(array($object, $method))) {
$value = $this->hydrateValue($property, $value, $data);
$object->$method($value);
Expand Down
@@ -0,0 +1,37 @@
<?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\NamingStrategy;

/**
* Allow property extraction / hydration for hydrator
*
* Interface PropertyStrategyInterface
* @package Zend\Stdlib\Hydrator\NamingStrategy
*/
interface NamingStrategyInterface
{
/**
* Converts the given name so that it can be extracted by the hydrator.
*
* @param string $name The original name
* @param object $object (optional) The original object for context.
* @return mixed The hydrated name
*/
public function hydrate($name);

/**
* Converts the given name so that it can be hydrated by the hydrator.
*
* @param string $name The original name
* @param array $data (optional) The original data for context.
* @return mixed The extracted name
*/
public function extract($name);
}
@@ -0,0 +1,47 @@
<?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\NamingStrategy;

/**
* Class UnderscoreNamingStrategy
* @package Zend\Stdlib\Hydrator\NamingStrategy
*/
class UnderscoreNamingStrategy implements NamingStrategyInterface
{
/**
* Remove underscores and capitalize letters
*
* @param string $name
* @return string
*/
public function hydrate($name)
{
return preg_replace_callback('/(_[a-z])/i', function($letters) {
$letter = substr(array_shift($letters), 1, 1);

return ucfirst($letter);
}, $name);
}

/**
* Remove capitalized letters and prepend underscores.
*
* @param string $name
* @return string
*/
public function extract($name)
{
return preg_replace_callback('/([A-Z])/', function($letters) {
$letter = array_shift($letters);

return '_' . strtolower($letter);
}, $name);
}
}
44 changes: 44 additions & 0 deletions library/Zend/Stdlib/Hydrator/NamingStrategyEnabledInterface.php
@@ -0,0 +1,44 @@
<?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;

use Zend\Stdlib\Hydrator\NamingStrategy\NamingStrategyInterface;

interface NamingStrategyEnabledInterface
{
/**
* Adds the given naming strategy
*
* @param NamingStrategyInterface $strategy The naming to register.
* @return NamingStrategyEnabledInterface
*/
public function setNamingStrategy(NamingStrategyInterface $strategy);

/**
* Gets the naming strategy.
*
* @return NamingStrategyInterface
*/
public function getNamingStrategy();

/**
* Checks if a naming strategy exists.
*
* @return bool
*/
public function hasNamingStrategy();

/**
* Removes the naming with the given name.
*
* @return NamingStrategyEnabledInterface
*/
public function removeNamingStrategy();
}

0 comments on commit d8e150b

Please sign in to comment.