diff --git a/lib/equal/data/DataGenerator.class.php b/lib/equal/data/DataGenerator.class.php
new file mode 100644
index 000000000..cf3aeeae8
--- /dev/null
+++ b/lib/equal/data/DataGenerator.class.php
@@ -0,0 +1,823 @@
+
+ Some Rights Reserved, Cedric Francoys, 2010-2024
+ Licensed under GNU LGPL 3 license
+*/
+
+namespace equal\data;
+
+use equal\orm\UsageFactory;
+
+class DataGenerator {
+
+ /**
+ * @return array|bool|float|int|mixed|string|null
+ */
+ public static function generateByFieldConf(string $field, array $field_conf, string $lang = null) {
+ if(isset($field_conf['usage'])) {
+ try {
+ $usage = UsageFactory::create($field_conf['usage']);
+ return $usage->generateRandomValue();
+ }
+ catch(\Exception $e) {
+ // Usage problem
+ }
+ }
+
+ switch($field) {
+ case 'username':
+ return self::username();
+ case 'firstname':
+ return self::firstname($lang);
+ case 'lastname':
+ return self::lastname($lang);
+ case 'fullname':
+ return self::fullname($lang);
+ case 'legal_name':
+ return self::legalName($lang);
+ case 'address_street':
+ return self::addressStreet($lang);
+ case 'address_zip':
+ return self::addressZip();
+ case 'address_city':
+ return self::addressCity($lang);
+ case 'address_country':
+ return self::addressCountry($lang);
+ case 'address':
+ return self::address($lang);
+ }
+
+ switch($field_conf['type']) {
+ case 'string':
+ if(!empty($field_conf['selection'])) {
+ if(isset($field_conf['selection'][0])) {
+ $values = array_values($field_conf['selection']);
+ }
+ else {
+ $values = array_keys($field_conf['selection']);
+ }
+ return $values[array_rand($values)];
+ }
+ elseif(isset($field_conf['default'])) {
+ return $field_conf['default'];
+ }
+
+ return self::plainText();
+ case 'boolean':
+ return self::boolean();
+ case 'integer':
+ return self::integer(9);
+ case 'float':
+ return self::realNumber(9, 2);
+ }
+
+ return null;
+ }
+
+ public static function plainText($min = 0, $max = 255): string {
+ $words = [
+ 'lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur',
+ 'adipiscing', 'elit', 'sed', 'do', 'eiusmod', 'tempor',
+ 'incididunt', 'ut', 'labore', 'et', 'dolore', 'magna',
+ 'aliqua', 'ut', 'enim', 'ad', 'minim', 'veniam', 'quis',
+ 'nostrud', 'exercitation', 'ullamco', 'laboris', 'nisi',
+ 'ut', 'aliquip', 'ex', 'ea', 'commodo', 'consequat'
+ ];
+
+ $generate_sentence = function() use ($words) {
+ $sentence_length = mt_rand(6, 12);
+ $sentence = [];
+ for ($i = 0; $i < $sentence_length; $i++) {
+ $sentence[] = $words[array_rand($words)];
+ }
+ return ucfirst(implode(' ', $sentence)) . '.';
+ };
+
+ $random_length = mt_rand($min, $max);
+ $random_text = '';
+
+ while (strlen($random_text) < $random_length) {
+ $paragraph_length = mt_rand(3, 7);
+ $paragraph = '';
+ for ($i = 0; $i < $paragraph_length; $i++) {
+ $paragraph .= $generate_sentence() . ' ';
+ }
+ $random_text .= trim($paragraph) . "\n\n";
+ }
+
+ return trim(substr($random_text, 0, $random_length));
+ }
+
+ public static function boolean($probability = 0.5): bool {
+ $probability = max(0, min(1, $probability));
+
+ return mt_rand() / mt_getrandmax() < $probability;
+ }
+
+ public static function integer(int $length): int {
+ $min = (pow(10, $length) - 1) * -1;
+ $max = pow(10, $length) - 1;
+
+ return mt_rand($min, $max);
+ }
+
+ public static function realNumber(int $precision, int $scale): float {
+ $max_int_part = pow(10, $precision) - 1;
+ $min_int_part = -$max_int_part;
+
+ $int_part = mt_rand($min_int_part, $max_int_part);
+
+ $fractional_part = mt_rand(0, pow(10, $scale) - 1) / pow(10, $scale);
+
+ $random_float = $int_part + $fractional_part;
+
+ return round($random_float, $scale);
+ }
+
+ public static function hexadecimal(int $length): string {
+ $num_bytes = ceil($length / 2);
+ $random_bytes = random_bytes($num_bytes);
+ $hexadecimal_string = bin2hex($random_bytes);
+
+ return substr($hexadecimal_string, 0, $length);
+ }
+
+ public static function email(): string {
+ $domains = [
+ 'example.com', 'test.com', 'demo.com', 'sample.org', 'mywebsite.net',
+ 'mail.com', 'webmail.org', 'inbox.net', 'mailservice.io', 'emailprovider.co',
+ 'messaging.com', 'mailbox.org', 'fastmail.com', 'corpmail.net', 'freemail.org',
+ 'onlinemail.io', 'postbox.com', 'securemail.net', 'cloudmail.org', 'hostmail.co',
+ 'netmail.com', 'simplemail.io', 'yourmail.net', 'webservice.org', 'globalmail.com'
+ ];
+
+ $characters = '0123456789abcdefghijklmnopqrstuvwxyz';
+ $username_length = mt_rand(5, 10);
+ $username = '';
+
+ for ($i = 0; $i < $username_length; $i++) {
+ $username .= $characters[mt_rand(0, strlen($characters) - 1)];
+ }
+
+ $domain = $domains[array_rand($domains)];
+
+ return $username . '@' . $domain;
+ }
+
+ public static function phoneNumberE164(): string {
+ $country_codes = [
+ '+1', '+7', '+27', '+31', '+32', '+33', '+34', '+352', '+39', '+44', '+46',
+ '+47', '+48', '+49', '+55', '+61', '+64', '+81', '+86', '+90', '+91', '+972'
+ ];
+
+ $country_code = $country_codes[array_rand($country_codes)];
+
+ $number_length = 15 - strlen($country_code);
+ $number = '';
+ for ($i = 0; $i < $number_length; $i++) {
+ $number .= mt_rand(0, 9);
+ }
+
+ return $country_code . $number;
+ }
+
+ public static function time(): string {
+ $hours = str_pad(mt_rand(0, 23), 2, '0', STR_PAD_LEFT);
+ $minutes = str_pad(mt_rand(0, 59), 2, '0', STR_PAD_LEFT);
+ $seconds = str_pad(mt_rand(0, 59), 2, '0', STR_PAD_LEFT);
+
+ return $hours . ':' . $minutes . ':' . $seconds;
+ }
+
+ public static function relativeUrl(): string {
+ $depth = mt_rand(1, 5);
+
+ $generateRandomString = function($length) {
+ $characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
+ $random_string = '';
+ for ($i = 0; $i < $length; $i++) {
+ $random_string .= $characters[mt_rand(0, strlen($characters) - 1)];
+ }
+ return $random_string;
+ };
+
+ $url_path = '';
+ for ($i = 0; $i < $depth; $i++) {
+ $url_path .= '/' . $generateRandomString(6);
+ }
+
+ return $url_path;
+ }
+
+ public static function url($protocol = null): string {
+ $protocols = ['http', 'https', 'ldap', 'dns', 'ftp'];
+
+ if(is_null($protocol)) {
+ $protocol = $protocols[array_rand($protocols)];
+ }
+
+ $domain_length = mt_rand(3, 10);
+ $path_depth = mt_rand(0, 5);
+
+ // Helper function to generate a random string of given length
+ $generateRandomString = function($length) {
+ $characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
+ $random_string = '';
+ for ($i = 0; $i < $length; $i++) {
+ $random_string .= $characters[random_int(0, strlen($characters) - 1)];
+ }
+ return $random_string;
+ };
+
+ // Generate domain
+ $domain = $generateRandomString($domain_length) . '.' . $generateRandomString(3); // e.g., 'example.com'
+
+ // Generate path
+ $path = '';
+ for ($i = 0; $i < $path_depth; $i++) {
+ $path .= '/' . $generateRandomString(6);
+ }
+
+ return $protocol . '://' . $domain . $path;
+ }
+
+ public static function urlTel(): string {
+ return 'tel:' . self::phoneNumberE164();
+ }
+
+ public static function urlMailto(): string {
+ return 'mailto:' . self::email();
+ }
+
+ public static function iban(): string {
+ $account_number_lengths = [
+ 'DE' => 10,
+ 'GB' => 10,
+ 'FR' => 11,
+ 'ES' => 12,
+ 'IT' => 12,
+ 'NL' => 10,
+ 'BE' => 9
+ ];
+
+ $bank_code_lengths = [
+ 'DE' => 8,
+ 'GB' => 6,
+ 'FR' => 5,
+ 'ES' => 4,
+ 'IT' => 5,
+ 'NL' => 4,
+ 'BE' => 3
+ ];
+
+ $bank_codes = array_keys($bank_code_lengths);
+ $country_code = $bank_codes[array_rand($bank_codes)];
+ $bank_code_length = $bank_code_lengths[$country_code];
+
+ $generateRandomNumericString = function($length) {
+ $number = '';
+ for ($i = 0; $i < $length; $i++) {
+ $number .= mt_rand(0, 9);
+ }
+ return $number;
+ };
+
+ $bank_code = $generateRandomNumericString($bank_code_length);
+ $account_number_length = $account_number_lengths[$country_code];
+ $account_number = $generateRandomNumericString($account_number_length);
+
+ $iban_base = $country_code . '00' . $bank_code . $account_number;
+
+ $iban_numeric = '';
+ foreach (str_split($iban_base) as $char) {
+ if (ctype_alpha($char)) {
+ $iban_numeric .= ord($char) - 55;
+ } else {
+ $iban_numeric .= $char;
+ }
+ }
+
+ $mod97 = bcmod($iban_numeric, '97');
+ $check_digits = str_pad(98 - $mod97, 2, '0', STR_PAD_LEFT);
+
+ return $country_code . $check_digits . $bank_code . $account_number;
+ }
+
+ public static function ean13(): string {
+ $ean12 = '';
+ for ($i = 0; $i < 12; $i++) {
+ $ean12 .= mt_rand(0, 9);
+ }
+
+ $sum = 0;
+ for ($i = 0; $i < 12; $i++) {
+ $digit = (int)$ean12[$i];
+ if ($i % 2 === 0) {
+ $sum += $digit;
+ } else {
+ $sum += $digit * 3;
+ }
+ }
+
+ $check_digit = (10 - ($sum % 10)) % 10;
+
+ return $ean12 . $check_digit;
+ }
+
+ public static function username(): string {
+ $usernames = [
+ 'user', 'coolUser', 'jane-doe', 'johnnyBravo', 'theRealMike',
+ 'superstar', 'gameMaster', 'techGuru', 'quickSilver', 'happyCamper',
+ 'blueSky', 'codingWizard', 'magicMikey', 'fastTrack', 'misterX',
+ 'adventureSeeker', 'pixelPioneer', 'ninja-warrior', 'starGazer', 'drSmart',
+ 'boldExplorer', 'zenMaster', 'risingStar', 'rocket-rider', 'digitalNomad',
+ 'echoEcho', 'nightOwl', 'lightSpeed', 'trueBeliever', 'cyberHawk',
+ 'galacticHero', 'luckyCharm', 'urbanVibes', 'silentStorm', 'wildWanderer',
+ 'moonWalker', 'brightStar', 'vividDreamer', 'vortexVoyager', 'infiniteLoop',
+ 'horizonChaser', 'quickSilverFox', 'shadowKnight', 'dataMaster', 'epicQuest',
+ 'cosmicDancer', 'virtualVictor', 'alphaBravo', 'gammaRay', 'quantumLeap',
+ 'alphaWolf', 'digitalDynamo', 'codeNinja', 'retro-rider', 'futureFreak',
+ 'hyperLink', 'wizardKing', 'neonNinja', 'techTitan', 'starshipPilot',
+ 'legendaryHero', 'phantomShadow', 'urbanLegend', 'novaStar', 'daringDiva',
+ 'trailBlazer', 'cyberChampion', 'epicGamer', 'stellarScribe', 'stormChaser',
+ 'lunarExplorer', 'plasma-bolt', 'infinityEdge', 'quantumQuest', 'stellar-voyager'
+ ];
+
+ $number = mt_rand(0, 9999);
+
+ return $usernames[array_rand($usernames)] . $number;
+ }
+
+ public static function firstname($lang = null): string {
+ $map_lang_firstnames = [
+ 'en' => [
+ 'John', 'Jane', 'Michael', 'Emily', 'Robert', 'Jessica', 'David', 'Sarah',
+ 'James', 'Laura', 'Daniel', 'Sophia', 'Matthew', 'Olivia', 'Andrew', 'Isabella',
+ 'William', 'Mia', 'Joseph', 'Charlotte', 'Charles', 'Amelia', 'Thomas', 'Harper',
+ 'Christopher', 'Evelyn', 'Benjamin', 'Abigail', 'Samuel', 'Ella', 'Henry', 'Avery',
+ 'Lucas', 'Sofia', 'Jack', 'Grace', 'Jackson', 'Chloe', 'Ethan', 'Zoe', 'Alexander',
+ 'Lily', 'Ryan', 'Hannah', 'Nathan', 'Scarlett', 'Gabriel', 'Aria', 'Carter', 'Mila',
+ 'Isaac', 'Ella', 'Luke', 'Madison', 'Owen', 'Penelope', 'Caleb', 'Riley', 'Aiden',
+ 'Samantha', 'Dylan', 'Eleanor', 'Joshua', 'Layla', 'Mason', 'Nora', 'Logan', 'Lila',
+ 'Eli', 'Hazel', 'Cameron', 'Audrey', 'Sebastian', 'Ellie', 'Grayson', 'Stella',
+ 'Julian', 'Luna', 'Hudson', 'Lila', 'Wyatt', 'Nina', 'Mateo', 'Cora', 'Isaiah',
+ 'Vivian', 'Jordan', 'Katherine', 'Leo', 'Mackenzie', 'Harrison', 'Paige', 'Evan',
+ 'Alice', 'Jaxon', 'Eliana', 'Asher', 'Lydia', 'Leo', 'Julia', 'Miles', 'Caroline',
+ 'Jeremiah', 'Kylie', 'Jasper', 'Adeline', 'Roman', 'Piper', 'Ezekiel', 'Claire',
+ 'Xavier', 'Riley', 'Sawyer', 'Serenity', 'Kinsley', 'Maya', 'Zachary', 'Madeline',
+ 'Ariana', 'Aiden', 'Eliza', 'Avery', 'Liam', 'Sophie', 'Jaxon', 'Evangeline',
+ 'Daniel', 'Anna', 'Hudson', 'Natalie', 'Eli', 'Mia', 'Sebastian', 'Quinn',
+ 'Jameson', 'Everly', 'Santiago', 'Aurora', 'Roman', 'Naomi', 'Jackson', 'Ivy',
+ 'Finn', 'Riley', 'Oliver', 'Jade', 'Landon', 'Brianna', 'Gavin', 'Savannah',
+ 'Connor', 'Lily', 'Parker', 'Aubrey', 'Nolan', 'Violet', 'Bentley', 'Clara',
+ 'Levi', 'Ruby', 'Carson', 'Alyssa', 'Hunter', 'Faith', 'Eli', 'Zoey', 'Adrian',
+ 'Sienna', 'Cooper', 'Elise', 'Brody', 'Genesis', 'Grant', 'Harley', 'Tristan',
+ 'Eva', 'Easton', 'Sage', 'Tanner', 'Summer', 'Dominic', 'Maddie', 'Micah',
+ 'Tessa', 'Elias', 'Brooke', 'Elliot', 'Mallory', 'Theo', 'Delilah', 'Ryder',
+ 'Lana', 'Beckett', 'Reese', 'Axel', 'Anastasia', 'Malachi', 'Gemma', 'Bennett',
+ 'Talia', 'Brayden', 'Nadia', 'Silas', 'Camila', 'Jonah', 'Iris', 'Maxwell',
+ 'Isla', 'Tyler', 'Jasmine', 'Diego', 'Nova', 'Eric', 'Maren', 'Dean', 'Bianca',
+ 'Lincoln', 'Paisley', 'Hayden', 'Rose', 'Declan', 'Carmen', 'Oscar', 'Willa',
+ 'Griffin', 'Aspen', 'Ronan', 'Freya', 'Ezra', 'Willow', 'Kaden', 'Georgia'
+ ],
+ 'fr' => [
+ 'Jean', 'Marie', 'Pierre', 'Sophie', 'Louis', 'Camille', 'Paul', 'Juliette',
+ 'Jacques', 'Chloé', 'Léon', 'Clara', 'Henri', 'Lucie', 'Thomas', 'Élodie',
+ 'Philippe', 'Manon', 'Michel', 'Léa', 'Nicolas', 'Amandine', 'François', 'Anaïs',
+ 'Antoine', 'Aurélie', 'Guillaume', 'Margaux', 'Étienne', 'Charlotte', 'Benoît',
+ 'Alice', 'Maxime', 'Julie', 'Hugo', 'Emilie', 'Théo', 'Isabelle', 'Vincent',
+ 'Valérie', 'Laurent', 'Cécile', 'Olivier', 'Maëlys', 'Damien', 'Catherine',
+ 'Adrien', 'Amélie', 'Georges', 'Émilie', 'Baptiste', 'Inès', 'Rémi', 'Océane',
+ 'Mathieu', 'Florian', 'Yves', 'Elsa', 'René', 'Jade', 'Claude', 'Clémentine',
+ 'André', 'Victoria', 'Gérard', 'Laure', 'Lucas', 'Sarah', 'Alain', 'Gabrielle',
+ 'Patrick', 'Madeleine', 'Simon', 'Louise', 'Raphaël', 'Soline', 'Arnaud', 'Léna',
+ 'Sébastien', 'Victoire', 'Gaspard', 'Maëlle', 'Charles', 'Rose', 'Mathis', 'Fanny',
+ 'Luc', 'Noémie', 'Christophe', 'Caroline', 'David', 'Jeanne', 'Emmanuel', 'Justine',
+ 'Xavier', 'Adèle', 'Pascal', 'Diane', 'Romain', 'Noé', 'Marc', 'Marion', 'Gaël',
+ 'Coralie', 'Cédric', 'Ariane','Françoise', 'Yvonne', 'Clément', 'Solange', 'Mathilde',
+ 'Bérénice', 'Thierry', 'Agnès', 'Pascaline', 'Alix', 'Roland', 'Brigitte', 'Sylvain',
+ 'Estelle', 'Fabrice', 'Lilian', 'Josiane', 'Éric', 'Serge', 'Cyril', 'Bernadette',
+ 'Guilhem', 'Axelle', 'Dominique', 'Ludovic', 'Véronique', 'Raymond', 'Sandrine',
+ 'Patrice', 'Colette', 'Basile', 'Félix', 'Jean-Marc', 'Maurice', 'Sylvie', 'Jacqueline',
+ 'Augustin', 'Gaston', 'Jean-Baptiste', 'Odile', 'Arlette', 'Marius', 'Christiane',
+ 'Fabien', 'Louison', 'Léonie', 'Yann', 'Noémie', 'Raphaëlle', 'Sébastienne', 'Florence',
+ 'Lucien', 'Jean-Luc', 'Fernand', 'Antoinette', 'Gisèle', 'Solène', 'Angèle', 'Edmond',
+ 'Céleste', 'Hélène', 'Violette'
+ ]
+ ];
+
+ if(is_null($lang) || !isset($map_lang_firstnames[$lang])) {
+ $all_firstnames = array_merge(
+ $map_lang_firstnames['en'],
+ $map_lang_firstnames['fr']
+ );
+
+ return $all_firstnames[array_rand($all_firstnames)];
+ }
+
+ return $map_lang_firstnames[$lang][array_rand($map_lang_firstnames[$lang])];
+ }
+
+ public static function lastname($lang = null): string {
+ $map_lang_lastnames = [
+ 'en' => [
+ 'Smith', 'Johnson', 'Williams', 'Jones', 'Brown', 'Davis', 'Miller', 'Wilson',
+ 'Moore', 'Taylor', 'Anderson', 'Thomas', 'Jackson', 'White', 'Harris', 'Martin',
+ 'Thompson', 'Garcia', 'Martinez', 'Robinson', 'Clark', 'Rodriguez', 'Lewis',
+ 'Lee', 'Walker', 'Hall', 'Allen', 'Young', 'King', 'Wright', 'Scott', 'Torres',
+ 'Nguyen', 'Hill', 'Adams', 'Baker', 'Nelson', 'Carter', 'Mitchell', 'Perez',
+ 'Roberts', 'Turner', 'Phillips', 'Campbell', 'Parker', 'Evans', 'Edwards',
+ 'Collins', 'Stewart', 'Sanchez', 'Morris', 'Rogers', 'Reed', 'Cook', 'Morgan',
+ 'Bell', 'Murphy', 'Bailey', 'Rivera', 'Cooper', 'Richardson', 'Cox', 'Howard',
+ 'Ward', 'Flores', 'Wood', 'James', 'Bennett', 'Gray', 'Mendoza', 'Cruz',
+ 'Hughes', 'Price', 'Myers', 'Long', 'Foster', 'Sanders', 'Ross', 'Morales',
+ 'Powell', 'Jenkins', 'Perry', 'Butler', 'Barnes', 'Fisher', 'Henderson',
+ 'Coleman', 'Simmons', 'Patterson', 'Jordan', 'Reynolds', 'Hamilton',
+ 'Graham', 'Kim', 'Gonzalez', 'Vasquez', 'Sullivan', 'Bryant', 'Alexander',
+ 'Russell', 'Griffin', 'Diaz', 'Hayes', 'Wells', 'Chavez', 'Burke', 'Wood',
+ 'Harrison', 'Gordon', 'Walters', 'McDonald', 'Murray', 'Ford', 'Hamilton',
+ 'Gibson', 'Ellis', 'Ramos', 'Fisher', 'George', 'Miller', 'Harris', 'James',
+ 'Stone', 'Richards', 'Hunter', 'Bennett', 'Perry', 'Matthews', 'Hughes',
+ 'Palmer', 'Burns', 'Floyd', 'Nguyen', 'Snyder', 'Bishop', 'Newman', 'Boone',
+ 'Dean', 'Carr', 'Cunningham', 'Sampson', 'Marshall', 'Barnett', 'Farrell',
+ 'Weaver', 'Wade', 'Bradley', 'Mason', 'Newton', 'Olson',
+ 'Hawkins', 'Chapman', 'Bowman', 'Lawrence', 'Glover', 'Barber', 'Grant', 'Wallace',
+ 'Keller', 'Webb', 'Spencer', 'Harvey', 'Brooks', 'Pearson', 'Francis', 'Burgess',
+ 'Graves', 'Lambert', 'Cross', 'Tucker', 'Fields', 'Reeves', 'Gibbs', 'Porter',
+ 'Daniels', 'Brady', 'Owen', 'Horton', 'McCarthy', 'Fletcher', 'Simon', 'Norris',
+ 'Clayton', 'Kemp', 'Fuller', 'Tyler', 'Pearce', 'Moss', 'Rowe', 'Hodges', 'Barker',
+ 'Hardy', 'Jennings', 'Gilbert', 'Payne', 'Webster', 'Neal', 'Sutton', 'Davidson',
+ 'Carlson', 'Morton', 'Kirk', 'Holland', 'Greer', 'Wheeler', 'Peters', 'Fordham'
+ ],
+ 'fr' => [
+ 'Martin', 'Bernard', 'Dubois', 'Thomas', 'Robert', 'Richard', 'Petit', 'Durand', 'Leroy', 'Moreau',
+ 'Simon', 'Laurent', 'Lefebvre', 'Michel', 'Garcia', 'David', 'Bertrand', 'Roux', 'Vincent', 'Fournier',
+ 'Morel', 'Girard', 'Andre', 'Lefevre', 'Mercier', 'Dupont', 'Lambert', 'Bonnet', 'Francois', 'Martinez',
+ 'Legrand', 'Garnier', 'Faure', 'Rousseau', 'Blanc', 'Guerin', 'Muller', 'Henry', 'Roussel', 'Nicolas',
+ 'Perrin', 'Morin', 'Mathieu', 'Clement', 'Gauthier', 'Dumont', 'Lopez', 'Fontaine', 'Chevalier',
+ 'Robin', 'Masson', 'Sanchez', 'Gerard', 'Nguyen', 'Boyer', 'Denis', 'Lemoine', 'Duval', 'Joly',
+ 'Gautier', 'Roger', 'Renaud', 'Gaillard', 'Hamond', 'Boucher', 'Carpentier', 'Menard', 'Marechal',
+ 'Charpentier', 'Dupuis', 'Leclerc', 'Poirier', 'Guillaume', 'Leconte', 'Benoit', 'Collet',
+ 'Perrot', 'Jacquet', 'Rey', 'Gilles', 'Herve', 'Charrier', 'Schmitt', 'Baron', 'Perret',
+ 'Leblanc', 'Verdier', 'Giraud', 'Marty', 'Lemoine', 'Poulain', 'Vallet', 'Renard',
+ 'Marion', 'Marchand', 'Chauvin', 'Langlois', 'Teixeira', 'Bellamy', 'Lemoigne', 'Bazin',
+ 'Da Silva', 'Delorme', 'Aubry', 'Ferreira', 'Chauvet', 'Delaunay', 'Joubert', 'Vidal',
+ 'Pires', 'Blondel', 'Noel', 'Collin', 'Lucas', 'Monnier', 'Breton', 'Lejeune', 'Prevost',
+ 'Allard', 'Pichon', 'Le Gall', 'Lavigne', 'Roy', 'Gros', 'Chartier', 'Briand', 'Maillet',
+ 'Lemois', 'Dufour', 'Boutin', 'Guichard', 'Vasseur', 'Hoarau', 'Lebrun', 'Giraudet',
+ 'Dubois', 'Maillard', 'Millet', 'Carre', 'Coste', 'Laborde', 'Bertin', 'Moulin',
+ 'Turpin', 'Deschamps', 'Barthelemy', 'Descamps', 'Riviere', 'Guilbert', 'Tanguy',
+ 'Duchamp', 'Pasquier', 'Gaudin', 'Vial', 'Letellier', 'Meunier', 'Bouchet', 'Hebert',
+ 'Gosselin', 'Le Roux', 'Renou', 'Guillon', 'Delattre', 'Lefranc', 'Peltier', 'Delacroix',
+ 'Labbe', 'Bellanger', 'Perrier', 'Chretien', 'Bouvet', 'Ferrand', 'Vallee', 'Boulanger',
+ 'Vautier', 'Morvan', 'Leclercq', 'Picard', 'Jourdain', 'Cornu', 'Bodin', 'Courtois',
+ 'Duhamel', 'Leveque', 'Leconte', 'Aubert', 'Delaire', 'Letourneau', 'Tessier', 'Barre',
+ 'Fleury', 'Mallet', 'Deniau', 'Royer', 'Rigal', 'Levy', 'Bouchard', 'Charron', 'Laroche'
+ ]
+ ];
+
+ if(is_null($lang) || !isset($map_lang_lastnames[$lang])) {
+ $all_lastnames = array_merge(
+ $map_lang_lastnames['en'],
+ $map_lang_lastnames['fr']
+ );
+
+ return $all_lastnames[array_rand($all_lastnames)];
+ }
+
+ return $map_lang_lastnames[$lang][array_rand($map_lang_lastnames[$lang])];
+ }
+
+ public static function fullname($lang = null): string {
+ return sprintf('%s %s', self::firstname($lang), self::lastname($lang));
+ }
+
+ public static function legalName($lang = null): string {
+ $map_lang_legalNames = [
+ 'en' => [
+ 'Pinnacle Innovations Ltd.', 'GlobalTech Solutions LLC',
+ 'Blue Horizon Enterprises Inc.', 'Silverline Consulting Group',
+ 'Evergreen Holdings Co.', 'Brightway Capital Partners',
+ 'NextGen Software Corp.', 'Summit Legal Advisors LLP',
+ 'Aspire Marketing Associates', 'Crestview Financial Services',
+ 'Vanguard Media Networks', 'Oceanic Development Group',
+ 'Phoenix Engineering Systems', 'Cascade Resource Management',
+ 'Momentum Logistics Group', 'EagleRock Ventures LLC',
+ 'Fusion Health & Wellness Inc.', 'Broadway Research Institute',
+ 'Skyline Construction Co.', 'Peak Performance Consulting',
+ 'Heritage Legal Solutions LLP', 'Infinity Investment Trust',
+ 'Starlight Communications Inc.', 'Aurora Environmental Services',
+ 'Velocity Tech Innovators LLC', 'Redwood Analytics Solutions',
+ 'Everest Property Management', 'Sapphire Insurance Group Ltd.',
+ 'Nova Digital Media Inc.', 'Paramount Energy Solutions',
+ 'UrbanCore Construction Co.', 'TerraNova Agricultural Services',
+ 'Quantum Financial Consulting', 'Synergy Global Partners',
+ 'Horizon Security Solutions LLC', 'NorthStar Investments Group',
+ 'Zenith Technology Ventures', 'PrimeCare Medical Solutions',
+ 'Aurora Legal Advisory Group', 'Lakeside Manufacturing Co.',
+ 'Falcon Ridge Asset Management', 'Emerald Coast Logistics LLC',
+ 'Atlas Legal Services LLP', 'Titanium Energy Systems',
+ 'Genesis Marketing Innovations', 'Renaissance Capital Advisors',
+ 'TrueNorth Consulting Group', 'BluePeak Industries Inc.',
+ 'Omega Transportation Services', 'GoldenBridge Infrastructure Co.',
+ 'Sunrise Financial Holdings', 'Pioneer Technology Group LLC'
+ ],
+ 'fr' => [
+ 'Solutions Pinnacle SARL', 'GlobalTech Innovations SAS',
+ 'Horizon Bleu Entreprises SA', 'Consulting Silverline Group',
+ 'Evergreen Holdings SARL', 'Capital Brightway Partners',
+ 'NextGen Software Corp.', 'Conseil Juridique Summit SCP',
+ 'Aspire Marketing Associés', 'Services Financiers Crestview',
+ 'Vanguard Médias Réseaux SARL', 'Groupe de Développement Océanique',
+ 'Phoenix Ingénierie Systèmes', 'Gestion des Ressources Cascade',
+ 'Momentum Logistique SARL', 'EagleRock Ventures SAS',
+ 'Fusion Santé & Bien-être Inc.', 'Institut de Recherche Broadway',
+ 'Construction Skyline SARL', 'Performance Consulting Peak',
+ 'Solutions Juridiques Héritage SCP', 'Infinity Investissement Trust',
+ 'Communications Starlight Inc.', 'Services Environnementaux Aurora',
+ 'Innovateurs Technologiques Velocity SAS', 'Alpha Conseil et Stratégie',
+ 'Groupe Nexus Immobilier', 'Aquitaine Développement Durable',
+ 'Astéria Informatique SARL', 'Helios Technologies SAS',
+ 'Artisanat Moderne & Tradition', 'Biotech Avancée France SA',
+ 'Espace Vert Solutions', 'Union des Commerçants Réunis',
+ 'Nouvelle Génération Énergies', 'Réseaux Mondial Média',
+ 'EcoSys Environnement SAS', 'Orion Énergie Renouvelable',
+ 'Alliance Pharmaceutique France', 'Cœur de Ville Projets Urbains',
+ 'Pôle d\'Innovation Numérique', 'Ciel Bleu Aviation SARL',
+ 'Altura Services Financiers', 'Vision Logistique Internationale',
+ 'Verdi Éco-Construction SARL', 'Genèse Création et Design',
+ 'Solstice Groupe Juridique', 'TechnoVentures France',
+ 'Esprit Nature & Bien-être SARL', 'Voies Nouvelles Mobilité SAS',
+ 'Groupe Horizon Santé SAS'
+ ]
+ ];
+
+ if(is_null($lang) || !isset($map_lang_legalNames[$lang])) {
+ $all_legal_names = array_merge(
+ $map_lang_legalNames['en'],
+ $map_lang_legalNames['fr']
+ );
+
+ return $all_legal_names[array_rand($all_legal_names)];
+ }
+
+ return $map_lang_legalNames[$lang][array_rand($map_lang_legalNames[$lang])];
+ }
+
+ public static function addressStreet($lang = null): string {
+ $number = mt_rand(1, 1200);
+
+ $map_lang_streets = [
+ 'en' => [
+ 'High Street', 'Main Road', 'Church Lane', 'King Street', 'Victoria Avenue', 'Queen’s Road',
+ 'Park Lane', 'Elm Street', 'Bridge Road', 'Cedar Drive', 'Oxford Street', 'Market Square',
+ 'Mill Lane', 'Greenwich Way', 'Meadow Road', 'Kingfisher Close', 'Rosemary Avenue',
+ 'West End', 'Holly Road', 'Sunset Boulevard', 'Newcastle Street', 'Broadway', 'Pine Hill',
+ 'St. James’s Street', 'Bayview Road', 'Shakespeare Avenue', 'Cloverleaf Drive', 'Springfield Road',
+ 'Wellington Street', 'Harrison Close', 'Golden Grove', 'Elmwood Avenue', 'Rose Lane',
+ 'Abbey Road', 'Silver Street', 'Orchard Way', 'Granite Road', 'Oakfield Drive', 'Riverside Walk',
+ 'Broad Street', 'Main Avenue', 'River Lane', 'Hampton Road', 'Baker Street', 'Long Lane',
+ 'Park Avenue', 'Crescent Road', 'Hilltop Drive', 'Northgate Street', 'Cleveland Avenue',
+ 'St. John’s Road', 'Meadowbrook Lane', 'Silverwood Drive', 'Greenfield Road', 'Windsor Crescent',
+ 'Castle Street', 'Fairview Avenue', 'Ridgeway Road', 'Cumberland Street', 'Abbey Lane',
+ 'Kingsway', 'Dove Court', 'Hollingsworth Road', 'Starlight Avenue', 'Sunrise Lane',
+ 'Copperfield Road', 'Thornfield Drive', 'Holly Hill', 'Fairfax Street', 'Violet Lane',
+ 'Laurel Avenue', 'Tudor Street', 'Bramble Road', 'Claremont Drive', 'Woodland Avenue',
+ 'Glenwood Road', 'Beaumont Street', 'Ridgewood Avenue', 'Daisy Lane', 'Waverley Road',
+ 'King’s Crescent', 'Hawthorn Road', 'Elmwood Drive', 'Haven Street', 'Meadow Street'
+ ],
+ 'fr' => [
+ 'Rue de la Paix', 'Avenue des Champs-Élysées', 'Boulevard Saint-Germain', 'Place de la Concorde',
+ 'Rue de Rivoli', 'Avenue Victor Hugo', 'Boulevard Haussmann', 'Rue du Faubourg Saint-Honoré',
+ 'Avenue de l\'Opéra', 'Rue Saint-Denis', 'Place Vendôme', 'Rue de la République',
+ 'Boulevard Voltaire', 'Rue Lafayette', 'Avenue de la Grande Armée', 'Rue du Bac',
+ 'Avenue Montaigne', 'Boulevard de Sébastopol', 'Place d’Italie', 'Rue de la Fontaine',
+ 'Rue des Rosiers', 'Rue de Vaugirard', 'Avenue de Paris', 'Boulevard de Strasbourg',
+ 'Place des Vosges', 'Rue Monge', 'Avenue Foch', 'Rue de la Garenne', 'Boulevard Saint-Michel',
+ 'Rue de la Chapelle', 'Place du Trocadéro', 'Rue de l’Université', 'Boulevard Diderot',
+ 'Rue des Écoles', 'Avenue de l\'Alma', 'Rue du Temple', 'Boulevard de la Madeleine',
+ 'Rue du Commerce', 'Avenue des Ternes', 'Boulevard de la Liberté', 'Place des Jardins',
+ 'Rue du Pont-Neuf', 'Avenue de la République', 'Boulevard de la Gare', 'Rue des Fleurs',
+ 'Place du Marché', 'Rue du Général Leclerc', 'Avenue des Écoles', 'Boulevard du Palais',
+ 'Rue des Lilas', 'Avenue de la Mairie', 'Boulevard des Capucines', 'Place des Armes',
+ 'Rue des Peupliers', 'Avenue du Président Wilson', 'Boulevard de l’Indépendance', 'Rue des Roses',
+ 'Place du Général de Gaulle', 'Rue des Pommiers', 'Avenue de la Victoire', 'Boulevard de la Mer',
+ 'Rue des Vergers', 'Avenue des Arts', 'Boulevard de la Côte', 'Place du Château', 'Rue de la Gare',
+ 'Rue de l’Église', 'Avenue de la Forêt', 'Boulevard du Parc', 'Place du Soleil', 'Rue des Vignes',
+ 'Rue de la Liberté', 'Avenue des Érables', 'Boulevard des Temples', 'Place de la République',
+ 'Rue des Champs', 'Avenue des Pyramides', 'Boulevard des Pruniers', 'Place de la Bastille'
+ ]
+ ];
+
+ if(is_null($lang) || !isset($map_lang_streets[$lang])) {
+ $all_streets = array_merge(
+ $map_lang_streets['en'],
+ $map_lang_streets['fr']
+ );
+
+ return $all_streets[array_rand($all_streets)] . ' ' . $number;
+ }
+
+ return $map_lang_streets[$lang][array_rand($map_lang_streets[$lang])] . ' ' . $number;
+ }
+
+ public static function addressZip(): string {
+ return mt_rand(1000, 9999);
+ }
+
+ public static function addressCity($lang = null): string {
+ $map_lang_cities = [
+ 'en' => [
+ 'New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix',
+ 'Philadelphia', 'San Antonio', 'San Diego', 'Dallas', 'San Jose',
+ 'Toronto', 'Vancouver', 'Montreal', 'Calgary', 'Edmonton',
+ 'Ottawa', 'Winnipeg', 'Quebec City', 'Hamilton', 'Kitchener',
+ 'London', 'Birmingham', 'Manchester', 'Glasgow', 'Liverpool',
+ 'Edinburgh', 'Leeds', 'Sheffield', 'Bristol', 'Cardiff',
+ 'Sydney', 'Melbourne', 'Brisbane', 'Perth', 'Adelaide',
+ 'Gold Coast', 'Canberra', 'Hobart', 'Darwin', 'Newcastle',
+ 'Berlin', 'Hamburg', 'Munich', 'Cologne', 'Frankfurt',
+ 'Stuttgart', 'Dusseldorf', 'Dortmund', 'Essen', 'Leipzig',
+ 'Paris', 'Marseille', 'Lyon', 'Toulouse', 'Nice',
+ 'Nantes', 'Montpellier', 'Strasbourg', 'Bordeaux', 'Lille',
+ 'Rome', 'Milan', 'Naples', 'Turin', 'Palermo',
+ 'Genoa', 'Bologna', 'Florence', 'Catania', 'Venice',
+ 'Madrid', 'Barcelona', 'Valencia', 'Seville', 'Zaragoza',
+ 'Malaga', 'Murcia', 'Palma', 'Las Palmas', 'Bilbao',
+ 'Brussels', 'Antwerp', 'Ghent', 'Bruges', 'Liege',
+ 'Namur', 'Ostend', 'Leuven', 'Hasselt', 'Mechelen',
+ 'Amsterdam', 'Rotterdam', 'The Hague', 'Utrecht', 'Eindhoven',
+ 'Groningen', 'Maastricht', 'Arnhem', 'Nijmegen', 'Haarlem',
+ 'Zurich', 'Geneva', 'Bern', 'Basel', 'Lausanne',
+ 'Lucerne', 'St. Moritz', 'Zug', 'Neuchatel', 'La Chaux-de-Fonds',
+ 'Tokyo', 'Osaka', 'Kyoto', 'Nagoya', 'Hiroshima',
+ 'Fukuoka', 'Kobe', 'Yokohama', 'Sapporo', 'Sendai',
+ 'Beijing', 'Shanghai', 'Guangzhou', 'Shenzhen', 'Chengdu',
+ 'Hong Kong', 'Hangzhou', 'Nanjing', 'Wuhan', 'Xi\'an',
+ 'Mumbai', 'Delhi', 'Bangalore', 'Hyderabad', 'Ahmedabad',
+ 'Chennai', 'Kolkata', 'Pune', 'Jaipur', 'Surat',
+ 'Sao Paulo', 'Rio de Janeiro', 'Salvador', 'Fortaleza', 'Belo Horizonte',
+ 'Brasilia', 'Curitiba', 'Manaus', 'Recife', 'Porto Alegre',
+ 'Johannesburg', 'Cape Town', 'Durban', 'Pretoria', 'Port Elizabeth',
+ 'Bloemfontein', 'East London', 'Polokwane', 'Nelspruit', 'Mbombela'
+ ],
+ 'fr' => [
+ 'New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix',
+ 'Philadelphie', 'San Antonio', 'San Diego', 'Dallas', 'San José',
+ 'Toronto', 'Vancouver', 'Montréal', 'Calgary', 'Edmonton',
+ 'Ottawa', 'Winnipeg', 'Québec', 'Hamilton', 'Kitchener',
+ 'Londres', 'Birmingham', 'Manchester', 'Glasgow', 'Liverpool',
+ 'Édimbourg', 'Leeds', 'Sheffield', 'Bristol', 'Cardiff',
+ 'Sydney', 'Melbourne', 'Brisbane', 'Perth', 'Adélaïde',
+ 'Gold Coast', 'Canberra', 'Hobart', 'Darwin', 'Newcastle',
+ 'Berlin', 'Hambourg', 'Munich', 'Cologne', 'Francfort',
+ 'Stuttgart', 'Dusseldorf', 'Dortmund', 'Essen', 'Leipzig',
+ 'Paris', 'Marseille', 'Lyon', 'Toulouse', 'Nice',
+ 'Nantes', 'Montpellier', 'Strasbourg', 'Bordeaux', 'Lille',
+ 'Rome', 'Milan', 'Naples', 'Turin', 'Palermo',
+ 'Gênes', 'Bologne', 'Florence', 'Catane', 'Venise',
+ 'Madrid', 'Barcelone', 'Valence', 'Séville', 'Saragosse',
+ 'Malaga', 'Murcie', 'Palma', 'Las Palmas', 'Bilbao',
+ 'Bruxelles', 'Anvers', 'Gand', 'Bruges', 'Liège',
+ 'Namur', 'Ostende', 'Leuven', 'Hasselt', 'Malines',
+ 'Amsterdam', 'Rotterdam', 'La Haye', 'Utrecht', 'Eindhoven',
+ 'Groningue', 'Maastricht', 'Arnhem', 'Nijmegen', 'Haarlem',
+ 'Zurich', 'Genève', 'Berne', 'Bâle', 'Lausanne',
+ 'Lucerne', 'Saint-Moritz', 'Zoug', 'Neuchâtel', 'La Chaux-de-Fonds',
+ 'Tokyo', 'Osaka', 'Kyoto', 'Nagoya', 'Hiroshima',
+ 'Fukuoka', 'Kobe', 'Yokohama', 'Sapporo', 'Sendai',
+ 'Pékin', 'Shanghai', 'Guangzhou', 'Shenzhen', 'Chengdu',
+ 'Hong Kong', 'Hangzhou', 'Nankin', 'Wuhan', 'Xi’an',
+ 'Mumbai', 'Delhi', 'Bangalore', 'Hyderabad', 'Ahmedabad',
+ 'Chennai', 'Kolkata', 'Pune', 'Jaipur', 'Surat',
+ 'Sao Paulo', 'Rio de Janeiro', 'Salvador', 'Fortaleza', 'Belo Horizonte',
+ 'Brasilia', 'Curitiba', 'Manaus', 'Recife', 'Porto Alegre',
+ 'Johannesbourg', 'Le Cap', 'Durban', 'Prétoria', 'Port Elizabeth',
+ 'Bloemfontein', 'East London', 'Polokwane', 'Nelspruit', 'Mbombela'
+ ]
+ ];
+
+ if(is_null($lang) || !isset($map_lang_cities[$lang])) {
+ $all_cities = array_merge(
+ $map_lang_cities['en'],
+ $map_lang_cities['fr']
+ );
+
+ return $all_cities[array_rand($all_cities)];
+ }
+
+ return $map_lang_cities[$lang][array_rand($map_lang_cities[$lang])];
+ }
+
+ public static function addressCountry($lang = null): string {
+ $map_lang_countries = [
+ 'en' => [
+ 'Afghanistan', 'Albania', 'Algeria', 'Andorra', 'Angola',
+ 'Antigua and Barbuda', 'Argentina', 'Armenia', 'Australia', 'Austria',
+ 'Azerbaijan', 'Bahamas', 'Bahrain', 'Bangladesh', 'Barbados',
+ 'Belarus', 'Belgium', 'Belize', 'Benin', 'Bhutan',
+ 'Bolivia', 'Bosnia and Herzegovina', 'Botswana', 'Brazil', 'Brunei',
+ 'Bulgaria', 'Burkina Faso', 'Burundi', 'Cabo Verde', 'Cambodia',
+ 'Cameroon', 'Canada', 'Central African Republic', 'Chad', 'Chile',
+ 'China', 'Colombia', 'Comoros', 'Congo, Democratic Republic of the', 'Congo, Republic of the',
+ 'Costa Rica', 'Croatia', 'Cuba', 'Cyprus', 'Czech Republic',
+ 'Denmark', 'Djibouti', 'Dominica', 'Dominican Republic',
+ 'East Timor', 'Ecuador', 'Egypt', 'El Salvador', 'Equatorial Guinea',
+ 'Eritrea', 'Estonia', 'Eswatini', 'Ethiopia', 'Fiji',
+ 'Finland', 'France', 'Gabon', 'Gambia', 'Georgia',
+ 'Germany', 'Ghana', 'Greece', 'Grenada', 'Guatemala',
+ 'Guinea', 'Guinea-Bissau', 'Guyana', 'Haiti', 'Honduras',
+ 'Hungary', 'Iceland', 'India', 'Indonesia', 'Iran',
+ 'Iraq', 'Ireland', 'Israel', 'Italy', 'Jamaica',
+ 'Japan', 'Jordan', 'Kazakhstan', 'Kenya', 'Kiribati',
+ 'Korea, North', 'Korea, South', 'Kosovo', 'Kuwait', 'Kyrgyzstan',
+ 'Laos', 'Latvia', 'Lebanon', 'Lesotho', 'Liberia',
+ 'Libya', 'Liechtenstein', 'Lithuania', 'Luxembourg', 'Madagascar',
+ 'Malawi', 'Malaysia', 'Maldives', 'Mali', 'Malta',
+ 'Marshall Islands', 'Mauritania', 'Mauritius', 'Mexico', 'Micronesia',
+ 'Moldova', 'Monaco', 'Mongolia', 'Montenegro', 'Morocco',
+ 'Mozambique', 'Myanmar', 'Namibia', 'Nauru', 'Nepal',
+ 'Netherlands', 'New Zealand', 'Nicaragua', 'Niger', 'Nigeria',
+ 'North Macedonia', 'Norway', 'Oman', 'Pakistan', 'Palau',
+ 'Panama', 'Papua New Guinea', 'Paraguay', 'Peru', 'Philippines',
+ 'Poland', 'Portugal', 'Qatar', 'Romania', 'Russia',
+ 'Rwanda', 'Saint Kitts and Nevis', 'Saint Lucia', 'Saint Vincent and the Grenadines', 'Samoa',
+ 'San Marino', 'Sao Tome and Principe', 'Saudi Arabia', 'Senegal', 'Serbia',
+ 'Seychelles', 'Sierra Leone', 'Singapore', 'Slovakia', 'Slovenia',
+ 'Solomon Islands', 'Somalia', 'South Africa', 'South Sudan', 'Spain',
+ 'Sri Lanka', 'Sudan', 'Suriname', 'Sweden', 'Switzerland',
+ 'Syria', 'Taiwan', 'Tajikistan', 'Tanzania', 'Thailand',
+ 'Timor-Leste', 'Togo', 'Tonga', 'Trinidad and Tobago', 'Tunisia',
+ 'Turkey', 'Turkmenistan', 'Tuvalu', 'Uganda', 'Ukraine',
+ 'United Arab Emirates', 'United Kingdom', 'United States', 'Uruguay', 'Uzbekistan',
+ 'Vanuatu', 'Vatican City', 'Venezuela', 'Vietnam', 'Yemen',
+ 'Zambia', 'Zimbabwe'
+ ],
+ 'fr' => [
+ 'Afghanistan', 'Albanie', 'Algérie', 'Andorre', 'Angola',
+ 'Antigua-et-Barbuda', 'Argentine', 'Arménie', 'Australie', 'Autriche',
+ 'Azerbaïdjan', 'Bahamas', 'Bahreïn', 'Bangladesh', 'Barbade',
+ 'Bélarus', 'Belgique', 'Belize', 'Bénin', 'Bhoutan',
+ 'Bolivie', 'Bosnie-Herzégovine', 'Botswana', 'Brésil', 'Brunei',
+ 'Bulgarie', 'Burkina Faso', 'Burundi', 'Cap-Vert', 'Cambodge',
+ 'Cameroun', 'Canada', 'République Centrafricaine', 'Tchad', 'Chili',
+ 'Chine', 'Colombie', 'Comores', 'République Démocratique du Congo', 'République du Congo',
+ 'Côte d\'Ivoire', 'Costa Rica', 'Croatie', 'Cuba', 'Chypre',
+ 'République tchèque', 'Danemark', 'Djibouti', 'Dominique', 'République Dominicaine',
+ 'Timor oriental', 'Équateur', 'Égypte', 'El Salvador', 'Guinée équatoriale',
+ 'Érythrée', 'Estonie', 'Eswatini', 'Éthiopie', 'Fidji',
+ 'Finlande', 'France', 'Gabon', 'Gambie', 'Géorgie',
+ 'Allemagne', 'Ghana', 'Grèce', 'Grenade', 'Guatemala',
+ 'Guinée', 'Guinée-Bissau', 'Guyane', 'Haïti', 'Honduras',
+ 'Hongrie', 'Islande', 'Inde', 'Indonésie', 'Iran',
+ 'Irak', 'Irlande', 'Israël', 'Italie', 'Jamaïque',
+ 'Japon', 'Jordanie', 'Kazakhstan', 'Kenya', 'Kiribati',
+ 'Corée du Nord', 'Corée du Sud', 'Kosovo', 'Koweït', 'Kyrgyzstan',
+ 'Laos', 'Lettonie', 'Liban', 'Lesotho', 'Liberia',
+ 'Libye', 'Liechtenstein', 'Lituanie', 'Luxembourg', 'Madagascar',
+ 'Malawi', 'Malaisie', 'Maldives', 'Mali', 'Malte',
+ 'Îles Marshall', 'Mauritanie', 'Maurice', 'Mexique', 'Micronésie',
+ 'Moldova', 'Monaco', 'Mongolie', 'Monténégro', 'Maroc',
+ 'Mozambique', 'Myanmar', 'Namibie', 'Nauru', 'Népal',
+ 'Pays-Bas', 'Nouvelle-Zélande', 'Nicaragua', 'Niger', 'Nigeria',
+ 'Macédoine du Nord', 'Norvège', 'Oman', 'Pakistan', 'Palaos',
+ 'Panama', 'Papouasie-Nouvelle-Guinée', 'Paraguay', 'Pérou', 'Philippines',
+ 'Pologne', 'Portugal', 'Qatar', 'Roumanie', 'Russie',
+ 'Rwanda', 'Saint-Kitts-et-Nevis', 'Sainte-Lucie', 'Saint-Vincent-et-les-Grenadines', 'Samoa',
+ 'Saint-Marin', 'Sao Tomé-et-Principe', 'Arabie Saoudite', 'Sénégal', 'Serbie',
+ 'Seychelles', 'Sierra Leone', 'Singapour', 'Slovaquie', 'Slovénie',
+ 'Îles Salomon', 'Somalie', 'Afrique du Sud', 'Soudan du Sud', 'Espagne',
+ 'Sri Lanka', 'Soudan', 'Suriname', 'Suède', 'Suisse',
+ 'Syrie', 'Taïwan', 'Tadjikistan', 'Tanzanie', 'Thaïlande',
+ 'Timor-Leste', 'Togo', 'Tonga', 'Trinité-et-Tobago', 'Tunisie',
+ 'Turquie', 'Turkménistan', 'Tuvalu', 'Ouganda', 'Ukraine',
+ 'Émirats Arabes Unis', 'Royaume-Uni', 'États-Unis', 'Uruguay', 'Ouzbékistan',
+ 'Vanuatu', 'Vatican', 'Venezuela', 'Vietnam', 'Yémen',
+ 'Zambie', 'Zimbabwe'
+ ]
+ ];
+
+ if(is_null($lang) || !isset($map_lang_countries[$lang])) {
+ $all_countries = array_merge(
+ $map_lang_countries['en'],
+ $map_lang_countries['fr']
+ );
+
+ return $all_countries[array_rand($all_countries)];
+ }
+
+ return $map_lang_countries[$lang][array_rand($map_lang_countries[$lang])];
+ }
+
+ public static function address($lang = null): string {
+ return sprintf(
+ '%s, %s %s, %s',
+ self::addressStreet($lang),
+ self::addressZip(),
+ self::addressCity($lang),
+ self::addressCountry($lang)
+ );
+ }
+
+}
diff --git a/lib/equal/orm/Domain.class.php b/lib/equal/orm/Domain.class.php
index 45caf479c..a838b7b55 100644
--- a/lib/equal/orm/Domain.class.php
+++ b/lib/equal/orm/Domain.class.php
@@ -122,7 +122,7 @@ public function parse($object = [], $user = []) {
// handle object references as `value` part
if(is_string($value) && strpos($value, 'object.') == 0 ) {
- $target = substr($value, 0, strlen('object.'));
+ $target = substr($value, strlen('object.'));
if(!$object || !isset($object[$target])) {
continue;
}
@@ -145,7 +145,7 @@ public function parse($object = [], $user = []) {
}
// handle user references as `value` part
elseif(is_string($value) && strpos($value, 'user.') == 0) {
- $target = substr($value, 0, strlen('user.'));
+ $target = substr($value, strlen('user.'));
if(!$user || !isset($user[$target])) {
continue;
}
diff --git a/lib/equal/orm/usages/Usage.class.php b/lib/equal/orm/usages/Usage.class.php
index adda6606b..7022a082b 100644
--- a/lib/equal/orm/usages/Usage.class.php
+++ b/lib/equal/orm/usages/Usage.class.php
@@ -83,6 +83,10 @@ public function getConstraints(): array {
return [];
}
+ public function generateRandomValue() {
+ return null;
+ }
+
final public function getName() : string {
return $this->usage_str;
}
diff --git a/lib/equal/orm/usages/UsageAmount.class.php b/lib/equal/orm/usages/UsageAmount.class.php
index dd27d90d3..340ee0002 100644
--- a/lib/equal/orm/usages/UsageAmount.class.php
+++ b/lib/equal/orm/usages/UsageAmount.class.php
@@ -6,8 +6,7 @@
*/
namespace equal\orm\usages;
-use equal\locale\Locale;
-use core\setting\Setting;
+use equal\data\DataGenerator;
class UsageAmount extends Usage {
@@ -61,4 +60,14 @@ public function getConstraints(): array {
];
}
+ public function generateRandomValue(): float {
+ switch($this->getSubtype()) {
+ case 'money':
+ case 'percent':
+ case 'rate':
+ return DataGenerator::realNumber($this->getPrecision(), $this->getScale());
+ }
+ return 0;
+ }
+
}
diff --git a/lib/equal/orm/usages/UsageArray.class.php b/lib/equal/orm/usages/UsageArray.class.php
index 23f6200d7..e35c1f576 100644
--- a/lib/equal/orm/usages/UsageArray.class.php
+++ b/lib/equal/orm/usages/UsageArray.class.php
@@ -26,4 +26,8 @@ public function getConstraints(): array {
];
}
+ public function generateRandomValue(): array {
+ return [];
+ }
+
}
diff --git a/lib/equal/orm/usages/UsageCountry.class.php b/lib/equal/orm/usages/UsageCountry.class.php
index b177eda74..3c00c81c9 100644
--- a/lib/equal/orm/usages/UsageCountry.class.php
+++ b/lib/equal/orm/usages/UsageCountry.class.php
@@ -9,6 +9,12 @@
class UsageCountry extends Usage {
+ private $numeric_country_codes = ['004','008','010','012','016','020','024','028','031','032','036','040','044','048','050','051','052','056','060','064','068','070','072','074','076','084','086','090','092','096','100','104','108','112','116','120','124','132','136','140','144','148','152','156','158','162','166','170','174','175','178','180','184','188','191','192','196','203','204','208','212','214','218','222','226','231','232','233','234','238','239','242','246','248','250','254','258','260','262','266','268','270','275','','276','288','292','296','300','304','308','312','316','320','324','328','332','334','336','340','344','348','352','356','360','364','368','372','376','380','384','388','392','398','400','404','408','410','414','417','418','422','426','428','430','434','438','440','442','446','450','454','458','462','466','470','474','478','480','484','492','496','498','499','500','504','508','512','516','520','524','528','531','533','534','535','540','548','554','558','562','566','570','574','578','580','581','583','584','585','586','591','598','600','604','608','612','616','620','624','626','630','634','638','642','643','646','652','654','659','660','662','663','666','670','674','678','682','686','688','690','694','702','703','704','705','706','710','716','724','728','729','732','740','744','748','752','756','760','762','764','768','772','776','780','784','788','792','795','796','798','800','804','807','818','826','831','832','833','834','840','850','854','858','860','862','876','882','887','894'];
+
+ private $three_letters_country_codes = ['ABW','AFG','AGO','AIA','ALA','ALB','AND','ARE','ARG','ARM','ASM','ATA','ATF','ATG','AUS','AUT','AZE','BDI','BEL','BEN','BES','BFA','BGD','BGR','BHR','BHS','BIH','BLM','BLR','BLZ','BMU','BOL','BRA','BRB','BRN','BTN','BVT','BWA','CAF','CAN','CCK','CHE','CHL','CHN','CIV','CMR','COD','COG','COK','COL','COM','CPV','CRI','CUB','CUW','CXR','CYM','CYP','CZE','DEU','DJI','DMA','DNK','DOM','DZA','ECU','EGY','ERI','ESH','ESP','EST','ETH','FIN','FJI','FLK','FRA','FRO','FSM','GAB','GBR','GEO','GGY','GHA','GIB','GIN','GLP','GMB','GNB','GNQ','GRC','GRD','GRL','GTM','GUF','GUM','GUY','HKG','HMD','HND','HRV','HTI','HUN','IDN','IMN','IND','IOT','IRL','IRN','IRQ','ISL','ISR','ITA','JAM','JEY','JOR','JPN','KAZ','KEN','KGZ','KHM','KIR','KNA','KOR','KWT','LAO','LBN','LBR','LBY','LCA','LIE','LKA','LSO','LTU','LUX','LVA','MAC','MAF','MAR','MCO','MDA','MDG','MDV','MEX','MHL','MKD','MLI','MLT','MMR','MNE','MNG','MNP','MOZ','MRT','MSR','MTQ','MUS','MWI','MYS','MYT','NAM','NCL','NER','NFK','NGA','NIC','NIU','NLD','NOR','NPL','NRU','NZL','OMN','PAK','PAN','PCN','PER','PHL','PLW','PNG','POL','PRI','PRK','PRT','PRY','PSE','PYF','QAT','REU','ROU','RUS','RWA','SAU','SDN','SEN','SGP','SGS','SHN','SJM','SLB','SLE','SLV','SMR','SOM','SPM','SRB','SSD','STP','SUR','SVK','SVN','SWE','SWZ','SXM','SYC','SYR','TCA','TCD','TGO','THA','TJK','TKL','TKM','TLS','TON','TTO','TUN','TUR','TUV','TWN','TZA','UGA','UKR','UMI','URY','USA','UZB','VAT','VCT','VEN','VGB','VIR','VNM','VUT','WLF','WSM','YEM','ZAF','ZMB','ZWE'];
+
+ private $two_letters_country_codes = ['AF','AX','AL','DZ','AS','AD','AO','AI','AQ','AG','AR','AM','AW','AU','AT','AZ','BS','BH','BD','BB','BY','BE','BZ','BJ','BM','BT','BO','BA','BW','BV','BR','IO','BN','BG','BF','BI','KH','CM','CA','CV','KY','CF','TD','CL','CN','CX','CC','CO','KM','CG','CD','CK','CR','CI','HR','CU','CY','CZ','DK','DJ','DM','DO','EC','EG','SV','GQ','ER','EE','ET','FK','FO','FJ','FI','FR','GF','PF','TF','GA','GM','GE','DE','GH','GI','GR','GL','GD','GP','GU','GT','GG','GN','GW','GY','HT','HM','VA','HN','HK','HU','IS','IN','ID','IR','IQ','IE','IM','IL','IT','JM','JP','JE','JO','KZ','KE','KI','KR','KW','KG','LA','LV','LB','LS','LR','LY','LI','LT','LU','MO','MK','MG','MW','MY','MV','ML','MT','MH','MQ','MR','MU','YT','MX','FM','MD','MC','MN','ME','MS','MA','MZ','MM','NA','NR','NP','NL','AN','NC','NZ','NI','NE','NG','NU','NF','MP','NO','OM','PK','PW','PS','PA','PG','PY','PE','PH','PN','PL','PT','PR','QA','RE','RO','RU','RW','BL','SH','KN','LC','MF','PM','VC','WS','SM','ST','SA','SN','RS','SC','SL','SG','SK','SI','SB','SO','ZA','GS','ES','LK','SD','SR','SJ','SZ','SE','CH','SY','TW','TJ','TZ','TH','TL','TG','TK','TO','TT','TN','TR','TM','TC','TV','UG','UA','AE','GB','US','UM','UY','UZ','VU','VE','VN','VG','VI','WF','EH','YE','ZM','ZW'];
+
public function __construct(string $usage_str) {
parent::__construct($usage_str);
if($this->length == 0) {
@@ -22,7 +28,7 @@ public function getConstraints(): array {
'invalid_country' => [
'message' => 'Value is not a 3-digits country code (iso-3166-1 numeric).',
'function' => function($value) {
- return (in_array($value, ['004','008','010','012','016','020','024','028','031','032','036','040','044','048','050','051','052','056','060','064','068','070','072','074','076','084','086','090','092','096','100','104','108','112','116','120','124','132','136','140','144','148','152','156','158','162','166','170','174','175','178','180','184','188','191','192','196','203','204','208','212','214','218','222','226','231','232','233','234','238','239','242','246','248','250','254','258','260','262','266','268','270','275','','276','288','292','296','300','304','308','312','316','320','324','328','332','334','336','340','344','348','352','356','360','364','368','372','376','380','384','388','392','398','400','404','408','410','414','417','418','422','426','428','430','434','438','440','442','446','450','454','458','462','466','470','474','478','480','484','492','496','498','499','500','504','508','512','516','520','524','528','531','533','534','535','540','548','554','558','562','566','570','574','578','580','581','583','584','585','586','591','598','600','604','608','612','616','620','624','626','630','634','638','642','643','646','652','654','659','660','662','663','666','670','674','678','682','686','688','690','694','702','703','704','705','706','710','716','724','728','729','732','740','744','748','752','756','760','762','764','768','772','776','780','784','788','792','795','796','798','800','804','807','818','826','831','832','833','834','840','850','854','858','860','862','876','882','887','894']));
+ return (in_array($value, $this->numeric_country_codes));
}
]
];
@@ -34,7 +40,7 @@ public function getConstraints(): array {
'invalid_country' => [
'message' => 'Value is not a 3-letters country code (iso-3166-1 alpha-3).',
'function' => function($value) {
- return (in_array($value, ['ABW','AFG','AGO','AIA','ALA','ALB','AND','ARE','ARG','ARM','ASM','ATA','ATF','ATG','AUS','AUT','AZE','BDI','BEL','BEN','BES','BFA','BGD','BGR','BHR','BHS','BIH','BLM','BLR','BLZ','BMU','BOL','BRA','BRB','BRN','BTN','BVT','BWA','CAF','CAN','CCK','CHE','CHL','CHN','CIV','CMR','COD','COG','COK','COL','COM','CPV','CRI','CUB','CUW','CXR','CYM','CYP','CZE','DEU','DJI','DMA','DNK','DOM','DZA','ECU','EGY','ERI','ESH','ESP','EST','ETH','FIN','FJI','FLK','FRA','FRO','FSM','GAB','GBR','GEO','GGY','GHA','GIB','GIN','GLP','GMB','GNB','GNQ','GRC','GRD','GRL','GTM','GUF','GUM','GUY','HKG','HMD','HND','HRV','HTI','HUN','IDN','IMN','IND','IOT','IRL','IRN','IRQ','ISL','ISR','ITA','JAM','JEY','JOR','JPN','KAZ','KEN','KGZ','KHM','KIR','KNA','KOR','KWT','LAO','LBN','LBR','LBY','LCA','LIE','LKA','LSO','LTU','LUX','LVA','MAC','MAF','MAR','MCO','MDA','MDG','MDV','MEX','MHL','MKD','MLI','MLT','MMR','MNE','MNG','MNP','MOZ','MRT','MSR','MTQ','MUS','MWI','MYS','MYT','NAM','NCL','NER','NFK','NGA','NIC','NIU','NLD','NOR','NPL','NRU','NZL','OMN','PAK','PAN','PCN','PER','PHL','PLW','PNG','POL','PRI','PRK','PRT','PRY','PSE','PYF','QAT','REU','ROU','RUS','RWA','SAU','SDN','SEN','SGP','SGS','SHN','SJM','SLB','SLE','SLV','SMR','SOM','SPM','SRB','SSD','STP','SUR','SVK','SVN','SWE','SWZ','SXM','SYC','SYR','TCA','TCD','TGO','THA','TJK','TKL','TKM','TLS','TON','TTO','TUN','TUR','TUV','TWN','TZA','UGA','UKR','UMI','URY','USA','UZB','VAT','VCT','VEN','VGB','VIR','VNM','VUT','WLF','WSM','YEM','ZAF','ZMB','ZWE']));
+ return (in_array($value, $this->three_letters_country_codes));
}
]
];
@@ -45,11 +51,25 @@ public function getConstraints(): array {
'invalid_country' => [
'message' => 'Value is not a 2-letters country code (iso-3166-1 alpha-2).',
'function' => function($value) {
- return (in_array($value, ['AF','AX','AL','DZ','AS','AD','AO','AI','AQ','AG','AR','AM','AW','AU','AT','AZ','BS','BH','BD','BB','BY','BE','BZ','BJ','BM','BT','BO','BA','BW','BV','BR','IO','BN','BG','BF','BI','KH','CM','CA','CV','KY','CF','TD','CL','CN','CX','CC','CO','KM','CG','CD','CK','CR','CI','HR','CU','CY','CZ','DK','DJ','DM','DO','EC','EG','SV','GQ','ER','EE','ET','FK','FO','FJ','FI','FR','GF','PF','TF','GA','GM','GE','DE','GH','GI','GR','GL','GD','GP','GU','GT','GG','GN','GW','GY','HT','HM','VA','HN','HK','HU','IS','IN','ID','IR','IQ','IE','IM','IL','IT','JM','JP','JE','JO','KZ','KE','KI','KR','KW','KG','LA','LV','LB','LS','LR','LY','LI','LT','LU','MO','MK','MG','MW','MY','MV','ML','MT','MH','MQ','MR','MU','YT','MX','FM','MD','MC','MN','ME','MS','MA','MZ','MM','NA','NR','NP','NL','AN','NC','NZ','NI','NE','NG','NU','NF','MP','NO','OM','PK','PW','PS','PA','PG','PY','PE','PH','PN','PL','PT','PR','QA','RE','RO','RU','RW','BL','SH','KN','LC','MF','PM','VC','WS','SM','ST','SA','SN','RS','SC','SL','SG','SK','SI','SB','SO','ZA','GS','ES','LK','SD','SR','SJ','SZ','SE','CH','SY','TW','TJ','TZ','TH','TL','TG','TK','TO','TT','TN','TR','TM','TC','TV','UG','UA','AE','GB','US','UM','UY','UZ','VU','VE','VN','VG','VI','WF','EH','YE','ZM','ZW']));
+ return (in_array($value, $this->two_letters_country_codes));
}
]
];
}
}
+ public function generateRandomValue(): string {
+ if($this->getSubtype() == 'country.numeric') {
+ $country_identifiers = $this->numeric_country_codes;
+ }
+ elseif($this->getLength() === 3) {
+ $country_identifiers = $this->three_letters_country_codes;
+ }
+ else {
+ $country_identifiers = $this->two_letters_country_codes;
+ }
+
+ return $country_identifiers[array_rand($country_identifiers)];
+ }
+
}
diff --git a/lib/equal/orm/usages/UsageCurrency.class.php b/lib/equal/orm/usages/UsageCurrency.class.php
index 77f88f410..151d7bdf6 100644
--- a/lib/equal/orm/usages/UsageCurrency.class.php
+++ b/lib/equal/orm/usages/UsageCurrency.class.php
@@ -9,6 +9,10 @@
class UsageCurrency extends Usage {
+ private $three_digits_country_codes = ['004','008','010','012','016','020','024','028','031','032','036','040','044','048','050','051','052','056','060','064','068','070','072','074','076','084','086','090','092','096','100','104','108','112','116','120','124','132','136','140','144','148','152','156','158','162','166','170','174','175','178','180','184','188','191','192','196','203','204','208','212','214','218','222','226','231','232','233','234','238','239','242','246','248','250','254','258','260','262','266','268','270','275','','276','288','292','296','300','304','308','312','316','320','324','328','332','334','336','340','344','348','352','356','360','364','368','372','376','380','384','388','392','398','400','404','408','410','414','417','418','422','426','428','430','434','438','440','442','446','450','454','458','462','466','470','474','478','480','484','492','496','498','499','500','504','508','512','516','520','524','528','531','533','534','535','540','548','554','558','562','566','570','574','578','580','581','583','584','585','586','591','598','600','604','608','612','616','620','624','626','630','634','638','642','643','646','652','654','659','660','662','663','666','670','674','678','682','686','688','690','694','702','703','704','705','706','710','716','724','728','729','732','740','744','748','752','756','760','762','764','768','772','776','780','784','788','792','795','796','798','800','804','807','818','826','831','832','833','834','840','850','854','858','860','862','876','882','887','894'];
+
+ private $three_letters_currency_codes = ['ADF','ADP','AED','AFA','AFN','ALL','AMD','ANG','AOA','AOK','AON','AOR','ARP','ARS','ATS','AUD','AWG','AZM','AZN','BAM','BBD','BDT','BEF','BGL','BGN','BHD','BIF','BMD','BND','BOB','BOP','BOV','BRL','BRR','BSD','BTN','BWP','BYB','BYR','BYN','BZD','CAD','CDF','CHE','CHF','CHW','CLF','CLP','CNY','COP','COU','CRC','CSD','CSK','CUC','CUP','CVE','CYP','CZK','DEM','DJF','DKK','DOP','DZD','ECS','ECV','EEK','EGP','ERN','ESP','ETB','EUR','FIM','FJD','FKP','FRF','GBP','GEL','GHS','GIP','GMD','GNF','GRD','GTQ','GWP','GYD','HKD','HNL','HRK','HTG','HUF','IDR','IEP','ILS','INR','IQD','IRR','ISK','ITL','JMD','JOD','JPY','KES','KGS','KHR','KMF','KPW','KRW','KZT','KWD','KYD','LAK','LBP','LKR','LRD','LSL','LTL','LUF','LVL','LVR','LYD','MAD','MDL','MGA','MGF','MKD','MMK','MNT','MOP','MRO','MRU','MTL','MUR','MVR','MWK','MXN','MXV','MYR','MZE','MZM','MZN','NAD','NGN','NHF','NIC','NIO','NLG','NOK','NPR','NZD','OMR','PAB','PEN','PES','PGK','PHP','PKR','PLN','PLZ','PTE','PYG','QAR','ROL','RON','RSD','RUB','RWF','SAR','SBD','SCR','SDD','SDG','SDP','SEK','SGD','SHP','SIT','SKK','SLL','SML','SOS','SRD','SSP','STD','SUB','SUR','SVC','SYP','SZL','THB','TJS','TMM','TMT','TND','TOP','TPE','TRL','TRY','TTD','TWD','TZS','UAH','UGX','USD','USN','USS','UYU','UYW','UZS','VAL','VEB','VEF','VES','VND','VUV','WST','XAF','XAG','XAU','XBA','XBB','XBC','XBD','XCD','XDR','XEU','XFO','XFU','XOF','XPD','XPF','XPT','XSU','XUA','YER','YUD','YUM','ZAR','ZMK','ZWD','ZWL','ZWR'];
+
public function __construct(string $usage_str) {
parent::__construct($usage_str);
if($this->length == 0) {
@@ -22,7 +26,7 @@ public function getConstraints(): array {
'invalid_currency' => [
'message' => 'Value is not a 3-digits country code (as of iso-3166-1).',
'function' => function($value) {
- return (in_array($value, ['004','008','010','012','016','020','024','028','031','032','036','040','044','048','050','051','052','056','060','064','068','070','072','074','076','084','086','090','092','096','100','104','108','112','116','120','124','132','136','140','144','148','152','156','158','162','166','170','174','175','178','180','184','188','191','192','196','203','204','208','212','214','218','222','226','231','232','233','234','238','239','242','246','248','250','254','258','260','262','266','268','270','275','','276','288','292','296','300','304','308','312','316','320','324','328','332','334','336','340','344','348','352','356','360','364','368','372','376','380','384','388','392','398','400','404','408','410','414','417','418','422','426','428','430','434','438','440','442','446','450','454','458','462','466','470','474','478','480','484','492','496','498','499','500','504','508','512','516','520','524','528','531','533','534','535','540','548','554','558','562','566','570','574','578','580','581','583','584','585','586','591','598','600','604','608','612','616','620','624','626','630','634','638','642','643','646','652','654','659','660','662','663','666','670','674','678','682','686','688','690','694','702','703','704','705','706','710','716','724','728','729','732','740','744','748','752','756','760','762','764','768','772','776','780','784','788','792','795','796','798','800','804','807','818','826','831','832','833','834','840','850','854','858','860','862','876','882','887','894']));
+ return (in_array($value, $this->three_digits_country_codes));
}
]
];
@@ -34,13 +38,21 @@ public function getConstraints(): array {
default:
return [
'invalid_currency' => [
- 'message' => 'Value is not a 2-letters language code (as of iso-4217 alpha-3).',
+ 'message' => 'Value is not a 3-letters currency code (as of iso-4217 alpha-3).',
'function' => function($value) {
- return (in_array($value, ['ADF','ADP','AED','AFA','AFN','ALL','AMD','ANG','AOA','AOK','AON','AOR','ARP','ARS','ATS','AUD','AWG','AZM','AZN','BAM','BBD','BDT','BEF','BGL','BGN','BHD','BIF','BMD','BND','BOB','BOP','BOV','BRL','BRR','BSD','BTN','BWP','BYB','BYR','BYN','BZD','CAD','CDF','CHE','CHF','CHW','CLF','CLP','CNY','COP','COU','CRC','CSD','CSK','CUC','CUP','CVE','CYP','CZK','DEM','DJF','DKK','DOP','DZD','ECS','ECV','EEK','EGP','ERN','ESP','ETB','EUR','FIM','FJD','FKP','FRF','GBP','GEL','GHS','GIP','GMD','GNF','GRD','GTQ','GWP','GYD','HKD','HNL','HRK','HTG','HUF','IDR','IEP','ILS','INR','IQD','IRR','ISK','ITL','JMD','JOD','JPY','KES','KGS','KHR','KMF','KPW','KRW','KZT','KWD','KYD','LAK','LBP','LKR','LRD','LSL','LTL','LUF','LVL','LVR','LYD','MAD','MDL','MGA','MGF','MKD','MMK','MNT','MOP','MRO','MRU','MTL','MUR','MVR','MWK','MXN','MXV','MYR','MZE','MZM','MZN','NAD','NGN','NHF','NIC','NIO','NLG','NOK','NPR','NZD','OMR','PAB','PEN','PES','PGK','PHP','PKR','PLN','PLZ','PTE','PYG','QAR','ROL','RON','RSD','RUB','RWF','SAR','SBD','SCR','SDD','SDG','SDP','SEK','SGD','SHP','SIT','SKK','SLL','SML','SOS','SRD','SSP','STD','SUB','SUR','SVC','SYP','SZL','THB','TJS','TMM','TMT','TND','TOP','TPE','TRL','TRY','TTD','TWD','TZS','UAH','UGX','USD','USN','USS','UYU','UYW','UZS','VAL','VEB','VEF','VES','VND','VUV','WST','XAF','XAG','XAU','XBA','XBB','XBC','XBD','XCD','XDR','XEU','XFO','XFU','XOF','XPD','XPF','XPT','XSU','XUA','YER','YUD','YUM','ZAR','ZMK','ZWD','ZWL','ZWR']));
+ return (in_array($value, $this->three_letters_currency_codes));
}
]
];
}
}
+ public function generateRandomValue(): string {
+ if($this->getSubtype() == 'iso-4217.numeric') {
+ return $this->three_digits_country_codes[array_rand($this->three_digits_country_codes)];
+ }
+
+ return $this->three_letters_currency_codes[array_rand($this->three_letters_currency_codes)];
+ }
+
}
diff --git a/lib/equal/orm/usages/UsageDate.class.php b/lib/equal/orm/usages/UsageDate.class.php
index afdeb5547..b53dbb244 100644
--- a/lib/equal/orm/usages/UsageDate.class.php
+++ b/lib/equal/orm/usages/UsageDate.class.php
@@ -79,4 +79,30 @@ public function getConstraints(): array {
return $constraints;
}
+ public function generateRandomValue(): int {
+ switch($this->getSubtype(0)) {
+ case 'day':
+ return mt_rand(1, 31);
+ case 'weekday.mon':
+ return mt_rand(1, 7);
+ case 'weekday.sun':
+ return mt_rand(0, 6);
+ case 'month':
+ return mt_rand(1, 12);
+ case 'year':
+ return mt_rand(1, 9999);
+ case 'yearweek':
+ return mt_rand(1, 52);
+ case 'yearday':
+ return mt_rand(1, 365);
+ case 'time':
+ case 'plain':
+ default:
+ $start_timestamp = strtotime('1970-01-01 00:00:00');
+ $end_timestamp = time();
+
+ return mt_rand($start_timestamp, $end_timestamp);
+ }
+ }
+
}
diff --git a/lib/equal/orm/usages/UsageEmail.class.php b/lib/equal/orm/usages/UsageEmail.class.php
index 3623190d6..5e5eb9840 100644
--- a/lib/equal/orm/usages/UsageEmail.class.php
+++ b/lib/equal/orm/usages/UsageEmail.class.php
@@ -7,6 +7,8 @@
namespace equal\orm\usages;
+use equal\data\DataGenerator;
+
class UsageEmail extends Usage {
public function __construct(string $usage_str) {
@@ -39,4 +41,8 @@ public function getConstraints(): array {
];
}
+ public function generateRandomValue(): string {
+ return DataGenerator::email();
+ }
+
}
diff --git a/lib/equal/orm/usages/UsageLanguage.class.php b/lib/equal/orm/usages/UsageLanguage.class.php
index e86272c93..90ead5142 100644
--- a/lib/equal/orm/usages/UsageLanguage.class.php
+++ b/lib/equal/orm/usages/UsageLanguage.class.php
@@ -9,6 +9,10 @@
class UsageLanguage extends Usage {
+ private $three_letters_langue_codes = ['aar','abk','ace','ach','ada','ady','afa','afh','afr','ain','aka','akk','alb','sqi','ale','alg','alt','amh','ang','anp','apa','ara','arc','arg','arm','hye','arn','arp','art','arw','asm','ast','ath','aus','ava','ave','awa','aym','aze','bad','bai','bak','bal','bam','ban','baq','eus','bas','bat','bej','bel','bem','ben','ber','bho','bih','bik','bin','bis','bla','bnt','tib','bod','bos','bra','bre','btk','bua','bug','bul','bur','mya','byn','cad','cai','car','cat','cau','ceb','cel','cze','ces','cha','chb','che','chg','chi','zho','chk','chm','chn','cho','chp','chr','chu','chv','chy','cmc','cnr','cop','cor','cos','cpe','cpf','cpp','cre','crh','crp','csb','cus','wel','cym','cze','ces','dak','dan','dar','day','del','den','ger','deu','dgr','din','div','doi','dra','dsb','dua','dum','dut','nld','dyu','dzo','efi','egy','eka','gre','ell','elx','eng','enm','epo','est','baq','eus','ewe','ewo','fan','fao','per','fas','fat','fij','fil','fin','fiu','fon','fra','fre','frm','fro','frr','frs','fry','ful','fur','gaa','gay','gba','gem','geo','kat','ger','deu','gez','gil','gla','gle','glg','glv','gmh','goh','gon','gor','got','grb','grc','gre','ell','grn','gsw','guj','gwi','hai','hat','hau','haw','heb','her','hil','him','hin','hit','hmn','hmo','hrv','hsb','hun','hup','arm','hye','iba','ibo','ice','isl','ido','iii','ijo','iku','ile','ilo','ina','inc','ind','ine','inh','ipk','ira','iro','ice','isl','ita','jav','jbo','jpn','jpr','jrb','kaa','kab','kac','kal','kam','kan','kar','kas','geo','kat','kau','kaw','kaz','kbd','kha','khi','khm','kho','kik','kin','kir','kmb','kok','kom','kon','kor','kos','kpe','krc','krl','kro','kru','kua','kum','kur','kut','lad','lah','lam','lao','lat','lav','lez','lim','lin','lit','lol','loz','ltz','lua','lub','lug','lui','lun','luo','lus','mac','mkd','mad','mag','mah','mai','mak','mal','man','mao','mri','map','mar','mas','may','msa','mdf','mdr','men','mga','mic','min','mis','mac','mkd','mkh','mlg','mlt','mnc','mni','mno','moh','mon','mos','mao','mri','may','msa','mul','mun','mus','mwl','mwr','bur','mya','myn','myv','nah','nai','nap','nau','nav','nbl','nde','ndo','nds','nep','new','nia','nic','niu','dut','nld','nno','nob','nog','non','nor','nqo','nso','nub','nwc','nya','nym','nyn','nyo','nzi','oci','oji','ori','orm','osa','oss','ota','oto','paa','pag','pal','pam','pan','pap','pau','peo','per','fas','phi','phn','pli','pol','pon','por','pra','pro','pus','qaa','que','raj','rap','rar','roa','roh','rom','rum','ron','rum','ron','run','rup','rus','sad','sag','sah','sai','sal','sam','san','sas','sat','scn','sco','sel','sem','sga','sgn','shn','sid','sin','sio','sit','sla','slo','slk','slo','slk','slv','sma','sme','smi','smj','smn','smo','sms','sna','snd','snk','sog','som','son','sot','spa','alb','sqi','srd','srn','srp','srr','ssa','ssw','suk','sun','sus','sux','swa','swe','syc','syr','tah','tai','tam','tat','tel','tem','ter','tet','tgk','tgl','tha','tib','bod','tig','tir','tiv','tkl','tlh','tli','tmh','tog','ton','tpi','tsi','tsn','tso','tuk','tum','tup','tur','tut','tvl','twi','tyv','udm','uga','uig','ukr','umb','und','urd','uzb','vai','ven','vie','vol','vot','wak','wal','war','was','wel','cym','wen','wln','wol','xal','xho','yao','yap','yid','yor','ypk','zap','zbl','zen','zgh','zha','chi','zho','znd','zul','zun','zxx','zza'];
+
+ private $two_letters_language_codes = ['aa','ab','af','ak','sq','am','ar','an','hy','as','av','ae','ay','az','ba','bm','eu','be','bn','bh','bi','bo','bs','br','bg','my','ca','cs','ch','ce','zh','cu','cv','kw','co','cr','cy','cs','da','de','dv','nl','dz','el','en','eo','et','eu','ee','fo','fa','fj','fi','fr','fy','ff','ka','de','gd','ga','gl','gv','el','gn','gu','ht','ha','he','hz','hi','ho','hr','hu','hy','ig','is','io','ii','iu','ie','ia','id','ik','is','it','jv','ja','kl','kn','ks','ka','kr','kk','km','ki','rw','ky','kv','kg','ko','kj','ku','lo','la','lv','li','ln','lt','lb','lu','lg','mk','mh','ml','mi','mr','ms','mk','mg','mt','mn','mi','ms','my','na','nv','nr','nd','ng','ne','nl','nn','nb','no','ny','oc','oj','or','om','os','pa','fa','pi','pl','pt','ps','qu','rm','ro','ro','rn','ru','sg','sa','si','sk','sk','sl','se','sm','sn','sd','so','st','es','sq','sc','sr','ss','su','sw','sv','ty','ta','tt','te','tg','tl','th','bo','ti','to','tn','ts','tk','tr','tw','ug','uk','ur','uz','ve','vi','vo','cy','wa','wo','xh','yi','yo','za','zh','zu'];
+
public function __construct(string $usage_str) {
parent::__construct($usage_str);
if($this->length == 0) {
@@ -24,7 +28,7 @@ public function getConstraints(): array {
'invalid_language' => [
'message' => 'Value is not a 3-letters language code (iso-639-2 alpha-3).',
'function' => function($value) {
- return (in_array($value, ['aar','abk','ace','ach','ada','ady','afa','afh','afr','ain','aka','akk','alb','sqi','ale','alg','alt','amh','ang','anp','apa','ara','arc','arg','arm','hye','arn','arp','art','arw','asm','ast','ath','aus','ava','ave','awa','aym','aze','bad','bai','bak','bal','bam','ban','baq','eus','bas','bat','bej','bel','bem','ben','ber','bho','bih','bik','bin','bis','bla','bnt','tib','bod','bos','bra','bre','btk','bua','bug','bul','bur','mya','byn','cad','cai','car','cat','cau','ceb','cel','cze','ces','cha','chb','che','chg','chi','zho','chk','chm','chn','cho','chp','chr','chu','chv','chy','cmc','cnr','cop','cor','cos','cpe','cpf','cpp','cre','crh','crp','csb','cus','wel','cym','cze','ces','dak','dan','dar','day','del','den','ger','deu','dgr','din','div','doi','dra','dsb','dua','dum','dut','nld','dyu','dzo','efi','egy','eka','gre','ell','elx','eng','enm','epo','est','baq','eus','ewe','ewo','fan','fao','per','fas','fat','fij','fil','fin','fiu','fon','fra','fre','frm','fro','frr','frs','fry','ful','fur','gaa','gay','gba','gem','geo','kat','ger','deu','gez','gil','gla','gle','glg','glv','gmh','goh','gon','gor','got','grb','grc','gre','ell','grn','gsw','guj','gwi','hai','hat','hau','haw','heb','her','hil','him','hin','hit','hmn','hmo','hrv','hsb','hun','hup','arm','hye','iba','ibo','ice','isl','ido','iii','ijo','iku','ile','ilo','ina','inc','ind','ine','inh','ipk','ira','iro','ice','isl','ita','jav','jbo','jpn','jpr','jrb','kaa','kab','kac','kal','kam','kan','kar','kas','geo','kat','kau','kaw','kaz','kbd','kha','khi','khm','kho','kik','kin','kir','kmb','kok','kom','kon','kor','kos','kpe','krc','krl','kro','kru','kua','kum','kur','kut','lad','lah','lam','lao','lat','lav','lez','lim','lin','lit','lol','loz','ltz','lua','lub','lug','lui','lun','luo','lus','mac','mkd','mad','mag','mah','mai','mak','mal','man','mao','mri','map','mar','mas','may','msa','mdf','mdr','men','mga','mic','min','mis','mac','mkd','mkh','mlg','mlt','mnc','mni','mno','moh','mon','mos','mao','mri','may','msa','mul','mun','mus','mwl','mwr','bur','mya','myn','myv','nah','nai','nap','nau','nav','nbl','nde','ndo','nds','nep','new','nia','nic','niu','dut','nld','nno','nob','nog','non','nor','nqo','nso','nub','nwc','nya','nym','nyn','nyo','nzi','oci','oji','ori','orm','osa','oss','ota','oto','paa','pag','pal','pam','pan','pap','pau','peo','per','fas','phi','phn','pli','pol','pon','por','pra','pro','pus','qaa','que','raj','rap','rar','roa','roh','rom','rum','ron','rum','ron','run','rup','rus','sad','sag','sah','sai','sal','sam','san','sas','sat','scn','sco','sel','sem','sga','sgn','shn','sid','sin','sio','sit','sla','slo','slk','slo','slk','slv','sma','sme','smi','smj','smn','smo','sms','sna','snd','snk','sog','som','son','sot','spa','alb','sqi','srd','srn','srp','srr','ssa','ssw','suk','sun','sus','sux','swa','swe','syc','syr','tah','tai','tam','tat','tel','tem','ter','tet','tgk','tgl','tha','tib','bod','tig','tir','tiv','tkl','tlh','tli','tmh','tog','ton','tpi','tsi','tsn','tso','tuk','tum','tup','tur','tut','tvl','twi','tyv','udm','uga','uig','ukr','umb','und','urd','uzb','vai','ven','vie','vol','vot','wak','wal','war','was','wel','cym','wen','wln','wol','xal','xho','yao','yap','yid','yor','ypk','zap','zbl','zen','zgh','zha','chi','zho','znd','zul','zun','zxx','zza']));
+ return (in_array($value, $this->three_letters_langue_codes));
}
]
];
@@ -35,11 +39,17 @@ public function getConstraints(): array {
'invalid_language' => [
'message' => 'Value is not a 2-letters language code (iso-639-1 alpha-2).',
'function' => function($value) {
- return (in_array($value, ['aa','ab','af','ak','sq','am','ar','an','hy','as','av','ae','ay','az','ba','bm','eu','be','bn','bh','bi','bo','bs','br','bg','my','ca','cs','ch','ce','zh','cu','cv','kw','co','cr','cy','cs','da','de','dv','nl','dz','el','en','eo','et','eu','ee','fo','fa','fj','fi','fr','fy','ff','ka','de','gd','ga','gl','gv','el','gn','gu','ht','ha','he','hz','hi','ho','hr','hu','hy','ig','is','io','ii','iu','ie','ia','id','ik','is','it','jv','ja','kl','kn','ks','ka','kr','kk','km','ki','rw','ky','kv','kg','ko','kj','ku','lo','la','lv','li','ln','lt','lb','lu','lg','mk','mh','ml','mi','mr','ms','mk','mg','mt','mn','mi','ms','my','na','nv','nr','nd','ng','ne','nl','nn','nb','no','ny','oc','oj','or','om','os','pa','fa','pi','pl','pt','ps','qu','rm','ro','ro','rn','ru','sg','sa','si','sk','sk','sl','se','sm','sn','sd','so','st','es','sq','sc','sr','ss','su','sw','sv','ty','ta','tt','te','tg','tl','th','bo','ti','to','tn','ts','tk','tr','tw','ug','uk','ur','uz','ve','vi','vo','cy','wa','wo','xh','yi','yo','za','zh','zu']));
+ return (in_array($value, $this->two_letters_language_codes));
}
]
];
}
}
+ public function generateRandomValue(): string {
+ $language_codes = $this->getLength() === 3 ? $this->three_letters_langue_codes : $this->two_letters_language_codes;
+
+ return $language_codes[array_rand($language_codes)];
+ }
+
}
diff --git a/lib/equal/orm/usages/UsageNumber.class.php b/lib/equal/orm/usages/UsageNumber.class.php
index 85ed4754e..99e6fcfde 100644
--- a/lib/equal/orm/usages/UsageNumber.class.php
+++ b/lib/equal/orm/usages/UsageNumber.class.php
@@ -6,7 +6,7 @@
*/
namespace equal\orm\usages;
-use equal\locale\Locale;
+use equal\data\DataGenerator;
class UsageNumber extends Usage {
@@ -91,4 +91,22 @@ public function getConstraints(): array {
}
}
+ /**
+ * @return bool|float|int|string|null
+ */
+ public function generateRandomValue() {
+ switch($this->getSubtype(0)) {
+ case 'boolean':
+ return DataGenerator::boolean();
+ case 'integer':
+ return DataGenerator::integer($this->getLength());
+ case 'real':
+ return DataGenerator::realNumber($this->getPrecision(), $this->getScale());
+ case 'hexadecimal':
+ return DataGenerator::hexadecimal($this->getLength());
+ }
+
+ return 0;
+ }
+
}
diff --git a/lib/equal/orm/usages/UsagePassword.class.php b/lib/equal/orm/usages/UsagePassword.class.php
index e81575472..88862a073 100644
--- a/lib/equal/orm/usages/UsagePassword.class.php
+++ b/lib/equal/orm/usages/UsagePassword.class.php
@@ -47,4 +47,15 @@ public function getConstraints(): array {
}
}
+ public function generateRandomValue(): string {
+ $password = '';
+ $dict = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
+ $len = strlen($dict) - 1;
+ for ($i = 0; $i < 10; $i++) {
+ $password .= $dict[mt_rand(0, $len)];
+ }
+
+ return $password;
+ }
+
}
diff --git a/lib/equal/orm/usages/UsagePhone.class.php b/lib/equal/orm/usages/UsagePhone.class.php
index 8af6dd26d..13aa598bd 100644
--- a/lib/equal/orm/usages/UsagePhone.class.php
+++ b/lib/equal/orm/usages/UsagePhone.class.php
@@ -7,6 +7,8 @@
namespace equal\orm\usages;
+use equal\data\DataGenerator;
+
class UsagePhone extends Usage {
public function __construct(string $usage_str) {
@@ -27,4 +29,8 @@ public function getConstraints(): array {
];
}
+ public function generateRandomValue(): string {
+ return DataGenerator::phoneNumberE164();
+ }
+
}
diff --git a/lib/equal/orm/usages/UsageText.class.php b/lib/equal/orm/usages/UsageText.class.php
index 1b449300a..8fa3d7f01 100644
--- a/lib/equal/orm/usages/UsageText.class.php
+++ b/lib/equal/orm/usages/UsageText.class.php
@@ -6,6 +6,8 @@
*/
namespace equal\orm\usages;
+use equal\data\DataGenerator;
+
class UsageText extends Usage {
/**
@@ -100,4 +102,13 @@ public function getConstraints(): array {
];
}
+ public function generateRandomValue(): string {
+ $max = $this->getMax();
+ if($max === 0) {
+ $max = $this->getLength();
+ }
+
+ return DataGenerator::plainText($this->getMin(), $max);
+ }
+
}
diff --git a/lib/equal/orm/usages/UsageTime.php b/lib/equal/orm/usages/UsageTime.php
index f76a0c02d..dbc3d692b 100644
--- a/lib/equal/orm/usages/UsageTime.php
+++ b/lib/equal/orm/usages/UsageTime.php
@@ -6,8 +6,7 @@
*/
namespace equal\orm\usages;
-use equal\locale\Locale;
-use core\setting\Setting;
+use equal\data\DataGenerator;
class UsageTime extends Usage {
@@ -23,4 +22,8 @@ public function getConstraints(): array {
return [];
}
+ public function generateRandomValue(): string {
+ return DataGenerator::time();
+ }
+
}
diff --git a/lib/equal/orm/usages/UsageUri.class.php b/lib/equal/orm/usages/UsageUri.class.php
index d8e014db8..3f0d3f738 100644
--- a/lib/equal/orm/usages/UsageUri.class.php
+++ b/lib/equal/orm/usages/UsageUri.class.php
@@ -7,6 +7,8 @@
namespace equal\orm\usages;
+use equal\data\DataGenerator;
+
class UsageUri extends Usage {
public function __construct(string $usage_str) {
@@ -94,4 +96,22 @@ public function getConstraints(): array {
return [];
}
+ public function generateRandomValue(): string {
+ switch($this->getSubtype()) {
+ case 'url.relative':
+ return DataGenerator::relativeUrl();
+ case 'url.tel':
+ return DataGenerator::urlTel();
+ case 'url.mailto':
+ return DataGenerator::urlMailto();
+ case 'urn.iban':
+ return DataGenerator::iban();
+ case 'urn.ean':
+ return DataGenerator::ean13();
+ case 'url':
+ default:
+ return DataGenerator::url();
+ }
+ }
+
}
diff --git a/packages/core/actions/init/anonymize.php b/packages/core/actions/init/anonymize.php
new file mode 100644
index 000000000..1ade4a3e6
--- /dev/null
+++ b/packages/core/actions/init/anonymize.php
@@ -0,0 +1,75 @@
+
+ Some Rights Reserved, Cedric Francoys, 2010-2021
+ Licensed under GNU LGPL 3 license
+*/
+
+list($params, $providers) = eQual::announce([
+ 'description' => 'Anonymize objects using json configuration files in "{package}/init/anonymize/".',
+ 'params' => [
+ 'package' => [
+ 'description' => 'Name of the package to anonymize.',
+ 'type' => 'string',
+ 'usage' => 'orm/package',
+ 'required' => true
+ ],
+ 'config_file' => [
+ 'description' => 'Name of the configuration file to use to anonymize objects.',
+ 'help' => 'Configuration file must match the format "{package}/init/anonymize/{config_file}.json".'
+ . ' If no config file specified, then all files of anonymize folder are used.',
+ 'type' => 'string'
+ ]
+ ],
+ 'response' => [
+ 'content-type' => 'application/json',
+ 'charset' => 'UTF-8',
+ 'accept-origin' => '*'
+ ],
+ 'access' => [
+ 'visibility' => 'protected'
+ ],
+ 'providers' => ['context']
+]);
+
+/**
+ * @var \equal\php\Context $context
+ */
+list('context' => $context) = $providers;
+
+$data_folder = "packages/{$params['package']}/init/anonymize";
+
+if(file_exists($data_folder) && is_dir($data_folder)) {
+ // handle JSON files
+ foreach(glob("$data_folder/*.json") as $json_file) {
+ if(isset($params['config_file']) && $params['config_file'] !== basename($json_file, '.json')) {
+ continue;
+ }
+
+ $data = file_get_contents($json_file);
+ $classes = json_decode($data, true);
+ if(!$classes) {
+ continue;
+ }
+ foreach($classes as $class) {
+ if(!isset($class['name'])) {
+ continue;
+ }
+
+ $anonymize_params = [
+ 'entity' => $class['name'],
+ ];
+ foreach(['lang', 'fields', 'relations', 'domain'] as $param_key) {
+ if(isset($class[$param_key])) {
+ $anonymize_params[$param_key] = $class[$param_key];
+ }
+ }
+
+ eQual::run('do', 'core_model_anonymize', $anonymize_params);
+ }
+ }
+}
+
+$context->httpResponse()
+ ->status(204)
+ ->send();
diff --git a/packages/core/actions/init/seed.php b/packages/core/actions/init/seed.php
new file mode 100644
index 000000000..eef32b50f
--- /dev/null
+++ b/packages/core/actions/init/seed.php
@@ -0,0 +1,79 @@
+
+ Some Rights Reserved, Cedric Francoys, 2010-2021
+ Licensed under GNU LGPL 3 license
+*/
+
+list($params, $providers) = eQual::announce([
+ 'description' => 'Seed objects for package using json configuration files in "{package}/init/seed/".',
+ 'params' => [
+ 'package' => [
+ 'description' => 'Name of the package to seed.',
+ 'type' => 'string',
+ 'usage' => 'orm/package',
+ 'required' => true
+ ],
+ 'config_file' => [
+ 'description' => 'Name of the configuration file to use to seed objects.',
+ 'help' => 'Configuration file must match the format "{package}/init/seed/{config_file}.json".'
+ . ' If no config file specified, then all files of seed folder are used.',
+ 'type' => 'string'
+ ]
+ ],
+ 'response' => [
+ 'content-type' => 'application/json',
+ 'charset' => 'UTF-8',
+ 'accept-origin' => '*'
+ ],
+ 'access' => [
+ 'visibility' => 'protected'
+ ],
+ 'constants' => ['DEFAULT_LANG'],
+ 'providers' => ['context']
+]);
+
+/**
+ * @var \equal\php\Context $context
+ */
+list('context' => $context) = $providers;
+
+$data_folder = "packages/{$params['package']}/init/seed";
+
+if(file_exists($data_folder) && is_dir($data_folder)) {
+ // handle JSON files
+ foreach(glob("$data_folder/*.json") as $json_file) {
+ if(isset($params['config_file']) && $params['config_file'] !== basename($json_file, '.json')) {
+ continue;
+ }
+
+ $data = file_get_contents($json_file);
+ $classes = json_decode($data, true);
+ if(!$classes) {
+ continue;
+ }
+ foreach($classes as $class) {
+ if(!isset($class['name'], $class['qty'])) {
+ continue;
+ }
+
+ $generate_params = [
+ 'entity' => $class['name'],
+ ];
+ foreach(['lang', 'fields', 'relations', 'add_to_domain_data'] as $param_key) {
+ if(isset($class[$param_key])) {
+ $generate_params[$param_key] = $class[$param_key];
+ }
+ }
+
+ $qty = is_array($class['qty']) ? mt_rand($class['qty'][0], $class['qty'][1]) : $class['qty'];
+ for($i = 0; $i < $qty; $i++) {
+ eQual::run('do', 'core_model_generate', $generate_params);
+ }
+ }
+ }
+}
+
+$context->httpResponse()
+ ->status(201)
+ ->send();
diff --git a/packages/core/actions/model/anonymize.php b/packages/core/actions/model/anonymize.php
new file mode 100644
index 000000000..9ac655c14
--- /dev/null
+++ b/packages/core/actions/model/anonymize.php
@@ -0,0 +1,135 @@
+
+ Some Rights Reserved, Cedric Francoys, 2010-2021
+ Licensed under GNU LGPL 3 license
+*/
+
+use equal\data\DataGenerator;
+
+list($params, $providers) = eQual::announce([
+ 'description' => "Anonymize an existing object with random data and given values.",
+ 'params' => [
+ 'entity' => [
+ 'description' => 'Full name (including namespace) of the class to return (e.g. \'core\\User\').',
+ 'type' => 'string',
+ 'required' => true
+ ],
+ 'fields' => [
+ 'description' => 'List of fields that must be anonymized.',
+ 'type' => 'array',
+ 'default' => []
+ ],
+ 'relations' => [
+ 'description' => 'How to handle the object relations (many2one and one2many)',
+ 'type' => 'array',
+ 'default' => []
+ ],
+ 'lang' => [
+ 'description ' => 'Specific language for multilang field.',
+ 'type' => 'string',
+ 'default' => constant('DEFAULT_LANG')
+ ],
+ 'domain' => [
+ 'description' => 'Criteria that results have to match (series of conjunctions)',
+ 'type' => 'array',
+ 'default' => []
+ ]
+ ],
+ 'response' => [
+ 'content-type' => 'application/json',
+ 'charset' => 'UTF-8',
+ 'accept-origin' => '*'
+ ],
+ 'access' => [
+ 'visibility' => 'protected'
+ ],
+ 'constants' => ['DEFAULT_LANG'],
+ 'providers' => ['context', 'orm']
+]);
+
+/**
+ * @var \equal\php\Context $context
+ * @var \equal\orm\ObjectManager $orm
+ */
+list('context' => $context, 'orm' => $orm) = $providers;
+
+$anonymized_values = [];
+
+$model = $orm->getModel($params['entity']);
+if(!$model) {
+ throw new Exception("unknown_entity", QN_ERROR_INVALID_PARAM);
+}
+
+$schema = $model->getSchema();
+
+$ids = $params['entity']::search($params['domain'])->ids();
+foreach($ids as $id) {
+ foreach($schema as $field => $conf) {
+ if(!($conf['sensitive'] ?? false) && !in_array($field, $params['fields'])) {
+ continue;
+ }
+
+ if(isset($conf['generate']) && method_exists($params['entity'], $conf['generate'])) {
+ $anonymized_values[$field] = $params['entity']::{$conf['generate']}();
+ }
+ else {
+ $required = $conf['required'] ?? false;
+ if(!$required && DataGenerator::boolean(0.05)) {
+ $anonymized_values[$field] = null;
+ }
+ else {
+ $anonymized_values[$field] = DataGenerator::generateByFieldConf($field, $conf, $params['lang']);
+ }
+ }
+ }
+
+ if(!empty($anonymized_values)) {
+ $instance = $params['entity']::id($id)
+ ->update($anonymized_values)
+ ->read(['id'])
+ ->first();
+ }
+
+ foreach($schema as $field => $conf) {
+ if(!in_array($conf['type'], ['one2many', 'many2one']) || !isset($params['relations'][$field])) {
+ continue;
+ }
+
+ $relation_params = [
+ 'entity' => $conf['foreign_object'],
+ 'lang' => $params['lang']
+ ];
+
+ foreach(['fields', 'relations', 'domain'] as $param_key) {
+ if(isset($params['relations'][$field][$param_key])) {
+ $relation_params[$param_key] = $params['relations'][$field][$param_key];
+ }
+ }
+
+ if(!isset($relation_params['domain'])) {
+ $relation_params['domain'] = [];
+ }
+
+ switch($conf['type']) {
+ case 'one2many':
+ $relation_params['domain'][] = [$conf['foreign_field'], '=', $id];
+ break;
+ case 'many2one':
+ $instance = $params['entity']::id($id)
+ ->read([$field])
+ ->first();
+
+ if(!is_null($instance[$field])) {
+ $relation_params['domain'][] = ['id', '=', $instance[$field]];
+ }
+ break;
+ }
+
+ eQual::run('do', 'core_model_anonymize', $relation_params);
+ }
+}
+
+$context->httpResponse()
+ ->status(204)
+ ->send();
diff --git a/packages/core/actions/model/generate.php b/packages/core/actions/model/generate.php
new file mode 100644
index 000000000..be52d083b
--- /dev/null
+++ b/packages/core/actions/model/generate.php
@@ -0,0 +1,366 @@
+
+ Some Rights Reserved, Cedric Francoys, 2010-2021
+ Licensed under GNU LGPL 3 license
+*/
+
+use equal\data\DataGenerator;
+use equal\orm\Domain;
+
+list($params, $providers) = eQual::announce([
+ 'description' => "Generate a new object with random data and given values.",
+ 'params' => [
+ 'entity' => [
+ 'description' => 'Full name (including namespace) of the class to return (e.g. \'core\\User\').',
+ 'type' => 'string',
+ 'required' => true
+ ],
+ 'fields' => [
+ 'description' => 'Associative array mapping fields to their related values.',
+ 'type' => 'array',
+ 'default' => []
+ ],
+ 'relations' => [
+ 'description' => 'How to handle the object relations (many2one, one2many and many2many)',
+ 'type' => 'array',
+ 'default' => []
+ ],
+ 'add_to_domain_data' => [
+ 'description' => 'Global domain data.',
+ 'type' => 'array',
+ 'default' => []
+ ],
+ 'domain_data' => [
+ 'description' => 'Global domain data.',
+ 'type' => 'array',
+ 'default' => []
+ ],
+ 'lang' => [
+ 'description ' => 'Specific language for multilang field.',
+ 'type' => 'string',
+ 'default' => constant('DEFAULT_LANG')
+ ]
+ ],
+ 'response' => [
+ 'content-type' => 'application/json',
+ 'charset' => 'UTF-8',
+ 'accept-origin' => '*'
+ ],
+ 'access' => [
+ 'visibility' => 'protected'
+ ],
+ 'constants' => ['DEFAULT_LANG'],
+ 'providers' => ['context', 'orm']
+]);
+
+/**
+ * @var \equal\php\Context $context
+ * @var \equal\orm\ObjectManager $orm
+ */
+list('context' => $context, 'orm' => $orm) = $providers;
+
+/**
+ * Methods
+ */
+
+$generateMany2One = function($field_conf, $relation_conf, $lang, $domain_data) {
+ $model_generate_params = [
+ 'entity' => $field_conf['foreign_object'],
+ 'lang' => $lang
+ ];
+ foreach(['fields', 'relations', 'add_to_domain_data'] as $param_key) {
+ if(isset($relation_conf[$param_key])) {
+ $model_generate_params[$param_key] = $relation_conf[$param_key];
+ }
+ }
+
+ if(!empty($domain_data)) {
+ $model_generate_params['domain_data'] = $domain_data;
+ }
+
+ return eQual::run('do', 'core_model_generate', $model_generate_params);
+};
+
+$generateMany2Many = function($qty, $field_conf, $relation_conf, $lang, $domain_data) {
+ $model_generate_params = [
+ 'entity' => $field_conf['foreign_object'],
+ 'lang' => $lang
+ ];
+ foreach(['fields', 'relations', 'add_to_domain_data'] as $param_key) {
+ if(isset($relation_conf[$param_key])) {
+ $model_generate_params[$param_key] = $relation_conf[$param_key];
+ }
+ }
+
+ if(!empty($domain_data)) {
+ $model_generate_params['domain_data'] = $domain_data;
+ }
+
+ $results = [];
+ for($i = 0; $i < $qty; $i++) {
+ $results[] = eQual::run('do', 'core_model_generate', $model_generate_params);
+ }
+
+ return $results;
+};
+
+$generateOne2Many = function($id, $qty, $field_conf, $relation_conf, $lang, $domain_data) {
+ $model_generate_params = [
+ 'entity' => $field_conf['foreign_object'],
+ 'lang' => $lang
+ ];
+ foreach(['fields', 'relations', 'add_to_domain_data'] as $param_key) {
+ if(isset($relation_conf[$param_key])) {
+ $model_generate_params[$param_key] = $relation_conf[$param_key];
+ }
+ }
+
+ if(!isset($model_generate_params['fields'])) {
+ $model_generate_params['fields'] = [];
+ }
+ $model_generate_params['fields'][$field_conf['foreign_field']] = $id;
+
+ if(!empty($domain_data)) {
+ $model_generate_params['domain_data'] = $domain_data;
+ }
+
+ $results = [];
+ for($i = 0; $i < $qty; $i++) {
+ $results[] = eQual::run('do', 'core_model_generate', $model_generate_params);
+ }
+
+ return $results;
+};
+
+/**
+ * Action
+ */
+
+$new_entity = [];
+
+$model = $orm->getModel($params['entity']);
+if(!$model) {
+ throw new Exception("unknown_entity", QN_ERROR_INVALID_PARAM);
+}
+
+$root_fields = ['id', 'creator', 'created', 'modifier', 'modified', 'deleted', 'state'];
+
+$model_unique_conf = [];
+if(method_exists($params['entity'], 'getUnique')) {
+ $model_unique_conf = (new $params['entity'])->getUnique();
+}
+
+$schema = $model->getSchema();
+foreach($schema as $field => $field_conf) {
+ $field_value_forced = isset($params['fields'][$field]);
+ $field_has_generate_function = isset($field_conf['generate']) && method_exists($params['entity'], $field_conf['generate']);
+
+ if(
+ !$field_value_forced
+ && !$field_has_generate_function
+ && (
+ in_array($field, $root_fields)
+ || in_array($field_conf['type'], ['alias', 'computed', 'one2many', 'many2one', 'many2many'])
+ )
+ ) {
+ continue;
+ }
+
+ $should_be_unique = $field_conf['unique'] ?? false;
+ if(!$should_be_unique && !empty($model_unique_conf)) {
+ foreach($model_unique_conf as $unique_conf) {
+ if(count($unique_conf) === 1 && $unique_conf[0] === $field) {
+ $should_be_unique = true;
+ break;
+ }
+ }
+ }
+
+ $field_value_allowed = false;
+ $unique_retry_count = 10;
+ while($unique_retry_count > 0 && !$field_value_allowed) {
+ $unique_retry_count--;
+
+ if($field_value_forced) {
+ $new_entity[$field] = $params['fields'][$field];
+ }
+ elseif($field_has_generate_function) {
+ $new_entity[$field] = $params['entity']::{$field_conf['generate']}();
+ }
+ else {
+ $required = $field_conf['required'] ?? false;
+ if(!$required && DataGenerator::boolean(0.05)) {
+ $new_entity[$field] = null;
+ }
+ else {
+ $new_entity[$field] = DataGenerator::generateByFieldConf($field, $field_conf, $params['lang']);
+ }
+ }
+
+ if($should_be_unique) {
+ $ids = $params['entity']::search([$field, '=', $new_entity[$field]])->ids();
+ if(empty($ids)) {
+ $field_value_allowed = true;
+ }
+ }
+ else {
+ $field_value_allowed = true;
+ }
+ }
+
+ if(!$field_value_allowed) {
+ unset($new_entity[$field]);
+ }
+}
+
+foreach($params['relations'] as $field => $relation_conf) {
+ $field_conf = $schema[$field] ?? null;
+ $field_type = $field_conf['result_type'] ?? $field_conf['type'] ?? null;
+ if(is_null($field_conf) || !in_array($field_type, ['many2one', 'many2many'])) {
+ continue;
+ }
+
+ switch($field_type) {
+ case 'many2one':
+ $domain = [];
+ if($relation_conf['domain']) {
+ $domain = (new Domain($relation_conf['domain']))
+ ->parse(array_merge($new_entity, $params['domain_data'] ?? []))
+ ->toArray();
+ }
+
+ $ids = $field_conf['foreign_object']::search($domain)->ids();
+ $mode = $relation_conf['mode'] ?? 'use-existing-or-create';
+ if($mode === 'use-existing-or-create') {
+ $mode = empty($ids) || DataGenerator::boolean() ? 'create' : 'use-existing';
+ }
+
+ switch($mode) {
+ case 'use-existing':
+ if(!empty($ids)) {
+ if(!($field_conf['required'] ?? false)) {
+ $ids[] = null;
+ }
+
+ $new_entity[$field] = $ids[array_rand($ids)];
+ }
+ break;
+ case 'create':
+ $result = $generateMany2One($field_conf, $relation_conf, $params['lang'], $params['domain_data'] ?? []);
+
+ $new_entity[$field] = $result['id'];
+
+ foreach(array_keys($relation_conf['add_to_domain_data'] ?? []) as $key) {
+ if(isset($result['domain_data'][$key])) {
+ $params['domain_data']["$field.$key"] = $result['domain_data'][$key];
+ }
+ }
+ break;
+ }
+ break;
+ case 'many2many':
+ $mode = $relation_conf['mode'] ?? 'use-existing-or-create';
+
+ $qty_conf = $relation_conf['qty'] ?? [0, 5];
+ $qty = is_array($qty_conf) ? mt_rand($qty_conf[0], $qty_conf[1]) : $qty_conf;
+
+ switch($mode) {
+ case 'use-existing':
+ $domain = [];
+ if($relation_conf['domain']) {
+ $domain = (new Domain($relation_conf['domain']))
+ ->parse(array_merge($new_entity, $params['domain_data'] ?? []))
+ ->toArray();
+ }
+
+ $ids = $field_conf['foreign_object']::search($domain)->ids();
+ $random_ids = [];
+ for($i = 0; $i < $qty; $i++) {
+ if(empty($ids)) {
+ break;
+ }
+
+ $random_index = array_rand($ids);
+ $random_ids[] = $ids[$random_index];
+ array_splice($ids, $random_index, 1);
+ }
+
+ if(!empty($random_ids)) {
+ $new_entity[$field] = $random_ids;
+ }
+ break;
+ case 'create':
+ $results = $generateMany2Many($qty, $field_conf, $relation_conf, $params['lang'], $params['domain_data'] ?? []);
+
+ $new_relation_entities_ids = array_column($results, 'id');
+ if(!empty($new_relation_entities_ids)) {
+ $new_entity[$field] = $new_relation_entities_ids;
+ }
+
+ $i = 0;
+ foreach($results as $result) {
+ foreach(array_keys($relation_conf['add_to_domain_data'] ?? []) as $key) {
+ if(isset($result['domain_data'][$key])) {
+ $params['domain_data']["$field.$i.$key"] = $result['domain_data'][$key];
+ }
+ }
+ $i++;
+ }
+ break;
+ }
+ break;
+ }
+}
+
+$field_to_read = array_values($params['add_to_domain_data']);
+
+$instance = $params['entity']::create($new_entity, $params['lang'])
+ ->read($field_to_read)
+ ->adapt('json')
+ ->first(true);
+
+foreach($params['add_to_domain_data'] as $key => $field) {
+ if(isset($instance[$field])) {
+ $params['domain_data'][$key] = $instance[$field];
+ }
+}
+
+foreach($params['relations'] as $field => $relation_conf) {
+ $field_conf = $schema[$field] ?? null;
+ $field_type = $field_conf['result_type'] ?? $field_conf['type'] ?? null;
+ if(is_null($field_conf) || $field_type !== 'one2many') {
+ continue;
+ }
+
+ $qty_conf = $relation_conf['qty'] ?? [0, 3];
+ $qty = is_array($qty_conf) ? mt_rand($qty_conf[0], $qty_conf[1]) : $qty_conf;
+
+ $results = $generateOne2Many($instance['id'], $qty, $field_conf, $relation_conf, $params['lang'], $params['domain_data']);
+
+ $new_relation_entities_ids = array_column($results, 'id');
+ if(!empty($new_relation_entities_ids)) {
+ $new_entity[$field] = $new_relation_entities_ids;
+ }
+
+ $i = 0;
+ foreach($results as $result) {
+ foreach(array_keys($relation_conf['add_to_domain_data'] ?? []) as $key) {
+ if(isset($result['domain_data'][$key])) {
+ $params['domain_data']["$field.$i.$key"] = $result['domain_data'][$key];
+ }
+ }
+ $i++;
+ }
+}
+
+$result = [
+ 'entity' => $params['entity'],
+ 'id' => $instance['id'],
+ 'domain_data' => $params['domain_data']
+];
+
+$context->httpResponse()
+ ->status(201)
+ ->body($result)
+ ->send();