_db = JFactory::getDBO(); $query = "select distinct reference_table from #__jf_content"; $this->_db->setQuery( $query ); $this->_mlTableList = $this->_db->loadResultArray(); if( !$this->_mlTableList ){ echo $this->_db->getErrorMsg(); } } function getErrorNum(){ return $this->_db->getErrorNum(); } function debug( $debug ){ return $this->_db->debug( $debug ); } function setQuery( $sql, $offset = 0, $limit = 0, $prefix='#__' ){ return $this->_db->setQuery( $sql, $offset, $limit, $prefix); } /** * This global function loads the first row of a query into an object * * If an object is passed to this function, the returned row is bound to the existing elements of object. * If object has a value of null, then all of the returned query fields returned in the object. * @param string The SQL query * @param object The address of variable */ function loadObject( $translate=true, $language=null ) { global $mosConfig_lang, $_JOOMFISH_MANAGER; if( $language===null) $language = $mosConfig_lang; $object = $this->_db->loadObject( ); if( $translate && isset($_JOOMFISH_MANAGER)) { $doTranslate=false; $tables =$this->_getRefTables(); foreach ($tables["fieldTablePairs"] as $i=>$table) { if ($this->translatedContentAvailable($table)) { $doTranslate=true; break; } } if ( $doTranslate) { JoomFish::translate( $object, $this->_getTableName(), $language, $this->_getRefTables()); } } return $object; } /** * Public function to test if table has translated content available * * @param string $table : tablename to test */ function translatedContentAvailable($table){ return in_array( $table, $this->_mlTableList) || $table=="content"; } /** * Load a list of database objects * @param string The field name of a primary key * @return array If key is empty as sequential list of returned TRANSLATED records. * If key is not empty then the returned array is indexed by the value * the database key. Returns null if the query fails. */ function loadObjectList( $key='', $translate=true, $language=null ) { global $mosConfig_lang, $_JOOMFISH_MANAGER; if( $language===null) { $jlang =& JFactory::getLanguage(); $language = $jlang->getTag(); } $result = $this->_db->loadObjectList( $key ); if( $translate && isset($_JOOMFISH_MANAGER)) { $doTranslate=false; $tables =$this->_getRefTables(); if ($tables == null) return $result; // an unstranslatable query to return result as is foreach ($tables["fieldTablePairs"] as $i=>$table) { if ($this->translatedContentAvailable($table)) { $doTranslate=true; break; } } if ($doTranslate ) { JoomFish::translateList( $result, $this->_getTableName(), $language, $this->_getRefTables() ); } } return $result; } /** * Overwritten method to loads the first field of the first row returned by the query. * * @return The value returned in the query or null if the query failed. */ function loadResult( $translate=true, $language=null ) { $result=null; $ret=null; $result = $this->loadObject( $translate, $language ); if( $result != null ) { $fields = get_object_vars( $result ); $field = each($fields); $ret = $field[1]; } return $ret; } /** * Overwritten insert function to enable storage of material created in non-default language. * Note that this creates a translation which is identical to the original - when we update * the original in the default language we then keep the translation (although it will appread out of date!). * * @param string table name * @param object instance with information to store * @param string primary key name of table * @param boolean debug info printed or not * @param boolean passthru without storing information in a translation table */ function insertObject( $table, &$object, $keyName = NULL, $verbose=false , $passthru=false) { global $mosConfig_lang, $mosConfig_defaultLang, $_JOOMFISH_MANAGER; $passthru = $mosConfig_lang == $mosConfig_defaultLang; if( !$passthru && isset($_JOOMFISH_MANAGER)) { //Must insert parent first to get reference id ! $parentInsertReturn = $this->_db->insertObject( $table, $object, $keyName, $verbose); $actContentObject=null; if( isset($table) && $table!="" ) { $tableName = ereg_replace( '^#__', '', $table); // *** QUESTION ***// // IS THIS TEST APPROPRIATE HERE - I THINK IT MEANS YOU CAN'T DO A FIRST TRANSLATION FOR A TABLE VIA THE FRONT END // ** TEST BEFORE 1.8 **// //if ($this->translatedContentAvailable($table)) { $contentElement = $_JOOMFISH_MANAGER->getContentElement( $tableName ); if( isset( $contentElement ) ) { $actContentObject = new ContentObject( $_JOOMFISH_MANAGER->getLanguageID($mosConfig_lang), $contentElement ); if( isset( $object->$keyName ) ) { $actContentObject->loadFromContentID( $object->$keyName ); $actContentObject->updateMLContent( $object ); if( isset( $object->state ) ) { $actContentObject->published = ($object->state == 1) ? true : false; } else if ( isset( $object->published ) ) { $actContentObject->published = ($object->published == 1) ? true : false; } if ($actContentObject->published){ if ( $_JOOMFISH_MANAGER->getCfg("frontEndPublish")){ global $acl; $user =& JFactory::getUser(); $access = new stdClass(); $access->canPublish = $acl->acl_check( 'action', 'publish', 'users', $user->usertype, 'content', 'all' ); if ($access->canPublish) $actContentObject->setPublished($actContentObject->published); } } $actContentObject->store(); } } //} } return $parentInsertReturn; } else { return $this->_db->insertObject( $table, $object, $keyName, $verbose); } } /** * Overwritten update function to enable storage of translated information. * Based on the configuration in the content elements the automatic storage of * information is activated or not. It is important that this upgraded method will ensure * that all information will be written into the translation table. Only in the case that the * default language is choosen the information will be updated directly within the original tables. * To make sure that all other information will be written into the tables as expected the * statements will be manipulated as needed. * * @param string table name * @param object instance with information to store * @param string primary key name of table * @param boolean update fields with null or not * @param boolean passthru without storing information in a translation table */ function updateObject( $table, &$object, $keyName, $updateNulls=true, $passthru=false ) { global $mosConfig_lang, $mosConfig_defaultLang, $_JOOMFISH_MANAGER; // if the currect language is the site default language the translations will not be updated! $passthru = $mosConfig_lang == $mosConfig_defaultLang; if( !$passthru && isset($_JOOMFISH_MANAGER)) { $actContentObject=null; if( isset($table) && $table!="" ) { $tableName = ereg_replace( '^#__', '', $table); // *** QUESTION ***// // IS THIS TEST APPROPRIATE HERE - I THINK IT MEANS YOU CAN'T DO A FIRST TRANSLATION FOR A TABLE VIA THE FRONT END // ** TEST BEFORE 1.8 **// //if ($this->translatedContentAvailable($table)) { $contentElement = $_JOOMFISH_MANAGER->getContentElement( $tableName ); if( isset( $contentElement ) ) { $actContentObject = new ContentObject( $_JOOMFISH_MANAGER->getLanguageID($mosConfig_lang), $contentElement ); if( isset( $object->$keyName ) ) { $actContentObject->loadFromContentID( $object->$keyName ); $actContentObject->updateMLContent( $object ); if( isset( $object->state ) ) { $actContentObject->published = ($object->state == 1) ? true : false; } else if ( isset( $object->published ) ) { $actContentObject->published = ($object->published == 1) ? true : false; } if ( $_JOOMFISH_MANAGER->getCfg("frontEndPublish")){ global $acl; $user =& JFactory::getUser(); $access = new stdClass(); $access->canPublish = $acl->acl_check( 'action', 'publish', 'users', $user->usertype, 'content', 'all' ); if ($access->canPublish) $actContentObject->setPublished($actContentObject->published); } $actContentObject->store(); } } //} } return $this->_db->updateObject( $table, $object, $keyName, $updateNulls ); } else { return $this->_db->updateObject( $table, $object, $keyName, $updateNulls ); } } /** Internal function to determit the table name from an sql query * * @return string table name */ function _getTableName() { global $mosConfig_dbprefix; $posFrom = strpos( strtoupper($this->_sql), 'FROM ') + 5; // after 'FROM ' $posWhere = strpos( strtoupper($this->_sql), 'WHERE '); $table = substr( $this->_sql, $posFrom, $posWhere - $posFrom); if( strpos( $table, ' ' ) !== false ) { $table = substr( $table, 0, strpos( $table, ' ' ) ); } if (isset($mosConfig_dbprefix) && strlen($mosConfig_dbprefix)>0) $table = ereg_replace( $mosConfig_dbprefix, '', $table); $table = ereg_replace( "\n", "", $table) ; return $table; } /** * Override query in order to extract ref tables data * * @return n/a */ function query() { $this->_db->query(); $this->setRefTables(); return $this->_cursor; } function fillRefTableCache($cacheDir,$cacheFile){ $cacheFileContent = serialize($this->_refTables); $handle = fopen($cacheFile,"w"); fwrite($handle,$cacheFileContent); fclose($handle); // clean out old cache files $this->cleanRefTableCache($cacheDir); } function cleanRefTableCache($cacheDir){ if (!($dh = opendir($cacheDir))) { return false; } while ($file = readdir($dh)) { if (($file != '.') && ($file != '..')) { $file = "$cacheDir/$file"; if (is_file($file) && @filemtime($file) < $this->cacheExpiry) { if (!@unlink($file)) { echo "problems clearing cache file $file"; } } } } return true; } function setRefTables(){ // Before joomfish manager is created since we can't translate so skip this anaylsis global $_JOOMFISH_MANAGER; if (!$_JOOMFISH_MANAGER) return; // This could be speeded up by the use of a cache - but only of benefit is global caching is off $tempsql = $this->_sql; // only needed for selects at present - possibly add for inserts/updates later if (strpos(strtoupper($tempsql),"SELECT")===false) { return; } $registry =& JFactory::getConfig(); $cache =& JFactory::getCache('com_joomfish'); // TODO try to use Joomla caching routines directly // remove time formats (assume all numbers are not necessay - this could be dodgy?! $nos = array("0","1","2","3","4","5","6","7","8","9"); $sql_exNos = str_replace($nos,"",$tempsql); $sqlHash = md5($sql_exNos ); $this->cacheExpiry = time() - $cache->_options["lifetime"]/60; $cacheDir = $cache->_options["cachebase"]."/refTableSQL"; if (!file_exists($cacheDir)) mkdir($cacheDir); $cacheFile = "$cacheDir/$sqlHash"; if (file_exists($cacheFile) && @filemtime($cacheFile) > $this->cacheExpiry) { $cacheFileContent = file_get_contents($cacheFile); $this->_refTables = unserialize($cacheFileContent); return; } if($this->_cursor===true || $this->_cursor===false) { $this->fillRefTableCache($cacheDir,$cacheFile); return; } // get column metadata $i = 0; //echo " $this->_sql $this->_cursor ".var_export( $this->_cursor, true )."
"; //$cursorType = get_resource_type($this->_cursor); if (is_object($this->_cursor) && get_class($this->_cursor)=="mysqli_result"){ $dbIsMySQL = false; } else { $cursorType = get_resource_type($this->_cursor); if ($cursorType == "mysql result") { $dbIsMySQL = true; } else $dbIsMySQL = false; } if (!$dbIsMySQL && function_exists("mysqli_num_fields")) $fields = mysqli_num_fields($this->_cursor); else $fields = mysql_num_fields($this->_cursor); //print "
$tempsql $this->_cursor $fields"; if ($fields<=0) { $this->fillRefTableCache($cacheDir,$cacheFile); return; } $this->_refTables=array(); $this->_refTables["fieldTablePairs"]=array(); $this->_refTables["tableAliases"]=array(); $this->_refTables["fieldAliases"]=array(); $this->_refTables["fieldTableAliasData"]=array(); $this->_refTables["fieldCount"]=$fields; $this->_refTables["sql"]=$tempsql; // local variable to keep track of aliases that have already been analysed $tableAliases = array(); for ($i = 0; $i < $fields; ++$i) { if (!$dbIsMySQL && function_exists("mysqli_fetch_field")) $meta = mysqli_fetch_field($this->_cursor); else $meta = mysql_fetch_field($this->_cursor, $i); if (!$meta) { echo "No information available
\n"; } else { $tempTable = $meta->table; // if I have already found the table alias no need to do it again! if (array_key_exists($tempTable,$tableAliases)){ $value = $tableAliases[$tempTable]; } else { if (!isset($tempTable) || strlen($tempTable)==0) { continue; } //echo "
Information for column $i of ".($fields-1)." ".$meta->name." : $tempTable="; $tempArray=array(); $prefix = $this->_table_prefix; preg_match_all("/$prefix(\w*)\s+AS\s+".$tempTable."[,\s]/i",$this->_sql, $tempArray, PREG_PATTERN_ORDER); if (count($tempArray)>1 && count($tempArray[1])>0) $value = $tempArray[1][0]; else $value = null; if (isset($this->_table_prefix) && strlen($this->_table_prefix)>0 && strpos($tempTable,$this->_table_prefix)===0) $tempTable = substr($tempTable, strlen( $this->_table_prefix)); $value = $value?$value:$tempTable; $tableAliases[$tempTable]=$value; } if ((!($value=="session" || strpos($value,"jf_")===0)) && $this->translatedContentAvailable($value)){ /// ARGH !!! I must also look for aliases for fieldname !! $tempName = $meta->name; $tempArray=array(); preg_match_all("/(\w*)\s+AS\s+".$tempName."[,\s]/i",$this->_sql, $tempArray, PREG_PATTERN_ORDER); if (count($tempArray)>1 && count($tempArray[1])>0) { //echo "$meta->name is an alias for ".$tempArray[1][0]."
"; $nameValue = $tempArray[1][0]; } else $nameValue = $meta->name; if (!array_key_exists($value,$this->_refTables["tableAliases"])) $this->_refTables["tableAliases"][$value]=$meta->table; // I can't use the field name as the key since it may not be unique! if (!in_array($value,$this->_refTables["fieldTablePairs"])) $this->_refTables["fieldTablePairs"][]=$value; if (!array_key_exists($nameValue,$this->_refTables["fieldAliases"])) $this->_refTables["fieldAliases"][$meta->name]=$nameValue; // Put all the mapping data together so that everything is in sync and I can check fields vs aliases vs tables in one place $this->_refTables["fieldTableAliasData"][$i]=array("fieldNameAlias"=>$meta->name, "fieldName"=>$nameValue,"tableNameAlias"=>$meta->table,"tableName"=>$value); } } } $this->fillRefTableCache($cacheDir,$cacheFile); } /** Internal function to return reference table names from an sql query * * @return string table name */ function _getRefTables(){ return $this->_refTables; } /** * Returns a reference to the global Database object, only creating it * if it doesn't already exist. And keeps sure that there is only one * instace for a specific combination of the JDatabase signature * * @param string Database driver * @param string Database host * @param string Database user name * @param string Database user password * @param string Database name * @param string Common prefix for all tables * @return database A database object * @since 1.5 */ function &getInstance( $driver='mysql', $host='localhost', $user, $pass, $db='', $table_prefix='' ) { $signature = serialize(array($driver, $host, $user, $pass, $db, $table_prefix)); $database = JDatabase::_getStaticInstance($signature,'JFDatabase',true); return $database; } } class mldatabase extends JFDatabase { function mldatabase($options){ $this->_db->JFDatabase( $options); } function loadObject( &$object, $translate=true, $language=null ) { $object = $this->_db->loadObject($translate, $language); } } ?>