2 /*********************************************************************************
3 * SugarCRM Community Edition is a customer relationship management program developed by
4 * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
6 * This program is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Affero General Public License version 3 as published by the
8 * Free Software Foundation with the addition of the following permission added
9 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
10 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
11 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
18 * You should have received a copy of the GNU Affero General Public License along with
19 * this program; if not, see http://www.gnu.org/licenses or write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
24 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26 * The interactive user interfaces in modified source and object code versions
27 * of this program must display Appropriate Legal Notices, as required under
28 * Section 5 of the GNU Affero General Public License version 3.
30 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
31 * these Appropriate Legal Notices must retain the display of the "Powered by
32 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
33 * technical reasons, the Appropriate Legal Notices must display the words
34 * "Powered by SugarCRM".
35 ********************************************************************************/
39 class UpgradeMetaHelper{
44 var $customized_modules;
49 var $path_to_master_copy;
52 * This is the constructor for the UpgradeMetaHelper class
53 * @param $dir The root upgrade directory (where to copy working files)
54 * @param $masterCopyDirectory The root master directory (where SugarCRM 5.x files reside)
55 * @param $debugMode Debug mode, default is false
58 function UpgradeMetaHelper($dir='upgrade', $masterCopyDirecotry='modules_50', $debugMode = false) {
59 $this->upgrade_dir = $dir;
60 $this->debug_mode = $debugMode;
61 $this->upgrade_modules = $this->getModifiedModules();
63 if(count($this->upgrade_modules) > 0) {
64 $_SESSION['Upgraded_Modules'] = $this->upgrade_modules;
65 $this->create_upgrade_directory();
66 $this->path_to_master_copy = $masterCopyDirecotry;
70 $this->customized_modules = $this->getAllCustomizedModulesBeyondStudio();
71 if(count($this->customized_modules) > 0) {
72 $_SESSION['Customized_Modules'] = $this->customized_modules;
79 * This method returns a two-dimensional Array of Studio enabled
80 * modules that have been modified. The second Array index is an
81 * Array of files that do not match the md5 checksum for the module
82 * @return $return_array Two-dimensional Array of [module][modified file(s) Array]
84 function getModifiedModules() {
86 $md5_string = array();
87 if(file_exists(clean_path(getcwd().'/files.md5'))){
88 require(clean_path(getcwd().'/files.md5'));
91 $return_array = array();
92 $modules = $this->loadStudioModules();
93 foreach($modules as $mod) {
95 $editView = "modules/$mod/EditView.html";
96 $detailView = "modules/$mod/DetailView.html";
97 $searchForm = "modules/$mod/SearchForm.html";
98 if(file_exists($editView) && isset($md5_string['./' . $editView])) {
99 $fileContents = file_get_contents($editView);
100 if(md5($fileContents) != $md5_string['./' . $editView]) {
101 $return_array[$mod][] = $editView;
105 if(file_exists($detailView) && isset($md5_string['./' . $detailView])) {
106 $fileContents = file_get_contents($detailView);
107 if(md5($fileContents) != $md5_string['./' . $detailView]) {
108 $return_array[$mod][] = $detailView;
112 if(file_exists($searchForm) && isset($md5_string['./' . $searchForm])) {
113 $fileContents = file_get_contents($searchForm);
114 if(md5($fileContents) != $md5_string['./' . $searchForm]) {
115 $return_array[$mod][] = $searchForm;
121 return $return_array;
124 function saveMatchingFilesQueries($currStep,$value){
125 $upgrade_progress_dir = sugar_cached('upgrades/temp');
126 if(!is_dir($upgrade_progress_dir)){
127 mkdir($upgrade_progress_dir);
129 $file_queries_file = $upgrade_progress_dir.'/files_queries.php';
130 if(file_exists($file_queries_file)){
131 include($file_queries_file);
134 if(function_exists('sugar_fopen')){
135 sugar_fopen($file_queries_file, 'w+');
138 fopen($file_queries_file, 'w+');
141 if(!isset($files_queries) || $files_queries == NULL){
142 $files_queries = array();
144 $files_queries[$currStep]=$value;
145 if(is_writable($file_queries_file) && write_array_to_file( "file_queries", $file_queries,
146 $file_queries_file)) {
147 //writing to the file
151 function getAllCustomizedModulesBeyondStudio() {
153 require_once('modules/UpgradeWizard/uw_utils.php');
154 $md5_string = array();
155 if(file_exists(clean_path(getcwd().'/files.md5'))){
156 require(clean_path(getcwd().'/files.md5'));
158 $return_array = array();
159 $modules = $this->loadStudioModules();
160 $modulesAll = getAllModules(); //keep all modules as well
161 $allOtherModules = array_diff($modulesAll,$modules);
162 foreach($modules as $mod) {
163 if(!is_dir('modules/'.$mod)) continue;
164 $editView = "modules/$mod/EditView.html";
165 $detailView ="modules/$mod/DetailView.html";
166 $exclude_files[]=$editView;
167 $exclude_files[]=$detailView;
168 $allModFiles = array();
169 $allModFiles = findAllFiles('modules/'.$mod,$allModFiles);
170 foreach($allModFiles as $file){
171 //$file_md5_ref = str_replace(clean_path(getcwd()),'',$file);
172 if(file_exists($file) && !in_array($file,$exclude_files)){
173 if(isset($md5_string['./'.$file])) {
174 $fileContents = file_get_contents($file);
175 if(md5($fileContents) != $md5_string['./'.$file]) {
176 $return_array[$mod][] = $file;
179 //keep in the array to be deleted later
180 $_SESSION['removeMd5MatchingFiles'][] = $file;
186 //also check out other non-studio modules by taking the difference between
188 foreach($allOtherModules as $mod) {
189 if(!is_dir('modules/'.$mod)) continue;
190 $allModFiles = array();
191 $allModFiles = findAllFiles('modules/'.$mod,$allModFiles);
192 foreach($allModFiles as $file){
193 //$file_md5_ref = str_replace(clean_path(getcwd()),'',$file);
194 if(file_exists($file)){
195 if(isset($md5_string['./'.$file])) {
196 $fileContents = file_get_contents($file);
197 if(md5($fileContents) == $md5_string['./'.$file]) {
198 $_SESSION['removeMd5MatchingFiles'][] = $file;
204 //Also store in a file
205 //saveMatchingFilesQueries('removeMd5MatchingFiles',$_SESSION['removeMd5MatchingFiles']);
206 return $return_array;
212 * Get all the customized modules. Compare the file md5s with the base md5s
213 * If a file has been modified then put the module in the list of customized
214 * modules. Show the list in the preflight check UI.
216 function getAllCustomizedModules() {
218 require_once('files.md5');
220 $return_array = array();
221 $modules = getAllModules();
222 foreach($modules as $mod) {
223 //find all files in each module if the files have been modified
224 //as compared to the base version then add the module to the
225 //customized modules array
226 $modFiles = findAllFiles(clean_path(getcwd())."/modules/$mod", array());
227 foreach($modFiles as $file){
228 $fileContents = file_get_contents($file);
229 $file = str_replace(clean_path(getcwd()),'',$file);
230 if($md5_string['./' . $file]){
231 if(md5($fileContents) != $md5_string['./' . $file]) {
232 //A file has been customized in the module. Put the module into the
233 // customized modules array.
234 echo 'Changed File'.$file;
240 // This is a new file in user's version and indicates that module has been
241 //customized. Put the module in the customized array.
242 echo 'New File'.$file;
249 return $return_array;
254 * This method returns an Array of all modules where a studio.php file is
255 * present in the metadata directory of the module
256 * @return $modules Array of modules that are studio enabled
258 function loadStudioModules() {
261 while($e = $d->read()){
262 if(substr($e, 0, 1) == '.' || !is_dir('modules/' . $e))continue;
263 if(file_exists('modules/' . $e . '/metadata/studio.php')){
273 * This method creates the EditView and DetailView parser intances
274 * and runs the parsing for the modules to upgrade
277 function runParser() {
278 require_once('include/SugarFields/Parsers/EditViewMetaParser.php');
279 require_once('include/SugarFields/Parsers/DetailViewMetaParser.php');
280 require_once('include/SugarFields/Parsers/SearchFormMetaParser.php');
282 $this->evparser = new EditViewMetaParser();
283 $this->dvparser = new DetailViewMetaParser();
284 $this->svparser = new SearchFormMetaParser();
286 foreach($this->upgrade_modules as $module_name=>$files) {
287 $this->parseFile($module_name, $files);
294 * Hanldes parsing the files for given module where Studio or manual
295 * changes have been detected.
296 * @param $module_name The module to parse
297 * @param $files Array of files found to parse
300 function parseFile($module_name, $files) {
301 global $beanList, $dictionary;
302 foreach($files as $file) {
303 if(preg_match('/(EditView|DetailView|SearchForm|QuickCreate)(\.html|\.tpl)$/s', $file, $matches)) {
307 case 'EditView' : $parser = $this->evparser; break;
308 case 'DetailView' : $parser = $this->dvparser; break;
309 case 'SearchForm' : $parser = $this->svparser; break;
312 $lowerCaseView = $view == 'SearchForm' ? 'search' : strtolower($view);
314 include('modules/'.$module_name.'/vardefs.php');
315 $bean_name = $beanList[$module_name];
316 $newFile = $this->upgrade_dir.'/modules/'.$module_name.'/metadata/'.$lowerCaseView.'defs.php';
317 $evfp = fopen($newFile,'w');
319 $bean_name = $bean_name == 'aCase' ? 'Case' : $bean_name;
320 fwrite($evfp, $parser->parse($file,
321 $dictionary[$bean_name]['fields'],
324 $this->path_to_master_copy.'/modules/'.$module_name.'/metadata/'.$lowerCaseView.'defs.php'));
332 * create_upgrade_directory
333 * Creates a directory called upgrade to house all the modules that are studio enabled.
334 * Also creates subdirectories for all studio enabled modules.
337 function create_upgrade_directory() {
339 $dir = $this->upgrade_dir.'/modules';
340 if(!file_exists($this->upgrade_dir)) {
341 mkdir($this->upgrade_dir, 0755);
343 if(!file_exists($dir)) {
347 foreach($this->upgrade_modules as $module=>$files){
348 if(!file_exists($dir.'/'.$module)) {
349 mkdir($dir.'/'.$module, 0755);
351 if(!file_exists($dir.'/'.$module.'/metadata')) {
352 mkdir($dir.'/'.$module.'/metadata', 0755);
355 foreach($files as $file) {
356 if(file_exists($file) && is_file($file)) {
357 copy($file, $this->upgrade_dir.'/'.$file);
366 * This function does some quick checks to make sure the metadataFile at
367 * least has an Array panel
369 * @param $metadataFile The path to the metadata file to verify
370 * @param $module The module to verify
371 * @param $view The view (EditView or DetailView)
372 * @return boolean true if verification check is okay; false otherwise
374 function verifyMetaData($metadataFile, $module, $view) {
375 if(!file_exists($metadataFile) || !is_file($metadataFile)) {
379 include($metadataFile);
381 if(isset($viewdefs) && isset($viewdefs[$module][$view]['panels']) && is_array($viewdefs[$module][$view]['panels'])) {
385 if(isset($searchdefs) && isset($searchdefs[$module]) && is_array($searchdefs[$module])) {