PageRenderTime 68ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/include/SugarFields/Parsers/MetaParser.php

https://github.com/mikmagic/sugarcrm_dev
PHP | 808 lines | 480 code | 120 blank | 208 comment | 138 complexity | 4ff1d9bb7b178e4c2e525a9aef53faaf MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause, AGPL-3.0
  1. <?php
  2. if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
  3. /*********************************************************************************
  4. * SugarCRM Community Edition is a customer relationship management program developed by
  5. * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
  6. *
  7. * This program is free software; you can redistribute it and/or modify it under
  8. * the terms of the GNU Affero General Public License version 3 as published by the
  9. * Free Software Foundation with the addition of the following permission added
  10. * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
  11. * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
  12. * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
  13. *
  14. * This program is distributed in the hope that it will be useful, but WITHOUT
  15. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  16. * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  17. * details.
  18. *
  19. * You should have received a copy of the GNU Affero General Public License along with
  20. * this program; if not, see http://www.gnu.org/licenses or write to the Free
  21. * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  22. * 02110-1301 USA.
  23. *
  24. * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
  25. * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
  26. *
  27. * The interactive user interfaces in modified source and object code versions
  28. * of this program must display Appropriate Legal Notices, as required under
  29. * Section 5 of the GNU Affero General Public License version 3.
  30. *
  31. * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
  32. * these Appropriate Legal Notices must retain the display of the "Powered by
  33. * SugarCRM" logo. If the display of the logo is not reasonably feasible for
  34. * technical reasons, the Appropriate Legal Notices must display the words
  35. * "Powered by SugarCRM".
  36. ********************************************************************************/
  37. /**
  38. * MetaParser.php
  39. *
  40. * This is a utility base file to parse HTML
  41. * @author Collin Lee
  42. */
  43. class MetaParser {
  44. var $mPHPFile;
  45. var $mView;
  46. var $mModule;
  47. var $mCustomPanels;
  48. function MetaParser() {
  49. }
  50. function parse() {
  51. return "NOT AVAILABLE";
  52. }
  53. /**
  54. * getFormContents
  55. * Parses for contents enclosed within <form>...</form> tags
  56. */
  57. function getFormContents($contents, $all = true) {
  58. if($all) {
  59. preg_match_all("'(<form[^>]*?>)(.*?)(</form[^>]*?>)'si", $contents, $matches);
  60. return $matches;
  61. }
  62. preg_match("'(<form[^>]*?>)(.*?)(</form[^>]*?>)'si", $contents, $matches);
  63. return $this->convertToTagElement($matches);
  64. //return $matches;
  65. }
  66. /**
  67. * getFormElements
  68. * Parses for input, select, textarea types from string content
  69. * @param $contents The String contents to parse
  70. * @return $matches Array of matches of PREG_SET_ORDER
  71. */
  72. function getFormElements($contents) {
  73. preg_match_all("'(<[ ]*?)(textarea|input|select)([^>]*?)(>)'si", $contents, $matches, PREG_PATTERN_ORDER);
  74. $elems = array();
  75. foreach($matches[3] as $match) {
  76. $elems[] = $match;
  77. }
  78. return $elems;
  79. }
  80. /**
  81. * getFormElementsNames
  82. * Parses for the name values of input, select, textarea types from string content
  83. * @param $contents The String contents to parse
  84. * @return $matches Array of name/value pairs
  85. */
  86. function getFormElementsNames($contents) {
  87. preg_match_all("'(<[ ]*?)(textarea|input|select)[^>]*?name=[\'\"]([^\'\"]*?)(\[\])?(_basic)?[\'\"]([^>]*?>)'si", $contents, $matches, PREG_PATTERN_ORDER);
  88. return !empty($matches[3]) ? $matches[3] : null;
  89. }
  90. /**
  91. * getTagAttribute
  92. * Returns the name/value of a tag attribute where name is set to $name
  93. * @param $name The name of the attribute
  94. * @param $contents The contents to parse
  95. * @param $filter Option regular expression to filter value
  96. * @return Array of name/value for matching attribute
  97. */
  98. function getTagAttribute($name, $contents, $filter = '') {
  99. //$exp = "'".$name."[ ]*?=[ ]*?[\'\"]([a-zA-Z0-9\_\[\]]*)[\'\"]'si";
  100. $exp = "'".$name."[\s]*?=[\s]*?[\'\"]([^\'^\"]*?)[\'\"]'si";
  101. preg_match_all($exp, $contents, $matches, PREG_SET_ORDER);
  102. if(empty($filter)) {
  103. return !empty($matches[0][1]) ? $matches[0][1] : '';
  104. }
  105. $filtered = array();
  106. foreach($matches as $tag) {
  107. if(preg_match($filter, $tag[1])) {
  108. $filtered[] = $tag;
  109. }
  110. }
  111. return $filtered;
  112. }
  113. /**
  114. * getTables
  115. * Returns an Array of the tables found in the file. If $tableClass parameter
  116. * is supplied, it'll return only those tables that have a matching class attribute
  117. * equal to $tableClass
  118. * @param $tableClass Optional table class parameter value
  119. * @return Array of table elements found
  120. */
  121. function getTables($tableClass = null, $contents) {
  122. preg_match_all("'(<table[^>]*?>)(.*?)(</table[^>]*?>)'si", $contents, $matches, PREG_SET_ORDER);
  123. if($tableClass == null) {
  124. return $matches;
  125. }
  126. $tables = array();
  127. foreach($matches as $key => $table) {
  128. if(strpos($table[1], $tableClass) > 0) {
  129. $tables[] = $table;
  130. }
  131. }
  132. return $this->convertToTagElement($tables);
  133. }
  134. /**
  135. * getElementsByType
  136. *
  137. * Returns an Array of all elements matching type. It will match
  138. * for the outermost tags. For example given contents:
  139. * "<tr><td>Text <table><tr><td>a</td></tr></table></td></tr>"
  140. * and method call getElementsByType("<td>", $contents) returns
  141. * "<td>Text <table><tr><td>a</td></tr></table></td>"
  142. *
  143. * @param $type The type of element to parse out and return
  144. * @return a tag element format Array
  145. */
  146. function getElementsByType($type, $contents) {
  147. $x = strlen($contents);
  148. $mark = 0;
  149. $count = 0;
  150. $stag1 = "<" . trim($type, " <>") . '>';
  151. $stag2 = "<" . trim($type, " <>") . ' ';
  152. $etag = "</".$type.">";
  153. $sincrement = strlen($stag1);
  154. $eincrement = strlen($etag);
  155. $sarr = array();
  156. $values = array();
  157. while($count < $x) {
  158. $stok = substr($contents, $count, $sincrement);
  159. $etok = substr($contents, $count, $eincrement);
  160. if($stok == $stag1 || $stok == $stag2) {
  161. //Reset mark;
  162. if(count($sarr) == 0) {
  163. $mark = $count;
  164. }
  165. $sarr[] = $count;
  166. } else if($etok == $etag) {
  167. array_shift($sarr);
  168. if(count($sarr) == 0) {
  169. $val = substr($contents, $mark, ($count - $mark) + $eincrement);
  170. $values[] = $val;
  171. $mark = $count;
  172. }
  173. }
  174. $count++;
  175. }
  176. $count = 0;
  177. return $values;
  178. }
  179. /**
  180. * getElementValue
  181. *
  182. */
  183. function getElementValue($type, $contents, $filter = "(.*?)") {
  184. $exp = "'<".$type."[^>]*?>".$filter."</".$type."[^>]*?>'si";
  185. preg_match($exp, $contents, $matches);
  186. return isset($matches[1]) ? $matches[1] : '';
  187. }
  188. function stripComments($contents) {
  189. return preg_replace("'(<!--.*?-->)'si", "", $contents);
  190. }
  191. /**
  192. * stripFlavorTags
  193. * This method accepts the file contents and uses the $GLOBALS['sugar_flavor'] value
  194. * to remove the flavor tags in the file contents if present. If $GLOBALS['sugar_flavor']
  195. * is not set, it defaults to PRO flavor
  196. * @param $contents The file contents as a String value
  197. * @param $result The file contents with non-matching flavor tags and their nested comments removed
  198. */
  199. function stripFlavorTags($contents) {
  200. $flavor = isset($GLOBALS['sugar_flavor']) ? $GLOBALS['sugar_flavor'] : 'PRO';
  201. $isPro = ($flavor == 'ENT' || $flavor == 'PRO') ? true : false;
  202. if($isPro) {
  203. $contents = preg_replace('/<!-- BEGIN: open_source -->.*?<!-- END: open_source -->/', '', $contents);
  204. } else {
  205. $contents = preg_replace('/<!-- BEGIN: pro -->.*?<!-- END: pro -->/', '', $contents);
  206. }
  207. return $contents;
  208. }
  209. /**
  210. * getMaxColumns
  211. * Returns the highest number of <td>...</td> blocks within a <tr>...</tr> block.
  212. * @param $contents The table contents to parse
  213. * @param $filter Optional filter to parse for an attribute within the td block.
  214. * @return The maximum column count
  215. */
  216. function getMaxColumns($contents, $filter) {
  217. preg_match_all("'(<tr[^>]*?>)(.*?)(</tr[^>]*?>)'si", $contents, $matches, PREG_SET_ORDER);
  218. $max = 0;
  219. foreach($matches as $tableRows) {
  220. $count = substr_count($tableRows[2], $filter);
  221. if($count > $max) {
  222. $max = $count;
  223. }
  224. }
  225. return $max;
  226. }
  227. function convertToTagElement($matches) {
  228. $elements = array();
  229. foreach($matches as $data) {
  230. // We need 4 because the 1,2,3 indexes make up start,body,end
  231. if(count($data) == 4) {
  232. $element = array();
  233. $element['start'] = $data[1];
  234. $element['body'] = $data[2];
  235. $element['end'] = $data[3];
  236. $elements[] = $element;
  237. }
  238. }
  239. return empty($elements) ? $matches : $elements;
  240. }
  241. /*
  242. * trimHTML
  243. * This function removes the \r (return), \n (newline) and \t (tab) markup from string
  244. */
  245. function trimHTML($contents) {
  246. $contents = str_replace(array("\r"), array(""), $contents);
  247. $contents = str_replace(array("\n"), array(""), $contents);
  248. $contents = str_replace(array("\t"), array(""), $contents);
  249. return $contents;
  250. }
  251. /**
  252. * getJavascript
  253. *
  254. * This method parses the given $contents String and grabs all <script...>...</script> blocks.
  255. * The method also converts values enclosed within "{...}" blocks that may need to be converted
  256. * to Smarty syntax.
  257. *
  258. * @param $contents The HTML String contents to parse
  259. *
  260. * @return $javascript The formatted script blocks or null if none found
  261. */
  262. function getJavascript($contents, $addLiterals = true) {
  263. $javascript = null;
  264. //Check if there are Javascript blocks of code to process
  265. preg_match_all("'(<script[^>]*?>)(.*?)(</script[^>]*?>)'si", $contents, $matches, PREG_PATTERN_ORDER);
  266. if(empty($matches)) {
  267. return $javascript;
  268. }
  269. foreach($matches[0] as $scriptBlock) {
  270. $javascript .= "\n" . $scriptBlock;
  271. } //foreach
  272. $javascript = substr($javascript, 1);
  273. //Remove stuff first
  274. //1) Calendar.setup {..} blocks
  275. $javascript = preg_replace('/Calendar.setup[\s]*[\(][^\)]*?[\)][\s]*;/si', '', $javascript);
  276. //Find all blocks that may need to be replaced with Smarty syntax
  277. preg_match_all("'([\{])([a-zA-Z0-9_]*?)([\}])'si", $javascript, $matches, PREG_PATTERN_ORDER);
  278. if(!empty($matches)) {
  279. $replace = array();
  280. foreach($matches[0] as $xTemplateCode) {
  281. if(!isset($replace[$xTemplateCode])) {
  282. $replace[$xTemplateCode] = str_replace("{", "{\$", $xTemplateCode);
  283. } //if
  284. } //foreach
  285. $javascript = str_replace(array_keys($replace), array_values($replace), $javascript);
  286. } //if
  287. if(!$addLiterals) {
  288. return $javascript;
  289. }
  290. return $this->parseDelimiters($javascript);
  291. }
  292. function parseDelimiters($javascript) {
  293. $newJavascript = '';
  294. $scriptLength = strlen($javascript);
  295. $count = 0;
  296. $inSmartyVariable = false;
  297. while($count < $scriptLength) {
  298. if($inSmartyVariable) {
  299. $start = $count;
  300. $numOfChars = 1;
  301. while(isset($javascript[$count]) && $javascript[$count] != '}') {
  302. $count++;
  303. $numOfChars++;
  304. }
  305. $newJavascript .= substr($javascript, $start, $numOfChars);
  306. $inSmartyVariable = false;
  307. } else {
  308. $char = $javascript[$count];
  309. $nextChar = ($count + 1 >= $scriptLength) ? '' : $javascript[$count + 1];
  310. if($char == "{" && $nextChar == "$") {
  311. $inSmartyVariable = true;
  312. $newJavascript .= $javascript[$count];
  313. } else if($char == "{") {
  314. $newJavascript .= " {ldelim} ";
  315. } else if($char == "}") {
  316. $newJavascript .= " {rdelim} ";
  317. } else {
  318. $newJavascript .= $javascript[$count];
  319. }
  320. }
  321. $count++;
  322. } //while
  323. return $newJavascript;
  324. }
  325. /**
  326. * findAssignedVariableName
  327. * This method provides additional support in attempting to parse the module's corresponding
  328. * PHP file for either the EditView or DetailView. In the event that the subclasses cannot
  329. * find a matching vardefs.php entry in the HTML file, this method can be called to parse the
  330. * PHP file to see if the assignment was made using the bean's variable. If so, we return
  331. * this variable name.
  332. *
  333. * @param $name The tag name found in the HTML file for which we want to search
  334. * @param $filePath The full file path for the HTML file
  335. * @return The variable name found in PHP file, original $name variable if not found
  336. */
  337. function findAssignedVariableName($name, $filePath) {
  338. if($this->mPHPFile == "INVALID") {
  339. return $name;
  340. }
  341. if(!isset($this->mPHPFile)) {
  342. if(preg_match('/(.*?)(DetailView).html$/', $filePath, $matches)) {
  343. $dir = $matches[1];
  344. } else if(preg_match('/(.*?)(EditView).html$/', $filePath, $matches)) {
  345. $dir = $matches[1];
  346. }
  347. if(!isset($dir) || !is_dir($dir)) {
  348. $this->mPHPFile = "INVALID";
  349. return $name;
  350. }
  351. $filesInDir = $this->dirList($dir);
  352. $phpFile = $matches[2].'.*?[\.]php';
  353. foreach($filesInDir as $file) {
  354. if(preg_match("/$phpFile/", $file)) {
  355. $this->mPHPFile = $matches[1] . $file;
  356. break;
  357. }
  358. }
  359. if(!isset($this->mPHPFile) || !file_exists($this->mPHPFile)) {
  360. $this->mPHPFile = "INVALID";
  361. return $name;
  362. }
  363. }
  364. $phpContents = file_get_contents($this->mPHPFile);
  365. $uname = strtoupper($name);
  366. if(preg_match("/xtpl->assign[\(][\"\']".$uname."[\"\'][\s]*?,[\s]*?[\$]focus->(.*?)[\)]/si", $phpContents, $matches)) {
  367. return $matches[1];
  368. }
  369. return $name;
  370. }
  371. /**
  372. * dirList
  373. * Utility method to list all the files in a given directory.
  374. *
  375. * @param $directory The directory to scan
  376. * @return $results The files in the directory that were found
  377. */
  378. function dirList ($directory) {
  379. // create an array to hold directory list
  380. $results = array();
  381. // create a handler for the directory
  382. $handler = opendir($directory);
  383. // keep going until all files in directory have been read
  384. while ($file = readdir($handler)) {
  385. // if $file isn't this directory or its parent,
  386. // add it to the results array
  387. if ($file != '.' && $file != '..')
  388. $results[] = $file;
  389. }
  390. // tidy up: close the handler
  391. closedir($handler);
  392. return $results;
  393. }
  394. /**
  395. * isCustomField
  396. * This method checks the mixed variable $elementNames to see if it is a custom field. A custom
  397. * field is simply defined as a field that ends with "_c". If $elementNames is an Array
  398. * any matching custom field value will result in a true evaluation
  399. * @param $elementNames Array or String value of form element name(s).
  400. * @return String name of custom field; null if none found
  401. */
  402. function getCustomField($elementNames) {
  403. if(!isset($elementNames) || (!is_string($elementNames) && !is_array($elementNames))) {
  404. return null;
  405. }
  406. if(is_string($elementNames)) {
  407. if(preg_match('/(.+_c)(_basic)?(\[\])?$/', $elementNames, $matches)) {
  408. return count($matches) == 1 ? $matches[0] : $matches[1];
  409. }
  410. return null;
  411. }
  412. foreach($elementNames as $name) {
  413. if(preg_match('/(.+_c)(_basic)?(\[\])?$/', $name, $matches)) {
  414. return count($matches) == 1 ? $matches[0] : $matches[1];
  415. }
  416. }
  417. return null;
  418. }
  419. function applyPreRules($moduleDir, $panels) {
  420. if(file_exists("include/SugarFields/Parsers/Rules/".$moduleDir."ParseRule.php")) {
  421. require_once("include/SugarFields/Parsers/Rules/".$moduleDir."ParseRule.php");
  422. $class = $moduleDir."ParseRule";
  423. $parseRule = new $class();
  424. $panels = $parseRule->preParse($panels, $this->mView);
  425. }
  426. return $panels;
  427. }
  428. function applyRules($moduleDir, $panels) {
  429. return $this->applyPostRules($moduleDir, $panels);
  430. }
  431. function applyPostRules($moduleDir, $panels) {
  432. //Run module specific rules
  433. if(file_exists("include/SugarFields/Parsers/Rules/".$moduleDir."ParseRule.php")) {
  434. require_once("include/SugarFields/Parsers/Rules/".$moduleDir."ParseRule.php");
  435. $class = $moduleDir."ParseRule";
  436. $parseRule = new $class();
  437. $panels = $parseRule->parsePanels($panels, $this->mView);
  438. }
  439. //Now run defined rules
  440. require_once("include/SugarFields/Parsers/Rules/ParseRules.php");
  441. $rules = ParseRules::getRules();
  442. foreach($rules as $rule) {
  443. if(!file_exists($rule['file'])) {
  444. $GLOBALS['log']->error("Cannot run rule for " . $rule['file']);
  445. continue;
  446. } //if
  447. require_once($rule['file']);
  448. $runRule = new $rule['class'];
  449. $panels = $runRule->parsePanels($panels, $this->mView);
  450. } //foreach
  451. return $panels;
  452. }
  453. function createFileContents($moduleDir, $panels, $templateMeta=array(), $htmlFilePath) {
  454. $header = "<?php\n\n";
  455. if(empty($templateMeta)) {
  456. $header .= "\$viewdefs['$moduleDir']['$this->mView'] = array(
  457. 'templateMeta' => array('maxColumns' => '2',
  458. 'widths' => array(
  459. array('label' => '10', 'field' => '30'),
  460. array('label' => '10', 'field' => '30')
  461. ),
  462. ),";
  463. } else {
  464. $header .= "\$viewdefs['$moduleDir']['$this->mView'] = array(
  465. 'templateMeta' =>" . var_export($templateMeta, true) . ",";
  466. }
  467. //Replace all the @sq (single quote tags that may have been inserted)
  468. $header = preg_replace('/\@sq/', "'", $header);
  469. /*
  470. $contents = file_get_contents($htmlFilePath);
  471. $javascript = $this->getJavascript($contents, true);
  472. if(!empty($javascript)) {
  473. $javascript = str_replace("'", "\\'", $javascript);
  474. $header .= "\n 'javascript' => '" . $javascript . "',\n";
  475. } //if
  476. */
  477. $header .= "\n 'panels' =>";
  478. $footer = "
  479. \n
  480. );
  481. ?>";
  482. $metadata = '';
  483. $body = var_export($panels, true);
  484. $metadata = $header . $body . $footer;
  485. $metadata = preg_replace('/(\d+)[\s]=>[\s]?/',"",$metadata);
  486. return $metadata;
  487. }
  488. /**
  489. * mergePanels
  490. * This function merges the $panels Array against the $masterCopy's meta data definition
  491. * @param $panels meta data Array to merge
  492. * @param $moduleDir Directory name of the module
  493. * @param $masterCopy file path to the meta data master copy
  494. * @return Array of merged $panel definition
  495. */
  496. function mergePanels($panels, $vardefs, $moduleDir, $masterCopy) {
  497. require($masterCopy);
  498. $masterpanels = $viewdefs[$moduleDir][$this->mView]['panels'];
  499. $hasMultiplePanels = $this->hasMultiplePanels($masterpanels);
  500. if(!$hasMultiplePanels) {
  501. $keys = array_keys($viewdefs[$moduleDir][$this->mView]['panels']);
  502. if(!empty($keys) && count($keys) == 1) {
  503. if(strtolower($keys[0]) == 'default') {
  504. $masterpanels = array('default'=>$viewdefs[$moduleDir][$this->mView]['panels'][$keys[0]]);
  505. } else {
  506. $firstPanel = array_values($viewdefs[$moduleDir][$this->mView]['panels']);
  507. $masterpanels = array('default'=> $firstPanel[0]);
  508. }
  509. } else {
  510. $masterpanels = array('default'=>$viewdefs[$moduleDir][$this->mView]['panels']);
  511. }
  512. }
  513. foreach($masterpanels as $name=>$masterpanel) {
  514. if(isset($panels[$name])) {
  515. // Get all the names in the panel
  516. $existingElements = array();
  517. $existingLocation = array();
  518. foreach($panels[$name] as $rowKey=>$row) {
  519. foreach($row as $colKey=>$column) {
  520. if(is_array($column) && !empty($column['name'])) {
  521. $existingElements[$column['name']] = $column['name'];
  522. $existingLocation[$column['name']] = array("panel"=>$name, "row"=>$rowKey, "col"=>$colKey);
  523. } else if(!is_array($column) && !empty($column)) {
  524. $existingElements[$column] = $column;
  525. $existingLocation[$column] = array("panel"=>$name, "row"=>$rowKey, "col"=>$colKey);
  526. }
  527. } //foreach
  528. } //foreach
  529. // Now check against the $masterCopy
  530. foreach($masterpanel as $rowKey=>$row) {
  531. $addRow = array();
  532. foreach($row as $colKey=>$column) {
  533. if(is_array($column) && isset($column['name'])) {
  534. $id = $column['name'];
  535. } else if(!is_array($column) && !empty($column)) {
  536. $id = $column;
  537. } else {
  538. continue;
  539. }
  540. if(empty($existingElements[$id])) {
  541. //Only add if
  542. // 1) if it is a required field (as defined in metadata)
  543. // 2) or if it has a customLabel and customCode (a very deep customization)
  544. if((is_array($column) && !empty($column['displayParams']['required'])) ||
  545. (is_array($column) && !empty($column['customCode']) && !empty($column['customLabel']))) {
  546. $addRow[] = $column;
  547. }
  548. } else {
  549. //Use definition from master copy instead
  550. $panels[$existingLocation[$id]['panel']][$existingLocation[$id]['row']][$existingLocation[$id]['col']] = $column;
  551. }
  552. } //foreach
  553. // Add it to the $panels
  554. if(!empty($addRow)) {
  555. $panels[$name][] = $addRow;
  556. }
  557. } //foreach
  558. } else {
  559. $panels[$name] = $masterpanel;
  560. }
  561. } //foreach
  562. // We're not done yet... go through the $panels Array now and try to remove duplicate
  563. // or empty panels
  564. foreach($panels as $name=>$panel) {
  565. if(count($panel) == 0 || !isset($masterpanels[$name])) {
  566. unset($panels[$name]);
  567. }
  568. } //foreach
  569. return $panels;
  570. }
  571. /**
  572. * mergeTemplateMeta
  573. * This function merges the $templateMeta Array against the $masterCopy's meta data definition
  574. * @param $templateMeta meta data Array to merge
  575. * @param $moduleDir Directory name of the module
  576. * @param $masterCopy file path to the meta data master copy
  577. * @return Array of merged $templateMeta definition
  578. */
  579. function mergeTemplateMeta($templateMeta, $moduleDir, $masterCopy) {
  580. require($masterCopy);
  581. $masterTemplateMeta = $viewdefs[$moduleDir][$this->mView]['templateMeta'];
  582. if(isset($masterTemplateMeta['javascript'])) {
  583. //Insert the getJSPath code back into src value
  584. $masterTemplateMeta['javascript'] = preg_replace('/src\s*=\s*[\'\"].*?(modules\/|include\/)([^\.]*?\.js)([^\'\"]*?)[\'\"]/i', 'src="@sq . getJSPath(@sq${1}${2}@sq) . @sq"', $masterTemplateMeta['javascript']);
  585. }
  586. return $masterTemplateMeta;
  587. }
  588. function hasRequiredSpanLabel($html) {
  589. if(empty($html)) {
  590. return false;
  591. }
  592. return preg_match('/\<(div|span) class=(\")?required(\")?\s?>\*<\/(div|span)>/si', $html);
  593. }
  594. function hasMultiplePanels($panels) {
  595. if(!isset($panels) || empty($panels) || !is_array($panels)) {
  596. return false;
  597. }
  598. if(is_array($panels) && (count($panels) == 0 || count($panels) == 1)) {
  599. return false;
  600. }
  601. foreach($panels as $panel) {
  602. if(!empty($panel) && !is_array($panel)) {
  603. return false;
  604. } else {
  605. foreach($panel as $row) {
  606. if(!empty($row) && !is_array($row)) {
  607. return false;
  608. } //if
  609. } //foreach
  610. } //if-else
  611. } //foreach
  612. return true;
  613. }
  614. function getRelateFieldName($mixed='') {
  615. if(!is_array($mixed)) {
  616. return '';
  617. } else if(count($mixed) == 2){
  618. $id = '';
  619. $name = '';
  620. foreach($mixed as $el) {
  621. if(preg_match('/_id$/', $el)) {
  622. $id = $el;
  623. } else if(preg_match('/_name$/', $el)) {
  624. $name = $el;
  625. }
  626. }
  627. return (!empty($id) && !empty($name)) ? $name : '';
  628. }
  629. return '';
  630. }
  631. function getCustomPanels() {
  632. return $this->mCustomPanels;
  633. }
  634. /**
  635. * fixTablesWithMissingTr
  636. * This is a very crude function to fix instances where files declared a table as
  637. * <table...><td> instead of <table...><tr><td>. Without this helper function, the
  638. * parsing could messed up.
  639. *
  640. */
  641. function fixTablesWithMissingTr($tableContents) {
  642. if(preg_match('/(<table[^>]*?[\/]?>\s*?<td)/i', $tableContents, $matches)) {
  643. return preg_replace('/(<table[^>]*?[\/]?>\s*?<td)/i', '<table><tr><td', $tableContents);
  644. }
  645. return $tableContents;
  646. }
  647. /**
  648. * fixRowsWithMissingTr
  649. * This is a very crude function to fix instances where files have an </tr> tag immediately followed by a <td> tag
  650. */
  651. function fixRowsWithMissingTr($tableContents) {
  652. if(preg_match('/(<\/tr[^>]*?[\/]?>\s*?<td)/i', $tableContents, $matches)) {
  653. return preg_replace('/(<\/tr[^>]*?[\/]?>\s*?<td)/i', '</tr><tr><td', $tableContents);
  654. }
  655. return $tableContents;
  656. }
  657. /**
  658. * fixDuplicateTrTags
  659. * This is a very crude function to fix instances where files have two consecutive <tr> tags
  660. */
  661. function fixDuplicateTrTags($tableContents) {
  662. if(preg_match('/(<tr[^>]*?[\/]?>\s*?<tr)/i', $tableContents, $matches)) {
  663. return preg_replace('/(<tr[^>]*?[\/]?>\s*?<tr)/i', '<tr', $tableContents);
  664. }
  665. return $tableContents;
  666. }
  667. /**
  668. * findSingleVardefElement
  669. * Scans array of form elements to see if just one is a vardef element and, if so,
  670. * return that vardef name
  671. */
  672. function findSingleVardefElement($formElements=array(), $vardefs=array()) {
  673. if(empty($formElements) || !is_array($formElements)) {
  674. return '';
  675. }
  676. $found = array();
  677. foreach($formElements as $el) {
  678. if(isset($vardefs[$el])) {
  679. $found[] = $el;
  680. }
  681. }
  682. return count($found) == 1 ? $found[0] : '';
  683. }
  684. }
  685. ?>