@my wife Roline van der Merwe @copyright Copyright (C) 2015. All Rights Reserved @license GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html Builds Complex Joomla Components /-----------------------------------------------------------------------------------------------------------------------------*/ // No direct access to this file defined('_JEXEC') or die('Restricted access'); // import the Joomla librarys jimport('joomla.filesystem.file'); jimport('joomla.filesystem.folder'); jimport('joomla.filesystem.archive'); /** * Structure class */ class Structure extends Get { /* * The foulder counter * * @var int */ public $folderCount = 0; /* * The foulder counter * * @var int */ public $fileCount = 0; /* * The line counter * * @var int */ public $lineCount = 0; /* * The Joomla Version * * @var string */ public $joomlaVersion; /* * The template path * * @var string */ public $templatePath; /* * The custom template path * * @var string */ public $templatePathCustom; /* * The Joomla Version Data * * @var object */ public $joomlaVersionData; /* * Static File Content * * @var array */ public $fileContentStatic = array(); /* * Dynamic File Content * * @var array */ public $fileContentDynamic = array(); /* * The Component Sales name * * @var string */ public $componentSalesName; /* * The Component Backup name * * @var string */ public $componentBackupName; /* * The Component Folder name * * @var string */ public $componentFolderName; /* * The Component path * * @var string */ public $componentPath; /* * The not new static items * * @var array */ public $notNew = array(); /* * The new files * * @var array */ public $newFiles = array(); /* * The Checkin Switch * * @var boolean */ public $addCheckin = false; /** * Constructor */ public function __construct($config = array ()) { // first we run the perent constructor if (parent::__construct($config)) { // set the Joomla version $this->joomlaVersion = $config['joomlaVersion']; // set the template path $this->templatePath = $this->compilerPath.'/joomla_'.$config['joomlaVersion']; // set some default names $this->componentSalesName = 'com_'.$this->componentData->sales_name.'__J'.$this->joomlaVersion; $this->componentBackupName = 'com_'.$this->componentData->sales_name.'_v'.str_replace('.','_',$this->componentData->component_version).'__J'.$this->joomlaVersion; $this->componentFolderName = 'com_'.$this->componentData->name_code.'_v'.str_replace('.','_',$this->componentData->component_version).'__J'.$this->joomlaVersion; // set component folder path $this->componentPath = $this->compilerPath.'/'.$this->componentFolderName; // set the template path for custom $this->templatePathCustom = $this->params->get('custom_folder_path', JPATH_COMPONENT_ADMINISTRATOR.'/custom'); // set the Joomla Version Data $this->joomlaVersionData = $this->setJoomlaVersionData(); // make sure there is no old build $this->removeFolder($this->componentPath); // set the new folders if (!$this->setFolders()) { return false; } // set all static folders and files if (!$this->setStatic()) { return false; } // set all the dynamic folders and files if (!$this->setDynamique()) { return false; } return true; } return false; } /* * Build the Initial Folders * * @return void * */ private function setFolders() { if (ComponentbuilderHelper::checkObject($this->joomlaVersionData->create)) { // creat the main componet folder if (!JFolder::exists($this->componentPath)) { JFolder::create($this->componentPath); // count the folder created $this->folderCount++; $this->indexHTML(''); } // now build all folders needed for this component foreach ($this->joomlaVersionData->create as $main => $folders) { if (!JFolder::exists($this->componentPath.'/'.$main)) { JFolder::create($this->componentPath.'/'.$main); // count the folder created $this->folderCount++; $this->indexHTML($main); } if (ComponentbuilderHelper::checkObject($folders)) { foreach ($folders as $sub => $subFolders) { if (!JFolder::exists($this->componentPath.'/'.$main.'/'.$sub)) { JFolder::create($this->componentPath.'/'.$main.'/'.$sub); // count the folder created $this->folderCount++; $this->indexHTML($main.'/'.$sub); } if (ComponentbuilderHelper::checkObject($subFolders)) { foreach ($subFolders as $sub_2 => $subFolders_2) { if (!JFolder::exists($this->componentPath.'/'.$main.'/'.$sub.'/'.$sub_2)) { JFolder::create($this->componentPath.'/'.$main.'/'.$sub.'/'.$sub_2); // count the folder created $this->folderCount++; $this->indexHTML($main.'/'.$sub.'/'.$sub_2); } if (ComponentbuilderHelper::checkObject($subFolders_2)) { foreach ($subFolders_2 as $sub_3 => $subFolders_3) { if (!JFolder::exists($this->componentPath.'/'.$main.'/'.$sub.'/'.$sub_2.'/'.$sub_3)) { JFolder::create($this->componentPath.'/'.$main.'/'.$sub.'/'.$sub_2.'/'.$sub_3); // count the folder created $this->folderCount++; $this->indexHTML($main.'/'.$sub.'/'.$sub_2.'/'.$sub_3); } if (ComponentbuilderHelper::checkObject($subFolders_3)) { foreach ($subFolders_3 as $sub_4 => $subFolders_4) { if (!JFolder::exists($this->componentPath.'/'.$main.'/'.$sub.'/'.$sub_2.'/'.$sub_3.'/'.$sub_4)) { JFolder::create($this->componentPath.'/'.$main.'/'.$sub.'/'.$sub_2.'/'.$sub_3.'/'.$sub_4); // count the folder created $this->folderCount++; $this->indexHTML($main.'/'.$sub.'/'.$sub_2.'/'.$sub_3.'/'.$sub_4); } if (ComponentbuilderHelper::checkObject($subFolders_4)) { foreach ($subFolders_4 as $sub_5 => $subFolders_5) { if (!JFolder::exists($this->componentPath.'/'.$main.'/'.$sub.'/'.$sub_2.'/'.$sub_3.'/'.$sub_4.'/'.$sub_5)) { JFolder::create($this->componentPath.'/'.$main.'/'.$sub.'/'.$sub_2.'/'.$sub_3.'/'.$sub_4.'/'.$sub_5); // count the folder created $this->folderCount++; $this->indexHTML($main.'/'.$sub.'/'.$sub_2.'/'.$sub_3.'/'.$sub_4.'/'.$sub_5); } if (ComponentbuilderHelper::checkObject($subFolders_5)) { foreach ($subFolders_5 as $sub_6 => $subFolders_6) { if (!JFolder::exists($this->componentPath.'/'.$main.'/'.$sub.'/'.$sub_2.'/'.$sub_3.'/'.$sub_4.'/'.$sub_5.'/'.$sub_6)) { JFolder::create($this->componentPath.'/'.$main.'/'.$sub.'/'.$sub_2.'/'.$sub_3.'/'.$sub_4.'/'.$sub_5.'/'.$sub_6); // count the folder created $this->folderCount++; $this->indexHTML($main.'/'.$sub.'/'.$sub_2.'/'.$sub_3.'/'.$sub_4.'/'.$sub_5.'/'.$sub_6); } if (ComponentbuilderHelper::checkObject($subFolders_6)) { foreach ($subFolders_6 as $sub_7 => $subFolders_7) { if (!JFolder::exists($this->componentPath.'/'.$main.'/'.$sub.'/'.$sub_2.'/'.$sub_3.'/'.$sub_4.'/'.$sub_5.'/'.$sub_6.'/'.$sub_7)) { JFolder::create($this->componentPath.'/'.$main.'/'.$sub.'/'.$sub_2.'/'.$sub_3.'/'.$sub_4.'/'.$sub_5.'/'.$sub_6.'/'.$sub_7); // count the folder created $this->folderCount++; $this->indexHTML($main.'/'.$sub.'/'.$sub_2.'/'.$sub_3.'/'.$sub_4.'/'.$sub_5.'/'.$sub_6.'/'.$sub_7); } } } } } } } } } } } } } } } } return true; } return false; } /* * Set the Static File & Folder * * @return boolean * */ private function setStatic() { if (ComponentbuilderHelper::checkObject($this->joomlaVersionData->move->static)) { $codeName = ComponentbuilderHelper::safeString($this->componentData->name_code); // TODO needs more looking at this must be dynamic actualy $this->notNew[] = 'PHPExcel.php'; $this->notNew[] = 'LICENSE.txt'; // do license check $LICENSE = false; $licenseChecker = strtolower($this->componentData->license); if (strpos($licenseChecker,'gnu') !== false && strpos($licenseChecker,'gpl') !== false) { $LICENSE = true; } // do README check $README = false; // add the README file if needed if ($this->componentData->addreadme) { $README = true; } // start moving foreach ($this->joomlaVersionData->move->static as $ftem => $details) { // set item $item = $details->naam; // do the file renaming if ($details->rename) { if ($details->rename == 'new') { $new = $details->newName; } else { $new = str_replace($details->rename, $codeName, $item); } } else { $new = $item; } // if not gnu/gpl license dont add the LICENSE.txt file if ($item == 'LICENSE.txt' && !$LICENSE) { continue; } // if not needed do not add if ($item == 'README.md' && !$README) { continue; } // set destination path $zipPath = str_replace('c0mp0n3nt/','', $details->path); $path = str_replace('c0mp0n3nt/',$this->componentPath.'/', $details->path); // set the template folder path $templatePath = (isset($details->custom) && $details->custom) ? $this->templatePathCustom : $this->templatePath; // now mov the file if ($details->type == 'file') { // move the file to its place JFile::copy($templatePath.'/'.$item, $path.'/'.$new); // count the file created $this->fileCount++; // store the new files if (!in_array($ftem,$this->notNew)) { $this->newFiles['static'][] = array( 'path' => $path.'/'.$new, 'name' => $new, 'zip' => $zipPath.'/'.$new ); } } elseif ($details->type == 'folder') { // move the folder to its place JFolder::copy($templatePath.'/'.$item, $path.'/'.$new); // count the folder created $this->folderCount++; } } return true; } return false; } /* * Set the Dynamic File & Folder * * @return boolean * */ private function setDynamique() { $back = false; $front = false; if ((isset($this->joomlaVersionData->move->dynamic) && ComponentbuilderHelper::checkObject($this->joomlaVersionData->move->dynamic)) && (isset($this->componentData->admin_views) && ComponentbuilderHelper::checkArray($this->componentData->admin_views))) { // setup dashboard $target = array('admin' => $this->componentData->name_code); $this->buildDynamique($target,'dashboard'); // now the rest of the views foreach ($this->componentData->admin_views as $nr => $view) { if (ComponentbuilderHelper::checkObject($view['settings'])) { if ($view['settings']->name_list != 'null') { $target = array('admin' => $view['settings']->name_list); $this->buildDynamique($target,'list'); } if ($view['settings']->name_single != 'null') { $target = array('admin' => $view['settings']->name_single); $this->buildDynamique($target,'single'); } if($view['edit_create_site_view']) { // setup the front site edit-view files $target = array('site' => $view['settings']->name_single); $this->buildDynamique($target,'edit'); } } // quick set of checkin once if ($view['checkin'] == 1 && !$this->addCheckin) { // switch to add checking to config $this->addCheckin = true; } } $back = true; } if ((isset($this->joomlaVersionData->move->dynamic) && ComponentbuilderHelper::checkObject($this->joomlaVersionData->move->dynamic)) && (isset($this->componentData->site_views) && ComponentbuilderHelper::checkArray($this->componentData->site_views))) { foreach ($this->componentData->site_views as $nr => $view) { if ($view['settings']->main_get->gettype == 2) { // set list view $target = array('site' => $view['settings']->code); $this->buildDynamique($target,'list'); } elseif ($view['settings']->main_get->gettype == 1) { // set single view $target = array('site' => $view['settings']->code); $this->buildDynamique($target,'single'); } } $front = true; } if ((isset($this->joomlaVersionData->move->dynamic) && ComponentbuilderHelper::checkObject($this->joomlaVersionData->move->dynamic)) && (isset($this->componentData->custom_admin_views) && ComponentbuilderHelper::checkArray($this->componentData->custom_admin_views))) { foreach ($this->componentData->custom_admin_views as $nr => $view) { if ($view['settings']->main_get->gettype == 2) { // set list view $target = array('custom_admin' => $view['settings']->code); $this->buildDynamique($target,'list'); } elseif ($view['settings']->main_get->gettype == 1) { // set single view $target = array('custom_admin' => $view['settings']->code); $this->buildDynamique($target,'single'); } } $back = true; } // chekc if we had success if ($back || $front) { return true; } return false; } /* * Set the Static File & Folder * * @param array $target The main target and name * @param string $type The type in the target * @param string $fileName The custom file name * * @return boolean * */ public function buildDynamique($target,$type,$fileName = false) { if (ComponentbuilderHelper::checkArray($target)) { foreach ($target as $main => $name) { // make sure it is lower case $name = ComponentbuilderHelper::safeString($name); // setup the files foreach ($this->joomlaVersionData->move->dynamic->{$main} as $item => $details) { if ($details->type == $type) { // set destination path $path = ''; if (strpos($details->path,'VIEW') !== false) { $path = str_replace('VIEW',$name,$details->path); } else { $path = $details->path; } $zipPath = str_replace('c0mp0n3nt/','', $path); $path = str_replace('c0mp0n3nt/',$this->componentPath.'/', $path); // setup the folder if (!JFolder::exists($path)) { JFolder::create($path); $this->indexHTML($zipPath); // count the folder created $this->folderCount++; } // do the file renaming if ($details->rename) { if ($fileName) { $new = str_replace($details->rename, $fileName, $item); $name = $name.'_'.$fileName; } elseif ($details->rename == 'new') { $new = $details->newName; } else { $new = str_replace($details->rename, $name, $item); } } else { $new = $item; } if (!JFile::exists($path.'/'.$new)) { // move the file to its place JFile::copy($this->templatePath.'/'.$item, $path.'/'.$new,'',true); // count the file created $this->fileCount++; } // store the new files $this->newFiles['dynamic'][$name][] = array( 'path' => $path.'/'.$new, 'name' => $new , 'view' => $name, 'zip' => $zipPath.'/'.$new); } } } return true; } return false; } /* * set the Joomla Version Data * * * @return oject The version data * */ private function setJoomlaVersionData() { // set the version data $versionData = json_decode(file_get_contents($this->templatePath.'/settings.json')); // add custom folders if ((isset($this->componentData->folders) && ComponentbuilderHelper::checkArray($this->componentData->folders)) || $this->addEximport || $this->uikit || $this->footable) { if ($this->addEximport) { // move the import view folder in place $importView = array( 'folder' => 'importViews', 'path' => 'admin/views/import', 'rename' => 1); $this->componentData->folders[] = $importView; // move the PHPExel Folder $PHPExcel = array( 'folder' => 'PHPExcel', 'path' => 'admin/helpers', 'rename' => 0); $this->componentData->folders[] = $PHPExcel; } if ($this->uikit) { // move the UIKIT Folder into place $uikit = array( 'folder' => 'uikit', 'path' => 'media', 'rename' => 0); $this->componentData->folders[] = $uikit; } if ($this->footable) { // move the footable folder into place $footable = array( 'folder' => 'footable', 'path' => 'media', 'rename' => 0); $this->componentData->folders[] = $footable; } // pointer tracker $pointer_tracker = 'h'; foreach ($this->componentData->folders as $custom) { // fix path $custom['path'] = rtrim($custom['path'], '/'); $custom['path'] = ltrim($custom['path'], '/'); // make sure we use the correct name $pathArray = (array) explode('/',$custom['path']); $firstFolder = array_values($pathArray)[0]; $lastFolder = end($pathArray); // only rename folder if last has folder name if ($custom['rename'] == 1) { $custom['path'] = str_replace('/'.$lastFolder,'',$custom['path']); $rename = 'new'; $newname = $lastFolder; if(($tkey = array_search($lastFolder, $pathArray)) !== false) { unset($pathArray[$tkey]); } } else { $lastFolder = $custom['folder']; $rename = false; $newname = ''; } // check if we sould add it to the media xml list if (!isset($this->fileContentStatic['###EXSTRA_MEDIA_FOLDERS###'])) { $this->fileContentStatic['###EXSTRA_MEDIA_FOLDERS###'] = ''; } if (count($pathArray) == 1 && $firstFolder == 'media') { $this->fileContentStatic['###EXSTRA_MEDIA_FOLDERS###'] .= "\n\t\t".$lastFolder.""; } // check if we sould add it to the site xml list if (!isset($this->fileContentStatic['###EXSTRA_SITE_FOLDERS###'])) { $this->fileContentStatic['###EXSTRA_SITE_FOLDERS###'] = ''; } if (count($pathArray) == 1 && $firstFolder == 'site') { $this->fileContentStatic['###EXSTRA_SITE_FOLDERS###'] .= "\n\t\t".$lastFolder.""; } // check if we sould add it to the admin xml list if (!isset($this->fileContentStatic['###EXSTRA_ADMIN_FOLDERS###'])) { $this->fileContentStatic['###EXSTRA_ADMIN_FOLDERS###'] = ''; } if (count($pathArray) == 1 && $firstFolder == 'admin') { $this->fileContentStatic['###EXSTRA_ADMIN_FOLDERS###'] .= "\n\t\t\t".$lastFolder.""; } // make we have not duplicates $key_pointer = ComponentbuilderHelper::safeString($custom['folder']).'_f'.$pointer_tracker; $pointer_tracker++; // set new folder to object $versionData->move->static->$key_pointer = new stdClass(); $versionData->move->static->$key_pointer->naam = $custom['folder']; $versionData->move->static->$key_pointer->path = 'c0mp0n3nt/'.$custom['path']; $versionData->move->static->$key_pointer->rename = $rename; $versionData->move->static->$key_pointer->newName = $newname; $versionData->move->static->$key_pointer->type = 'folder'; $versionData->move->static->$key_pointer->custom = true; } unset($this->componentData->folders); unset($custom); } // add custom files if ((isset($this->componentData->files) && ComponentbuilderHelper::checkArray($this->componentData->files)) || $this->addEximport || $this->googlechart) { if ($this->addEximport) { // move the PHPExel main file $PHPExcel = array( 'file' => 'PHPExcel.php', 'path' => 'admin/helpers', 'rename' => 0); $this->componentData->files[] = $PHPExcel; } if ($this->googlechart) { // move the google chart files $googleChart = array( 'file' => 'google.jsapi.js', 'path' => 'media/js', 'rename' => 0); $this->componentData->files[] = $googleChart; $googleChart = array( 'file' => 'chartbuilder.php', 'path' => 'admin/helpers', 'rename' => 0); $this->componentData->files[] = $googleChart; } // pointer tracker $pointer_tracker = 'h'; foreach ($this->componentData->files as $custom) { // make we have not duplicates $key_pointer = ComponentbuilderHelper::safeString($custom['file']).'_g'.$pointer_tracker; $pointer_tracker++; // set new file to object $versionData->move->static->$key_pointer = new stdClass(); $versionData->move->static->$key_pointer->naam = $custom['file']; // get the path info $pathInfo = pathinfo($custom['path']); if (isset($pathInfo['extension']) && $pathInfo['extension']) { $pathInfo['dirname'] = rtrim($pathInfo['dirname'], '/'); $pathInfo['dirname'] = ltrim($pathInfo['dirname'], '/'); $versionData->move->static->$key_pointer->path = 'c0mp0n3nt/'.$pathInfo['dirname']; $versionData->move->static->$key_pointer->rename = 'new'; $versionData->move->static->$key_pointer->newName = $pathInfo['basename']; // set the name $name = $pathInfo['basename']; } else { $custom['path'] = rtrim($custom['path'], '/'); $custom['path'] = ltrim($custom['path'], '/'); $versionData->move->static->$key_pointer->path = 'c0mp0n3nt/'.$custom['path']; $versionData->move->static->$key_pointer->rename = false; // set the name $name = $custom['file']; } // check if file should be updated if (isset($custom['notnew']) && $custom['notnew'] == 0) { $this->notNew[] = $key_pointer; } $versionData->move->static->$key_pointer->type = 'file'; $versionData->move->static->$key_pointer->custom = true; } unset($this->componentData->files); unset($custom); } return $versionData; } /* * set the index.html file in a folder path * * @param string $path The path to place the index.html file in * * @return void * */ private function indexHTML($path) { if (strlen($path) > 0) { JFile::copy($this->templatePath.'/index.html', $this->componentPath.'/'.$path.'/index.html'); // count the file created $this->fileCount++; } else { JFile::copy($this->templatePath.'/index.html', $this->componentPath.'/index.html'); // count the file created $this->fileCount++; } } /* * Remove folders with files * * @param string $dir The path to folder to remove * @param boolean $git if there is a git folder in that must not be removed * * @return boolean True in all is removed * */ protected function removeFolder($dir, $git = false) { if (JFolder::exists($dir)) { $it = new RecursiveDirectoryIterator($dir); $it = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST); foreach ($it as $file) { if ('.' === $file->getBasename() || '..' === $file->getBasename()) continue; if ($file->isDir()) { if ($git && strpos($file->getPathname(), $dir.'/.git') !== false) continue; JFolder::delete($file->getPathname()); } else { if ($git && strpos($file->getPathname(), $dir.'/.git') !== false) continue; JFile::delete($file->getPathname()); } } if (!$git && JFolder::delete($dir)) { return true; } } return false; } }