XarayaTranslationMemory  1.6
TranslationString.php
Go to the documentation of this file.
1 <?php
2 /***************************************************************************
3  * Copyright (C) 2005-2020 by Ferenc Veres *
4  * lion@netngine.hu *
5  * *
6  * This program is free software; you can redistribute it and/or modify *
7  * it under the terms of the GNU General Public License as published by *
8  * the Free Software Foundation; either version 3 of the License, or *
9  * (at your option) any later version. *
10  * *
11  * This program is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14  * GNU General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU General Public License *
17  * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18  ***************************************************************************/
19 include_once('TranslationWordList.php');
20 
27 {
28  private $StringID;
29  private $ProjectID;
30  private $Original;
31  private $LocaleID;
32  private $Translation;
33  private $SentenceID;
34  private $LastSeen;
35  private $RowOrder;
37  private $Matches;
38  private $Words;
40  public static $SentenceLengthCache;
41  public static $WordSentencesCache;
65  function __construct($stringID = 0, $projectID = 0, $original = "", $localeID = 1, $translation = "", $sentenceID = 0, $lastSeen = 0, $rowOrder = 0)
66  {
67  $DB =& GetDbConn();
68  $Tables =& GetTables();
69 
70  // Load string from database?
71  if($stringID != 0 && $original == "")
72  {
73  $rs = $DB->Execute("SELECT ID, ProjectID, Original, LocaleID, Translation, SentenceID, LastSeen, RowOrder FROM ".$Tables["Strings"]." WHERE ID=?", array($stringID));
74 
75  // Found the string?
76  if($row = $rs->FetchRow())
77  {
78  // Yes! Load details.
79  $this->StringID = $row["ID"];
80  $this->ProjectID = $row["ProjectID"];
81  $this->Original = $row["Original"];
82  $this->LocaleID = $row["LocaleID"];
83  $this->Translation = $row["Translation"];
84  $this->SentenceID = ($row["SentenceID"] != null ? $row["SentenceID"] : 0);
85  $this->LastSeen = $row["LastSeen"];
86  $this->RowOrder = $row["RowOrder"];
87  }
88  else
89  {
90  throw new Exception("TranslationString: Requested not existing string from databse. ID: $stringID");
91  }
92  }
93 
94  // Initialize a new string from constructor call
95  // ($stringID may be 0, ->Save can identify the same $original in the same project or
96  // create a new string automaticly!)
97  if($original != "")
98  {
99  $this->StringID = $stringID;
100  $this->ProjectID = $projectID;
101  $this->Original = $original;
102  $this->LocaleID = $localeID;
103  $this->Translation = $translation;
104  $this->SentenceID = ($sentenceID != null ? $sentenceID : 0);
105  $this->LastSeen = $lastSeen;
106  $this->RowOrder = $rowOrder;
107  }
108  }
109 
110  /* Static cache initialization */
111 
124  public static function InitSentenceLengthCache()
125  {
126  $DB =& GetDbConn();
127  $Tables =& GetTables();
128 
129  // Load all already stored sentences' length for word counting
130  $rs = $DB->Execute("SELECT SentenceID, Sum(Occurences) AS Count FROM ".$Tables["SentenceIndex"]." GROUP BY SentenceID");
131 
132  while($row = $rs->FetchRow())
133  {
134  TranslationString::$SentenceLengthCache[$row["SentenceID"]] = $row["Count"];
135  }
136  }
137 
143  public static function InitWordSentencesCache()
144  {
145  $DB =& GetDbConn();
146  $Tables =& GetTables();
147 
148  // Load all already stored sentences
149  $rs = $DB->Execute("SELECT SentenceID, WordID FROM ".$Tables["SentenceIndex"]);
150 
151  while($row = $rs->FetchRow())
152  {
153  TranslationString::$WordSentencesCache[$row["WordID"]][] = $row["SentenceID"];
154  }
155  }
156 
157  /* Property access */
158 
165  public function GetStringID()
166  {
167  return $this->StringID;
168  }
169 
176  public function GetProjectID()
177  {
178  return $this->ProjectID;
179  }
180 
187  public function GetOriginal()
188  {
189  return $this->Original;
190  }
191 
198  public function GetLocaleID()
199  {
200  return $this->LocaleID;
201  }
202 
209  public function GetTranslation()
210  {
211  return $this->Translation;
212  }
213 
220  public function GetSentenceID()
221  {
222  return $this->SentenceID;
223  }
224 
231  public function GetLastSeen()
232  {
233  return $this->LastSeen;
234  }
235 
242  public function SetTranslation($translation)
243  {
244  $this->Translation = $translation;
245  }
246 
255  public function SetRowOrder($index)
256  {
257  $this->RowOrder= $index;
258  }
259 
260  /* Methods to STORE strings */
261 
272  function Save()
273  {
274  $DB =& GetDbConn();
275  $Tables =& GetTables();
276 
277  // Check paramters
278  if($this->Original == "")
279  {
280  throw new Exception("TranslationString->Save() called without Original string.");
281  }
282 
283  // Find and/or Store our words in the wordindex (always)
284  $this->Words = new TranslationWordList($this->Original);
285 
286  // Check if we have this Original string already
287  $rs = $DB->Execute("SELECT ID, SentenceID, ProjectID FROM ".$Tables["Strings"]." WHERE Original = ? AND LocaleID = ?", array($this->Original, $this->LocaleID));
288 
289  // Loop on all same Original strings (with same locale)
290  while($row = $rs->FetchRow())
291  {
292  if($this->SentenceID == 0)
293  {
294  // Will get the same for all nonzero (indexed), hopefully.
295  $this->SentenceID = ($row["SentenceID"] != null ? $row["SentenceID"] : 0);
296  }
297 
298  // If ProjectID matches too, won't create new string, just update it!
299  if($row["ProjectID"] == $this->ProjectID)
300  {
301  $this->StringID = $row["ID"];
302  }
303  }
304 
305  // Do a sentence index: if there was no Original yet and we have any words.
306  if($this->SentenceID == 0 && $this->Words->SumCount() != 0)
307  {
308  // Find in sentence index, store the 100% match's Sentence ID
309  $this->SentenceID = $this->FindSentenceIndex(false);
310 
311  // No 100% match? Store in sentence index!
312  if($this->SentenceID == 0)
313  {
314  $this->SentenceID = $this->StoreSentenceIndex();
315 
316  // Store length in the cache
318  }
319  }
320 
321  // Store string. Update or insert
322 
323  if($this->StringID == 0)
324  {
325  // INSERT: No same Original in same Project, insert as new
326 
327  $DB->Execute("INSERT INTO ".$Tables["Strings"]." (ProjectID, Original, SentenceID, LocaleID, Translation, LastSeen, RowOrder) VALUES (?,?,?,?,?, now(), ?)",
328  array(
329  $this->ProjectID,
330  $this->Original,
331  ($this->SentenceID != 0 ? $this->SentenceID : null),
332  $this->LocaleID,
333  $this->Translation,
334  $this->RowOrder));
335 
336  if(!$DB->Insert_ID())
337  {
338  throw new Exception("DB Error: Insert_ID not supported");
339  }
340 
341  // Get the new ID
342  $this->StringID = $DB->Insert_ID();
343  }
344  else
345  {
346  // UPDATE: Same Original exists in the same Project, no dupes! Overwrite.
347  $DB->Execute("UPDATE ".$Tables["Strings"]." SET Translation = ?, SentenceID = ?, LastSeen = now(), RowOrder = ? WHERE ID = ?",
348  array(
349  $this->Translation,
350  ($this->SentenceID != 0 ? $this->SentenceID : null),
351  $this->RowOrder,
352  $this->StringID));
353  }
354 
355 
356  // Return the found or new string ID. May be 0 for empty sentences.
357  return $this->StringID;
358  }
359 
365  public function DestroyData()
366  {
367  $DB =& GetDbConn();
368  $Tables =& GetTables();
369 
370  if($this->StringID == 0)
371  {
372  throw new Exception("String DestroyData called on a not loaded string.");
373  }
374  $DB->Execute("DELETE FROM Strings WHERE ID = ?", array($this->StringID));
375  $this->StringID = 0;
376  }
377 
378  /**** Methods to find strings ****/
379 
396  function FindSimilar($FindText = "", $localeID = 0, $FilterPercent = 60)
397  {
398  $DB =& GetDbConn();
399  $Tables =& GetTables();
400 
401  unset($translations);
402  unset($percents);
403 
404  if($FindText != "")
405  {
406  $this->Original = $FindText;
407  }
408  if($localeID != 0)
409  {
410  $this->LocaleID = $localeID;
411  }
412 
413  $this->Words = new TranslationWordList($this->Original);
414 
415  // No words at all? Return empty stuff.
416  if($this->Words->SumCount() == 0)
417  {
418  return;
419  }
420 
421  // Try finding it, allowing similar
422  $this->FindSentenceIndex(true);
423 
424  // No matches at all?
425  if(empty($this->Matches))
426  {
427  return;
428  }
429 
430  // Order the array to descending and filter unwanted percentage results
431  $res = $this->Matches;
432 
433  // Drop unwanted: Low percent
434  foreach($res as $id => $percent)
435  {
436  if($percent >= $FilterPercent)
437  {
438  $filtered[$id] = $percent;
439  }
440  }
441 
442  // No matches above the percent limit?
443  if(empty($filtered))
444  {
445  return;
446  }
447 
448  // Sort by percent
449  arsort($filtered);
450 
451  // Remember percentage
452  foreach($filtered as $id => $percent)
453  {
454  $translations[$id]["percent"] = $percent;
455  }
456 
457  // Get ALL (found above) strings in one pass
458  $idSQL = join(array_keys($filtered), ",");
459 
460  $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);
461 
462  // Loop on all strings and store in array
463  while($row = $rs->FetchRow())
464  {
465  $translations[$row["SentenceID"]]["strings"][] = new TranslationString(
466  $row["ID"],
467  $row["ProjectID"],
468  $row["Original"],
469  $row["LocaleID"],
470  $row["Translation"],
471  $row["SentenceID"],
472  $row["LastSeen"],
473  $row["RowOrder"]);
474  }
475 
476  // Drop the ones which were in wrong locale so no result now
477  // We need this so late, becase we do the percentage order above
478  foreach($translations as $id => $tr)
479  {
480  if(empty($translations[$id]["strings"]))
481  {
482  unset($translations[$id]);
483  }
484  }
485 
486  // Return the array containing the good matches (contains TranslationString objects)
487  return $translations;
488  }
489 
503  function FindText($findText = "", $localeID = 0, $findOriginal, $start = 0, $limit = 100)
504  {
505  $DB =& GetDbConn();
506  $Tables =& GetTables();
507 
508  unset($translations);
509 
510  // Find this object's text?
511  if($findText == "")
512  {
513  if($findOriginal)
514  {
515  $findText = $this->Original;
516  }
517  else
518  {
519  $findText = $this->Translation;
520  }
521  }
522 
523  // Cannot search empty, return.
524  if($findText == "")
525  {
526  return;
527  }
528 
529  // Use this object's locale ID?
530  if($localeID == 0)
531  {
532  $localeID = $this->LocaleID;
533  }
534 
535  // Which column to look in?
536  if($findOriginal)
537  {
538  $column = "Original";
539  }
540  else
541  {
542  $column = "Translation";
543  }
544 
545  // Select all similar strings with LIKE %%
546  $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));
547 
548  // Loop on all strings and store in array
549  while($row = $rs->FetchRow())
550  {
551  $translations[$row["SentenceID"]]["strings"][] = new TranslationString(
552  $row["ID"],
553  $row["ProjectID"],
554  $row["Original"],
555  $row["LocaleID"],
556  $row["Translation"],
557  $row["SentenceID"],
558  $row["LastSeen"],
559  $row["RowOrder"]);
560  }
561  $rs->Close();
562 
563  if(empty($translations))
564  {
565  return;
566  }
567 
568  return $translations;
569  }
570 
571  /* Private methods */
572 
584  private function FindSentenceIndex($findSimilarToo)
585  {
586  $DB =& GetDbConn();
587  $Tables =& GetTables();
588 
589  unset($this->Matches);
590 
591  // Create a word ID string for SQL
592  $idSQL = "";
593  foreach($this->Words as $w)
594  {
595  $idSQL .= ($idSQL != "") ? "," : "";
596  $idSQL .= $w->GetID();
597  }
598 
599  // Get all sentences with any of our words
600  $rs = $DB->Execute("SELECT SentenceID, WordID, Occurences FROM ".$Tables["SentenceIndex"]." WHERE WordID IN ($idSQL) ORDER BY SentenceID");
601 
602  // Loop on the possible sentences
603  $sID = 0;
604  $exactMatch = 0;
605  do
606  {
607  $row = $rs->FetchRow();
608 
609  // Another sentence coming or end of query?
610  if($row == false || $row["SentenceID"] != $sID)
611  {
612  // If finished with a sentence id, process it
613  if($sID != 0)
614  {
615  // Set real length, becuase the SQL does not fetch all words, just the common ones.
616  $oldWords->SetFakeLength(TranslationString::$SentenceLengthCache[$sID]);
617  $percent = $this->Words->CompareByID($oldWords);
618 
619  // Store match percent and exact match ID if any
620  if($findSimilarToo)
621  {
622  $this->Matches[$sID] = $percent;
623  }
624  if($percent == 100)
625  {
626  // Found exact match
627  $exactMatch = $sID;
628 
629  // Don't need similar entries, force quit searching
630  if(!$findSimilarToo)
631  {
632  break;
633  }
634  }
635  }
636 
637  // Start new sentence (if not query end)
638  if($row != false)
639  {
640  $oldWords = new TranslationWordList();
641  $sID = $row["SentenceID"];
642  }
643  }
644 
645  // Store current word, either first in this $oldWords or not,
646  // unless the query was over
647  if($row)
648  {
649  $oldWords->AddID($row["WordID"], $row["Occurences"]);
650  }
651 
652  }
653  while($row);
654 
655  return $exactMatch;
656  }
657 
666  private function StoreSentenceIndex()
667  {
668  $DB =& GetDbConn();
669  $Tables =& GetTables();
670 
671  // Get new max Sentence ID
672  $newID = $DB->GetOne("SELECT Max(SentenceID)+1 FROM ".$Tables["SentenceIndex"]);
673 
674  if(!$newID)
675  {
676  $newID = 1;
677  }
678 
679  // Insert all wordIDs and occurence counts for the new sentence ID
680  foreach($this->Words as $w)
681  {
682  $DB->Execute("INSERT INTO ".$Tables["SentenceIndex"]." VALUES (?,?,?)", array($newID, $w->GetID(), $w->GetCount()));
683 
684  // Update static cache too, add this sentence to all words.
685  //TranslationString::$WordSentencesCache[$w->GetID()][] = $newID;
686  }
687 
688  return $newID;
689  }
690 
691 }
692 ?>
fixstr($text)
Definition: Common.php:36
static InitSentenceLengthCache()
& GetTables()
Definition: Common.php:71
& GetDbConn()
Definition: Common.php:61
FindText($findText="", $localeID=0, $findOriginal, $start=0, $limit=100)
__construct($stringID=0, $projectID=0, $original="", $localeID=1, $translation="", $sentenceID=0, $lastSeen=0, $rowOrder=0)
FindSentenceIndex($findSimilarToo)
SetTranslation($translation)
$DB
Definition: export.php:28
FindSimilar($FindText="", $localeID=0, $FilterPercent=60)