доктрина orm — параметры для «AutoMapping» из объекта DTO / Domain с защищенными свойствами в «View Model» с открытыми свойствами в PHP 5.x

Ищите «AutoMapper» -подобную функцию / структуру / шаблон для получения данных из объекта / DTO домена Doctrine 2 и сопоставления защищенных свойств этого объекта с сопоставлением открытых свойств в модели представления.

$userEntity = $this-em->find(User::class, 1);

$userViewModel = AutoMapper->Map($userEntity, new UserViewModel());

Где единственная существенная разница между User а также UserViewModel в том, что User содержит методы доступа get / set с защищенными полями поддержки (согласно инструкциям доктрины), тогда как UserViewModel содержит открытые свойства, которые совпадают по имени [подмножеству] защищенных полей User,

Мысли о том, как это сделать? (желательно без отражения)

Обратите внимание, что у объекта домена есть общедоступный метод доступа get, поэтому решение может использовать эти средства доступа.

1

Решение

Для решения этой проблемы я разработал собственную грубую, но эффективную реализацию AutoMapper for PHP. Этот метод будет отображаться из общедоступных свойств или общедоступных получателей (именование на основе соглашения) в общедоступные свойства целевого объекта.

Надеюсь, это поможет кому-то:

class Mapper
{
/**
* This method will attempt to source all public property values on $target from $source.
*
* By convention, it'll look for properties on source with the same name,
* .. and will fallback camel-cased get/set accessors to use.
*
* Note that underscores in properties will be translated to capital letters in camel-cased getters.
*
* @param $source object
* @param $target object
* @return object
* @throws Exception
*/
public static function Map($source, $target)
{
$targetProperties = get_object_vars($target);
$sourceProperties = get_object_vars($source);

foreach ($targetProperties as $name => $value)
{
//
// match properties
//

$matchingSourcePropertyExists = array_key_exists($name, $sourceProperties);
if ($matchingSourcePropertyExists)
{
$target->{$name} = $source->{$name};
continue;
}

//
// fall back on matching by convention-based get accessors
//

$sourceMethods = get_class_methods(get_class($source));
$getterName = "get" . self::convertToPascalCase($name);
$matchingGetAccessorExists = in_array($getterName, $sourceMethods);
if ($matchingGetAccessorExists)
{
$target->{$name} = $source->{$getterName}();
continue;
}

//
// if we ever fail to map an entity on the target, throw
//

$className = get_class($target);
throw new Exception("Could not auto-map property $name on $className.");
}

return $target;
}

/**
* Converts this_kind_of_string into ThisKindOfString.
* @param $value string
* @return string
*/
private static function convertToPascalCase($value)
{
$value[0] = strtoupper($value[0]);

$func = create_function('$c', 'return strtoupper($c[1]);');

return preg_replace_callback('/_([a-z])/', $func, $value);
}
}
1

Другие решения

Других решений пока нет …