2016-01-30 20:28:43 +00:00
< ? php
2018-05-18 06:28:27 +00:00
/**
* @ package Joomla . Component . Builder
*
* @ created 30 th April , 2015
* @ author Llewellyn van der Merwe < http :// www . joomlacomponentbuilder . com >
* @ github Joomla Component Builder < https :// github . com / vdm - io / Joomla - Component - Builder >
2019-03-04 12:47:28 +00:00
* @ copyright Copyright ( C ) 2015 - 2019 Vast Development Method . All rights reserved .
2018-05-18 06:28:27 +00:00
* @ license GNU General Public License version 2 or later ; see LICENSE . txt
*/
2016-01-30 20:28:43 +00:00
// No direct access to this file
defined ( '_JEXEC' ) or die ( 'Restricted access' );
2016-02-29 11:05:37 +00:00
// Use the component builder autoloader
2016-02-26 00:20:09 +00:00
ComponentbuilderHelper :: autoLoader ();
2016-01-30 20:28:43 +00:00
/**
* Compiler class
*/
2016-02-26 00:20:09 +00:00
class Compiler extends Infusion
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
/*
* The Temp path
*
* @ var string
*/
private $tempPath ;
2017-12-14 23:10:47 +00:00
2017-02-13 23:24:38 +00:00
/*
* The timer
*
* @ var string
*/
private $time_start ;
private $time_end ;
2017-12-14 23:10:47 +00:00
public $secondsCompiled ;
public $filepath = '' ;
2016-01-30 20:28:43 +00:00
// fixed pathes
2017-12-14 23:10:47 +00:00
protected $dynamicIntegration = false ;
protected $backupPath = false ;
protected $repoPath = false ;
protected $addCustomCodeAt = array ();
2016-01-30 20:28:43 +00:00
/**
* Constructor
*/
2017-12-14 23:10:47 +00:00
public function __construct ( $config = array ())
2016-01-30 20:28:43 +00:00
{
2017-02-13 23:24:38 +00:00
// to check the compiler speed
$this -> time_start = microtime ( true );
2018-01-19 10:27:47 +00:00
// first we run the perent constructors
2016-02-26 00:20:09 +00:00
if ( parent :: __construct ( $config ))
2016-01-30 20:28:43 +00:00
{
// set temp directory
2017-12-14 23:10:47 +00:00
$comConfig = JFactory :: getConfig ();
$this -> tempPath = $comConfig -> get ( 'tmp_path' );
2016-01-30 20:28:43 +00:00
// set some folder paths in relation to distribution
2018-04-24 22:36:05 +00:00
if ( $config [ 'backup' ])
2016-01-30 20:28:43 +00:00
{
2017-12-14 23:10:47 +00:00
$this -> backupPath = $this -> params -> get ( 'backup_folder_path' , $this -> tempPath ) . '/' . $this -> componentBackupName . '.zip' ;
$this -> dynamicIntegration = true ;
2016-01-30 20:28:43 +00:00
}
2018-04-24 22:36:05 +00:00
if ( $config [ 'repository' ])
2016-01-30 20:28:43 +00:00
{
2017-12-14 23:10:47 +00:00
$this -> repoPath = $this -> params -> get ( 'git_folder_path' , null );
2016-01-30 20:28:43 +00:00
}
2017-02-01 13:17:04 +00:00
// remove site folder if not needed (TODO add check if custom script was moved to site folder then we must do a more complex cleanup here)
2018-08-07 12:25:26 +00:00
if ( $this -> removeSiteFolder && $this -> removeSiteEditFolder )
2017-01-20 00:16:50 +00:00
{
// first remove the files and folders
$this -> removeFolder ( $this -> componentPath . '/site' );
// clear form component xml
2018-05-22 19:01:36 +00:00
$xmlPath = $this -> componentPath . '/' . $this -> fileContentStatic [ $this -> hhh . 'component' . $this -> hhh ] . '.xml' ;
2017-11-16 04:37:32 +00:00
$componentXML = ComponentbuilderHelper :: getFileContents ( $xmlPath );
2017-12-14 23:10:47 +00:00
$textToSite = ComponentbuilderHelper :: getBetween ( $componentXML , '<files folder="site">' , '</files>' );
$textToSiteLang = ComponentbuilderHelper :: getBetween ( $componentXML , '<languages folder="site">' , '</languages>' );
$componentXML = str_replace ( array ( '<files folder="site">' . $textToSite . " </files> " , '<languages folder="site">' . $textToSiteLang . " </languages> " ), array ( '' , '' ), $componentXML );
$this -> writeFile ( $xmlPath , $componentXML );
2017-01-20 00:16:50 +00:00
}
2016-02-26 00:20:09 +00:00
// now update the files
2017-02-01 13:17:04 +00:00
if ( ! $this -> updateFiles ())
2016-01-30 20:28:43 +00:00
{
2017-02-01 13:17:04 +00:00
return false ;
}
// now insert into the new files
2017-02-13 23:24:38 +00:00
if ( $this -> getCustomCode ())
2017-12-14 23:10:47 +00:00
{
2017-02-13 23:24:38 +00:00
$this -> addCustomCode ();
2017-02-01 13:17:04 +00:00
}
2017-02-13 23:24:38 +00:00
// set the lang data now
$this -> setLangFileData ();
2017-10-26 16:43:51 +00:00
// set the language notice if it was set
if ( ComponentbuilderHelper :: checkArray ( $this -> langNot ) || ComponentbuilderHelper :: checkArray ( $this -> langSet ))
{
if ( ComponentbuilderHelper :: checkArray ( $this -> langNot ))
{
2018-09-25 20:02:48 +00:00
$this -> app -> enqueueMessage ( JText :: _ ( '<hr /><h3>Language Warning</h3>' ), 'Warning' );
2017-10-26 16:43:51 +00:00
foreach ( $this -> langNot as $tag => $percentage )
{
2017-12-14 23:10:47 +00:00
$this -> app -> enqueueMessage ( JText :: sprintf ( 'The <b>%s</b> language has %s% translated, you will need to translate %s% of the language strings before it will be added.' , $tag , $percentage , $this -> percentageLanguageAdd ), 'Warning' );
2017-10-26 16:43:51 +00:00
}
2018-09-25 20:02:48 +00:00
$this -> app -> enqueueMessage ( JText :: _ ( '<hr /><h3>Language Notice</h3>' ), 'Notice' );
2017-12-14 23:10:47 +00:00
$this -> app -> enqueueMessage ( JText :: sprintf ( '<b>You can change this percentage of translated strings required in the global options of JCB.</b><br />Please watch this <a href=%s>tutorial for more help surrounding the JCB translations manager</a>.' , '"https://youtu.be/zzAcVkn_cWU?list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE" target="_blank" title="JCB Tutorial surrounding Translation Manager"' ), 'Notice' );
2017-10-26 16:43:51 +00:00
}
// set why the strings were added
$whyAddedLang = JText :: sprintf ( 'because more then %s% of the strings have been translated.' , $this -> percentageLanguageAdd );
if ( $this -> debugLinenr )
{
$whyAddedLang = JText :: _ ( 'because the debugging mode is on. (debug line numbers)' );
}
// show languages that were added
if ( ComponentbuilderHelper :: checkArray ( $this -> langSet ))
{
2018-09-25 20:02:48 +00:00
$this -> app -> enqueueMessage ( JText :: _ ( '<hr /><h3>Language Notice</h3>' ), 'Notice' );
2017-10-26 16:43:51 +00:00
foreach ( $this -> langSet as $tag => $percentage )
{
2017-12-14 23:10:47 +00:00
$this -> app -> enqueueMessage ( JText :: sprintf ( 'The <b>%s</b> language has %s% translated. Was addeded %s' , $tag , $percentage , $whyAddedLang ), 'Notice' );
2017-10-26 16:43:51 +00:00
}
}
}
2017-02-01 13:17:04 +00:00
// move the update server into place
$this -> setUpdateServer ();
2017-03-08 04:49:54 +00:00
// set the global counters
$this -> setCountingStuff ();
2017-02-13 23:24:38 +00:00
// build read me
$this -> buildReadMe ();
2017-02-01 13:17:04 +00:00
// zip the component
if ( ! $this -> zipComponent ())
{
2017-02-13 23:24:38 +00:00
// done with error
2017-02-01 13:17:04 +00:00
return false ;
2016-01-30 20:28:43 +00:00
}
2017-12-14 13:30:21 +00:00
// do lang mismatch check
if ( ComponentbuilderHelper :: checkArray ( $this -> langMismatch ))
{
if ( ComponentbuilderHelper :: checkArray ( $this -> langMatch ))
{
$mismatch = array_diff ( array_unique ( $this -> langMismatch ), array_unique ( $this -> langMatch ));
}
else
{
$mismatch = array_unique ( $this -> langMismatch );
}
// set a notice if we have a mismatch
2017-12-14 23:10:47 +00:00
if ( isset ( $mismatch ) && ComponentbuilderHelper :: checkArray ( $mismatch ))
2017-12-14 13:30:21 +00:00
{
2018-09-25 20:02:48 +00:00
$this -> app -> enqueueMessage ( JText :: _ ( '<hr /><h3>Language Warning</h3>' ), 'Warning' );
2017-12-14 13:30:21 +00:00
if ( count ( $mismatch ) > 1 )
{
$this -> app -> enqueueMessage ( JText :: _ ( '<h3>Please check the following mismatching Joomla.JText language constants.</h3>' ), 'Warning' );
}
else
{
$this -> app -> enqueueMessage ( JText :: _ ( '<h3>Please check the following mismatch Joomla.JText language constant.</h3>' ), 'Warning' );
}
// add the mismatching issues
foreach ( $mismatch as $string )
{
2017-12-14 23:10:47 +00:00
$constant = $this -> langPrefix . '_' . ComponentbuilderHelper :: safeString ( $string , 'U' );
2018-05-22 20:35:39 +00:00
$this -> app -> enqueueMessage ( JText :: sprintf ( 'The <b>Joomla.JText._('%s')</b> language constant for <b>%s</b> does not have a corresponding <code>JText::script('%s')</code> decalaration, please add it.' , $constant , $string , $string ), 'Warning' );
2017-12-14 13:30:21 +00:00
}
}
}
2018-02-06 10:55:46 +00:00
// check if we should add a EXTERNALCODE notice
if ( ComponentbuilderHelper :: checkArray ( $this -> externalCodeString ))
{
// number of external code strings
$externalCount = count ( $this -> externalCodeString );
// the correct string
$externalCodeString = ( $externalCount == 1 ) ? JText :: _ ( 'code/string' ) : JText :: _ ( 'code/strings' );
// the notice
2018-03-05 00:13:42 +00:00
$this -> app -> enqueueMessage ( JText :: _ ( '<hr /><h3>External Code Notice</h3>' ), 'Notice' );
2018-02-06 10:55:46 +00:00
$this -> app -> enqueueMessage ( JText :: sprintf ( 'There has been <b>%s - %s</b> added to this component as EXTERNALCODE. To avoid shipping your component with malicious %s always make sure that the correct <b>code/string values</b> were used.' , $externalCount , $externalCodeString , $externalCodeString ), 'Notice' );
}
2017-02-13 23:24:38 +00:00
// end the timer here
$this -> time_end = microtime ( true );
$this -> secondsCompiled = $this -> time_end - $this -> time_start ;
// completed the compilation
2017-02-01 13:17:04 +00:00
return true ;
2016-01-30 20:28:43 +00:00
}
return false ;
}
2017-12-14 23:10:47 +00:00
2016-09-03 21:44:47 +00:00
/**
* Set the line number in comments
*
* @ param int $nr The line number
*
* @ return void
*
*/
private function setLine ( $nr )
{
2017-04-06 08:47:51 +00:00
if ( $this -> debugLinenr )
2016-09-03 21:44:47 +00:00
{
2017-12-14 23:10:47 +00:00
return ' [Compiler ' . $nr . ']' ;
2016-09-03 21:44:47 +00:00
}
return '' ;
}
2017-12-14 23:10:47 +00:00
2017-02-01 13:17:04 +00:00
/**
* Set the dynamic data to the created fils
2018-05-22 20:35:39 +00:00
*
2017-02-01 13:17:04 +00:00
* @ return bool true on success
2018-05-22 20:35:39 +00:00
*
2017-02-01 13:17:04 +00:00
*/
2016-02-26 00:20:09 +00:00
protected function updateFiles ()
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
if ( isset ( $this -> newFiles [ 'static' ]) && ComponentbuilderHelper :: checkArray ( $this -> newFiles [ 'static' ]) && isset ( $this -> newFiles [ 'dynamic' ]) && ComponentbuilderHelper :: checkArray ( $this -> newFiles [ 'dynamic' ]))
2017-04-05 13:21:10 +00:00
{
2016-02-26 00:20:09 +00:00
// get the bom file
2017-11-16 04:37:32 +00:00
$bom = ComponentbuilderHelper :: getFileContents ( $this -> bomPath );
2016-02-26 00:20:09 +00:00
// first we do the static files
foreach ( $this -> newFiles [ 'static' ] as $static )
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
if ( JFile :: exists ( $static [ 'path' ]))
2016-01-30 20:28:43 +00:00
{
2018-05-22 20:35:39 +00:00
$this -> setFileContent ( $static [ 'name' ], $static [ 'path' ], $bom );
2016-01-30 20:28:43 +00:00
}
2016-02-26 00:20:09 +00:00
}
// now we do the dynamic files
foreach ( $this -> newFiles [ 'dynamic' ] as $view => $files )
{
if ( isset ( $this -> fileContentDynamic [ $view ]) && ComponentbuilderHelper :: checkArray ( $this -> fileContentDynamic [ $view ]))
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
foreach ( $files as $file )
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
if ( $file [ 'view' ] == $view )
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
if ( JFile :: exists ( $file [ 'path' ]))
2016-01-30 20:28:43 +00:00
{
2018-05-22 20:35:39 +00:00
$this -> setFileContent ( $file [ 'name' ], $file [ 'path' ], $bom , $file [ 'view' ]);
2016-01-30 20:28:43 +00:00
}
}
}
}
2017-02-01 13:17:04 +00:00
// free up some memory
unset ( $this -> fileContentDynamic [ $view ]);
2016-01-30 20:28:43 +00:00
}
2017-02-01 13:17:04 +00:00
// free up some memory
unset ( $this -> newFiles [ 'dynamic' ]);
return true ;
}
return false ;
}
2017-12-14 23:10:47 +00:00
2018-05-22 20:35:39 +00:00
/**
* set the file content
*
* @ return void
*
*/
protected function setFileContent ( & $name , & $path , & $bom , $view = null )
{
2019-06-22 10:43:26 +00:00
// Trigger Event: jcb_ce_onBeforeSetFileContent
2019-07-01 16:10:28 +00:00
$this -> triggerEvent ( 'jcb_ce_onBeforeSetFileContent' , array ( & $this -> componentContext , & $name , & $path , & $bom , & $view ));
2018-05-22 20:35:39 +00:00
// set the file name
$this -> fileContentStatic [ $this -> hhh . 'FILENAME' . $this -> hhh ] = $name ;
// check if the file should get PHP opening
$php = '' ;
if ( ComponentbuilderHelper :: checkFileType ( $name , 'php' ))
{
$php = " <?php \n " ;
}
// get content of the file
$string = ComponentbuilderHelper :: getFileContents ( $path );
2019-06-22 10:43:26 +00:00
// Trigger Event: jcb_ce_onGetFileContents
2019-07-01 16:10:28 +00:00
$this -> triggerEvent ( 'jcb_ce_onGetFileContents' , array ( & $this -> componentContext , & $string , & $name , & $path , & $bom , & $view ));
2018-05-22 20:35:39 +00:00
// see if we should add a BOM
if ( strpos ( $string , $this -> hhh . 'BOM' . $this -> hhh ) !== false )
{
list ( $wast , $code ) = explode ( $this -> hhh . 'BOM' . $this -> hhh , $string );
$string = $php . $bom . $code ;
}
// set the answer
$answer = $this -> setPlaceholders ( $string , $this -> fileContentStatic , 3 );
// set the dynamic answer
if ( $view )
{
$answer = $this -> setPlaceholders ( $answer , $this -> fileContentDynamic [ $view ], 3 );
}
2018-09-25 20:02:48 +00:00
// check if this file needs extra care :)
if ( isset ( $this -> updateFileContent [ $path ]))
{
$answer = $this -> setDynamicValues ( $answer );
}
2019-06-22 10:43:26 +00:00
// Trigger Event: jcb_ce_onBeforeSetFileContent
2019-07-01 16:10:28 +00:00
$this -> triggerEvent ( 'jcb_ce_onBeforeWriteFileContent' , array ( & $this -> componentContext , & $answer , & $name , & $path , & $bom , & $view ));
2018-05-22 20:35:39 +00:00
// add answer back to file
$this -> writeFile ( $path , $answer );
// count the file lines
$this -> lineCount = $this -> lineCount + substr_count ( $answer , PHP_EOL );
}
2017-02-01 13:17:04 +00:00
/**
* move the local update server xml file to a remote ftp server
2018-05-22 20:35:39 +00:00
*
2017-02-01 13:17:04 +00:00
* @ return void
2018-05-22 20:35:39 +00:00
*
2017-02-01 13:17:04 +00:00
*/
protected function setUpdateServer ()
{
// move the update server to host
2017-08-25 01:46:12 +00:00
if ( $this -> componentData -> add_update_server == 1 && $this -> componentData -> update_server_target == 1 && isset ( $this -> updateServerFileName ) && $this -> dynamicIntegration )
2017-02-01 13:17:04 +00:00
{
2017-12-14 23:10:47 +00:00
$xml_update_server_path = $this -> componentPath . '/' . $this -> updateServerFileName . '.xml' ;
2017-02-01 13:17:04 +00:00
// make sure we have the correct file
2018-02-15 00:42:39 +00:00
if ( JFile :: exists ( $xml_update_server_path ) && isset ( $this -> componentData -> update_server ))
2017-02-01 13:17:04 +00:00
{
2018-02-20 20:46:29 +00:00
// move to server
ComponentbuilderHelper :: moveToServer ( $xml_update_server_path , $this -> updateServerFileName . '.xml' , ( int ) $this -> componentData -> update_server , $this -> componentData -> update_server_protocol );
// remove the local file
JFile :: delete ( $xml_update_server_path );
2017-02-01 13:17:04 +00:00
}
}
}
// link canges made to views into the file license
protected function fixLicenseValues ( $data )
{
2017-02-02 12:17:31 +00:00
// check if these files have its own config data)
2017-11-06 14:04:23 +00:00
if ( isset ( $data [ 'config' ]) && ComponentbuilderHelper :: checkArray ( $data [ 'config' ]) && $this -> componentData -> mvc_versiondate == 1 )
2017-02-01 13:17:04 +00:00
{
foreach ( $data [ 'config' ] as $key => $value )
2016-02-26 00:20:09 +00:00
{
2018-05-22 19:01:36 +00:00
if ( $this -> hhh . 'VERSION' . $this -> hhh === $key )
2016-01-30 20:28:43 +00:00
{
2017-02-01 13:17:04 +00:00
// hmm we sould in some way make it known that this version number
// is not in relation the the project but to the file only... any ideas?
// this is the best for now...
if ( 1 == $value )
2016-01-30 20:28:43 +00:00
{
2017-02-01 13:17:04 +00:00
$value = '@first version of this MVC' ;
}
else
{
2017-12-14 23:10:47 +00:00
$value = '@update number ' . $value . ' of this MVC' ;
2016-01-30 20:28:43 +00:00
}
}
2017-02-01 13:17:04 +00:00
$this -> fileContentStatic [ $key ] = $value ;
2016-01-30 20:28:43 +00:00
}
2016-02-26 00:20:09 +00:00
return true ;
2016-01-30 20:28:43 +00:00
}
2017-02-01 13:17:04 +00:00
// else insure to reset to global
2018-05-22 19:01:36 +00:00
$this -> fileContentStatic [ $this -> hhh . 'CREATIONDATE' . $this -> hhh ] = $this -> fileContentStatic [ $this -> hhh . 'CREATIONDATE' . $this -> hhh . 'GLOBAL' ];
$this -> fileContentStatic [ $this -> hhh . 'BUILDDATE' . $this -> hhh ] = $this -> fileContentStatic [ $this -> hhh . 'BUILDDATE' . $this -> hhh . 'GLOBAL' ];
$this -> fileContentStatic [ $this -> hhh . 'VERSION' . $this -> hhh ] = $this -> fileContentStatic [ $this -> hhh . 'VERSION' . $this -> hhh . 'GLOBAL' ];
2016-01-30 20:28:43 +00:00
}
2017-03-08 04:49:54 +00:00
// set all global numbers
protected function setCountingStuff ()
{
// what is the size in terms of an A4 book
2017-12-14 23:10:47 +00:00
$this -> pageCount = round ( $this -> lineCount / 56 );
2017-03-08 04:49:54 +00:00
// setup the unrealistic numbers
2017-12-14 23:10:47 +00:00
$this -> folderSeconds = $this -> folderCount * 5 ;
$this -> fileSeconds = $this -> fileCount * 5 ;
$this -> lineSeconds = $this -> lineCount * 10 ;
$this -> seconds = $this -> folderSeconds + $this -> fileSeconds + $this -> lineSeconds ;
$this -> totalHours = round ( $this -> seconds / 3600 );
$this -> totalDays = round ( $this -> totalHours / 8 );
2017-03-08 04:49:54 +00:00
// setup the more realistic numbers
2017-12-14 23:10:47 +00:00
$this -> secondsDebugging = $this -> seconds / 4 ;
$this -> secondsPlanning = $this -> seconds / 7 ;
$this -> secondsMapping = $this -> seconds / 10 ;
$this -> secondsOffice = $this -> seconds / 6 ;
$this -> actualSeconds = $this -> folderSeconds + $this -> fileSeconds + $this -> lineSeconds + $this -> secondsDebugging + $this -> secondsPlanning + $this -> secondsMapping + $this -> secondsOffice ;
$this -> actualTotalHours = round ( $this -> actualSeconds / 3600 );
$this -> actualTotalDays = round ( $this -> actualTotalHours / 8 );
$this -> debuggingHours = round ( $this -> secondsDebugging / 3600 );
$this -> planningHours = round ( $this -> secondsPlanning / 3600 );
$this -> mappingHours = round ( $this -> secondsMapping / 3600 );
$this -> officeHours = round ( $this -> secondsOffice / 3600 );
2017-03-08 04:49:54 +00:00
// the actual time spent
2017-12-14 23:10:47 +00:00
$this -> actualHoursSpent = $this -> actualTotalHours - $this -> totalHours ;
$this -> actualDaysSpent = $this -> actualTotalDays - $this -> totalDays ;
2017-03-08 04:49:54 +00:00
// calculate the projects actual time frame of completion
2017-12-14 23:10:47 +00:00
$this -> projectWeekTime = round ( $this -> actualTotalDays / 5 , 1 );
$this -> projectMonthTime = round ( $this -> actualTotalDays / 24 , 1 );
2017-03-08 04:49:54 +00:00
}
2017-12-14 23:10:47 +00:00
2017-02-13 23:24:38 +00:00
private function buildReadMe ()
{
// do a final run to update the readme file
$two = 0 ;
foreach ( $this -> newFiles [ 'static' ] as $static )
{
if (( 'README.md' === $static [ 'name' ] || 'README.txt' === $static [ 'name' ]) && $this -> componentData -> addreadme && JFile :: exists ( $static [ 'path' ]))
{
$this -> setReadMe ( $static [ 'path' ]);
$two ++ ;
}
if ( $two == 2 )
{
break ;
}
}
unset ( $this -> newFiles [ 'static' ]);
}
2017-12-14 23:10:47 +00:00
2017-02-13 23:24:38 +00:00
private function setReadMe ( $path )
2016-10-23 22:48:26 +00:00
{
// set readme data if not set already
2018-05-22 19:01:36 +00:00
if ( ! isset ( $this -> fileContentStatic [ $this -> hhh . 'LINE_COUNT' . $this -> hhh ]) || $this -> fileContentStatic [ $this -> hhh . 'LINE_COUNT' . $this -> hhh ] != $this -> lineCount )
2016-10-23 22:48:26 +00:00
{
$this -> buildReadMeData ();
}
// get the file
2017-11-16 04:37:32 +00:00
$string = ComponentbuilderHelper :: getFileContents ( $path );
2016-10-23 22:48:26 +00:00
// update the file
2017-02-11 02:24:26 +00:00
$answer = $this -> setPlaceholders ( $string , $this -> fileContentStatic );
2016-10-23 22:48:26 +00:00
// add to zip array
2017-12-14 23:10:47 +00:00
$this -> writeFile ( $path , $answer );
}
2016-10-23 22:48:26 +00:00
private function buildReadMeData ()
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
// set some defaults
2018-05-22 19:01:36 +00:00
$this -> fileContentStatic [ $this -> hhh . 'LINE_COUNT' . $this -> hhh ] = $this -> lineCount ;
$this -> fileContentStatic [ $this -> hhh . 'FIELD_COUNT' . $this -> hhh ] = $this -> fieldCount ;
$this -> fileContentStatic [ $this -> hhh . 'FILE_COUNT' . $this -> hhh ] = $this -> fileCount ;
$this -> fileContentStatic [ $this -> hhh . 'FOLDER_COUNT' . $this -> hhh ] = $this -> folderCount ;
$this -> fileContentStatic [ $this -> hhh . 'PAGE_COUNT' . $this -> hhh ] = $this -> pageCount ;
$this -> fileContentStatic [ $this -> hhh . 'folders' . $this -> hhh ] = $this -> folderSeconds ;
$this -> fileContentStatic [ $this -> hhh . 'foldersSeconds' . $this -> hhh ] = $this -> folderSeconds ;
$this -> fileContentStatic [ $this -> hhh . 'files' . $this -> hhh ] = $this -> fileSeconds ;
$this -> fileContentStatic [ $this -> hhh . 'filesSeconds' . $this -> hhh ] = $this -> fileSeconds ;
$this -> fileContentStatic [ $this -> hhh . 'lines' . $this -> hhh ] = $this -> lineSeconds ;
$this -> fileContentStatic [ $this -> hhh . 'linesSeconds' . $this -> hhh ] = $this -> lineSeconds ;
$this -> fileContentStatic [ $this -> hhh . 'seconds' . $this -> hhh ] = $this -> actualSeconds ;
$this -> fileContentStatic [ $this -> hhh . 'actualSeconds' . $this -> hhh ] = $this -> actualSeconds ;
$this -> fileContentStatic [ $this -> hhh . 'totalHours' . $this -> hhh ] = $this -> totalHours ;
$this -> fileContentStatic [ $this -> hhh . 'totalDays' . $this -> hhh ] = $this -> totalDays ;
$this -> fileContentStatic [ $this -> hhh . 'debugging' . $this -> hhh ] = $this -> secondsDebugging ;
$this -> fileContentStatic [ $this -> hhh . 'secondsDebugging' . $this -> hhh ] = $this -> secondsDebugging ;
$this -> fileContentStatic [ $this -> hhh . 'planning' . $this -> hhh ] = $this -> secondsPlanning ;
$this -> fileContentStatic [ $this -> hhh . 'secondsPlanning' . $this -> hhh ] = $this -> secondsPlanning ;
$this -> fileContentStatic [ $this -> hhh . 'mapping' . $this -> hhh ] = $this -> secondsMapping ;
$this -> fileContentStatic [ $this -> hhh . 'secondsMapping' . $this -> hhh ] = $this -> secondsMapping ;
$this -> fileContentStatic [ $this -> hhh . 'office' . $this -> hhh ] = $this -> secondsOffice ;
$this -> fileContentStatic [ $this -> hhh . 'secondsOffice' . $this -> hhh ] = $this -> secondsOffice ;
$this -> fileContentStatic [ $this -> hhh . 'actualTotalHours' . $this -> hhh ] = $this -> actualTotalHours ;
$this -> fileContentStatic [ $this -> hhh . 'actualTotalDays' . $this -> hhh ] = $this -> actualTotalDays ;
$this -> fileContentStatic [ $this -> hhh . 'debuggingHours' . $this -> hhh ] = $this -> debuggingHours ;
$this -> fileContentStatic [ $this -> hhh . 'planningHours' . $this -> hhh ] = $this -> planningHours ;
$this -> fileContentStatic [ $this -> hhh . 'mappingHours' . $this -> hhh ] = $this -> mappingHours ;
$this -> fileContentStatic [ $this -> hhh . 'officeHours' . $this -> hhh ] = $this -> officeHours ;
$this -> fileContentStatic [ $this -> hhh . 'actualHoursSpent' . $this -> hhh ] = $this -> actualHoursSpent ;
$this -> fileContentStatic [ $this -> hhh . 'actualDaysSpent' . $this -> hhh ] = $this -> actualDaysSpent ;
$this -> fileContentStatic [ $this -> hhh . 'projectWeekTime' . $this -> hhh ] = $this -> projectWeekTime ;
$this -> fileContentStatic [ $this -> hhh . 'projectMonthTime' . $this -> hhh ] = $this -> projectMonthTime ;
2016-01-30 20:28:43 +00:00
}
2016-02-26 00:20:09 +00:00
private function zipComponent ()
2016-01-30 20:28:43 +00:00
{
2017-09-18 00:18:23 +00:00
// before we zip the component we first need to move it to the repo folder if set
if ( ComponentbuilderHelper :: checkString ( $this -> repoPath ))
2016-02-26 00:20:09 +00:00
{
2017-09-18 00:18:23 +00:00
// set the repo path
2017-12-14 23:10:47 +00:00
$repoFullPath = $this -> repoPath . '/com_' . $this -> componentData -> sales_name . '__joomla_' . $this -> joomlaVersion ;
2016-02-26 00:20:09 +00:00
// remove old data
2017-09-18 00:18:23 +00:00
$this -> removeFolder ( $repoFullPath , $this -> componentData -> toignore );
2016-02-26 00:20:09 +00:00
// set the new data
2017-09-18 00:18:23 +00:00
JFolder :: copy ( $this -> componentPath , $repoFullPath , '' , true );
2016-02-26 00:20:09 +00:00
}
// the name of the zip file to create
2017-12-14 23:10:47 +00:00
$this -> filepath = $this -> tempPath . '/' . $this -> componentFolderName . '.zip' ;
2016-02-26 00:20:09 +00:00
//create the zip file
2017-03-20 22:07:14 +00:00
if ( ComponentbuilderHelper :: zip ( $this -> componentPath , $this -> filepath ))
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
// now move to backup if zip was made and backup is requered
2016-11-22 05:48:55 +00:00
if ( $this -> backupPath && $this -> dynamicIntegration )
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
JFile :: copy ( $this -> filepath , $this -> backupPath );
2016-01-30 20:28:43 +00:00
}
2017-12-14 23:10:47 +00:00
2016-02-26 00:20:09 +00:00
// move to sales server host
2017-08-25 01:46:12 +00:00
if ( $this -> componentData -> add_sales_server == 1 && $this -> dynamicIntegration )
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
// make sure we have the correct file
2018-02-15 00:42:39 +00:00
if ( isset ( $this -> componentData -> sales_server ))
2016-01-30 20:28:43 +00:00
{
2018-02-20 20:46:29 +00:00
// move to server
ComponentbuilderHelper :: moveToServer ( $this -> filepath , $this -> componentSalesName . '.zip' , ( int ) $this -> componentData -> sales_server , $this -> componentData -> sales_server_protocol );
2016-01-30 20:28:43 +00:00
}
}
2016-02-26 00:20:09 +00:00
// remove the component folder since we are done
if ( $this -> removeFolder ( $this -> componentPath ))
2016-01-30 20:28:43 +00:00
{
2016-02-26 00:20:09 +00:00
return true ;
2016-01-30 20:28:43 +00:00
}
}
2016-02-26 00:20:09 +00:00
return false ;
}
2017-12-14 23:10:47 +00:00
2017-02-13 23:24:38 +00:00
protected function addCustomCode ()
2017-02-01 13:17:04 +00:00
{
2017-02-11 02:24:26 +00:00
// reset all these
$this -> clearFromPlaceHolders ( 'view' );
$this -> clearFromPlaceHolders ( 'arg' );
2017-12-14 23:10:47 +00:00
foreach ( $this -> customCode as $nr => $target )
2017-02-01 13:17:04 +00:00
{
// reset each time per custom code
$fingerPrint = array ();
2017-12-14 23:10:47 +00:00
if ( isset ( $target [ 'hashtarget' ][ 0 ]) && $target [ 'hashtarget' ][ 0 ] > 3 && isset ( $target [ 'path' ]) && ComponentbuilderHelper :: checkString ( $target [ 'path' ]) && isset ( $target [ 'hashtarget' ][ 1 ]) && ComponentbuilderHelper :: checkString ( $target [ 'hashtarget' ][ 1 ]))
2017-02-01 13:17:04 +00:00
{
2017-12-14 23:10:47 +00:00
$file = $this -> componentPath . '/' . $target [ 'path' ];
$size = ( int ) $target [ 'hashtarget' ][ 0 ];
$hash = $target [ 'hashtarget' ][ 1 ];
$cut = $size - 1 ;
$found = false ;
$bites = 0 ;
$lineBites = array ();
$replace = array ();
2017-02-01 13:17:04 +00:00
if ( $target [ 'type' ] == 1 && isset ( $target [ 'hashendtarget' ][ 0 ]) && $target [ 'hashendtarget' ][ 0 ] > 0 )
{
2017-12-14 23:10:47 +00:00
$foundEnd = false ;
$sizeEnd = ( int ) $target [ 'hashendtarget' ][ 0 ];
$hashEnd = $target [ 'hashendtarget' ][ 1 ];
$cutEnd = $sizeEnd - 1 ;
2017-02-01 13:17:04 +00:00
}
else
{
// replace to the end of the file
2017-12-14 23:10:47 +00:00
$foundEnd = true ;
2017-02-01 13:17:04 +00:00
}
2017-12-14 23:10:47 +00:00
$counter = 0 ;
2017-02-11 02:24:26 +00:00
// check if file exist
2017-02-01 13:17:04 +00:00
if ( JFile :: exists ( $file ))
{
foreach ( new SplFileObject ( $file ) as $lineNumber => $lineContent )
{
2017-02-04 00:22:17 +00:00
// if not found we need to load line bites per line
$lineBites [ $lineNumber ] = ( int ) mb_strlen ( $lineContent , '8bit' );
2017-02-01 13:17:04 +00:00
if ( ! $found )
{
2018-08-30 21:22:48 +00:00
$bites = ( int ) ComponentbuilderHelper :: bcmath ( 'add' , $lineBites [ $lineNumber ], $bites );
2017-02-01 13:17:04 +00:00
}
if ( $found && ! $foundEnd )
{
2017-02-04 00:22:17 +00:00
$replace [] = ( int ) $lineBites [ $lineNumber ];
2017-02-01 13:17:04 +00:00
// we musk keep last three lines to dynamic find target entry
$fingerPrint [ $lineNumber ] = trim ( $lineContent );
// check lines each time if it fits our target
if ( count ( $fingerPrint ) === $sizeEnd && ! $foundEnd )
{
2017-12-14 23:10:47 +00:00
$fingerTest = md5 ( implode ( '' , $fingerPrint ));
2017-02-01 13:17:04 +00:00
if ( $fingerTest === $hashEnd )
{
// we are done here
$foundEnd = true ;
2017-12-14 23:10:47 +00:00
$replace = array_slice ( $replace , 0 , count ( $replace ) - $sizeEnd );
2017-02-01 13:17:04 +00:00
break ;
}
else
{
$fingerPrint = array_slice ( $fingerPrint , - $cutEnd , $cutEnd , true );
}
}
2017-02-04 00:22:17 +00:00
continue ;
2017-02-01 13:17:04 +00:00
}
if ( $found && $foundEnd )
{
2017-02-04 00:22:17 +00:00
$replace [] = ( int ) $lineBites [ $lineNumber ];
2017-02-01 13:17:04 +00:00
}
// we musk keep last three lines to dynamic find target entry
$fingerPrint [ $lineNumber ] = trim ( $lineContent );
// check lines each time if it fits our target
if ( count ( $fingerPrint ) === $size && ! $found )
{
2017-12-14 23:10:47 +00:00
$fingerTest = md5 ( implode ( '' , $fingerPrint ));
2017-02-01 13:17:04 +00:00
if ( $fingerTest === $hash )
{
// we are done here
$found = true ;
// reset in case
$fingerPrint = array ();
// break if it is insertion
if ( $target [ 'type' ] == 2 )
{
break ;
}
}
else
{
$fingerPrint = array_slice ( $fingerPrint , - $cut , $cut , true );
}
}
}
if ( $found )
{
2017-12-14 23:10:47 +00:00
$placeholder = $this -> getPlaceHolder (( int ) $target [ 'comment_type' ] . $target [ 'type' ], $target [ 'id' ]);
$data = $placeholder [ 'start' ] . PHP_EOL . $this -> setPlaceholders ( $target [ 'code' ], $this -> placeholders ) . $placeholder [ 'end' ] . PHP_EOL ;
2017-02-01 13:17:04 +00:00
if ( $target [ 'type' ] == 2 )
{
// found it now add code from the next line
$this -> addDataToFile ( $file , $data , $bites );
}
elseif ( $target [ 'type' ] == 1 && $foundEnd )
{
// found it now add code from the next line
2017-02-13 23:24:38 +00:00
$this -> addDataToFile ( $file , $data , $bites , ( int ) array_sum ( $replace ));
2017-02-01 13:17:04 +00:00
}
else
{
2017-02-04 00:22:17 +00:00
// Load escaped code since the target endhash has changed
$this -> loadEscapedCode ( $file , $target , $lineBites );
2018-09-25 20:02:48 +00:00
$this -> app -> enqueueMessage ( JText :: _ ( '<hr /><h3>Custom Code Warning</h3>' ), 'Warning' );
2018-02-06 10:55:46 +00:00
$this -> app -> enqueueMessage ( JText :: sprintf ( 'Custom code could not be added to <b>%s</b> please review the file at <b>line %s</b>. This could be due to a change to lines below the custom code.' , $target [ 'path' ], $target [ 'from_line' ]), 'Warning' );
2017-02-01 13:17:04 +00:00
}
}
else
{
2017-02-04 00:22:17 +00:00
// Load escaped code since the target hash has changed
$this -> loadEscapedCode ( $file , $target , $lineBites );
2018-09-25 20:02:48 +00:00
$this -> app -> enqueueMessage ( JText :: _ ( '<hr /><h3>Custom Code Warning</h3>' ), 'Warning' );
2018-02-06 10:55:46 +00:00
$this -> app -> enqueueMessage ( JText :: sprintf ( 'Custom code could not be added to <b>%s</b> please review the file at <b>line %s</b>. This could be due to a change to lines above the custom code.' , $target [ 'path' ], $target [ 'from_line' ]), 'Warning' );
2017-02-01 13:17:04 +00:00
}
}
else
{
2017-02-04 00:22:17 +00:00
// Give developer a notice that file is not found.
2018-09-25 20:02:48 +00:00
$this -> app -> enqueueMessage ( JText :: _ ( '<hr /><h3>Custom Code Warning</h3>' ), 'Warning' );
2018-02-06 10:55:46 +00:00
$this -> app -> enqueueMessage ( JText :: sprintf ( 'File <b>%s</b> could not be found, so the custom code for this file could not be addded.' , $target [ 'path' ]), 'Warning' );
2017-02-01 13:17:04 +00:00
}
}
}
}
2017-02-04 00:22:17 +00:00
protected function loadEscapedCode ( $file , $target , $lineBites )
{
2017-10-30 18:50:56 +00:00
// get comment type
if ( $target [ 'comment_type' ] == 1 )
{
$commentType = " // " ;
$_commentType = " " ;
}
else
{
$commentType = " <!-- " ;
$_commentType = " --> " ;
}
2017-02-04 00:22:17 +00:00
// escape the code
2017-02-09 16:11:10 +00:00
$code = explode ( PHP_EOL , $target [ 'code' ]);
2017-10-30 18:50:56 +00:00
$code = PHP_EOL . $commentType . implode ( $_commentType . PHP_EOL . $commentType , $code ) . $_commentType . PHP_EOL ;
2017-02-04 00:22:17 +00:00
// get place holders
2017-12-14 23:10:47 +00:00
$placeholder = $this -> getPlaceHolder (( int ) $target [ 'comment_type' ] . $target [ 'type' ], $target [ 'id' ]);
2017-02-04 00:22:17 +00:00
// build the data
2017-12-14 23:10:47 +00:00
$data = $placeholder [ 'start' ] . $code . $placeholder [ 'end' ] . PHP_EOL ;
2017-02-04 00:22:17 +00:00
// get the bites before insertion
2017-12-14 23:10:47 +00:00
$bitBucket = array ();
foreach ( $lineBites as $line => $value )
2017-02-04 00:22:17 +00:00
{
if ( $line < $target [ 'from_line' ])
{
$bitBucket [] = $value ;
}
}
// add to the file
$this -> addDataToFile ( $file , $data , ( int ) array_sum ( $bitBucket ));
}
2017-02-01 13:17:04 +00:00
// Thanks to http://stackoverflow.com/a/16813550/1429677
protected function addDataToFile ( $file , $data , $position , $replace = null )
{
2017-02-11 02:24:26 +00:00
// start the process
2017-02-01 13:17:04 +00:00
$fpFile = fopen ( $file , " rw+ " );
$fpTemp = fopen ( 'php://temp' , " rw+ " );
2017-02-11 02:24:26 +00:00
// make a copy of the file
stream_copy_to_stream ( $fpFile , $fpTemp );
// move to the position where we should add the data
fseek ( $fpFile , $position );
// Add the data
fwrite ( $fpFile , $data );
// truncate file at the end of the data that was added
2018-08-30 21:22:48 +00:00
$remove = ComponentbuilderHelper :: bcmath ( 'add' , $position , mb_strlen ( $data , '8bit' ));
2017-02-11 02:24:26 +00:00
ftruncate ( $fpFile , $remove );
// check if this was a replacement of data
2017-02-01 13:17:04 +00:00
if ( $replace )
{
2018-08-30 21:22:48 +00:00
$position = ComponentbuilderHelper :: bcmath ( 'add' , $position , $replace );
2017-02-01 13:17:04 +00:00
}
2017-02-11 02:24:26 +00:00
// move to the position of the data that should remain below the new data
fseek ( $fpTemp , $position );
// copy that remaining data to the file
2017-02-01 13:17:04 +00:00
stream_copy_to_stream ( $fpTemp , $fpFile ); // @Jack
2017-02-11 02:24:26 +00:00
// done close both files
fclose ( $fpFile );
fclose ( $fpTemp );
2017-12-14 23:10:47 +00:00
2017-02-11 02:24:26 +00:00
// any help to improve this is welcome...
2017-02-01 13:17:04 +00:00
}
2018-05-26 10:03:08 +00:00
2016-01-30 20:28:43 +00:00
}