Created
December 16, 2015 13:08
-
-
Save wodCZ/ab6b5e5914018dda9918 to your computer and use it in GitHub Desktop.
FillerUtil
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Libs\Utils; | |
use Nette\ComponentModel\IContainer; | |
use Nette\Forms\Controls\BaseControl; | |
use Nette\Utils\Strings; | |
use Symfony\Component\PropertyAccess\PropertyAccess; | |
class InvalidArgumentException extends \InvalidArgumentException | |
{ | |
} | |
final class FillerUtil | |
{ | |
private static $accessor; | |
private function __construct() | |
{ | |
} | |
private static function getAccessor() | |
{ | |
if (self::$accessor === NULL) { | |
$accessorBuilder = PropertyAccess::createPropertyAccessorBuilder(); | |
$accessorBuilder->disableExceptionOnInvalidIndex(); | |
self::$accessor = $accessorBuilder->getPropertyAccessor(); | |
} | |
return self::$accessor; | |
} | |
/** | |
* Tries to access entity property and set its value as related form input default value | |
* | |
* @param $container | |
* @param $source | |
* @param $map ['field'] in case of same faield names or ['formControlName' => 'sourceFieldName'], for collection set append [] after sourceFieldName | |
*/ | |
public static function fillFormDefaults(IContainer $container, $source, $map) | |
{ | |
self::fill(function ($field, $value) use ($container) { | |
$component = $container->getComponent($field); | |
if ($component instanceof BaseControl) { | |
$component->setDefaultValue($value); | |
} | |
}, $source, $map); | |
} | |
/** | |
* @param $targetOrSetter | |
* @param $sourceOrGetter | |
* @param $map | |
*/ | |
public static function fill($targetOrSetter, $sourceOrGetter, $map) | |
{ | |
if ( ! is_callable($targetOrSetter)) { | |
$targetOrSetter = self::createAccessorSetter($targetOrSetter); | |
} | |
if ( ! is_callable($sourceOrGetter)) { | |
$sourceOrGetter = self::createAccessorGetter($sourceOrGetter); | |
} | |
self::fillUsingCallback($map, $sourceOrGetter, $targetOrSetter); | |
} | |
/** | |
* @param $source | |
* @return \Closure | |
*/ | |
public static function createAccessorGetter($source) | |
{ | |
$accessor = self::getAccessor(); | |
return function ($field) use ($source, $accessor) { | |
return $accessor->getValue($source, $field); | |
}; | |
} | |
/** | |
* @param $target | |
* @return \Closure | |
*/ | |
public static function createAccessorSetter($target) | |
{ | |
$accessor = self::getAccessor(); | |
return function ($field, $value) use ($target, $accessor) { | |
$accessor->setValue($target, $field, $value); | |
}; | |
} | |
/** | |
* @param array $map ['field'] in case of same faield names or ['targetField' => 'sourceField'], for collection set append [] after collection field | |
* @param callable|\Closure $setCallback will be called ($field, $value) to set value | |
* @param callable|\Closure $getCallback will be called ($field) to get value | |
*/ | |
private static function fillUsingCallback(array $map, callable $getCallback = NULL, callable $setCallback = NULL) | |
{ | |
foreach ($map as $targetField => $sourceField) { | |
$sourceSubField = 'id'; // used if $source->$sourceField is array on its elements | |
$valueIsArray = FALSE; | |
if (Strings::contains($sourceField, '[]')) { // users[].id or users[] | |
$valueIsArray = TRUE; | |
list($sourceField, $sourceSubField) = array_filter(explode('[]', $sourceField, 2) + ['', $sourceSubField]); | |
$sourceSubField = Strings::trim($sourceSubField, '.'); | |
} | |
$targetField = is_int($targetField) ? $sourceField : $targetField; // checks for numerical index | |
try { | |
$value = $getCallback($sourceField); | |
if ($valueIsArray) { | |
if ($value instanceof \Iterator) { | |
$mapSource = iterator_to_array($value); | |
} elseif (is_array($value)) { | |
$mapSource = $value; | |
} else { | |
throw new InvalidArgumentException("Field {$sourceField} is not array nor iterator."); | |
} | |
$value = array_map(function ($item) use ($sourceSubField, $getCallback) { | |
return $getCallback($item, $sourceSubField); | |
}, $mapSource); | |
} | |
$setCallback($targetField, $value); | |
} catch (\Exception $e) { | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment