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();