Commit fe85f9be authored by alexpott's avatar alexpott

Issue #2320157 by moshe weitzman, Wim Leers, penyaskito, tim.plunkett:...

Issue #2320157 by moshe weitzman, Wim Leers, penyaskito, tim.plunkett: Generate placeholder content for Field types.
parent c925507a
......@@ -135,6 +135,32 @@ public function name($length = 8, $unique = FALSE) {
return $str;
}
/**
* Generate a string that looks like a word (letters only, alternating consonants and vowels).
*
* @param int $length
* The desired word length.
*
* @return string
*/
public function word($length) {
mt_srand((double) microtime()*1000000);
$vowels = array("a", "e", "i", "o", "u");
$cons = array("b", "c", "d", "g", "h", "j", "k", "l", "m", "n", "p", "r", "s", "t", "u", "v", "w", "tr",
"cr", "br", "fr", "th", "dr", "ch", "ph", "wr", "st", "sp", "sw", "pr", "sl", "cl", "sh");
$num_vowels = count($vowels);
$num_cons = count($cons);
$word = '';
while(strlen($word) < $length){
$word .= $cons[mt_rand(0, $num_cons - 1)] . $vowels[mt_rand(0, $num_vowels - 1)];
}
return substr($word, 0, $length);
}
/**
* Generates a random PHP object.
*
......@@ -155,4 +181,124 @@ public function object($size = 4) {
return $object;
}
/**
* Generates sentences Latin words, often used as placeholder text.
*
* @param int $min_word_count
* The minimum number of words in the return string. Total word count
* can slightly exceed provided this value in order to deliver
* sentences of random length.
* @param bool $capitalize
* Uppercase all the words in the string.
*
* @return string
* Nonsense latin words which form sentence(s).
*/
public function sentences($min_word_count, $capitalize = FALSE) {
$dictionary = array("abbas", "abdo", "abico", "abigo", "abluo", "accumsan",
"acsi", "ad", "adipiscing", "aliquam", "aliquip", "amet", "antehabeo",
"appellatio", "aptent", "at", "augue", "autem", "bene", "blandit",
"brevitas", "caecus", "camur", "capto", "causa", "cogo", "comis",
"commodo", "commoveo", "consectetuer", "consequat", "conventio", "cui",
"damnum", "decet", "defui", "diam", "dignissim", "distineo", "dolor",
"dolore", "dolus", "duis", "ea", "eligo", "elit", "enim", "erat",
"eros", "esca", "esse", "et", "eu", "euismod", "eum", "ex", "exerci",
"exputo", "facilisi", "facilisis", "fere", "feugiat", "gemino",
"genitus", "gilvus", "gravis", "haero", "hendrerit", "hos", "huic",
"humo", "iaceo", "ibidem", "ideo", "ille", "illum", "immitto",
"importunus", "imputo", "in", "incassum", "inhibeo", "interdico",
"iriure", "iusto", "iustum", "jugis", "jumentum", "jus", "laoreet",
"lenis", "letalis", "lobortis", "loquor", "lucidus", "luctus", "ludus",
"luptatum", "macto", "magna", "mauris", "melior", "metuo", "meus",
"minim", "modo", "molior", "mos", "natu", "neo", "neque", "nibh",
"nimis", "nisl", "nobis", "nostrud", "nulla", "nunc", "nutus", "obruo",
"occuro", "odio", "olim", "oppeto", "os", "pagus", "pala", "paratus",
"patria", "paulatim", "pecus", "persto", "pertineo", "plaga", "pneum",
"populus", "praemitto", "praesent", "premo", "probo", "proprius",
"quadrum", "quae", "qui", "quia", "quibus", "quidem", "quidne", "quis",
"ratis", "refero", "refoveo", "roto", "rusticus", "saepius",
"sagaciter", "saluto", "scisco", "secundum", "sed", "si", "similis",
"singularis", "sino", "sit", "sudo", "suscipere", "suscipit", "tamen",
"tation", "te", "tego", "tincidunt", "torqueo", "tum", "turpis",
"typicus", "ulciscor", "ullamcorper", "usitas", "ut", "utinam",
"utrum", "uxor", "valde", "valetudo", "validus", "vel", "velit",
"veniam", "venio", "vereor", "vero", "verto", "vicis", "vindico",
"virtus", "voco", "volutpat", "vulpes", "vulputate", "wisi", "ymo",
"zelus");
$dictionary_flipped = array_flip($dictionary);
$greeking = '';
if (!$capitalize) {
$words_remaining = $min_word_count;
while ($words_remaining > 0) {
$sentence_length = mt_rand(3, 10);
$words = array_rand($dictionary_flipped, $sentence_length);
$sentence = implode(' ', $words);
$greeking .= ucfirst($sentence) . '. ';
$words_remaining -= $sentence_length;
}
}
else {
// Use slightly different method for titles.
$words = array_rand($dictionary_flipped, $min_word_count);
$words = is_array($words) ? implode(' ', $words) : $words;
$greeking = ucwords($words);
}
return trim($greeking);
}
/**
* Generate paragraphs separated by double new line.
*
* @param int $paragraph_count
* @return string
*/
public function paragraphs($paragraph_count = 12) {
$output = '';
for ($i = 1; $i <= $paragraph_count; $i++) {
$output .= $this->sentences(mt_rand(20, 60)) ."\n\n";
}
return $output;
}
/**
* Create a placeholder image.
*
* @param string $destination
* The absolute file path where the image should be stored.
* @param int $min_resolution
* @param int $max_resolution
*
* @return string
* Path to image file.
*/
public function image($destination, $min_resolution, $max_resolution) {
$extension = pathinfo($destination, PATHINFO_EXTENSION);
$min = explode('x', $min_resolution);
$max = explode('x', $max_resolution);
$width = rand((int) $min[0], (int) $max[0]);
$height = rand((int) $min[1], (int) $max[1]);
// Make an image split into 4 sections with random colors.
$im = imagecreate($width, $height);
for ($n = 0; $n < 4; $n++) {
$color = imagecolorallocate($im, rand(0, 255), rand(0, 255), rand(0, 255));
$x = $width / 2 * ($n % 2);
$y = $height / 2 * (int) ($n >= 2);
imagefilledrectangle($im, $x, $y, $x + $width / 2, $y + $height / 2, $color);
}
// Make a perfect circle in the image middle.
$color = imagecolorallocate($im, rand(0, 255), rand(0, 255), rand(0, 255));
$smaller_dimension = min($width, $height);
$smaller_dimension = ($smaller_dimension % 2) ? $smaller_dimension : $smaller_dimension;
imageellipse($im, $width / 2, $height / 2, $smaller_dimension, $smaller_dimension, $color);
$save_function = 'image'. ($extension == 'jpg' ? 'jpeg' : $extension);
$save_function($im, $destination);
return $destination;
}
}
......@@ -237,6 +237,11 @@ public function update() { }
*/
public function delete() { }
/**
* {@inheritdoc}
*/
public static function generateSampleValue(FieldDefinitionInterface $field_definition) { }
/**
* {@inheritdoc}
*/
......
......@@ -216,6 +216,20 @@ public function delete();
*/
public function deleteRevision();
/**
* Generates placeholder field values.
*
* Useful when populating site with placeholder content during site building
* or profiling.
*
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
* The field definition.
*
* @return array
* An associative array of values.
*/
public static function generateSampleValue(FieldDefinitionInterface $field_definition);
/**
* Defines the field-level settings for this plugin.
*
......
......@@ -278,6 +278,18 @@ public function view($display_options = array()) {
return $view_builder->viewField($this, $display_options);
}
/**
* {@inheritdoc}
*/
public function generateSampleItems($count = 1) {
$field_definition = $this->getFieldDefinition();
$field_type_class = \Drupal::service('plugin.manager.field.field_type')->getPluginClass($field_definition->getType());
for ($delta = 0; $delta < $count; $delta++) {
$values[$delta] = $field_type_class::generateSampleValue($field_definition);
}
$this->setValue($values);
}
/**
* {@inheritdoc}
*/
......
......@@ -181,6 +181,14 @@ public function deleteRevision();
*/
public function view($display_options = array());
/*
* Populates a specified number of field items with valid sample data.
*
* @param int $count
* The number of items to create.
*/
public function generateSampleItems($count = 1);
/**
* Returns a form for the default value input.
*
......
......@@ -7,6 +7,7 @@
namespace Drupal\Core\Field\Plugin\Field\FieldType;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Form\FormStateInterface;
......@@ -113,5 +114,12 @@ public function getSettableOptions(AccountInterface $account = NULL) {
return $this->getPossibleOptions($account);
}
/**
* {@inheritdoc}
*/
public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
$values['value'] = mt_rand(0, 1);
return $values;
}
}
......@@ -7,6 +7,7 @@
namespace Drupal\Core\Field\Plugin\Field\FieldType;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\TypedData\DataDefinition;
......@@ -97,4 +98,51 @@ public function preSave() {
$this->value = round($this->value, $this->getSetting('scale'));
}
/**
* {@inheritdoc}
*/
public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
$settings = $field_definition->getSettings();
$precision = $settings['precision'] ?: 10;
$scale = $settings['scale'] ?: 2;
// $precision - $scale is the number of digits on the left of the decimal
// point.
// The maximum number you can get with 3 digits is 10^3 - 1 --> 999.
// The minimum number you can get with 3 digits is -1 * (10^3 - 1).
$max = is_numeric($settings['max']) ?: pow(10, ($precision - $scale)) - 1;
$min = is_numeric($settings['min']) ?: -pow(10, ($precision - $scale)) + 1;
// Get the number of decimal digits for the $max
$decimal_digits = self::getDecimalDigits($max);
// Do the same for the min and keep the higher number of decimal digits.
$decimal_digits = max(self::getDecimalDigits($min), $decimal_digits);
// If $min = 1.234 and $max = 1.33 then $decimal_digits = 3
$scale = rand($decimal_digits, $scale);
// @see "Example #1 Calculate a random floating-point number" in
// http://php.net/manual/en/function.mt-getrandmax.php
$random_decimal = $min + mt_rand() / mt_getrandmax() * ($max - $min);
$values['value'] = self::truncateDecimal($random_decimal, $scale);
return $values;
}
/**
* Helper method to get the number of decimal digits out of a decimal number.
*
* @param int $decimal
* The number to calculate the number of decimals digits from.
*
* @return int
* The number of decimal digits.
*/
protected static function getDecimalDigits($decimal) {
$digits = 0;
while ($decimal - round($decimal)) {
$decimal *= 10;
$digits++;
}
return $digits;
}
}
......@@ -7,6 +7,8 @@
namespace Drupal\Core\Field\Plugin\Field\FieldType;
use Drupal\Component\Utility\Random;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Render\Element\Email;
......@@ -69,6 +71,15 @@ public function getConstraints() {
return $constraints;
}
/**
* {@inheritdoc}
*/
public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
$random = new Random();
$values['value'] = $random->name() . '@example.com';
return $values;
}
/**
* {@inheritdoc}
*/
......
......@@ -9,6 +9,7 @@
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\TypedData\EntityDataDefinition;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\TypedData\DataDefinition;
......@@ -209,6 +210,18 @@ public function preSave() {
}
}
/**
* {@inheritdoc}
*/
public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
$manager = \Drupal::service('plugin.manager.entity_reference.selection');
if ($referenceable = $manager->getSelectionHandler($field_definition)->getReferenceableEntities()) {
$group = array_rand($referenceable);
$values['target_id'] = array_rand($referenceable[$group]);
return $values;
}
}
/**
* Determines whether the item holds an unsaved entity.
*
......
......@@ -7,6 +7,7 @@
namespace Drupal\Core\Field\Plugin\Field\FieldType;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\TypedData\DataDefinition;
......@@ -47,4 +48,20 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
);
}
/**
* {@inheritdoc}
*/
public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
$settings = $field_definition->getSettings();
$precision = rand(10, 32);
$scale = rand(0, 2);
$max = is_numeric($settings['max']) ?: pow(10, ($precision - $scale)) - 1;
$min = is_numeric($settings['min']) ?: -pow(10, ($precision - $scale)) + 1;
// @see "Example #1 Calculate a random floating-point number" in
// http://php.net/manual/en/function.mt-getrandmax.php
$random_decimal = $min + mt_rand() / mt_getrandmax() * ($max - $min);
$values['value'] = self::truncateDecimal($random_decimal, $scale);
return $values;
}
}
......@@ -7,6 +7,7 @@
namespace Drupal\Core\Field\Plugin\Field\FieldType;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\TypedData\DataDefinition;
......@@ -102,4 +103,14 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
);
}
/**
* {@inheritdoc}
*/
public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
$min = $field_definition->getSetting('min') ?: 0;
$max = $field_definition->getSetting('max') ?: 999;
$values['value'] = mt_rand($min, $max);
return $values;
}
}
......@@ -113,4 +113,19 @@ public function getConstraints() {
return $constraints;
}
/**
* Helper method to truncate a decimal number to a given number of decimals.
*
* @param float $decimal
* Decimal number to truncate.
* @param int $num
* Number of digits the output will have.
*
* @return float
* Decimal number truncated.
*/
protected static function truncateDecimal($decimal, $num) {
return floor($decimal * pow(10, $num)) / pow(10, $num);
}
}
......@@ -7,6 +7,8 @@
namespace Drupal\Core\Field\Plugin\Field\FieldType;
use Drupal\Component\Utility\Random;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\StringTranslation\TranslationWrapper;
......@@ -83,4 +85,14 @@ public function getConstraints() {
return $constraints;
}
/**
* {@inheritdoc}
*/
public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
$random = new Random();
$max = $field_definition->getSetting('max_length');
$values['value'] = $random->word(mt_rand(1, $max));
return $values;
}
}
......@@ -7,6 +7,7 @@
namespace Drupal\datetime\Plugin\Field\FieldType;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\TypedData\DataDefinition;
......@@ -101,6 +102,24 @@ public function settingsForm(array &$form, FormStateInterface $form_state, $has_
return $element;
}
/**
* {@inheritdoc}
*/
public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
$type = $field_definition->getSetting('datetime_type');
// Just pick a date in the past year. No guidance is provided by this Field
// type.
$timestamp = REQUEST_TIME - mt_rand(0, 86400*365);
if ($type == DateTimeItem::DATETIME_TYPE_DATE) {
$values['value'] = gmdate(DATETIME_DATE_STORAGE_FORMAT, $timestamp);
}
else {
$values['value'] = gmdate(DATETIME_DATETIME_STORAGE_FORMAT, $timestamp);
}
return $values;
}
/**
* {@inheritdoc}
*/
......
......@@ -74,6 +74,11 @@ public function testDateTimeItem() {
$entity->save();
$entity = entity_load('entity_test', $id);
$this->assertEqual($entity->field_datetime->value, $new_value);
// Test the generateSampleValue() method.
$entity = entity_create('entity_test');
$entity->field_datetime->generateSampleItems();
$this->entityValidateAndSave($entity);
}
/**
......
......@@ -112,6 +112,12 @@ public function testContentEntityReferenceItem() {
$term2->delete();
$entity = entity_create('entity_test', array('name' => $this->randomMachineName()));
$entity->save();
// Test the generateSampleValue() method.
$entity = entity_create('entity_test');
$entity->field_test_taxonomy_term->generateSampleItems();
$entity->field_test_taxonomy_vocabulary->generateSampleItems();
$this->entityValidateAndSave($entity);
}
/**
......
......@@ -72,6 +72,11 @@ public function testBooleanItem() {
$entity->save();
$entity = entity_load('entity_test', $id);
$this->assertEqual($entity->field_boolean->value, $new_value);
// Test sample item generation.
$entity = entity_create('entity_test');
$entity->field_boolean->generateSampleItems();
$this->entityValidateAndSave($entity);
}
}
......@@ -69,6 +69,11 @@ public function testEmailItem() {
$entity->save();
$entity = entity_load('entity_test', $id);
$this->assertEqual($entity->field_email->value, $new_value);
// Test sample item generation.
$entity = entity_create('entity_test');
$entity->field_email->generateSampleItems();
$this->entityValidateAndSave($entity);
}
}
......@@ -125,6 +125,24 @@ protected function entitySaveReload(EntityInterface $entity) {
return $controller->load($entity->id());
}
/**
* Validate and save entity. Fail if violations are found.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity to save.
*
* @return void
*/
protected function entityValidateAndSave(EntityInterface $entity) {
$violations = $entity->validate();
if ($violations->count()) {
$this->fail($violations);
}
else {
$entity->save();
}
}
/**
* Generate random values for a field_test field.
*
......
......@@ -91,6 +91,13 @@ public function testNumberItem() {
$this->assertEqual($entity->field_integer->value, $new_integer);
$this->assertEqual($entity->field_float->value, $new_float);
$this->assertEqual($entity->field_decimal->value, $new_decimal);
/// Test sample item generation.
$entity = entity_create('entity_test');
$entity->field_integer->generateSampleItems();
$entity->field_float->generateSampleItems();
$entity->field_decimal->generateSampleItems();
$this->entityValidateAndSave($entity);
}
}
......@@ -8,6 +8,8 @@
namespace Drupal\file\Plugin\Field\FieldType;
use Drupal\Component\Utility\Bytes;
use Drupal\Component\Utility\Random;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
use Drupal\Core\Form\FormStateInterface;
......@@ -303,6 +305,25 @@ public function getUploadValidators() {
return $validators;
}
/**
* {@inheritdoc}
*/
public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
$random = new Random();
$settings = $field_definition->getSettings();
// Generate a file entity.
$destination = $settings['uri_scheme'] . '://' . $settings['file_directory'] . $random->name(10, TRUE) . '.txt';
$data = $random->paragraphs(3);
$file = file_save_data($data, $destination, FILE_EXISTS_ERROR);
$values = array(
'target_id' => $file->id(),
'display' => (int)$settings['display_default'],
'description' => $random->sentences(10),
);
return $values;
}
/**
* Determines whether an item should be displayed when rendering the field.
*
......
......@@ -95,6 +95,11 @@ public function testFileItem() {
// a non-existing entity.
$file2->delete();
$entity->delete();
// Test the generateSampleValue() method.
$entity = entity_create('entity_test');
$entity->file_test->generateSampleItems();
$this->entityValidateAndSave($entity);
}
}
......@@ -7,9 +7,12 @@
namespace Drupal\image\Plugin\Field\FieldType;
use Drupal\Component\Utility\Random;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\TypedData\DataDefinition;
use Drupal\file\Entity\File;
use Drupal\file\Plugin\Field\FieldType\FileItem;
/**
......@@ -311,6 +314,56 @@ public function preSave() {
}
}
/**
* {@inheritdoc}
*/
public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
$random = new Random();
$settings = $field_definition->getSettings();
static $images = array();
$min_resolution = empty($settings['min_resolution']) ? '100x100' : $settings['min_resolution'];
$max_resolution = empty($settings['max_resolution']) ? '600x600' : $settings['max_resolution'];
$extensions = array_intersect(explode(' ', $settings['file_extensions']), array('png', 'gif', 'jpg', 'jpeg'));
$extension = array_rand(array_combine($extensions, $extensions));
// Generate a max of 5 different images.
if (!isset($images[$extension][$min_resolution][$max_resolution]) || count($images[$extension][$min_resolution][$max_resolution]) <= 5) {
$tmp_file = drupal_tempnam('temporary://', 'generateImage_');
$destination = $tmp_file . '.' . $extension;
file_unmanaged_move($tmp_file, $destination, FILE_CREATE_DIRECTORY);
if ($path = $random->image(drupal_realpath($destination), $min_resolution, $max_resolution)) {
$image = File::create();
$image->setFileUri($path);
// $image->setOwner($account);
$image->setMimeType('image/' . pathinfo($path, PATHINFO_EXTENSION));
$image->setFileName(drupal_basename($path));
$destination_dir = $settings['uri_scheme'] . '://' . $settings['file_directory'];
file_prepare_directory($destination_dir, FILE_CREATE_DIRECTORY);
$destination = $destination_dir . '/' . basename($path);
$file = file_move($image, $destination, FILE_CREATE_DIRECTORY);
$images[$extension][$min_resolution][$max_resolution][$file->id()] = $file;
}
else {
return array();
}
}
else {
// Select one of the images we've already generated for this field.
$image_index = array_rand($images[$extension][$min_resolution][$max_resolution]);
$file = $images[$extension][$min_resolution][$max_resolution][$image_index];
}
list($width, $height) = getimagesize($file->getFileUri());
$values = array(
'target_id' => $file->id(),
'alt' => $random->sentences(4),