data.generator.class.inc.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. <?php
  2. // Copyright (C) 2010-2012 Combodo SARL
  3. //
  4. // This file is part of iTop.
  5. //
  6. // iTop is free software; you can redistribute it and/or modify
  7. // it under the terms of the GNU Affero General Public License as published by
  8. // the Free Software Foundation, either version 3 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // iTop is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU Affero General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU Affero General Public License
  17. // along with iTop. If not, see <http://www.gnu.org/licenses/>
  18. /**
  19. * data generator
  20. * helps the consultants in creating dummy data sets, for various test purposes (validation, usability, scalability)
  21. *
  22. * @copyright Copyright (C) 2010-2012 Combodo SARL
  23. * @license http://opensource.org/licenses/AGPL-3.0
  24. */
  25. /**
  26. * Data Generator helper class
  27. *
  28. * This class is useful to generate a lot of sample data that look consistent
  29. * for a given organization in order to simulate a real CMDB
  30. */
  31. class cmdbDataGenerator
  32. {
  33. protected $m_sOrganizationKey;
  34. protected $m_sOrganizationCode;
  35. protected $m_sOrganizationName;
  36. protected $m_OrganizationDomains;
  37. /**
  38. * Constructor
  39. */
  40. public function __construct($sOrganizationId = "")
  41. {
  42. global $aCompanies, $aCompaniesCode;
  43. if ($sOrganizationId == '')
  44. {
  45. // No organization provided, pick a random and unused one from our predefined list
  46. $retries = 5*count($aCompanies);
  47. while ( ($retries > 0) && !isset($this->m_sOrganizationCode)) // Stupid algorithm, but I'm too lazy to do something bulletproof tonight
  48. {
  49. $index = rand(0, count($aCompanies) - 1);
  50. if (!$this->OrganizationExists($aCompanies[$index]['code']))
  51. {
  52. $this->m_sOrganizationCode = $aCompanies[$index]['code'];
  53. $this->m_sOrganizationName = $aCompanies[$index]['name'];
  54. $this->m_OrganizationDomains = $aCompanies[$index]['domain'];
  55. }
  56. $retries--;
  57. }
  58. }
  59. else
  60. {
  61. // A code has been provided, let's take the information we need from the organization itself
  62. $this->m_sOrganizationId = $sOrganizationId;
  63. $oOrg = $this->GetOrganization($sOrganizationId);
  64. if ($oOrg == null)
  65. {
  66. echo "Unable to find the organization '$sOrganisationCode' in the database... can not add objects into this organization.<br/>\n";
  67. exit();
  68. }
  69. $this->m_sOrganizationCode = $oOrg->Get('code');
  70. $this->m_sOrganizationName = $oOrg->Get('name');
  71. if (!isset($aCompaniesCode[$this->m_sOrganizationCode]['domain']))
  72. {
  73. // Generate some probable domain names for this organization
  74. $this->m_OrganizationDomains = array(strtolower($this->m_sOrganizationCode).".com", strtolower($this->m_sOrganizationCode).".org", strtolower($this->m_sOrganizationCode)."corp.net",);
  75. }
  76. else
  77. {
  78. // Pick the domain names for this organization from the predefined list
  79. $this->m_OrganizationDomains = $aCompaniesCode[$this->m_sOrganizationCode]['domain'];
  80. }
  81. }
  82. if (!isset($this->m_sOrganizationCode))
  83. {
  84. echo "Unable to find an organization code which is not already used... can not create a new organization. Enhance the list of fake organizations (\$aCompanies in data_sample.inc.php).<br/>\n";
  85. exit();
  86. }
  87. }
  88. /**
  89. * Get the current organization id used by the generator
  90. *
  91. * @return string The organization id
  92. */
  93. public function GetOrganizationId()
  94. {
  95. return $this->m_sOrganizationId;
  96. }
  97. /**
  98. * Get the current organization id used by the generator
  99. *
  100. * @param string The organization id
  101. * @return none
  102. */
  103. public function SetOrganizationId($sId)
  104. {
  105. $this->m_sOrganizationId = $sId;
  106. }
  107. /**
  108. * Get the current organization code used by the generator
  109. *
  110. * @return string The organization code
  111. */
  112. public function GetOrganizationCode()
  113. {
  114. return $this->m_sOrganizationCode;
  115. }
  116. /**
  117. * Get the current organization name used by the generator
  118. *
  119. * @return string The organization name
  120. */
  121. function GetOrganizationName()
  122. {
  123. return $this->m_sOrganizationName;
  124. }
  125. /**
  126. * Get a pseudo random first name taken from a (big) prefedined list
  127. *
  128. * @return string A random first name
  129. */
  130. function GenerateFirstName()
  131. {
  132. global $aFirstNames;
  133. return $aFirstNames[rand(0, count($aFirstNames) - 1)];
  134. }
  135. /**
  136. * Get a pseudo random last name taken from a (big) prefedined list
  137. *
  138. * @return string A random last name
  139. */
  140. function GenerateLastName()
  141. {
  142. global $aNames;
  143. return $aNames[rand(0, count($aNames) - 1)];
  144. }
  145. /**
  146. * Get a pseudo random country name taken from a prefedined list
  147. *
  148. * @return string A random city name
  149. */
  150. function GenerateCountryName()
  151. {
  152. global $aCountries;
  153. return $aCountries[rand(0, count($aCountries) - 1)];
  154. }
  155. /**
  156. * Get a pseudo random city name taken from a (big) prefedined list
  157. *
  158. * @return string A random city name
  159. */
  160. function GenerateCityName()
  161. {
  162. global $aCities;
  163. return $aCities[rand(0, count($aCities) - 1)];
  164. }
  165. /**
  166. * Get a pseudo random email address made of the first name, last name and organization's domain
  167. *
  168. * @return string A random email address
  169. */
  170. function GenerateEmail($sFirstName, $sLastName)
  171. {
  172. if (rand(1, 20) > 18)
  173. {
  174. // some people (let's say 5~10%) have an irregular email address
  175. $sEmail = strtolower($this->CleanForEmail($sLastName))."@".strtolower($this->GenerateDomain());
  176. }
  177. else
  178. {
  179. $sEmail = strtolower($this->CleanForEmail($sFirstName)).".".strtolower($this->CleanForEmail($sLastName))."@".strtolower($this->GenerateDomain());
  180. }
  181. return $sEmail;
  182. }
  183. /**
  184. * Generate (pseudo) random strings that follow a given pattern
  185. *
  186. * The template is made of any number of 'parts' separated by pipes '|'
  187. * Each part is either:
  188. * - domain() => returns a domain name for the current organization
  189. * - enum(aaa,bb,c,dddd) => returns randomly one of aaa,bb,c or dddd with the same
  190. * probability of occurence. If you want to change the probability you can repeat some values
  191. * i.e enum(most probable,most probable,most probable,most probable,most probable,rare)
  192. * - number(xxx-yyy) => a random number between xxx and yyy (bounds included)
  193. * note that if the first number (xxx) begins with a zero, then the result will zero padded
  194. * to the same number of digits as xxx.
  195. * All other 'part' that does not follow one of the above mentioned pattern is returned as is
  196. *
  197. * Example: GenerateString("enum(sw,rtr,gw)|number(00-99)|.|domain()")
  198. * will produce strings like "sw01.netcmdb.com" or "rtr45.itop.org"
  199. *
  200. * @param string $sTemplate The template used for generating the string
  201. * @return string The generated pseudo random the string
  202. */
  203. function GenerateString($sTemplate)
  204. {
  205. $sResult = "";
  206. $aParts = explode("\|", $sTemplate);
  207. foreach($aParts as $sPart)
  208. {
  209. if (preg_match("/domain\(\)/", $sPart, $aMatches))
  210. {
  211. $sResult .= strtolower($this->GenerateDomain());
  212. }
  213. elseif (preg_match("/enum\((.+)\)/", $sPart, $aMatches))
  214. {
  215. $sEnumValues = $aMatches[1];
  216. $aEnumValues = explode(",", $sEnumValues);
  217. $sResult .= $aEnumValues[rand(0, count($aEnumValues) - 1)];
  218. }
  219. elseif (preg_match("/number\((\d+)-(\d+)\)/", $sPart, $aMatches))
  220. {
  221. $sStartNumber = $aMatches[1];
  222. if ($sStartNumber[0] == '0')
  223. {
  224. // number must be zero padded
  225. $sFormat = "%0".strlen($sStartNumber)."d";
  226. }
  227. else
  228. {
  229. $sFormat = "%d";
  230. }
  231. $sEndNumber = $aMatches[2];
  232. $sResult .= sprintf($sFormat, rand($sStartNumber, $sEndNumber));
  233. }
  234. else
  235. {
  236. $sResult .= $sPart;
  237. }
  238. }
  239. return $sResult;
  240. }
  241. /**
  242. * Generate a foreign key by picking a random element of the given class in a set limited by the given search criteria
  243. *
  244. * Example: GenerateKey("bizLocation", array('org_id', $oGenerator->GetOrganizationId());
  245. * will produce the foreign key of a Location object picked at random in the same organization
  246. *
  247. * @param string $sClass The name of the class to search for
  248. * @param string $aFilterCriteria A hash array of filterCOde => FilterValue (the strict operator '=' is used )
  249. * @return mixed The key to an object of the given class, or null if none are found
  250. */
  251. function GenerateKey($sClass, $aFilterCriteria)
  252. {
  253. $retKey = null;
  254. $oFilter = new CMDBSearchFilter($sClass);
  255. foreach($aFilterCriteria as $sFilterCode => $filterValue)
  256. {
  257. $oFilter->AddCondition($sFilterCode, $filterValue, '=');
  258. }
  259. $oSet = new CMDBObjectSet($oFilter);
  260. if ($oSet->Count() > 0)
  261. {
  262. $max_count = $index = rand(1, $oSet->Count());
  263. do
  264. {
  265. $oObj = $oSet->Fetch();
  266. $index--;
  267. }
  268. while($index > 0);
  269. if (!is_object($oObj))
  270. {
  271. echo "<pre>";
  272. echo "ERROR: non empty set, but invalid object picked! class='$sClass'\n";
  273. echo "Index chosen: $max_count\n";
  274. echo "The set is supposed to contain ".$oSet->Count()." object(s)\n";
  275. echo "Filter criteria:\n";
  276. print_r($aFilterCriteria);
  277. echo "</pre>";
  278. }
  279. else
  280. {
  281. $retKey = $oObj->GetKey();
  282. }
  283. }
  284. return $retKey;
  285. }
  286. ///////////////////////////////////////////////////////////////////////////////
  287. //
  288. // Protected methods
  289. //
  290. ///////////////////////////////////////////////////////////////////////////////
  291. /**
  292. * Generate a (random) domain name consistent with the organization name & code
  293. *
  294. * The values are pulled from a (limited) predefined list. Note that a given
  295. * organization may have several domain names, so the result may be random
  296. *
  297. * @return string A domain name (like netcnmdb.com)
  298. */
  299. protected function GenerateDomain()
  300. {
  301. if (is_array($this->m_OrganizationDomains))
  302. {
  303. $sDomain = $this->m_OrganizationDomains[rand(0, count($this->m_OrganizationDomains)-1)];
  304. }
  305. else
  306. {
  307. $sDomain = $this->m_OrganizationDomains;
  308. }
  309. return $sDomain;
  310. }
  311. /**
  312. * Strips accented characters from a string in order to produce a suitable email address
  313. *
  314. * @param string The text string to clean
  315. * @return string The cleanified text string
  316. */
  317. protected function CleanForEmail($sText)
  318. {
  319. return str_replace(array("'", "é", "è", "ê", "ç", "à", "â", "ñ", "ö", "ä"), array("", "e", "e", "e", "c", "a", "a", "n", "oe", "ae"), $sText);
  320. }
  321. /**
  322. * Check if an organization with the given code already exists in the database
  323. *
  324. * @param string $sCode The code to look for
  325. * @return boolean true if the given organization exists, false otherwise
  326. */
  327. protected function OrganizationExists($sCode)
  328. {
  329. $oFilter = new CMDBSearchFilter('bizOrganization');
  330. $oFilter->AddCondition('code', $sCode, '=');
  331. $oSet = new CMDBObjectSet($oFilter);
  332. return ($oSet->Count() > 0);
  333. }
  334. /**
  335. * Search for an organization with the given code in the database
  336. *
  337. * @param string $Id The organization Id to look for
  338. * @return cmdbOrganization the organization if it exists, null otherwise
  339. */
  340. protected function GetOrganization($sId)
  341. {
  342. $oOrg = null;
  343. $oFilter = new CMDBSearchFilter('bizOrganization');
  344. $oFilter->AddCondition('id', $sId, '=');
  345. $oSet = new CMDBObjectSet($oFilter);
  346. if ($oSet->Count() > 0)
  347. {
  348. $oOrg = $oSet->Fetch(); // Let's take the first one found
  349. }
  350. return $oOrg;
  351. }
  352. }
  353. ?>