_name = basename(__FILE, '.php'); // just as note: protected can be accessed only within the class itself and by inherited and parent classes //This is normal name of the plugin family, custom, payment protected $_psType = 0; //Id of the joomla table where the plugins are registered protected $_jid = 0; protected $_vmpItable = 0; //the name of the table to store plugin internal data, like payment logs public $_tablename = 0; protected $_tableId = 'id'; protected $_tableChecked = false; //Name of the primary key of this table, for exampel virtuemart_calc_id or virtuemart_order_id protected $_tablepkey = 0; protected $_vmpCtable = 0; //the name of the table which holds the configuration like paymentmethods, shipmentmethods, customs protected $_configTable = 0; protected $_configTableFileName = 0; protected $_configTableClassName = 0; protected $_xParams = 0; protected $_varsToPushParam = array(); protected $_xmlFile = null; //id field of the config table protected $_idName = 0; //Name of the field in the configtable, which holds the parameters of the pluginmethod protected $_configTableFieldName = 0; protected $_debug = FALSE; protected $_loggable = FALSE; protected $_cryptedFields = false; protected $_toConvertInt = array(); protected $_toConvertDec = array(); protected $_dateFields = array(); /** * Constructor * * @param object $subject The object to observe * @param array $config An array that holds the plugin configuration * @since 1.5 */ function __construct (& $subject, $config) { $this->autoloadLanguage = false; parent::__construct( $subject, $config ); if(JVM_VERSION>3){ if (class_exists('ReflectionClass') and (method_exists($this, 'registerLegacyListener'))) { $class = new ReflectionClass($this); $methods = $class->getMethods(\ReflectionMethod::IS_PUBLIC); foreach ($methods as $m) { $methodName = $m->name; if (strpos($methodName, '_') !== 0 and strpos($methodName, 'on') !== 0) { $this->registerLegacyListener($methodName); } } } } //systemplugins must not load the language $wLang = ($this->_type != 'system'); if (!class_exists( 'VmConfig' )) { require(JPATH_ROOT .'/administrator/components/com_virtuemart/helpers/config.php'); VmConfig::loadConfig(FALSE, FALSE, $wLang); } $this->_psType = substr ($this->_type, 2); $filename = 'plg_' . $this->_type . '_' . $this->_name; if($wLang)$this->loadJLangThis($filename); $this->_tablename = '#__virtuemart_' . $this->_psType . '_plg_' . $this->_name; $this->_tableChecked = FALSE; $this->_xmlFile = vRequest::filterPath( VMPATH_ROOT .'/plugins/' . $this->_type .'/'. $this->_name .'/'. $this->_name . '.xml'); if(!JFile::exists($this->_xmlFile)){ $this->_xmlFile = vRequest::filterPath( JPATH_ROOT .'/plugins/' . $this->_type .'/'. $this->_name .'/'. $this->_name . '.xml'); } //vmTrace('Plugin constructed '.$this->_type.' '.$this->_name); } public function setConvertInt(array $toConvert){ $this->_toConvertInt = array_merge($this->_toConvertInt, $toConvert); } public function setConvertDecimal(array $toConvert) { $this->_toConvertDec = array_merge($this->_toConvertDec, $toConvert); } public function setDateFields(array $dateFields){ $this->_dateFields = array_merge($dateFields, $this->_dateFields); } public function loadJLangThis($fname,$type=0,$name=0){ if(empty($type)) $type = $this->_type; if(empty($name)) $name = $this->_name; self::loadJLang($fname,$type,$name); } static public function loadJLang($fname,$type,$name){ $tag = vmLanguage::$currLangTag; $cvalue = $fname.';'.$type; if(!isset(vmLanguage::$_loaded['plg'][$cvalue])){ vmLanguage::$_loaded['plg'][$cvalue] = $name; } vmLanguage::getLanguage($tag); $path = $basePath = VMPATH_ROOT .'/plugins/' .$type.'/'.$name; if(VmConfig::get('enableEnglish', true) and $tag!='en-GB'){ $testpath = $basePath .'/language/en-GB/en-GB.'.$fname.'.ini'; if(!file_exists($testpath)){ $epath = VMPATH_ADMINISTRATOR; } else { $epath = $path; } vmLanguage::$languages[$tag]->load($fname, $epath, 'en-GB', false, false); } $testpath = $basePath .'/language/'.$tag.'/'.$tag.'.'.$fname.'.ini'; if(!file_exists($testpath)){ $path = VMPATH_ADMINISTRATOR; } vmLanguage::$languages[$tag]->load($fname, $path,$tag, true, false); } function setPluginLoggable($set=TRUE){ $this->_loggable = $set; } function setCryptedFields($fieldNames){ $this->_cryptedFields = $fieldNames; } function getOwnUrl(){ $url = '/plugins/'.$this->_type.'/'.$this->_name; return $url; } function display3rdInfo($intro,$developer,$contactlink,$manlink){ $logolink = $this->getOwnUrl() ; return shopfunctions::display3rdInfo($this->_name,$intro,$developer,$logolink,$contactlink,$manlink); } /** * This function gets the parameters of a plugin from the given JForm $form. * This is used for the configuration GUI in the BE. * Attention: the xml Params must be always a subset of the varsToPushParams declared in the constructor * @param $form * @return array */ static public function getVarsToPushFromForm ($form){ $data = array(); $fieldSets = $form->getFieldsets(); foreach ($fieldSets as $name => $fieldSet) { foreach ($form->getFieldset($name) as $field) { $fieldname = (string)$field->fieldname; $private = false; if(strlen($fieldname)>1){ if(substr($fieldname,0,2)=='__'){ $private = true; } } if(!$private){ $type='char'; //vmdebug('getVarsToPushFromForm',$fieldname, $field->getAttribute('default')); $data[$fieldname] = array($field->getAttribute('default'), $type); } } } return $data; } /** * This function gets the parameters of a plugin by an xml file. * This is used for the configuration GUI in the BE. * Attention: the xml Params must be always a subset of the varsToPushParams declared in the constructor * @param $xmlFile * @param $name * @return array */ static public function getVarsToPushByXML ($xmlFile,$name){ try { $form = JForm::getInstance($name, $xmlFile, array(),false, '//vmconfig | //config[not(//vmconfig)]'); return vmPlugin::getVarsToPushFromForm($form); } catch (Exception $e) { vmError('getVarsToPushByXML, Error parsing '.$xmlFile); } } /** * Executes a function of a plugin directly, which is loaded via element * * @author Max Milbers * @deprecated Use function in class vDispatcher instead * @param $type type of the plugin, for example vmpayment * @param $element the element of the plugin as written in the extensions table (usually lowercase) * @param $trigger the function which was the trigger to execute * @param $args the arguments (as before for the triggers) * @return mixed */ static public function directTrigger($type,$element,$trigger, $args){ return vDispatcher::directTrigger($type,$element,$trigger, $args); } /** Creates a plugin object. Used by the directTrigger and therefore loads also unpublished plugins. * Otherwise, we would not be able to use the plug-in functions during the method saving process. * @deprecated Use the class vDispatcher instead * @param $type * @param $element * @return false|mixed */ static public function createPlugin($type, $element){ return vDispatcher::createPlugin($type, $element); } /** * Checks if this plugin should be active by the trigger * * @author Max Milbers * @param string $psType shipment,payment,custom * @param string the name of the plugin for example textinput, paypal * @param int/array $jid the registered plugin id(s) of the joomla table */ protected function selectedThis ($psType, $name = 0, $jid = null) { if ($psType !== 0) { if ($psType != $this->_psType) { vmdebug ('selectedThis $psType does not fit'); return FALSE; } } if ($name !== 0) { if ($name != $this->_name) { //vmdebug ('selectedThis $name ' . $name . ' does not fit pluginname ' . $this->_name); return FALSE; } } if ($jid === null) { return true; } else if($jid === 0){ return FALSE; } else { if ($this->_jid === 0) { $this->getJoomlaPluginId (); } if (is_array ($jid)) { if (!in_array ($this->_jid, $jid)) { vmdebug ('selectedThis id ' . $jid . ' not in array does not fit ' . $this->_jid); return FALSE; } } else { if ($jid != $this->_jid) { vmdebug ('selectedThis $jid ' . $jid . ' does not fit ' . $this->_jid); return FALSE; } } } return true; } static $c = null; /** * Checks if this plugin should be active by the trigger * * The function loads now all methods and caches them, so it is now cheap to use * * @author Max Milbers * @author Valérie Isaksen * * @param int/array $id the registered plugin id(s) of the joomla table */ function selectedThisByMethodId ($id = 'type') { if ($id === 'type') { return TRUE; } else { if(empty(self::$c[$this->_psType])){ $db = JFactory::getDBO (); $q = 'SELECT vm.* FROM `' . $this->_configTable . '` AS vm, #__extensions AS j WHERE vm.' . $this->_psType . '_jplugin_id = j.extension_id '; if (VmConfig::isSite() ) { $q .= 'AND vm.published = 1 '; } //Todo test this against the one above, maybe we do not need the extension table? /*$q = 'SELECT vm.* FROM `' . $this->_configTable . '` AS vm WHERE vm.' . $this->_psType . '_jplugin_id > 0 '; if (VmConfig::isSite() ) { $q .= 'AND vm.published = 1 '; }*/ $db->setQuery ($q); self::$c[$this->_psType] = $db->loadObjectList ($this->_idName); //vmdebug('selectedThisByMethodId loaded '.$this->_psType,self::$c); } else { //vmdebug('selectedThisByMethodId cached '.$this->_psType); } if(isset(self::$c[$this->_psType][$id]) and self::$c[$this->_psType][$id]->{$this->_psType.'_element'} == $this->_name){ //vmdebug('selectedThisByMethodId return true'); return self::$c[$this->_psType][$id]; } else { return false; } } } /** * Checks if this plugin should be active by the trigger * * @author Max Milbers * @author Valérie Isaksen * @param int/array $jplugin_id the registered plugin id(s) of the joomla table */ protected function selectedThisByJPluginId ($jplugin_id = 'type') { if ($jplugin_id === 'type') { return TRUE; } else { $db = JFactory::getDBO (); $q = 'SELECT vm.* FROM `' . $this->_configTable . '` AS vm, #__extensions AS j WHERE vm.`' . $this->_psType . '_jplugin_id` = "' . $jplugin_id . '" AND vm.`' . $this->_psType . '_jplugin_id` = j.extension_id AND j.`element` = "' . $this->_name . '"'; $db->setQuery ($q); if (!$res = $db->loadObject ()) { // vmError('selectedThisByMethodId '.$db->getQuery()); return FALSE; } else { return $res; } } } /** * Gets the id of the joomla table where the plugin is registered * * @author Max Milbers */ final protected function getJoomlaPluginId () { if (!empty($this->_jid)) { return $this->_jid; } $db = JFactory::getDBO (); $q = 'SELECT j.`extension_id` AS c FROM #__extensions AS j WHERE j.element = "' . $this->_name . '" AND j.`folder` = "' . $this->_type . '" and `enabled`= "1" and `state`="0" '; $db->setQuery ($q); try { $this->_jid = $db->loadResult (); } catch (Exception $e){ vmError ('getJoomlaPluginId ' . $e->getMessage() ); return FALSE; } return $this->_jid; } /** * Create the table for this plugin if it does not yet exist. * Or updates the table, if it exists. Please be aware that this function is slowing and is only called * storing a method or installing/udpating a plugin. This trigger is called via directTrigger so we dont need to check, if the plugin is active * * @param string $psType shipment,payment,custom * @author Valérie Isaksen * @author Max Milbers */ public function onStoreInstallPluginTable () { vmdebug('onStoreInstallPluginTable, going to execute onStoreInstallPluginTable '.$this->_name); $SQLfields = $this->getTableSQLFields(); if(empty($SQLfields)) return false; $loggablefields = $this->getTableSQLLoggablefields(); $tablesFields = array_merge($SQLfields, $loggablefields); $keys = array('id'=>'PRIMARY KEY (`id`)'); if(isset($tablesFields['virtuemart_order_id'])){ $keys['virtuemart_order_id'] = 'KEY (`virtuemart_order_id`)'; } $update[$this->_tablename] = array($tablesFields, $keys, array()); $updater = new GenericTableUpdater(); return $updater->updateMyVmTables($update); } /** * adds loggable fields to the table * * @return array */ function getTableSQLLoggablefields () { return array( 'created_on' => 'datetime', 'created_by' => "int(11) NOT NULL DEFAULT '0'", 'modified_on' => 'datetime', 'modified_by' => "int(11) NOT NULL DEFAULT '0'", 'locked_on' => 'datetime', 'locked_by' => 'int(11) NOT NULL DEFAULT \'0\'' ); } /** * @param $tableComment * @return string */ protected function createTableSQL ($tableComment,$tablesFields=0) { $query = "CREATE TABLE IF NOT EXISTS `" . $this->_tablename . "` ("; if(!empty($tablesFields)){ foreach ($tablesFields as $fieldname => $fieldtype) { $query .= '`' . $fieldname . '` ' . $fieldtype . " , "; } } else { $SQLfields = $this->getTableSQLFields (); $loggablefields = $this->getTableSQLLoggablefields (); foreach ($SQLfields as $fieldname => $fieldtype) { $query .= '`' . $fieldname . '` ' . $fieldtype . " , "; } foreach ($loggablefields as $fieldname => $fieldtype) { $query .= '`' . $fieldname . '` ' . $fieldtype . ", "; } } $query .= " PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_unicode_ci COMMENT='" . $tableComment . "' AUTO_INCREMENT=1 ;"; return $query; } /** * @return array */ function getTableSQLFields () { return false; } /** * Set with this function the provided plugin parameters * * @param string $paramsFieldName * @param array $varsToPushParam */ function setConfigParameterable ($paramsFieldName, $varsToPushParam) { $this->_xParams = $paramsFieldName; if(empty($varsToPushParam)) return false; $this->_varsToPushParam = array_merge($this->_varsToPushParam, $varsToPushParam); } /** * * @param $psType * @param $name * @param $id * @param $xParams * @param $varsToPush * @return bool */ protected function getTablePluginParams ($psType,$name, $id, &$xParams, &$varsToPush, &$table=0) { if (!empty($this->_psType) and !$this->selectedThis ($psType, $name, $id)) { //vmdebug('getTablePluginParams return ',$psType, $this->_psType, $name, $this->_name, $id,$this->_jid); return FALSE; } $varsToPush = $this->_varsToPushParam; $xParams = $this->_xParams; if($table!=0) { $table->setConvertInt($this->_toConvertInt); $table->setConvertDecimal($this->_toConvertDec); $table->setDatefields($this->_dateFields); } //vmdebug('getTablePluginParams '.$name.' sets xParams '.$xParams.' vars',$varsToPush); } /** * @param $name * @param $id * @param $table * @return bool */ protected function setOnTablePluginParams ($name, $id, &$table) { //Todo I think a test on this is wrong here //Adjusted it like already done in declarePluginParams if (!empty($this->_psType) and !$this->selectedThis ($this->_psType, $name, $id)) { return FALSE; } else { if($this->_cryptedFields){ $table->setCryptedFields($this->_cryptedFields); } $table->setParameterable ($this->_xParams, $this->_varsToPushParam); $table->setConvertDecimal($this->_toConvertDec); return TRUE; } } /** * Does VmTable::bindParameterable and setCryptedFields $name, $id, $data * @param $psType * @param $data * @return bool */ protected function declarePluginParams ($psType, &$data, $blind=0, $blind2=0) { if(!empty($this->_psType)){ if($this->_psType!=$psType){ return FALSE; } $element = $this->_psType.'_element'; $jplugin_id = $this->_psType.'_jplugin_id'; if(empty($data->{$element})) $data->{$element} = 0; if(empty($data->{$jplugin_id})) $data->{$jplugin_id} = 0; if(!$this->selectedThis($psType,$data->{$element})){ return FALSE; } } //New Vm3 way //Is only used for the config tables! //VmTable::bindParameterable ($data, $data->_xParams, $this->_varsToPushParam); if(isset($this->_varsToPushParam)){ if(isset($data->_varsToPushParam)){ $data->_varsToPushParam = array_merge((array)$data->_varsToPushParam, (array)$this->_varsToPushParam); } else { $data->_varsToPushParam = (array)$this->_varsToPushParam; } } else{ vmdebug('no vars to push?',$this); } if($this->_cryptedFields){ $data->setCryptedFields($this->_cryptedFields); } return TRUE; } /** * @param $int * @return mixed */ public function getVmPluginMethod ($int, $cache = true) { if ($this->_vmpCtable === 0 || !$cache) { $db = JFactory::getDBO (); if (!class_exists ($this->_configTableClassName)) { require(VMPATH_ADMIN .'/tables/'. $this->_configTableFileName . '.php'); } $this->_vmpCtable = new $this->_configTableClassName($db); if ($this->_xParams !== 0) { $this->_vmpCtable->setParameterable ($this->_configTableFieldName, $this->_varsToPushParam,true); } if($this->_cryptedFields){ $this->_vmpCtable->setCryptedFields($this->_cryptedFields); } } return $this->_vmpCtable->load ($int); } /** * This stores the data of the plugin, attention NOT the configuration of the pluginmethod, * this function should never be triggered only called from triggered functions. * * @author Max Milbers * @param array $values array or object with the data to store * @param int|string $primaryKey * @param int|string $id * @param boolean $preload * @return array */ public function storePluginInternalData (&$values, $primaryKey = 0, $id = 0, $preload = FALSE) { if ($primaryKey === 0) { $primaryKey = $this->_tablepkey; } if ($this->_vmpItable === 0 or $id==0) { $this->_vmpItable = $this->createPluginTableObject ($this->_tablename, $this->tableFields, $primaryKey, $this->_tableId, $this->_loggable); } if($this->_toConvertDec){ $this->_vmpItable->setConvertDecimal($this->_toConvertDec); } $this->_vmpItable->bindChecknStore ($values, $preload); return $values; } /** * This loads the data stored by the plugin before, NOT the configuration of the method, * this function should never be triggered only called from triggered functions. * * @param int $id * @param string $primaryKey */ protected function getPluginInternalData ($id, $primaryKey = 0) { if ($primaryKey === 0) { $primaryKey = $this->_tablepkey; } if ($this->_vmpItable === 0) { $this->_vmpItable = $this->createPluginTableObject ($this->_tablename, $this->tableFields, $primaryKey, $this->_tableId, $this->_loggable); } //vmdebug('getPluginInternalData $id '.$id.' and $primaryKey '.$primaryKey); return $this->_vmpItable->load ($id); } /** * @param $tableName * @param $tableFields * @param $primaryKey * @param $tableId * @param bool $loggable * @return VmTableData */ protected function createPluginTableObject ($tableName, $tableFields, $primaryKey, $tableId, $loggable = FALSE) { $db = JFactory::getDBO (); $table = new VmTable($tableName, $tableId, $db); foreach ($tableFields as $field) { $table->{$field} = 0; } if ($primaryKey !== 0) { $table->setPrimaryKey ($primaryKey); } if ($loggable) { $table->setLoggable (); } if($this->_cryptedFields){ $table->setCryptedFields($this->_cryptedFields); } if($this->_toConvertDec and is_array($this->_toConvertDec) ){ $table->setConvertDecimal($this->_toConvertDec); } /*if (!$this->_tableChecked) { $this->onStoreInstallPluginTable ($this->_psType); $this->_tableChecked = TRUE; }*/ return $table; } /** * @param $id * @param int $primaryKey * @return mixed */ protected function removePluginInternalData ($id, $primaryKey = 0) { if ($primaryKey === 0) { $primaryKey = $this->_tablepkey; } if ($this->_vmpItable === 0) { $this->_vmpItable = $this->createPluginTableObject ($this->_tablename, $this->tableFields, $primaryKey, $this->_tableId, $this->_loggable); } vmdebug ('removePluginInternalData $id ' . $id . ' and $primaryKey ' . $primaryKey); return $this->_vmpItable->delete ($id); } /** * @param string $layout * @param null $viewData * @param null $name * @param null $psType * @return string * @author Patrick Kohl, Valérie Isaksen, Max Milbers */ public function renderByLayout ($layout = 'default', $viewData = NULL, $name = NULL, $psType = NULL) { if ($name === NULL) { $name = $this->_name; } if ($psType === NULL) { $psType = 'vm'.$this->_psType; } $layout = vmPlugin::_getLayoutPath ($name, $psType, $layout); if($layout){ ob_start (); include ($layout); return ob_get_clean (); } else { vmdebug('renderByLayout: layout '.$layout.'not found '.$psType. ' '.$name.' default path '.$layout); } } /** * Note: We have 2 subfolders for versions > J15 for 3rd parties developers, to avoid 2 installers * Note: from Version 2.12: it is possible to have the tmpl folder directly in $pluginName folder * @author Max Milbers, Valérie Isaksen */ static public function _getLayoutPath ($pluginName, $group, $layout = 'default') { $layoutPath=$templatePathWithGroup=$defaultPathWithGroup=''; jimport ('joomla.filesystem.file'); // First search in the new system $vmStyle = VmTemplate::loadVmTemplateStyle(); $template = $vmStyle['template']; $templatePath = VMPATH_ROOT .'/templates/'. $template .'/html/'. $group . '/' . $pluginName . '/' . $layout . '.php'; $defaultPath = VMPATH_ROOT .'/plugins/'. $group . '/' . $pluginName .'/tmpl/'. $layout . '.php'; $defaultPathWithGroup = VMPATH_ROOT .'/plugins/'. $group . '/' . $pluginName . '/' . $pluginName .'/tmpl/'. $layout . '.php'; if (JFile::exists ($templatePath)) { $layoutPath= $templatePath; } elseif (JFile::exists ($defaultPath)) { $layoutPath= $defaultPath; } elseif (JFile::exists ($defaultPathWithGroup)) { $layoutPath = $defaultPathWithGroup; } if (empty($layoutPath)) { $warn='The layout: '. $layout. ' does not exist in:'; $warn.='
'. $templatePath.'
'.$defaultPath; if (!empty($defaultPathWithGroup)) { $warn.='
'.$defaultPathWithGroup .'
'; } vmWarn($warn); return false; } return $layoutPath; } /** * @param $pluginName * @param $group * @param string $layout * @return mixed * @author Valérie Isaksen */ static public function getTemplatePath($pluginName, $group, $layout = 'default') { $layoutPath = vmPlugin::_getLayoutPath ($pluginName, 'vm' . $group, $layout); return str_replace('/' . $layout . '.php','',$layoutPath ); } function plgVmOnDisplayEditCustoms($custom_id, &$html) { if ($this->_type == 'vmcustoms'){ return $this->plgVmOnDisplayEdit($custom_id, $html); } } function plgVmOnDisplayEditCalc(&$calc, &$html) { if ($this->_type == 'vmcalculation'){ return $this->plgVmOnDisplayEdit($calc, $html); } } /** * @param $custom_id * @param $html * @deprecated Use plgVmOnDisplayEditCustoms or plgVmOnDisplayEditCalc instead */ function plgVmOnDisplayEdit($custom_id, &$html) { } }