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-2012 SugarCRM Inc.
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.
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
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
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.
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.
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 ********************************************************************************/
40 * EdtiViewMetaParser.php
41 * This is a utility file that attempts to provide support for parsing pre 5.0 SugarCRM
42 * EditView.html files and produce a best guess editviewdefs.php file equivalent.
47 require_once('include/SugarFields/Parsers/MetaParser.php');
49 class EditViewMetaParser extends MetaParser {
51 function EditViewMetaParser() {
52 $this->mView = 'EditView';
58 * @param $filePath The file path of the HTML file to parse
59 * @param $vardefs The module's vardefs
60 * @param $moduleDir The module's directory
61 * @param $merge boolean value indicating whether or not to merge the parsed contents
62 * @param $masterCopy The file path of the mater copy of the metadata file to merge against
63 * @return String format of metadata contents
65 function parse($filePath, $vardefs = array(), $moduleDir = '', $merge=false, $masterCopy=null) {
68 $contents = file_get_contents($filePath);
69 $contents = $this->trimHTML($contents);
70 $contents = $this->stripFlavorTags($contents);
73 $contents = $this->fixDuplicateTrTags($contents);
74 $contents = $this->fixRowsWithMissingTr($contents);
76 $tables = $this->getElementsByType("table", $contents);
77 $formElements = $this->getFormElements($tables[0]);
78 $hiddenInputs = array();
79 foreach($formElements as $elem) {
80 $type = $this->getTagAttribute("type", $elem);
81 if(preg_match('/hidden/si',$type)) {
82 $name = $this->getTagAttribute("name", $elem);
83 $value = $this->getTagAttribute("value", $elem);
84 $hiddenInputs[$name] = $value;
88 // Get the second table in the page and onward
89 $tables = array_slice($tables, 1);
92 $addedElements = array();
93 $maxTableCountNum = 0;
95 foreach($tables as $table) {
96 $table = $this->fixTablesWithMissingTr($table);
97 $toptr = $this->getElementsByType("tr", $table);
98 foreach($toptr as $tr) {
99 $tabledata = $this->getElementsByType("table", $tr);
101 $panelKey = $tableCount == 0 ? "default" : '';
102 foreach($tabledata as $t) {
103 $vals = array_values($this->getElementsByType("tr", $t));
104 if(preg_match_all('/<h4[^>]*?>.*?(\{MOD\.|\{APP\.)(LBL_[^\}]*?)[\}].*?<\/h4>/s', $vals[0], $matches, PREG_SET_ORDER)) {
106 $panelKey = count($matches[0]) == 3 ? strtolower($matches[0][2]) : $panelKey;
109 //If $panelKey is empty use the maxTableCountNum value
110 if(empty($panelKey)) {
111 $panels[$maxTableCountNum++] = $vals;
113 $panels[$panelKey] = $vals;
120 foreach($panels as $id=>$tablerows) {
124 foreach($tablerows as $trow) {
127 $tablecolumns = $this->getElementsByType("td", $trow);
131 foreach($tablecolumns as $tcols) {
132 $hasRequiredLabel = false;
134 //Get the sugar attribute value in the span elements of each table row
135 $sugarAttrLabel = $this->getTagAttribute("sugar", $tcols, "'^slot[^b]+$'");
137 //If there was no sugar attribute, try id (some versions of EditView.html used this instead)
138 if(empty($sugarAttrLabel)) {
139 $sugarAttrLabel = $this->getTagAttribute("id", $tcols, "'^slot[^b]+$'");
142 //Check if this field is required
143 if(!empty($sugarAttrLabel)) {
144 $hasRequiredLabel = $this->hasRequiredSpanLabel($tcols);
147 $sugarAttrValue = $this->getTagAttribute("sugar", $tcols, "'slot[0-9]+b$'");
149 //If there was no sugar attribute, try id (some versions of EditView.html used this instead)
150 if(empty($sugarAttrValue)) {
151 $sugarAttrValue = $this->getTagAttribute("id", $tcols, "'slot[0-9]+b$'");
154 // If there wasn't any slot numbering/lettering then just default to expect label->vallue pairs
155 $sugarAttrLabel = count($sugarAttrLabel) != 0 ? $sugarAttrLabel : ($slot % 2 == 0) ? true : false;
156 $sugarAttrValue = count($sugarAttrValue) != 0 ? $sugarAttrValue : ($slot % 2 == 1) ? true : false;
159 if($sugarAttrValue) {
161 $spanValue = $this->getElementValue("span", $tcols);
163 if(empty($spanValue)) {
164 $spanValue = $this->getElementValue("slot", $tcols);
167 if(empty($spanValue)) {
168 $spanValue = $this->getElementValue("td", $tcols);
171 //Get all the editable form elements' names
172 $formElementNames = $this->getFormElementsNames($spanValue);
173 $customField = $this->getCustomField($formElementNames);
179 if(!empty($customField)) {
180 // If it's a custom field we just set the name
181 $name = $customField;
183 } else if(empty($formElementNames) && preg_match_all('/[\{]([^\}]*?)[\}]/s', $spanValue, $matches, PREG_SET_ORDER)) {
184 // We are here if the $spanValue did not contain a form element for editing.
185 // We will assume that it is read only (since there were no edit form elements)
188 // If there is more than one matching {} value then try to find the right one to key off
189 // based on vardefs.php file. Also, use the entire spanValue as customCode
190 if(count($matches) > 1) {
191 $name = $matches[0][1];
192 $customCode = $spanValue;
193 foreach($matches as $pair) {
194 if(preg_match("/^(mod[\.]|app[\.]).*?/i", $pair[1])) {
195 $customCode = str_replace($pair[1], '$'.strtoupper($pair[1]), $customCode);
197 if(!empty($vardefs[$pair[1]])) {
199 $customCode = str_replace($pair[1], '$fields.'.strtolower($pair[1]).'.value', $customCode);
201 $phpName = $this->findAssignedVariableName($pair[1], $filePath);
202 $customCode = str_replace($pair[1], '$fields.'.strtolower($phpName).'.value', $customCode);
207 //If it is only a label, skip
208 if(preg_match("/^(mod[\.]|app[\.]).*?/i", $matches[0][1])) {
211 $name = strtolower($matches[0][1]);
214 } else if(is_array($formElementNames)) {
216 if(count($formElementNames) == 1) {
218 if(!empty($vardefs[$formElementNames[0]])) {
219 $name = $formElementNames[0];
221 // Try to use the EdtiView.php file to find author's intent
222 $name = $this->findAssignedVariableName($formElementNames[0], $filePath);
224 //If it's still empty, just use the entire block as customCode
225 if(empty($vardefs[$name])) {
226 //Replace any { characters just in case
227 $customCode = str_replace('{', '{$', $spanValue);
231 //If it is an Array of form elements, it is likely the _id and _name relate field combo
232 $relateName = $this->getRelateFieldName($formElementNames);
233 if(!empty($relateName)) {
236 //One last attempt to scan $formElementNames for one vardef field only
237 $name = $this->findSingleVardefElement($formElementNames, $vardefs);
240 $name = $formElementNames[0];
241 foreach($formElementNames as $elementName) {
242 if(isset($vardefs[$elementName])) {
243 $fields[] = $elementName;
245 $fields[] = $this->findAssignedVariableName($elementName, $filePath);
254 if(preg_match("/<textarea/si", $spanValue)) {
255 //special case for textarea form elements (add the displayParams)
256 $displayParams = array();
257 $displayParams['rows'] = $this->getTagAttribute("rows", $spanValue);
258 $displayParams['cols'] = $this->getTagAttribute("cols", $spanValue);
260 if(!empty($displayParams['rows']) && !empty($displayParams['cols'])) {
262 $field['name'] = $name;
263 $field['displayParams'] = $displayParams;
269 if(isset($fields) || isset($customCode)) {
271 $field['name'] = $name;
273 $field['fields'] = $fields;
275 if(isset($customCode)) {
276 $field['customCode'] = $customCode;
277 $field['description'] = 'This field was auto generated';
280 $emptyCount = $name == '' ? $emptyCount + 1 : $emptyCount;
283 } //if-else if-else block
285 $addedField = is_array($field) ? $field['name'] : $field;
286 if(empty($addedField) || empty($addedElements[$addedField])) {
287 //Add the meta-data definition for required fields
288 if($hasRequiredLabel) {
289 if(is_array($field)) {
290 if(isset($field['displayParams']) && is_array($field['displayParams'])) {
291 $field['displayParams']['required']=true;
293 $field['displayParams'] = array('required'=>true);
296 $field = array('name'=>strtolower($field), 'displayParams'=>array('required'=>true));
299 $col[] = is_array($field) ? $field : strtolower($field);
300 $addedElements[$addedField] = $addedField;
302 } //if($sugarAttValue)
305 // One last final check. If $emptyCount does not equal Array $col count, don't add
306 if($emptyCount != count($col)) {
308 if($hasRequiredLabel) {
310 if(isset($col['displayParams'])) {
311 $col['displayParams']['required']=true;
313 $col['displayParams']=array('required'=>true);
316 $col = array('name'=>strtolower($col), 'displayParams'=>array('required'=>true));
324 $panels[$id] = $metarow;
328 $this->mCustomPanels = $panels;
329 $panels = $this->applyPreRules($moduleDir, $panels);
331 $templateMeta = array();
332 if($merge && !empty($masterCopy) && file_exists($masterCopy)) {
333 $panels = $this->mergePanels($panels, $vardefs, $moduleDir, $masterCopy);
334 $templateMeta = $this->mergeTemplateMeta($templateMeta, $moduleDir, $masterCopy);
336 $panels = $this->applyRules($moduleDir, $panels);
337 return $this->createFileContents($moduleDir, $panels, $templateMeta, $filePath);