【问题标题】:Zend 2 Hydrator Strategy restricting keysZend 2 Hydrator 策略限制键
【发布时间】:2016-12-09 21:00:15
【问题描述】:

我今天一直在玩 Zend Hydrator 类,刚刚发现了用于即时转换输入键的命名策略。但是当使用 MapNamingStrategy 和 ObjectProperty hydrator 时,如果输入数组包含它们,它似乎会添加最初不存在于对象中的属性。

有什么方法可以限制它在输入对象中添加新属性并仅填充/补充现有属性?

【问题讨论】:

  • 我正在从数据库中提取地址记录并尝试填充另一个库的 Address() 类。除了一些不同的键名,例如“address_1”和“address”,数据库还包括第三方库中没有的额外字段。我只需要填充与现有属性匹配的键。

标签: zend-framework2 php-5.5 hydration


【解决方案1】:

对此仍然没有回应 - 我最终做的是使用两种方案之一,但它仍然不理想。第一种是自己使用类反射来获取可访问的键列表或搜索标准名称访问器。 (当然,这不会找到魔术方法访问器) 第二个是预定义一个映射,它不仅包括不匹配的 key->property 映射,还包括所有一对一(匹配)的 key->property 映射,然后在运行之前使用 PHP 的数组函数过滤输入使用地图的键/值对进行水合。但是这种方式违背了使用水合作用的目的,因为到那时,我还不如使用 foreach 循环。它消除了任何使用抽象目的地的能力,因为您必须提前知道所有潜在的输入/输出键->属性关系。

我最终自己实现了第一个方法(同样,它不一定会处理魔术方法访问器),它寻找公共属性和/或公共访问器,适合标准驼峰式 setPropertyName()/getPropertyName() 访问器方法:

<?php
/**
 * simple object hydrator using class reflection to find publicly accessible properties and/or methods
 *
 * Created by PhpStorm.
 * User: scottw
 * Date: 12/12/16
 * Time: 12:06 PM
 */

namespace Finao\Util;

class SimpleHydrator
{
    /**
     * whether to reset the keyMap following each hydration to clear the hydrator for other data/object pairs
     *
     * @var bool $resetMap
     */
    private static $resetMap = true;

    /**
     * associative array of key mappings between incoming data and object property names/accessors
     * @var array $keyMap
     */
    private static $keyMap = array();
    public static function setKeyMap($map) {
        if(self::is_assoc($map))
            static::$keyMap = $map;
    }
    public static function populateObject(&$targetObject, $dataArray)
    {
        if (self::is_assoc($dataArray) && is_object($targetObject)) {
            // step through array elements and see if there are matching properties or methods
            try {
                foreach ($dataArray as $k => $v) {
                    $key = $k;
                    if(self::is_assoc(static::$keyMap) && array_key_exists($k))
                        $key = static::$keyMap[$k];
                    // if original value contains an object, try populating it if the associated value is also array
                    $origVal = self::getObjectPropertyValue($targetObject, $key);
                    if (is_object($origVal) && self::is_assoc($v)) {
                        self::populateObject($origVal, $v);
                        $v = $origVal;
                    }

                    $accessor = 'set' . ucfirst($key);
                    if (in_array($key, self::getObjectPublicProperties($targetObject)))
                        $targetObject->$key = $v;
                    elseif (in_array($accessor, self::getObjectPublicMethods($targetObject)))
                        $targetObject->$accessor($v);

                }
            } catch (\Exception $d) {
                // do something with failures
            }

            if(static::$resetMap) static::$keyMap = array();
        }

        return $targetObject;
    }

    public static function getObjectPropertyValue($object, $property)
    {
        $objectReflection = new \ReflectionClass($object);
        if ($objectReflection->hasProperty($property) && $objectReflection->getProperty($property)->isPublic())
            return $object->$property;
        else {
            $accessor = 'get' . ucfirst($property);
            if ($objectReflection->hasProperty($accessor) && $objectReflection->getMethod($accessor)->isPublic())
                return $object->$accessor();
        }
    }

    public static function getObjectPublicProperties($object)
    {
        if (is_object($object)) {
            $publicProperties = array();
            $objectReflection = new \ReflectionClass($object);
            foreach ($objectReflection->getProperties(\ReflectionProperty::IS_PUBLIC) as $p)
                array_push($publicProperties, $p->name);
            return $publicProperties;
        }
    }

    public static function getObjectPublicMethods($object)
    {
        if (is_object($object)) {
            $publicMethods = array();
            $objectReflection = new \ReflectionClass($object);
            foreach ($objectReflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $p)
                array_push($publicMethods, $p->name);
            return $publicMethods;
        }
    }

    /**
     * Determine if a variable is an associative array.
     *
     * @param  mixed   Input variable
     * @return boolean If the input variable is an associative array.
     * @see http://us2.php.net/manual/en/function.is-array.php
     */
    public static function is_assoc($array) {
        return (is_array($array) && 0 !== count(array_diff_key($array, array_keys(array_keys($array)))));
    }
}

我最终为它添加了一个简单的键映射功能。 (请注意,这尚未经过严格测试,顾名思义,这只是一个简单的解决方案。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-26
    • 1970-01-01
    • 2020-08-11
    • 2012-02-08
    • 2014-03-05
    相关资源
    最近更新 更多