src/Sham/DataGenerator.php
<?php
namespace Trellis\Sham;
use Trellis\Common\Error\BadValueException;
use Trellis\Runtime\Attribute\AttributeInterface;
use Trellis\Runtime\Attribute\EmbeddedEntityList\EmbeddedEntityListAttribute;
use Trellis\Runtime\Attribute\Image\ImageAttribute;
use Trellis\Runtime\ValueHolder\ComplexValue;
use Trellis\Runtime\EntityTypeInterface;
use Trellis\Runtime\Entity\EntityInterface;
use Trellis\Runtime\Entity\EntityList;
use Trellis\Sham\TextGuesser;
use Faker\Factory;
/**
* Sham\DataGenerator is a class that is able to create or fill entities
* containing fake data.
*/
class DataGenerator
{
protected $faker;
protected $locale;
/**
* name of options array key to use for an array of attribute_name => value pairs
*/
const OPTION_FIELD_VALUES = 'attribute_values';
/**
* name of options array key to use to exclude certain attributes from fake data generation
*/
const OPTION_EXCLUDED_FIELDS = 'excluded_attributes';
/**
* name of options array key to use to mark changed entities as clean
*/
const OPTION_MARK_CLEAN = 'mark_clean';
/**
* name of options array key to use to set the locale used for fake data generation
*/
const OPTION_LOCALE = 'locale';
/**
* name of options array key to use to set the number of entities to generate
*/
const OPTION_COUNT = 'count';
/**
* name of options array key to use to disable the guessing of fake data provider by attribute_name
*/
const OPTION_GUESS_PROVIDER_BY_NAME = 'guess_provider_by_name';
/**
* name of options array key to use to set the current level of recursion (for reference attributes)
*/
const OPTION_RECURSION_LEVEL = 'recursion_level';
public function __construct($locale = 'de_DE')
{
$this->locale = $locale;
$this->faker = Factory::create($this->locale);
}
/**
* This method fills the given entity with fake data. You may customize
* the fake data generation used for each attribute by using the options array.
*
* Supported options:
* - OPTION_LOCALE: Locale for fake data (e.g. 'en_UK', defaults to 'de_DE').
* - OPTION_MARK_CLEAN: Calls `$entity->markClean()` at the end to prevent
* change events to occur after faking data. Default is false.
* - OPTION_FIELD_VALUES: array of `attribute_name` => `value` pairs to customize
* fake values per attribute of the given entity. You can
* either specify a direct value or provide a closure. The
* closure must return the value you want to set on that attribute.
* - OPTION_EXCLUDED_FIELDS: Array of attribute_names to excluded from filling
* with fake data.
* - OPTION_GUESS_PROVIDER_BY_NAME: Boolean true by default. Certain attribute_names
* trigger different providers (e.g. firstname or email).
*
* @param EntityInterface $entity an instance of the entity to fill with fake data.
* @param array $options array of options to customize fake data creation.
*
* @return void
*
* @throws \Trellis\Runtime\Entity\InvalidValueException in case of fake data being invalid for the given attribute
* @throws \Trellis\Runtime\Entity\BadValueException in case of invalid locale option string
* @throws \Trellis\Common\Error\RuntimeException on EmbeddedEntityListAttribute misconfiguration
*/
public function fake(EntityInterface $entity, array $options = array())
{
if (!empty($options[self::OPTION_LOCALE])) {
$loc = $options[self::OPTION_LOCALE];
if (!is_string($loc) || !preg_match('#[a-z]{2,6}_[A-Z]{2,6}#', $loc)) {
throw new BadValueException(
'Given option "' . self::OPTION_LOCALE
. '" is not a valid string. Use "languageCode_countryCode", e.g. "de_DE" or "en_UK".'
);
}
$this->locale = $loc;
$this->faker = Factory::create($this->locale);
}
$attributes_to_exclude = array();
if (!empty($options[self::OPTION_EXCLUDED_FIELDS])) {
$excluded = $options[self::OPTION_EXCLUDED_FIELDS];
if (!is_array($excluded)) {
throw new BadValueException(
'Given option "' . self::OPTION_EXCLUDED_FIELDS
. '" is not an array. It should be an array of attribute_names.'
);
}
$attributes_to_exclude = $excluded;
}
$type = $entity->getType();
foreach ($type->getAttributes() as $attribute_name => $attribute) {
if (in_array($attribute_name, $attributes_to_exclude, true)) {
continue;
}
$name = $this->getMethodNameFor($attribute);
if (null !== $name) {
$this->$name($entity, $attribute, $options);
} else {
$this->setValue($entity, $attribute, $attribute->getDefaultValue(), $options);
}
}
if (array_key_exists(self::OPTION_MARK_CLEAN, $options)
&& true === $options[self::OPTION_MARK_CLEAN]
) {
$entity->markClean();
}
}
/**
* Creates an array with fake data for the given type.
*
* @param EntityTypeInterface $type type to create fake data for
* @param array $options For valid options see fake() method
*
* @return array of fake data for the given type
*
* @throws \Trellis\Runtime\Entity\InvalidValueException in case of fake data being invalid for the given attribute
* @throws \Trellis\Runtime\Entity\BadValueException in case of invalid locale option string
* @throws \Trellis\Common\Error\RuntimeException on EmbeddedEntityListAttribute misconfiguration
*/
public function fakeData(EntityTypeInterface $type, array $options = array())
{
$entity = $type->createEntity();
$this->fake($entity, $options);
return $entity->toArray();
}
/**
* Creates a entity with fake data for the given type.
*
* @param EntityTypeInterface $type type to create entities for
* @param array $options For valid options see fake() method
* @param EntityInterface $parent Parent entity to create entity within
*
* @return EntityInterface newly created with fake data
*
* @throws \Trellis\Runtime\Entity\InvalidValueException in case of fake data being invalid for the given attribute
* @throws \Trellis\Runtime\Entity\BadValueException in case of invalid locale option string
* @throws \Trellis\Common\Error\RuntimeException on EmbeddedEntityListAttribute misconfiguration
*/
public function createFakeEntity(
EntityTypeInterface $type,
array $options = array(),
EntityInterface $parent = null
) {
$options[self::OPTION_MARK_CLEAN] = true;
$entity = $type->createEntity([], $parent);
$this->fake($entity, $options);
return $entity;
}
/**
* Creates `count` number of entities with fake data for the given type.
*
* @param EntityTypeInterface $type type to create entities for
* @param array $options use `count` for number of entities to create. For other options see fake() method.
* @param EntityInterface $parent Parent entity to create entity within
*
* @return array of new entities with fake data
*
* @throws \Trellis\Runtime\Entity\InvalidValueException in case of fake data being invalid for the given attribute
* @throws \Trellis\Runtime\Entity\BadValueException in case of invalid locale option string
* @throws \Trellis\Common\Error\RuntimeException on EmbeddedEntityListAttribute misconfiguration
*/
public function createFakeEntities(
EntityTypeInterface $type,
array $options = array(),
EntityInterface $parent = null
) {
$entities = array();
$count = 10;
if (!empty($options[self::OPTION_COUNT])) {
$cnt = $options[self::OPTION_COUNT];
if (!is_int($cnt)) {
throw new BadValueException(
'Given option "' . self::OPTION_COUNT
. '" is not an integer. Provide a correct value or use fallback to default count.'
);
}
$count = $cnt;
unset($options[self::OPTION_COUNT]);
}
for ($i = 0; $i < $count; $i++) {
$entities[] = $this->createFakeEntity($type, $options, $parent);
}
return $entities;
}
/**
* This method fills the entity with fake data. You may customize the
* fake data used for each attribute by using the options array.
*
* Supported options:
* - OPTION_LOCALE: Locale for fake data (e.g. 'en_UK', defaults to 'de_DE').
* - OPTION_MARK_CLEAN: Calls `$entity->markClean()` at the end to prevent
* change events to occur after faking data. Default is false.
* - OPTION_FIELD_VALUES: array of `attribute_name` => `value` pairs to customize
* fake values per attribute of the given entity. You can
* either specify a direct value or provide a closure. The
* closure must return the value you want to set on that attribute.
* - OPTION_EXCLUDED_FIELDS: Array of attribute_names to excluded from filling
* with fake data.
* - OPTION_GUESS_PROVIDER_BY_NAME: Boolean true by default. Certain attribute_names
* trigger different providers (e.g. firstname or email).
*
* @param EntityInterface $entity an instance of the entity to fill with fake data.
* @param array $options array of options to customize fake data creation.
*
* @return void
*
* @throws \Trellis\Runtime\Entity\InvalidValueException in case of fake data being invalid for the given attribute
* @throws \Trellis\Runtime\Entity\BadValueException in case of invalid locale option string
* @throws \Trellis\Common\Error\RuntimeException on EmbeddedEntityListAttribute misconfiguration
*/
public static function fill(EntityInterface $entity, array $options = array())
{
$data_generator = new static();
$data_generator->fake($entity, $options);
}
/**
* Creates an array with fake data for the given type.
*
* @param EntityTypeInterface $type type to create fake data for
* @param array $options For valid options see fill() method
*
* @return array of fake data for the given type
*
* @throws \Trellis\Runtime\Entity\InvalidValueException in case of fake data being invalid for the given attribute
* @throws \Trellis\Runtime\Entity\BadValueException in case of invalid locale option string
* @throws \Trellis\Common\Error\RuntimeException on EmbeddedEntityListAttribute misconfiguration
*/
public static function createDataFor(EntityTypeInterface $type, array $options = array())
{
$data_generator = new static();
return $data_generator->fakeData($type, $options);
}
/**
* Creates a entity with fake data for the given type.
*
* @param EntityTypeInterface $type type to create entities for
* @param array $options For valid options see fill() method
*
* @return EntityInterface newly created with fake data
*
* @throws \Trellis\Runtime\Entity\InvalidValueException in case of fake data being invalid for the given attribute
* @throws \Trellis\Runtime\Entity\BadValueException in case of invalid locale option string
* @throws \Trellis\Common\Error\RuntimeException on EmbeddedEntityListAttribute misconfiguration
*/
public static function createEntity(EntityTypeInterface $type, array $options = array())
{
$data_generator = new static();
return $data_generator->createFakeEntity($type, $options);
}
/**
* Creates `count` number of entities with fake data for the given type.
*
* @param EntityTypeInterface $type type to create entities for
* @param array $options use `count` for number of entities to create. For other options see fill() method.
*
* @return array of new entities with fake data
*
* @throws \Trellis\Runtime\Entity\InvalidValueException in case of fake data being invalid for the given attribute
* @throws \Trellis\Runtime\Entity\BadValueException in case of invalid locale option string
* @throws \Trellis\Common\Error\RuntimeException on EmbeddedEntityListAttribute misconfiguration
*/
public static function createEntities(EntityTypeInterface $type, array $options = array())
{
$data_generator = new DataGenerator();
return $data_generator->createFakeEntities($type, $options);
}
/**
* Generates and adds fake data for a Text on a entity.
*
* @param EntityInterface $entity an instance of the entity to fill with fake data.
* @param AttributeInterface $attribute an instance of the Text to fill with fake data.
* @param array $options array of options to customize fake data creation.
*
* @return void
*/
protected function addText(EntityInterface $entity, AttributeInterface $attribute, array $options = array())
{
$min_length = $attribute->getOption('min_length');
$max_length = $attribute->getOption('max_length');
if ($this->shouldGuessByName($options)) {
$value = TextGuesser::guess($attribute->getName(), $this->faker);
}
if (!isset($value)) {
$value = $this->faker->words($this->faker->numberBetween(2, 10), true);
}
if ($min_length && ($len = mb_strlen($value)) < $min_length) {
$repeat = ceil(($min_length - $len) / $len);
$value .= str_repeat($value, $repeat);
}
if ($max_length && mb_strlen($value) > $max_length) {
$value = substr($value, 0, $max_length);
$value = preg_replace('#\s$#', 'o', $value);
}
$this->setValue($entity, $attribute, $value, $options);
}
/**
* Generates and adds fake data for a TextCollection on a entity.
*
* @param EntityInterface $entity an instance of the entity to fill with fake data.
* @param AttributeInterface $attribute an instance of the TextCollection to fill with fake data.
* @param array $options array of options to customize fake data creation.
*
* @return void
*/
protected function addTextList(
EntityInterface $entity,
AttributeInterface $attribute,
array $options = array()
) {
$values = array();
$number_of_values = $this->faker->numberBetween(1, 5);
for ($i = 0; $i < $number_of_values; $i++) {
$text = $this->faker->words($this->faker->numberBetween(1, 3), true);
if ($this->shouldGuessByName($options)) {
$closure = TextGuesser::guess($attribute->getName(), $this->faker);
if (!empty($closure) && is_callable($closure)) {
$text = call_user_func($closure);
}
}
$values[] = $text;
}
$this->setValue($entity, $attribute, $values, $options);
}
/**
* Generates and adds fake data for a Textarea on a entity.
*
* @param EntityInterface $entity an instance of the entity to fill with fake data.
* @param AttributeInterface $attribute an instance of the Textarea to fill with fake data.
* @param array $options array of options to customize fake data creation.
*
* @return void
*/
protected function addTextarea(EntityInterface $entity, AttributeInterface $attribute, array $options = array())
{
$text = $this->faker->paragraphs($this->faker->numberBetween(1, 5));
$this->setValue($entity, $attribute, implode(PHP_EOL . PHP_EOL, $text), $options);
}
/**
* Generates and adds fake data for an Integer on a entity.
*
* @param EntityInterface $entity an instance of the entity to fill with fake data.
* @param AttributeInterface $attribute an instance of the Integer to fill with fake data.
* @param array $options array of options to customize fake data creation.
*
* @return void
*/
protected function addInteger(EntityInterface $entity, AttributeInterface $attribute, array $options = array())
{
$this->setValue($entity, $attribute, $this->faker->randomNumber(5), $options);
}
/**
* Generates and adds fake data for an IntegerList on a entity.
*
* @param EntityInterface $entity an instance of the entity to fill with fake data.
* @param AttributeInterface $attribute an instance of the IntegerList to fill with fake data.
* @param array $options array of options to customize fake data creation.
*
* @return void
*/
protected function addIntegerList(
EntityInterface $entity,
AttributeInterface $attribute,
array $options = array()
) {
$values = array();
$number_of_values = $this->faker->numberBetween(1, 5);
for ($i = 0; $i < $number_of_values; $i++) {
$values[] = $this->faker->randomNumber(5);
}
$this->setValue($entity, $attribute, $values, $options);
}
/**
* Generates and adds fake data for a Float on a entity.
*
* @param EntityInterface $entity an instance of the entity to fill with fake data.
* @param AttributeInterface $attribute an instance of the Float to fill with fake data.
* @param array $options array of options to customize fake data creation.
*
* @return void
*/
protected function addFloat(EntityInterface $entity, AttributeInterface $attribute, array $options = array())
{
$this->setValue($entity, $attribute, $this->faker->randomFloat(5), $options);
}
/**
* Generates and adds fake data for a Url on a entity.
*
* @param EntityInterface $entity an instance of the entity to fill with fake data.
* @param AttributeInterface $attribute an instance of the Url to fill with fake data.
* @param array $options array of options to customize fake data creation.
*
* @return void
*/
protected function addUrl(EntityInterface $entity, AttributeInterface $attribute, array $options = array())
{
$this->setValue($entity, $attribute, $this->faker->url(), $options);
}
/**
* Generates and adds fake data for a Uuid on a entity.
*
* @param EntityInterface $entity an instance of the entity to fill with fake data.
* @param AttributeInterface $attribute an instance of the Uuid to fill with fake data.
* @param array $options array of options to customize fake data creation.
*
* @return void
*/
protected function addUuid(EntityInterface $entity, AttributeInterface $attribute, array $options = array())
{
$this->setValue($entity, $attribute, $this->faker->uuid(), $options);
}
/**
* Generates and adds fake data for a choice attribute on a entity.
*
* @param EntityInterface $entity an instance of the entity to fill with fake data.
* @param AttributeInterface $attribute an instance of the Choice to fill with fake data.
* @param array $options array of options to customize fake data creation.
*
* @return void
*/
protected function addChoice(EntityInterface $entity, AttributeInterface $attribute, array $options = array())
{
$allowed_values = $attribute->getOption('allowed_values');
$choice = $allowed_values[array_rand($allowed_values)];
$this->setValue($entity, $attribute, $choice, $options);
}
/**
* Generates and adds fake data for a KeyValue on a entity.
*
* @param EntityInterface $entity an instance of the entity to fill with fake data.
* @param AttributeInterface $attribute an instance of the KeyValue to fill with fake data.
* @param array $options array of options to customize fake data creation.
*
* @return void
*/
protected function addKeyValue(EntityInterface $entity, AttributeInterface $attribute, array $options = array())
{
$values = array();
$number_of_values = $this->faker->numberBetween(1, 5);
for ($i = 0; $i < $number_of_values; $i++) {
$values[$this->faker->word] = $this->faker->sentence;
}
$this->setValue($entity, $attribute, $values, $options);
}
/**
* Generates and adds fake data for a KeyValueList on a entity.
*
* @param EntityInterface $entity an instance of the entity to fill with fake data.
* @param AttributeInterface $attribute an instance of the KeyValueList to fill with fake data.
* @param array $options array of options to customize fake data creation.
*
* @return void
*/
protected function addKeyValueList(
EntityInterface $entity,
AttributeInterface $attribute,
array $options = array()
) {
$collection = array();
$numberOfEntries = $this->faker->numberBetween(1, 5);
for ($i = 0; $i < $numberOfEntries; $i++) {
$number_of_values = $this->faker->numberBetween(1, 5);
for ($i = 0; $i < $number_of_values; $i++) {
$collection[$this->faker->word] = $this->faker->words($this->faker->numberBetween(1, 3), true);
}
}
$this->setValue($entity, $attribute, $collection, $options);
}
/**
* Generates and adds fake data for a ComplexValue on a entity.
*
* @param AttributeInterface $attribute an instance of the ComplexValue to fill with fake data.
* @param array $options array of options to customize fake data creation.
*
* @return mixed
*/
protected function createComplexValue(AttributeInterface $attribute, array $options = array())
{
$values = array();
$value_holder = $attribute->createValueHolder();
$value_type = $value_holder->getValueType();
if (class_exists($value_type)
&& preg_grep('#ComplexValueInterface$#', class_implements($value_type))
) {
foreach ($value_type::getPropertyMap() as $property_name => $property_type) {
switch ($property_type) {
case ComplexValue::VALUE_TYPE_TEXT:
if ($this->shouldGuessByName($options)) {
$values[$property_name] = TextGuesser::guess($property_name, $this->faker);
}
if (empty($values[$property_name])) {
$values[$property_name] = $this->faker->words(3, true);
}
break;
case ComplexValue::VALUE_TYPE_URL:
$values[$property_name] = $this->faker->url;
break;
case ComplexValue::VALUE_TYPE_BOOLEAN:
$values[$property_name] = $this->faker->boolean();
break;
case ComplexValue::VALUE_TYPE_INTEGER:
$values[$property_name] = $this->faker->numberBetween(0, 10);
break;
case ComplexValue::VALUE_TYPE_FLOAT:
$values[$property_name] = $this->faker->randomFloat(5);
break;
case ComplexValue::VALUE_TYPE_ARRAY:
$numberOfEntries = $this->faker->numberBetween(0, 3);
for ($i = 0; $i < $numberOfEntries; $i++) {
$values[$property_name][$this->faker->word] = $this->faker->word;
}
break;
default:
throw new BadValueException(sprintf(
'Unexpected ComplexValue property type "%s" on %s',
$property_type,
$value_type
));
}
}
}
return new $value_type($values);
}
/**
* Generates and adds fake data for an Image on a entity.
*
* @param EntityInterface $entity an instance of the entity to fill with fake data.
* @param AttributeInterface $attribute an instance of the Image to fill with fake data.
* @param array $options array of options to customize fake data creation.
*
* @return void
*/
protected function addImage(
EntityInterface $entity,
AttributeInterface $attribute,
array $options = array()
) {
$image = $this->createComplexValue($attribute, $options);
$this->setValue($entity, $attribute, $image, $options);
}
/**
* Generates and adds fake data for a ImageList on a entity.
*
* @param EntityInterface $entity an instance of the entity to fill with fake data.
* @param AttributeInterface $attribute an instance of the ImageList to fill with fake data.
* @param array $options array of options to customize fake data creation.
*
* @return void
*/
protected function addImageList(
EntityInterface $entity,
AttributeInterface $attribute,
array $options = array()
) {
$collection = array();
$min_count = $attribute->getOption('min_count', 0);
$max_count = $attribute->getOption('max_count', 3);
$numberOfEntries = $this->faker->numberBetween($min_count, $max_count);
$image_attribute = new ImageAttribute('someimage', $entity->getType());
// @todo should we have an ImageList collection?
for ($i = 0; $i < $numberOfEntries; $i++) {
$collection[] = $this->createComplexValue($image_attribute, $options);
}
$this->setValue($entity, $attribute, $collection, $options);
}
/**
* Generates and adds fake data for a Boolean on a entity.
*
* @param EntityInterface $entity an instance of the entity to fill with fake data.
* @param AttributeInterface $attribute an instance of the Boolean to fill with fake data.
* @param array $options array of options to customize fake data creation.
*
* @return void
*/
protected function addBoolean(EntityInterface $entity, AttributeInterface $attribute, array $options = array())
{
$this->setValue($entity, $attribute, $this->faker->boolean, $options);
}
/**
* Generates and adds fake data for a embed entities.
*
* @param EntityInterface $entity an instance of the entity to fill with fake data.
* @param EmbeddedEntityListAttribute $attribute instance of the EmbeddedEntityListAttribute to fill with fake data.
* @param array $options array of options to customize fake data creation.
*
* @return void
*/
protected function addEmbeddedEntityList(
EntityInterface $entity,
EmbeddedEntityListAttribute $attribute,
array $options = array()
) {
$options_clone = $options;
$entity_collection = new EntityList();
$embedded_type_map = $attribute->getEmbeddedEntityTypeMap();
$min_count = $attribute->getOption('min_count', 0);
$max_count = $attribute->getOption('max_count', 3);
$inline_mode = $attribute->getOption('inline_mode', false);
if (true === $inline_mode) {
$number_of_new_embed_entries = 1;
} else {
$number_of_new_embed_entries = $this->faker->numberBetween($min_count, $max_count);
}
// add new entities to collection for embed types
for ($i = 0; $i < $number_of_new_embed_entries; $i++) {
$embed_type = $this->faker->randomElement($embedded_type_map->getValues());
$new_entity = $this->createFakeEntity($embed_type, $options_clone, $entity);
$entity_collection->addItem($new_entity);
}
$this->setValue($entity, $attribute, $entity_collection, $options);
}
/**
* Generates and adds fake data for a Timestamp on a entity.
*
* @param EntityInterface $entity an instance of the entity to fill with fake data.
* @param AttributeInterface $attribute an instance of the Timestamp to fill with fake data.
* @param array $options array of options to customize fake data creation.
*
* @return void
*/
protected function addTimestamp(EntityInterface $entity, AttributeInterface $attribute, array $options = array())
{
$default_value = $attribute->getDefaultValue();
$this->setValue($entity, $attribute, $default_value ?: $this->faker->iso8601, $options);
}
/**
* Generates and adds fake data for a GeoPoint on a entity.
*
* @param EntityInterface $entity an instance of the entity to fill with fake data.
* @param AttributeInterface $attribute an instance of the GeoPoint to fill with fake data.
* @param array $options array of options to customize fake data creation.
*
* @return void
*/
protected function addGeoPoint(EntityInterface $entity, AttributeInterface $attribute, array $options = array())
{
$geopoint = [
'lon' => $this->faker->longitude,
'lat' => $this->faker->latitude
];
$this->setValue($entity, $attribute, $geopoint, $options);
}
/**
* Generates and adds fake data for a Token on a entity.
*
* @param EntityInterface $entity an instance of the entity to fill with fake data.
* @param AttributeInterface $attribute an instance of the Token to fill with fake data.
* @param array $options array of options to customize fake data creation.
*
* @return void
*/
protected function addToken(EntityInterface $entity, AttributeInterface $attribute, array $options = array())
{
$min_length = $attribute->getOption('min_length', 1);
$max_length = $attribute->getOption('max_length', 40);
$size = $this->faker->numberBetween($min_length, $max_length);
$token = bin2hex(mcrypt_create_iv(ceil($size/2), MCRYPT_DEV_URANDOM));
$truncated_token = substr($token, 0, $size);
$this->setValue($entity, $attribute, $truncated_token, $options);
}
/**
* Sets either given default value or value from option to the given attribute.
*
* @param EntityInterface $entity the entity to modify
* @param AttributeInterface $attribute the attribute to set a value for
* @param mixed $default_value Default value to set.
* @param array $options Array containing a `attribute_name => $mixed` entry.
* $mixed is set as value instead of $default_value.
* If $mixed is a closure it will be called and used.
* $mixed may also be another callable like an array
* `array($class, "$methodName")` or a string like
* `'Your\Namespace\Foo::getStaticTrololo'`.
*
* @return void
*/
protected function setValue(
EntityInterface $entity,
AttributeInterface $attribute,
$default_value,
array $options = array()
) {
$attribute_name = $attribute->getName();
$attribute_options = array();
if (!empty($options[self::OPTION_FIELD_VALUES])
&& is_array($options[self::OPTION_FIELD_VALUES])
) {
$attribute_options = $options[self::OPTION_FIELD_VALUES];
}
if (empty($attribute_options[$attribute_name])) {
$entity->setValue($attribute_name, $default_value);
} else {
$option = $attribute_options[$attribute_name];
if (is_callable($option)) {
$entity->setValue($attribute_name, call_user_func($option));
} else {
$entity->setValue($attribute_name, $option);
}
}
}
/**
* Returns whether or not the fake data generation should be dependant on
* the attribute_names the used types have.
*
* @param array $options array of options to customize fake data creation.
*
* @return bool true if the fake data provider should be guessed by attribute_name.
* False if specified self::OPTION_GUESS_PROVIDER_BY_NAME is set to false.
*/
protected function shouldGuessByName(array $options = array())
{
if (array_key_exists(self::OPTION_GUESS_PROVIDER_BY_NAME, $options)
&& false === $options[self::OPTION_GUESS_PROVIDER_BY_NAME]
) {
return false;
}
return true;
}
/**
* Returns the name of the internal method to call when fake data should
* be generated and added to the given attribute. The pattern is like this:
*
* - `addText` for `\Trellis\Runtime\Attribute\Type\Text`
* - `addNumberCollection` for `\Trellis\Runtime\Attribute\Type\NumberCollection`
*
* etc. pp.
*
* @param AttributeInterface $attribute attribute instance to generate fake data for
*
* @return string|null method name to use for fake data addition for given attribute
*/
protected function getMethodNameFor(AttributeInterface $attribute)
{
$hierarchy = array(get_class($attribute)) + class_parents($attribute, false);
foreach ($hierarchy as $attribute_class) {
$attribute_class_parts = explode('\\', $attribute_class);
$attribute_class = array_pop($attribute_class_parts);
$clean_type_name = preg_replace('#Attribute$#', '', $attribute_class);
$method_name = 'add' . ucfirst($clean_type_name);
if (is_callable([ $this, $method_name ])) {
return $method_name;
}
}
}
}