compiler.class.inc.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919
  1. <?php
  2. // Copyright (C) 2011 Combodo SARL
  3. //
  4. // This program is free software; you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation; version 3 of the License.
  7. //
  8. // This program is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program; if not, write to the Free Software
  15. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. class DOMFormatException extends Exception
  17. {
  18. }
  19. class CompilerEchoPage
  20. {
  21. public function p($s)
  22. {
  23. echo "<p>\n$s</p>\n";
  24. }
  25. public function add($s)
  26. {
  27. //echo $s;
  28. }
  29. public function output()
  30. {
  31. }
  32. }
  33. /**
  34. * Compiler class
  35. */
  36. class MFCompiler
  37. {
  38. protected $oFactory;
  39. protected $sSourceDir;
  40. public function __construct($oModelFactory, $sSourceDir)
  41. {
  42. $this->oFactory = $oModelFactory;
  43. $this->sSourceDir = $sSourceDir;
  44. }
  45. public function Compile($sTargetDir, $oP = null)
  46. {
  47. if (is_null($oP))
  48. {
  49. $oP = new CompilerEchoPage();
  50. }
  51. $aResultFiles = array();
  52. $aModules = $this->oFactory->GetLoadedModules();
  53. foreach($aModules as $foo => $oModule)
  54. {
  55. $sModuleName = $oModule->GetName();
  56. $sModuleVersion = $oModule->GetVersion();
  57. $sModuleRootDir = realpath($oModule->GetRootDir());
  58. $sRelativeDir = substr($sModuleRootDir, strlen($this->sSourceDir) + 1);
  59. // Push the other module files
  60. $this->CopyDirectory($sModuleRootDir, $sTargetDir.'/'.$sRelativeDir);
  61. $oClasses = $this->oFactory->ListClasses($sModuleName);
  62. $iClassCount = $oClasses->length;
  63. if ($iClassCount == 0)
  64. {
  65. $oP->p("Found module without classes declared: $sModuleName");
  66. }
  67. else
  68. {
  69. $sResultFile = $sTargetDir.'/'.$sRelativeDir.'/model.'.$sModuleName.'.php';
  70. if (is_file($sResultFile))
  71. {
  72. $oP->p("Updating <a href=\"#$sModuleName\">$sResultFile</a> for module $sModuleName in version $sModuleVersion ($iClassCount classes)");
  73. }
  74. else
  75. {
  76. $sResultDir = dirname($sResultFile);
  77. if (!is_dir($sResultDir))
  78. {
  79. $oP->p("Creating directory $sResultDir");
  80. mkdir($sResultDir, 0777, true);
  81. }
  82. $oP->p("Creating <a href=\"#$sModuleName\">$sResultFile</a> for module $sModuleName in version $sModuleVersion ($iClassCount classes)");
  83. }
  84. // Compile the module into a single file
  85. //
  86. $sId = $sModuleName;
  87. $aResultFiles[$sId] = $sResultFile;
  88. $sCurrDate = date(DATE_ISO8601);
  89. $sAuthor = 'Combodo compiler';
  90. $sLicence = 'http://www.opensource.org/licenses/gpl-3.0.html LGPL';
  91. $sFileHeader =
  92. <<<EOF
  93. <?php
  94. //
  95. // File generated by ... on the $sCurrDate
  96. // Please do not edit manually
  97. //
  98. //
  99. // Copyright (C) 2010 Combodo SARL
  100. //
  101. // ben on met quoi ici ?
  102. // Signé: Romain
  103. //
  104. // This program is free software; you can redistribute it and/or modify
  105. // it under the terms of the GNU General Public License as published by
  106. // the Free Software Foundation; version 3 of the License.
  107. //
  108. // This program is distributed in the hope that it will be useful,
  109. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  110. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  111. // GNU General Public License for more details.
  112. //
  113. // You should have received a copy of the GNU General Public License
  114. // along with this program; if not, write to the Free Software
  115. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  116. /**
  117. * Persistent classes for $sModuleName (version $sModuleVersion)
  118. *
  119. * @author $sAuthor
  120. * @license $sLicence
  121. */
  122. EOF;
  123. file_put_contents($sResultFile, $sFileHeader);
  124. foreach($oClasses as $oClass)
  125. {
  126. $sClass = $oClass->getAttribute("name");
  127. try
  128. {
  129. $this->CompileClass($oClass, $sResultFile, $sRelativeDir, $oP);
  130. }
  131. catch (ssDOMFormatException $e)
  132. {
  133. $sClass = $oClass->getAttribute("name");
  134. throw new Exception("Failed to process class '$sClass', from '$sModuleRootDir': ".$e->getMessage());
  135. }
  136. }
  137. }
  138. $oMenus = $this->oFactory->ListMenus($sModuleName);
  139. $iMenuCount = $oMenus->length;
  140. if ($iMenuCount == 0)
  141. {
  142. $oP->p("Found module without menus declared: $sModuleName");
  143. }
  144. else
  145. {
  146. $sMenusHeader =
  147. <<<EOF
  148. //
  149. // Menus
  150. //
  151. EOF;
  152. file_put_contents($sResultFile, $sMenusHeader, FILE_APPEND);
  153. // Preliminary: determine parent menus not defined within the current module
  154. $aMenusToLoad = array();
  155. foreach($oMenus as $oMenu)
  156. {
  157. if ($oParent = $this->GetOptionalElement($oMenu, 'parent'))
  158. {
  159. $aMenusToLoad[] = $oParent->GetAttribute('value');
  160. }
  161. // Note: the order matters: the parents must be defined BEFORE
  162. $aMenusToLoad[] = $oMenu->GetAttribute('id');
  163. }
  164. $aMenusToLoad = array_unique($aMenusToLoad);
  165. foreach($aMenusToLoad as $sMenuId)
  166. {
  167. $oMenu = $this->oFactory->GetMenu($sMenuId);
  168. try
  169. {
  170. $this->CompileMenu($oMenu, $sResultFile, $sRelativeDir, $oP);
  171. }
  172. catch (ssDOMFormatException $e)
  173. {
  174. $sMenu = $oMenu->getAttribute("name");
  175. throw new Exception("Failed to process menu '$sMenu', from '$sModuleRootDir': ".$e->getMessage());
  176. }
  177. }
  178. }
  179. }
  180. if (count($aResultFiles))
  181. {
  182. $oP->add('<h2>Files</h2>');
  183. foreach ($aResultFiles as $sModuleName => $sFile)
  184. {
  185. $oP->add('<h3>'.$sFile.'</h3>');
  186. $oP->add('<a name="'.$sModuleName.'"/><div style="border:1;">');
  187. $oP->add(highlight_file($sFile, true));
  188. $oP->add('</div style="">');
  189. }
  190. }
  191. $oP->output();
  192. //$this->oFactory->Dump();
  193. }
  194. /**
  195. * Helper to copy the module files to the exploitation environment
  196. * Returns true if successfull
  197. */
  198. protected function CopyDirectory($sSource, $sDest)
  199. {
  200. if (is_dir($sSource))
  201. {
  202. if (!is_dir($sDest))
  203. {
  204. mkdir($sDest);
  205. }
  206. $aFiles = scandir($sSource);
  207. if(sizeof($aFiles) > 0 )
  208. {
  209. foreach($aFiles as $sFile)
  210. {
  211. if ($sFile == '.' || $sFile == '..' || $sFile == '.svn')
  212. {
  213. // Skip
  214. continue;
  215. }
  216. if (is_dir($sSource.'/'.$sFile))
  217. {
  218. $this->CopyDirectory($sSource.'/'.$sFile, $sDest.'/'.$sFile);
  219. }
  220. else
  221. {
  222. copy($sSource.'/'.$sFile, $sDest.'/'.$sFile);
  223. }
  224. }
  225. }
  226. return true;
  227. }
  228. elseif (is_file($sSource))
  229. {
  230. return copy($sSource, $sDest);
  231. }
  232. else
  233. {
  234. return false;
  235. }
  236. }
  237. /**
  238. * Helper to browse the DOM -could be factorized in ModelFactory
  239. * Returns the node directly under the given node, and that is supposed to be always present and unique
  240. */
  241. protected function GetUniqueElement($oDOMNode, $sTagName, $bMustExist = true)
  242. {
  243. $oNode = null;
  244. if ($oDOMNode->hasChildNodes())
  245. {
  246. foreach($oDOMNode->childNodes as $oChildNode)
  247. {
  248. if ($oChildNode->nodeName == $sTagName)
  249. {
  250. $oNode = $oChildNode;
  251. break;
  252. }
  253. }
  254. }
  255. if ($bMustExist && is_null($oNode))
  256. {
  257. throw new DOMFormatException('Missing unique tag: '.$sTagName);
  258. }
  259. return $oNode;
  260. }
  261. /**
  262. * Helper to browse the DOM -could be factorized in ModelFactory
  263. * Returns the node directly under the given node, or null is missing
  264. */
  265. protected function GetOptionalElement($oDOMNode, $sTagName)
  266. {
  267. return $this->GetUniqueElement($oDOMNode, $sTagName, false);
  268. }
  269. /**
  270. * Helper to browse the DOM -could be factorized in ModelFactory
  271. * Returns the TEXT of the given node (possibly from several subnodes)
  272. */
  273. protected function GetNodeText($oNode)
  274. {
  275. $sText = '';
  276. if ($oNode->hasChildNodes())
  277. {
  278. foreach($oNode->childNodes as $oChildNode)
  279. {
  280. if ($oChildNode instanceof DOMCharacterData) // Base class of DOMText and DOMCdataSection
  281. {
  282. $sText .= $oChildNode->wholeText;
  283. }
  284. }
  285. }
  286. return $sText;
  287. }
  288. /**
  289. * Helper to browse the DOM -could be factorized in ModelFactory
  290. * Assumes the given node to be either a text or
  291. * <items>
  292. * <item [key]="..."]>value<item>
  293. * <item [key]="..."]>value<item>
  294. * </items>
  295. * where value can be the either a text or an array of items... recursively
  296. * Returns a PHP array
  297. */
  298. protected function GetNodeAsArrayOfItems($oNode)
  299. {
  300. $oItems = $this->GetOptionalElement($oNode, 'items');
  301. if ($oItems)
  302. {
  303. $res = array();
  304. if ($oItems->hasChildNodes())
  305. {
  306. foreach($oItems->childNodes as $oItem)
  307. {
  308. // When an attribute is msising
  309. if ($oItem->hasAttributes() && $oItem->hasAttribute('key'))
  310. {
  311. $key = $oItem->getAttribute('key');
  312. $res[$key] = $this->GetNodeAsArrayOfItems($oItem);
  313. }
  314. else
  315. {
  316. $res[] = $this->GetNodeAsArrayOfItems($oItem);
  317. }
  318. }
  319. }
  320. }
  321. else
  322. {
  323. $res = $this->GetNodeText($oNode);
  324. }
  325. return $res;
  326. }
  327. /**
  328. * Helper to format the flags for an attribute, in a given state
  329. * @param object $oAttNode DOM node containing the information to build the flags
  330. * Returns string PHP flags, based on the OPT_ATT_ constants, or empty (meaning 0, can be omitted)
  331. */
  332. protected function FlagsToPHP($oAttNode)
  333. {
  334. static $aNodeAttributeToFlag = array(
  335. 'mandatory' => 'OPT_ATT_MANDATORY',
  336. 'read_only' => 'OPT_ATT_READONLY',
  337. 'must_prompt' => 'OPT_ATT_MUSTPROMPT',
  338. 'must_change' => 'OPT_ATT_MUSTCHANGE',
  339. 'hidden' => 'OPT_ATT_HIDDEN',
  340. );
  341. $aFlags = array();
  342. foreach ($aNodeAttributeToFlag as $sNodeAttribute => $sFlag)
  343. {
  344. $bFlag = ($oAttNode->GetAttribute($sNodeAttribute) == '1');
  345. if ($bFlag)
  346. {
  347. $aFlags[] = $sFlag;
  348. }
  349. }
  350. $sRes = implode(' | ', $aFlags);
  351. return $sRes;
  352. }
  353. /**
  354. * Format a path (file or url) as an absolute path or relative to the module or the app
  355. */
  356. protected function PathToPHP($sPath, $sModuleRelativeDir, $bIsUrl = false)
  357. {
  358. if (substr($sPath, 0, 2) == '$$')
  359. {
  360. // Absolute
  361. $sPHP = "'".addslashes(substr($sPath, 2))."'";
  362. }
  363. elseif (substr($sPath, 0, 1) == '$')
  364. {
  365. // Relative to the application
  366. if ($bIsUrl)
  367. {
  368. $sPHP = "utils::GetAbsoluteUrlAppRoot().'".addslashes(substr($sPath, 1))."'";
  369. }
  370. else
  371. {
  372. $sPHP = "APPROOT.'".addslashes(substr($sPath, 1))."'";
  373. }
  374. }
  375. else
  376. {
  377. // Relative to the module
  378. if ($bIsUrl)
  379. {
  380. $sPHP = "utils::GetAbsoluteUrlAppRoot().'".addslashes($sModuleRelativeDir.''.$sPath)."'";
  381. }
  382. else
  383. {
  384. $sPHP = "dirname(__FILE__).'/$sPath'";
  385. }
  386. }
  387. return $sPHP;
  388. }
  389. protected function CompileClass($oClass, $sResFile, $sModuleRelativeDir, $oP)
  390. {
  391. $sClass = $oClass->getAttribute('name');
  392. $oProperties = $this->GetUniqueElement($oClass, 'properties');
  393. // Class caracteristics
  394. //
  395. $aClassParams = array();
  396. $aClassParams['category'] = "'".$oClass->getAttribute('category')."'";
  397. $aClassParams['key_type'] = "'autoincrement'";
  398. $oNaming = $this->GetUniqueElement($oProperties, 'naming');
  399. $oNameAttributes = $this->GetUniqueElement($oNaming, 'attributes');
  400. $oAttributes = $oNameAttributes->getElementsByTagName('attribute');
  401. $aNameAttCodes = array();
  402. foreach($oAttributes as $oAttribute)
  403. {
  404. $aNameAttCodes[] = $oAttribute->getAttribute('name');
  405. }
  406. if (count($aNameAttCodes) > 1)
  407. {
  408. // New style...
  409. $sNameAttCode = "array('".implode("', '", $aNameAttCodes)."')";
  410. }
  411. elseif (count($aNameAttCodes) == 1)
  412. {
  413. // New style...
  414. $sNameAttCode = "'$aNameAttCodes[0]'";
  415. }
  416. else
  417. {
  418. $sNameAttCode = "''";
  419. }
  420. $aClassParams['name_attcode'] = $sNameAttCode;
  421. $oLifecycle = $this->GetOptionalElement($oClass, 'lifecycle');
  422. if ($oLifecycle)
  423. {
  424. $sStateAttCode = $oLifecycle->getAttribute('attribute');
  425. }
  426. else
  427. {
  428. $sStateAttCode = "";
  429. }
  430. $aClassParams['state_attcode'] = "'$sStateAttCode'";
  431. $oReconciliation = $this->GetUniqueElement($oProperties, 'reconciliation');
  432. $oReconcAttributes = $oReconciliation->getElementsByTagName('attribute');
  433. $aReconcAttCodes = array();
  434. foreach($oReconcAttributes as $oAttribute)
  435. {
  436. $aReconcAttCodes[] = $oAttribute->getAttribute('name');
  437. }
  438. $sReconcKeys = "array('".implode("', '", $aReconcAttCodes)."')";
  439. $aClassParams['reconc_keys'] = $sReconcKeys;
  440. $aClassParams['db_table'] = "'".$oClass->getAttribute('db_table')."'";
  441. $aClassParams['db_key_field'] = "'".$oClass->getAttribute('db_key_field')."'";
  442. $aClassParams['db_finalclass_field'] = "'".$oClass->getAttribute('db_final_class_field')."'";
  443. $oDisplayTemplate = $this->GetOptionalElement($oProperties, 'display_template');
  444. if ($oDisplayTemplate && (strlen($oDisplayTemplate->textContent) > 0))
  445. {
  446. $sDisplayTemplate = $sModuleRelativeDir.'/'.$oDisplayTemplate->textContent;
  447. $aClassParams['display_template'] = "utils::GetAbsoluteUrlModulesRoot().'$sDisplayTemplate'";
  448. }
  449. $oIcon = $this->GetOptionalElement($oProperties, 'icon');
  450. if ($oIcon && (strlen($oIcon->textContent) > 0))
  451. {
  452. $sIcon = $sModuleRelativeDir.'/'.$oIcon->textContent;
  453. $aClassParams['icon'] = "utils::GetAbsoluteUrlModulesRoot().'$sIcon'";
  454. }
  455. $oOrder = $this->GetOptionalElement($oProperties, 'order');
  456. if ($oOrder)
  457. {
  458. $oColumnsNode = $this->GetUniqueElement($oOrder, 'columns');
  459. $oColumns = $oColumnsNode->getElementsByTagName('column');
  460. $aSortColumns = array();
  461. foreach($oColumns as $oColumn)
  462. {
  463. $aSortColumns[] = "'".$oColumn->getAttribute('name')."' => ".(($oColumn->getAttribute('ascending') == 'true') ? 'true' : 'false');
  464. }
  465. if (count($aSortColumns) > 0)
  466. {
  467. $aClassParams['order_by_default'] = "array(".implode(", ", $aSortColumns).")";
  468. }
  469. }
  470. // Finalize class params declaration
  471. //
  472. $aClassParamsPHP = array();
  473. foreach($aClassParams as $sKey => $sPHPValue)
  474. {
  475. $aClassParamsPHP[] = " '$sKey' => $sPHPValue,";
  476. }
  477. $sClassParams = implode("\n", $aClassParamsPHP);
  478. // Comment on top of the class declaration
  479. //
  480. $oComment = $this->GetOptionalElement($oProperties, 'comment');
  481. if ($oComment)
  482. {
  483. $sCodeComment = $oComment->textContent;
  484. }
  485. else
  486. {
  487. $sCodeComment = '';
  488. }
  489. // Fields
  490. //
  491. $sAttributes = '';
  492. foreach($this->oFactory->ListFields($oClass) as $oField)
  493. {
  494. // $oField
  495. $sAttCode = $oField->getAttribute('name');
  496. $sAttType = 'Attribute'.$oField->getAttribute('type');
  497. $aDependencies = array();
  498. $oDependencies = $this->GetOptionalElement($oField, 'dependencies');
  499. if (!is_null($oDependencies))
  500. {
  501. $oDepNodes = $oDependencies->getElementsByTagName('attribute');
  502. foreach($oDepNodes as $oDepAttribute)
  503. {
  504. $aDependencies[] = "'".$oDepAttribute->getAttribute('name')."'";
  505. }
  506. }
  507. $sDependencies = 'array('.implode(', ', $aDependencies).')';
  508. $aParameters = array();
  509. if ($sAttType == 'AttributeLinkedSetIndirect')
  510. {
  511. $aParameters['linked_class'] = "'".$oField->getAttribute('linked_class')."'";
  512. $aParameters['ext_key_to_me'] = "'".$oField->getAttribute('ext_key_to_me')."'";
  513. $aParameters['ext_key_to_remote'] = "'".$oField->getAttribute('ext_key_to_remote')."'";
  514. // todo - utile ?
  515. $aParameters['allowed_values'] = 'null';
  516. $aParameters['count_min'] = $oField->getAttribute('count_min');
  517. $aParameters['count_max'] = $oField->getAttribute('count_max');
  518. $aParameters['depends_on'] = $sDependencies;
  519. }
  520. elseif ($sAttType == 'AttributeLinkedSet')
  521. {
  522. $aParameters['linked_class'] = "'".$oField->getAttribute('linked_class')."'";
  523. $aParameters['ext_key_to_me'] = "'".$oField->getAttribute('ext_key_to_me')."'";
  524. // todo - utile ?
  525. $aParameters['allowed_values'] = 'null';
  526. $aParameters['count_min'] = $oField->getAttribute('count_min');
  527. $aParameters['count_max'] = $oField->getAttribute('count_max');
  528. $aParameters['depends_on'] = $sDependencies;
  529. }
  530. elseif ($sAttType == 'AttributeExternalKey')
  531. {
  532. $aParameters['targetclass'] = "'".$oField->getAttribute('target_class')."'";
  533. // todo = v�rifier l'utilit�
  534. $aParameters['jointype'] = 'null';
  535. if (($sOql = $oField->getAttribute('filter')) != '')
  536. {
  537. $sEscapedOql = addslashes($sOql);
  538. $aParameters['allowed_values'] = "new ValueSetObjects('$sEscapedOql')"; // or "new ValueSetObjects('SELECT xxxx')"
  539. }
  540. else
  541. {
  542. $aParameters['allowed_values'] = 'null'; // or "new ValueSetObjects('SELECT xxxx')"
  543. }
  544. $aParameters['sql'] = "'".$oField->getAttribute('sql')."'";
  545. $aParameters['is_null_allowed'] = $oField->getAttribute('is_null_allowed') == 'true' ? 'true' : 'false';
  546. $aParameters['on_target_delete'] = $oField->getAttribute('on_target_delete');
  547. $aParameters['depends_on'] = $sDependencies;
  548. }
  549. elseif ($sAttType == 'AttributeHierarchicalKey')
  550. {
  551. if (($sOql = $oField->getAttribute('filter')) != '')
  552. {
  553. $sEscapedOql = addslashes($sOql);
  554. $aParameters['allowed_values'] = "new ValueSetObjects('$sEscapedOql')"; // or "new ValueSetObjects('SELECT xxxx')"
  555. }
  556. else
  557. {
  558. $aParameters['allowed_values'] = 'null'; // or "new ValueSetObjects('SELECT xxxx')"
  559. }
  560. $aParameters['sql'] = "'".$oField->getAttribute('sql')."'";
  561. $aParameters['is_null_allowed'] = $oField->getAttribute('is_null_allowed') == 'true' ? 'true' : 'false';
  562. $aParameters['on_target_delete'] = $oField->getAttribute('on_target_delete');
  563. $aParameters['depends_on'] = $sDependencies;
  564. }
  565. elseif ($sAttType == 'AttributeExternalField')
  566. {
  567. $aParameters['allowed_values'] = 'null';
  568. $aParameters['extkey_attcode'] = "'".$oField->getAttribute('extkey_attcode')."'";
  569. $aParameters['target_attcode'] = "'".$oField->getAttribute('target_attcode')."'";
  570. }
  571. elseif ($sAttType == 'AttributeURL')
  572. {
  573. $aParameters['target'] = "'".$oField->getAttribute('target')."'";
  574. $aParameters['allowed_values'] = 'null';
  575. $aParameters['sql'] = "'".$oField->getAttribute('sql')."'";
  576. $aParameters['default_value'] = "'".$oField->getAttribute('default_value')."'";
  577. $aParameters['is_null_allowed'] = $oField->getAttribute('is_null_allowed') == 'true' ? 'true' : 'false';
  578. $aParameters['depends_on'] = $sDependencies;
  579. }
  580. elseif ($sAttType == 'AttributeEnum')
  581. {
  582. $oValues = $this->GetUniqueElement($oField, 'values');
  583. $oValueNodes = $oValues->getElementsByTagName('value');
  584. $aValues = array();
  585. foreach($oValueNodes as $oValue)
  586. {
  587. // new style... $aValues[] = "'".addslashes($oValue->textContent)."'";
  588. $aValues[] = $oValue->textContent;
  589. }
  590. // new style... $sValues = 'array('.implode(', ', $aValues).')';
  591. $sValues = '"'.implode(',', $aValues).'"';
  592. $aParameters['allowed_values'] = "new ValueSetEnum($sValues)";
  593. $aParameters['sql'] = "'".$oField->getAttribute('sql')."'";
  594. $aParameters['default_value'] = "'".$oField->getAttribute('default_value')."'";
  595. $aParameters['is_null_allowed'] = $oField->getAttribute('is_null_allowed') == 'true' ? 'true' : 'false';
  596. $aParameters['depends_on'] = $sDependencies;
  597. }
  598. elseif ($sAttType == 'AttributeBlob')
  599. {
  600. $aParameters['depends_on'] = $sDependencies;
  601. }
  602. else
  603. {
  604. $aParameters['allowed_values'] = 'null'; // or "new ValueSetEnum('SELECT xxxx')"
  605. $aParameters['sql'] = "'".$oField->getAttribute('sql')."'";
  606. $aParameters['default_value'] = "'".$oField->getAttribute('default_value')."'";
  607. $aParameters['is_null_allowed'] = $oField->getAttribute('is_null_allowed') == 'true' ? 'true' : 'false';
  608. $aParameters['depends_on'] = $sDependencies;
  609. if ($sValidationPattern = $oField->getAttribute('validation_pattern'))
  610. {
  611. $aParameters['validation_pattern'] = '"'.addslashes($sValidationPattern).'"';
  612. }
  613. }
  614. $aParams = array();
  615. foreach($aParameters as $sKey => $sValue)
  616. {
  617. $aParams[] = '"'.$sKey.'"=>'.$sValue;
  618. }
  619. $sParams = implode(', ', $aParams);
  620. $sAttributes .= " MetaModel::Init_AddAttribute(new $sAttType(\"$sAttCode\", array($sParams)));\n";
  621. }
  622. // Lifecycle
  623. //
  624. $sLifecycle = '';
  625. if ($oLifecycle)
  626. {
  627. $sLifecycle .= "\t\t// Lifecycle (status attribute: $sStateAttCode)\n";
  628. $sLifecycle .= "\t\t//\n";
  629. $oStimuli = $this->GetUniqueElement($oLifecycle, 'stimuli');
  630. foreach ($oStimuli->getElementsByTagName('stimulus') as $oStimulus)
  631. {
  632. $sStimulus = $oStimulus->getAttribute('name');
  633. $sStimulusClass = $oStimulus->getAttribute('type');
  634. $sLifecycle .= " MetaModel::Init_DefineStimulus(new ".$sStimulusClass."(\"".$sStimulus."\", array()));\n";
  635. }
  636. $oStates = $this->GetUniqueElement($oLifecycle, 'states');
  637. foreach ($oStates->getElementsByTagName('state') as $oState)
  638. {
  639. $sState = $oState->getAttribute('name');
  640. $sLifecycle .= " MetaModel::Init_DefineState(\n";
  641. $sLifecycle .= " \"".$sState."\",\n";
  642. $sLifecycle .= " array(\n";
  643. $sLifecycle .= " \"attribute_inherit\" => '',\n";
  644. $sLifecycle .= " \"attribute_list\" => array(\n";
  645. $oFlags = $this->GetUniqueElement($oState, 'flags');
  646. foreach ($oFlags->getElementsByTagName('attribute') as $oAttributeNode)
  647. {
  648. $sFlags = $this->FlagsToPHP($oAttributeNode);
  649. if (strlen($sFlags) > 0)
  650. {
  651. $sAttCode = $oAttributeNode->GetAttribute('name');
  652. $sLifecycle .= " '$sAttCode' => $sFlags,\n";
  653. }
  654. }
  655. $sLifecycle .= " ),\n";
  656. $sLifecycle .= " )\n";
  657. $sLifecycle .= " );\n";
  658. $oTransitions = $this->GetUniqueElement($oState, 'transitions');
  659. foreach ($oTransitions->getElementsByTagName('transition') as $oTransition)
  660. {
  661. $sStimulus = $oTransition->getAttribute('stimulus');
  662. $sTargetState = $oTransition->getAttribute('target');
  663. $oActions = $this->GetUniqueElement($oTransition, 'actions');
  664. $aVerbs = array();
  665. foreach ($oActions->getElementsByTagName('action') as $oAction)
  666. {
  667. $sVerb = $oAction->getAttribute('verb');
  668. $aVerbs[] = "'$sVerb'";
  669. }
  670. $sActions = implode(', ', $aVerbs);
  671. $sLifecycle .= " MetaModel::Init_DefineTransition(\"$sState\", \"$sStimulus\", array(\"target_state\"=>\"$sTargetState\", \"actions\"=>array($sActions), \"user_restriction\"=>null));\n";
  672. }
  673. }
  674. }
  675. // ZLists
  676. //
  677. $aListRef = array(
  678. 'details' => 'details',
  679. 'standard_search' => 'search',
  680. 'list' => 'list'
  681. );
  682. $oPresentation = $this->GetUniqueElement($oClass, 'presentation');
  683. $sZlists = '';
  684. foreach ($aListRef as $sListCode => $sListTag)
  685. {
  686. $oListNode = $this->GetOptionalElement($oPresentation, $sListTag);
  687. if ($oListNode)
  688. {
  689. $aAttributes = $this->GetNodeAsArrayOfItems($oListNode);
  690. $sZAttributes = var_export($aAttributes, true);
  691. $sZlists .= " MetaModel::Init_SetZListItems('$sListCode', $sZAttributes);\n";
  692. }
  693. }
  694. // Methods
  695. $sMethods = "";
  696. $oMethods = $this->GetUniqueElement($oClass, 'methods');
  697. foreach($oMethods->getElementsByTagName('method') as $oMethod)
  698. {
  699. $sMethodCode = $this->GetNodeText($oMethod);
  700. $oMethodComment = $this->GetOptionalElement($oMethod, 'comment');
  701. if ($oMethodComment)
  702. {
  703. $sMethods .= "\n\t".$oMethodComment->textContent."\n".$sMethodCode."\n";
  704. }
  705. else
  706. {
  707. $sMethods .= "\n\n".$sMethodCode."\n";
  708. }
  709. }
  710. // Let's make the whole class declaration
  711. //
  712. $sPHP = "\n\n$sCodeComment\n";
  713. if ($oClass->getAttribute('abstract') == 'true')
  714. {
  715. $sPHP .= 'abstract class '.$oClass->getAttribute('name');
  716. }
  717. else
  718. {
  719. $sPHP .= 'class '.$oClass->getAttribute('name');
  720. }
  721. $sPHP .= " extends ".$oClass->getAttribute('parent')."\n";
  722. $sPHP .=
  723. <<<EOF
  724. {
  725. public static function Init()
  726. {
  727. \$aParams = array
  728. (
  729. $sClassParams
  730. );
  731. MetaModel::Init_Params(\$aParams);
  732. MetaModel::Init_InheritAttributes();
  733. $sAttributes
  734. $sLifecycle
  735. $sZlists
  736. }
  737. $sMethods
  738. }
  739. EOF;
  740. file_put_contents($sResFile, $sPHP, FILE_APPEND);
  741. }// function CompileClass()
  742. protected function CompileMenu($oMenu, $sResFile, $sModuleRelativeDir, $oP)
  743. {
  744. $sMenuId = $oMenu->getAttribute("id");
  745. $sMenuClass = $oMenu->getAttribute("type");
  746. $oParent = $this->GetOptionalElement($oMenu, 'parent');
  747. if ($oParent)
  748. {
  749. $sParent = $oParent->GetAttribute('value');
  750. $sParentSpec = "\$__comp_menus__['$sParent']->GetIndex()";
  751. }
  752. else
  753. {
  754. $sParentSpec = '-1';
  755. }
  756. $fRank = $this->GetUniqueElement($oMenu, 'rank')->GetAttribute('value');
  757. switch($sMenuClass)
  758. {
  759. case 'WebPageMenuNode':
  760. $sUrl = $this->GetUniqueElement($oMenu, 'url')->GetAttribute('value');
  761. $sUrlSpec = $this->PathToPHP($sUrl, $sModuleRelativeDir, true /* Url */);
  762. $sNewMenu = "new WebPageMenuNode('$sMenuId', $sUrlSpec, $sParentSpec, $fRank);";
  763. break;
  764. case 'TemplateMenuNode':
  765. $sTemplateFile = $this->GetUniqueElement($oMenu, 'template_file')->GetAttribute('value');
  766. $sTemplateSpec = $this->PathToPHP($sTemplateFile, $sModuleRelativeDir);
  767. $sNewMenu = "new TemplateMenuNode('$sMenuId', $sTemplateSpec, $sParentSpec, $fRank);";
  768. break;
  769. case 'OQLMenuNode':
  770. $sOQL = $this->GetUniqueElement($oMenu, 'oql')->GetAttribute('value');
  771. $bSearch = ($this->GetUniqueElement($oMenu, 'do_search')->GetAttribute('value') == '1') ? 'true' : 'false';
  772. $sNewMenu = "new OQLMenuNode('$sMenuId', '$sOQL', $sParentSpec, $fRank, $bSearch);";
  773. break;
  774. case 'NewObjectMenuNode':
  775. $sClass = $this->GetUniqueElement($oMenu, 'class')->GetAttribute('value');
  776. $sNewMenu = "new NewObjectMenuNode('$sMenuId', '$sClass', $sParentSpec, $fRank);";
  777. break;
  778. case 'SearchMenuNode':
  779. $sClass = $this->GetUniqueElement($oMenu, 'class')->GetAttribute('value');
  780. $sNewMenu = "new SearchMenuNode('$sMenuId', '$sClass', $sParentSpec, $fRank);";
  781. break;
  782. case 'MenuGroup':
  783. default:
  784. if ($oEnableClass = $this->GetOptionalElement($oMenu, 'enable_class'))
  785. {
  786. $sEnableClass = $oEnableClass->GetAttribute('value');
  787. $sEnableAction = $this->GetUniqueElement($oMenu, 'enable_action')->GetAttribute('value');
  788. $sEnablePermission = $this->GetUniqueElement($oMenu, 'enable_permission')->GetAttribute('value');
  789. $sEnableStimulus = $this->GetUniqueElement($oMenu, 'enable_stimulus')->GetAttribute('value');
  790. if (strlen($sEnableStimulus) > 0)
  791. {
  792. $sNewMenu = "new MenuGroup('$sMenuId', $fRank, '$sEnableClass', $sEnableAction, $sEnablePermission, '$sEnableStimulus');";
  793. }
  794. else
  795. {
  796. $sNewMenu = "new MenuGroup('$sMenuId', $fRank, '$sEnableClass', $sEnableAction, $sEnablePermission);";
  797. }
  798. //$sNewMenu = "new MenuGroup('$sMenuId', $fRank, '$sEnableClass', UR_ACTION_MODIFY, UR_ALLOWED_YES|UR_ALLOWED_DEPENDS);";
  799. }
  800. else
  801. {
  802. $sNewMenu = "new MenuGroup('$sMenuId', $fRank);";
  803. }
  804. }
  805. $sIndent = '';
  806. $aPHPMenu = array("\$__comp_menus__['$sMenuId'] = $sNewMenu");
  807. if ($oAutoReload = $this->GetOptionalElement($oMenu, 'auto_reload'))
  808. {
  809. $sAutoReload = addslashes($oAutoReload->GetAttribute("value"));
  810. $aPHPMenu[] = "\$__comp_menus__['$sMenuId']->SetParameters(array('auto_reload' => '$sAutoReload'));";
  811. }
  812. $oAdminOnly = $this->GetOptionalElement($oMenu, 'enable_admin_only');
  813. if ($oAdminOnly && $oAdminOnly->GetAttribute('value') == '1')
  814. {
  815. $sPHP = $sIndent."if (UserRights::IsAdministrator())\n";
  816. $sPHP .= $sIndent."{\n";
  817. foreach($aPHPMenu as $sPHPLine)
  818. {
  819. $sPHP .= $sIndent." $sPHPLine\n";
  820. }
  821. $sPHP .= $sIndent."}\n";
  822. }
  823. else
  824. {
  825. $sPHP = '';
  826. foreach($aPHPMenu as $sPHPLine)
  827. {
  828. $sPHP .= $sIndent.$sPHPLine."\n";
  829. }
  830. }
  831. file_put_contents($sResFile, $sPHP, FILE_APPEND);
  832. }
  833. }
  834. ?>