TranslationString.php

Go to the documentation of this file.
00001 <?
00002 /***************************************************************************
00003  *   Copyright (C) 2005 by Ferenc Veres   *
00004  *   lion@netngine.hu   *
00005  *                                                                         *
00006  *   This program is free software; you can redistribute it and/or modify  *
00007  *   it under the terms of the GNU General Public License as published by  *
00008  *   the Free Software Foundation; either version 2 of the License, or     *
00009  *   (at your option) any later version.                                   *
00010  *                                                                         *
00011  *   This program is distributed in the hope that it will be useful,       *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU General Public License for more details.                          *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU General Public License     *
00017  *   along with this program; if not, write to the                         *
00018  *   Free Software Foundation, Inc.,                                       *
00019  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00020  ***************************************************************************/
00021 include_once('TranslationWordList.php');
00022 
00028 class TranslationString
00029 {
00030         private $StringID;      
00031         private $ProjectID;     
00032         private $Original;      
00033         private $LocaleID;      
00034         private $Translation;   
00035         private $SentenceID;    
00036         private $LastSeen;      
00037         private $RowOrder;      
00039         private $Matches;       
00040         private $Words;         
00042         public static $SentenceLengthCache; 
00043         public static $WordSentencesCache; 
00067         function __construct($stringID = 0, $projectID = 0, $original = "", $localeID = 1, $translation = "", $sentenceID = 0, $lastSeen = 0, $rowOrder = 0)
00068         {
00069                 $DB =& GetDbConn();
00070                 $Tables =& GetTables();
00071                 
00072                 // Load string from database?
00073                 if($stringID != 0 && $original == "")
00074                 {
00075                         $rs = $DB->Execute("SELECT ID, ProjectID, Original, LocaleID, Translation, SentenceID, LastSeen, RowOrder FROM ".$Tables["Strings"]." WHERE ID=?", array($stringID));
00076                         
00077                         // Found the string?
00078                         if($row = $rs->FetchRow())
00079                         {
00080                                 // Yes! Load details.
00081                                 $this->StringID = $row["ID"];
00082                                 $this->ProjectID = $row["ProjectID"];
00083                                 $this->Original = $row["Original"];
00084                                 $this->LocaleID = $row["LocaleID"];
00085                                 $this->Translation = $row["Translation"];
00086                                 $this->SentenceID = ($row["SentenceID"] != null ? $row["SentenceID"] : 0);
00087                                 $this->LastSeen = $row["LastSeen"];
00088                                 $this->RowOrder = $row["RowOrder"];
00089                         }
00090                         else
00091                         {
00092                                 throw new Exception("TranslationString: Requested not existing string from databse. ID: $stringID");
00093                         }
00094                 }
00095 
00096                 // Initialize a new string from constructor call
00097                 // ($stringID may be 0, ->Save can identify the same $original in the same project or
00098                 // create a new string automaticly!)
00099                 if($original != "")
00100                 {
00101                         $this->StringID = $stringID;
00102                         $this->ProjectID = $projectID;
00103                         $this->Original = $original;
00104                         $this->LocaleID = $localeID;
00105                         $this->Translation = $translation;
00106                         $this->SentenceID = ($sentenceID != null ? $sentenceID : 0);
00107                         $this->LastSeen = $lastSeen;
00108                         $this->RowOrder = $rowOrder;
00109                 }
00110         }
00111 
00112         /* Static cache initialization */
00113         
00126         public static function InitSentenceLengthCache()
00127         {
00128                 $DB =& GetDbConn();
00129                 $Tables =& GetTables();
00130                 
00131                 // Load all already stored sentences' length for word counting
00132                 $rs = $DB->Execute("SELECT SentenceID, Sum(Occurences) AS Count FROM ".$Tables["SentenceIndex"]." GROUP BY SentenceID");
00133         
00134                 while($row = $rs->FetchRow())
00135                 {
00136                         TranslationString::$SentenceLengthCache[$row["SentenceID"]] = $row["Count"];
00137                 }
00138         }
00139         
00145         public static function InitWordSentencesCache()
00146         {
00147                 $DB =& GetDbConn();
00148                 $Tables =& GetTables();
00149                 
00150                 // Load all already stored sentences
00151                 $rs = $DB->Execute("SELECT SentenceID, WordID FROM ".$Tables["SentenceIndex"]);
00152         
00153                 while($row = $rs->FetchRow())
00154                 {
00155                         TranslationString::$WordSentencesCache[$row["WordID"]][] = $row["SentenceID"];
00156                 }
00157         }
00158         
00159         /* Property access */
00160 
00167         public function GetStringID()
00168         {
00169                 return $this->StringID;
00170         }
00171 
00178         public function GetProjectID()
00179         {
00180                 return $this->ProjectID;
00181         }
00182         
00189         public function GetOriginal()
00190         {
00191                 return $this->Original;
00192         }
00193 
00200         public function GetLocaleID()
00201         {
00202                 return $this->LocaleID;
00203         }
00204 
00211         public function GetTranslation()
00212         {
00213                 return $this->Translation;
00214         }
00215 
00222         public function GetSentenceID()
00223         {
00224                 return $this->SentenceID;
00225         }
00226 
00233         public function GetLastSeen()
00234         {
00235                 return $this->LastSeen;
00236         }
00237 
00244         public function SetTranslation($translation)
00245         {
00246                 $this->Translation = $translation;
00247         }
00248 
00257         public function SetRowOrder($index)
00258         {
00259                 $this->RowOrder= $index;
00260         }
00261 
00262         /* Methods to STORE strings */
00263 
00274         function Save()
00275         {
00276                 $DB =& GetDbConn();
00277                 $Tables =& GetTables();
00278 
00279                 // Check paramters
00280                 if($this->Original == "")
00281                 {
00282                         throw new Exception("TranslationString->Save() called without Original string.");
00283                 }
00284 
00285                 // Find and/or Store our words in the wordindex (always)
00286                 $this->Words = new TranslationWordList($this->Original);
00287 
00288                 // Check if we have this Original string already
00289                 $rs = $DB->Execute("SELECT ID, SentenceID, ProjectID FROM ".$Tables["Strings"]." WHERE Original = ? AND LocaleID = ?", array($this->Original, $this->LocaleID));
00290 
00291                 // Loop on all same Original strings (with same locale)
00292                 while($row = $rs->FetchRow())
00293                 {
00294                         if($this->SentenceID == 0)
00295                         {
00296                                 // Will get the same for all nonzero (indexed), hopefully.
00297                                 $this->SentenceID = ($row["SentenceID"] != null ? $row["SentenceID"] : 0);
00298                         }
00299 
00300                         // If ProjectID matches too, won't create new string, just update it!
00301                         if($row["ProjectID"] == $this->ProjectID)
00302                         {
00303                                 $this->StringID = $row["ID"];
00304                         }
00305                 }
00306 
00307                 // Do a sentence index: if there was no Original yet and we have any words.
00308                 if($this->SentenceID == 0 && $this->Words->SumCount() != 0)
00309                 {
00310                         // Find in sentence index, store the 100% match's Sentence ID
00311                         $this->SentenceID = $this->FindSentenceIndex(false);
00312 
00313                         // No 100% match? Store in sentence index!
00314                         if($this->SentenceID == 0)
00315                         {       
00316                                 $this->SentenceID = $this->StoreSentenceIndex();
00317 
00318                                 // Store length in the cache
00319                                 TranslationString::$SentenceLengthCache[$this->SentenceID] = $this->Words->SumCount();
00320                         }
00321                 }
00322                 
00323                 // Store string. Update or insert
00324 
00325                 if($this->StringID == 0)
00326                 {
00327                         // INSERT: No same Original in same Project, insert as new
00328 
00329                         $DB->Execute("INSERT INTO ".$Tables["Strings"]." (ProjectID, Original, SentenceID, LocaleID, Translation, LastSeen, RowOrder) VALUES (?,?,?,?,?, now(), ?)",
00330                                 array(
00331                                         $this->ProjectID,
00332                                         $this->Original,
00333                                         ($this->SentenceID != 0 ? $this->SentenceID : null),
00334                                         $this->LocaleID,
00335                                         $this->Translation,
00336                                         $this->RowOrder));
00337 
00338                         if(!$DB->Insert_ID())
00339                         {
00340                                 throw new Exception("DB Error: Insert_ID not supported");
00341                         }
00342 
00343                         // Get the new ID
00344                         $this->StringID = $DB->Insert_ID();
00345                 }
00346                 else
00347                 {
00348                         // UPDATE: Same Original exists in the same Project, no dupes! Overwrite.
00349                         $DB->Execute("UPDATE ".$Tables["Strings"]." SET Translation = ?, SentenceID = ?, LastSeen = now(), RowOrder = ? WHERE ID = ?",
00350                                 array(
00351                                         $this->Translation,
00352                                         ($this->SentenceID != 0 ? $this->SentenceID : null),
00353                                         $this->RowOrder,
00354                                         $this->StringID));
00355                 }
00356 
00357 
00358                 // Return the found or new string ID. May be 0 for empty sentences.
00359                 return $this->StringID;
00360         }
00361 
00367         public function DestroyData()
00368         {
00369                 $DB =& GetDbConn();
00370                 $Tables =& GetTables();
00371                 
00372                 if($this->StringID == 0)
00373                 {
00374                         throw new Exception("String DestroyData called on a not loaded string.");
00375                 }
00376                 $DB->Execute("DELETE FROM Strings WHERE ID = ?", array($this->StringID));
00377                 $this->StringID = 0;
00378         }
00379 
00380         /**** Methods to find strings ****/
00381 
00398         function FindSimilar($FindText = "", $localeID = 0, $FilterPercent = 60)
00399         {
00400                 $DB =& GetDbConn();
00401                 $Tables =& GetTables();
00402                 
00403                 unset($translations);
00404                 unset($percents);
00405 
00406                 if($FindText != "")
00407                 {
00408                         $this->Original = $FindText;
00409                 }
00410                 if($localeID != 0)
00411                 {
00412                         $this->LocaleID = $localeID;
00413                 }
00414 
00415                 $this->Words = new TranslationWordList($this->Original);
00416 
00417                 // No words at all? Return empty stuff.
00418                 if($this->Words->SumCount() == 0)
00419                 {
00420                         return;
00421                 }
00422 
00423                 // Try finding it, allowing similar
00424                 $this->FindSentenceIndex(true);
00425 
00426                 // No matches at all?
00427                 if(empty($this->Matches))
00428                 {
00429                         return;
00430                 }
00431 
00432                 // Order the array to descending and filter unwanted percentage results
00433                 $res = $this->Matches;
00434 
00435                 // Drop unwanted: Low percent
00436                 foreach($res as $id => $percent)
00437                 {
00438                         if($percent >= $FilterPercent)
00439                         {
00440                                 $filtered[$id] = $percent;
00441                         }
00442                 }
00443 
00444                 // No matches above the percent limit?
00445                 if(empty($filtered))
00446                 {
00447                         return;
00448                 }
00449                 
00450                 // Sort by percent
00451                 arsort($filtered);
00452 
00453                 // Remember percentage
00454                 foreach($filtered as $id => $percent)
00455                 {
00456                         $translations[$id]["percent"] = $percent;
00457                 }
00458 
00459                 // Get ALL (found above) strings in one pass
00460                 $idSQL = join(array_keys($filtered), ",");
00461                 
00462                 $rs = $DB->Execute("SELECT ID, ProjectID, Original, Translation, LocaleID, SentenceID, TIMESTAMP(LastSeen) as LastSeen, RowOrder FROM ".$Tables["Strings"]." WHERE SentenceID IN ($idSQL) AND LocaleID = ".$this->LocaleID);
00463 
00464                 // Loop on all strings and store in array
00465                 while($row = $rs->FetchRow())
00466                 {
00467                         $translations[$row["SentenceID"]]["strings"][] = new TranslationString(
00468                                 $row["ID"], 
00469                                 $row["ProjectID"], 
00470                                 $row["Original"], 
00471                                 $row["LocaleID"], 
00472                                 $row["Translation"], 
00473                                 $row["SentenceID"],
00474                                 $row["LastSeen"],
00475                                 $row["RowOrder"]);
00476                 }
00477 
00478                 // Drop the ones which were in wrong locale so no result now
00479                 // We need this so late, becase we do the percentage order above
00480                 foreach($translations as $id => $tr)
00481                 {
00482                         if(empty($translations[$id]["strings"]))
00483                         {
00484                                 unset($translations[$id]);
00485                         }
00486                 }
00487 
00488                 // Return the array containing the good matches (contains TranslationString objects)
00489                 return $translations;
00490         }
00491 
00505         function FindText($findText = "", $localeID = 0, $findOriginal, $start = 0, $limit = 100)
00506         {
00507                 $DB =& GetDbConn();
00508                 $Tables =& GetTables();
00509 
00510                 unset($translations);
00511 
00512                 // Find this object's text?
00513                 if($findText == "")
00514                 {
00515                         if($findOriginal)
00516                         {
00517                                 $findText = $this->Original;
00518                         }
00519                         else
00520                         {
00521                                 $findText = $this->Translation;
00522                         }
00523                 }
00524 
00525                 // Cannot search empty, return.
00526                 if($findText == "")
00527                 {
00528                         return;
00529                 }
00530 
00531                 // Use this object's locale ID?
00532                 if($localeID == 0)
00533                 {
00534                         $localeID = $this->LocaleID;
00535                 }
00536 
00537                 // Which column to look in?
00538                 if($findOriginal)
00539                 {
00540                         $column = "Original";
00541                 }
00542                 else
00543                 {
00544                         $column = "Translation";
00545                 }
00546 
00547                 // Select all similar strings with LIKE %%
00548                 $rs = $DB->Execute("SELECT ID, ProjectID, Original, Translation, LocaleID, SentenceID, TIMESTAMP(LastSeen) as LastSeen, RowOrder FROM ".$Tables["Strings"]." WHERE $column LIKE '%".fixstr($findText)."%'  AND LocaleID = ? LIMIT ?,?", array($localeID, $start, $limit));
00549 
00550                 // Loop on all strings and store in array
00551                 while($row = $rs->FetchRow())
00552                 {
00553                         $translations[$row["SentenceID"]]["strings"][] = new TranslationString(
00554                                 $row["ID"], 
00555                                 $row["ProjectID"], 
00556                                 $row["Original"], 
00557                                 $row["LocaleID"], 
00558                                 $row["Translation"], 
00559                                 $row["SentenceID"],
00560                                 $row["LastSeen"],
00561                                 $row["RowOrder"]);
00562                 }
00563                 $rs->Close();
00564 
00565                 if(empty($translations))
00566                 {
00567                         return;
00568                 }
00569                 
00570                 return $translations;
00571         }
00572 
00573         /* Private methods */
00574         
00586         private function FindSentenceIndex($findSimilarToo)
00587         {
00588                 $DB =& GetDbConn();
00589                 $Tables =& GetTables();
00590                 
00591                 unset($this->Matches);
00592                 
00593                 // Create a word ID string for SQL
00594                 $idSQL = "";
00595                 foreach($this->Words as $w)
00596                 {
00597                         $idSQL .= ($idSQL != "") ? "," : "";
00598                         $idSQL .= $w->GetID();
00599                 }
00600 
00601                 // Get all sentences with any of our words
00602                 $rs = $DB->Execute("SELECT SentenceID, WordID, Occurences FROM ".$Tables["SentenceIndex"]." WHERE WordID IN ($idSQL) ORDER BY SentenceID");
00603 
00604                 // Loop on the possible sentences
00605                 $sID = 0;
00606                 $exactMatch = 0;
00607                 do
00608                 {
00609                         $row = $rs->FetchRow();
00610 
00611                         // Another sentence coming or end of query?
00612                         if($row == false || $row["SentenceID"] != $sID)
00613                         {
00614                                 // If finished with a sentence id, process it
00615                                 if($sID != 0)
00616                                 {
00617                                         // Set real length, becuase the SQL does not fetch all words, just the common ones.
00618                                         $oldWords->SetFakeLength(TranslationString::$SentenceLengthCache[$sID]);
00619                                         $percent = $this->Words->CompareByID($oldWords);
00620 
00621                                         // Store match percent and exact match ID if any
00622                                         if($findSimilarToo)
00623                                         {
00624                                                 $this->Matches[$sID] = $percent;
00625                                         }
00626                                         if($percent == 100)
00627                                         {
00628                                                 // Found exact match
00629                                                 $exactMatch = $sID;
00630 
00631                                                 // Don't need similar entries, force quit searching
00632                                                 if(!$findSimilarToo)
00633                                                 {
00634                                                         break;
00635                                                 }
00636                                         }
00637                                 }
00638                                 
00639                                 // Start new sentence (if not query end)
00640                                 if($row != false)
00641                                 {
00642                                         $oldWords = new TranslationWordList();
00643                                         $sID = $row["SentenceID"];
00644                                 }
00645                         }
00646 
00647                         // Store current word, either first in this $oldWords or not,
00648                         // unless the query was over
00649                         if($row)
00650                         {
00651                                 $oldWords->AddID($row["WordID"], $row["Occurences"]);
00652                         }
00653                         
00654                 }
00655                 while($row);
00656 
00657                 return $exactMatch;
00658         }
00659 
00668         private function StoreSentenceIndex()
00669         {
00670                 $DB =& GetDbConn();
00671                 $Tables =& GetTables();
00672                 
00673                 // Get new max Sentence ID
00674                 $newID = $DB->GetOne("SELECT Max(SentenceID)+1 FROM ".$Tables["SentenceIndex"]);
00675 
00676                 if(!$newID)
00677                 {
00678                         $newID = 1;
00679                 }
00680 
00681                 // Insert all wordIDs and occurence counts for the new sentence ID
00682                 foreach($this->Words as $w)
00683                 {
00684                         $DB->Execute("INSERT INTO ".$Tables["SentenceIndex"]." VALUES (?,?,?)", array($newID, $w->GetID(), $w->GetCount()));
00685 
00686                         // Update static cache too, add this sentence to all words.
00687                         //TranslationString::$WordSentencesCache[$w->GetID()][] = $newID;
00688                 }
00689 
00690                 return $newID;
00691         }
00692 
00693 }
00694 ?>

Generated on Tue Mar 20 00:42:40 2007 for XarayaTranslationMemory by  doxygen 1.4.7