Translation2
[ class tree: Translation2 ] [ index: Translation2 ] [ all elements ]

Source for file db.php

Documentation is available at db.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3.  
  4. /**
  5.  * Contains the Translation2_Admin_Container_db class
  6.  *
  7.  * This storage driver can use all databases which are supported
  8.  * by the PEAR::DB abstraction layer to fetch data.
  9.  *
  10.  * PHP versions 4 and 5
  11.  *
  12.  * LICENSE: Redistribution and use in source and binary forms, with or without
  13.  * modification, are permitted provided that the following conditions are met:
  14.  * 1. Redistributions of source code must retain the above copyright
  15.  *    notice, this list of conditions and the following disclaimer.
  16.  * 2. Redistributions in binary form must reproduce the above copyright
  17.  *    notice, this list of conditions and the following disclaimer in the
  18.  *    documentation and/or other materials provided with the distribution.
  19.  * 3. The name of the author may not be used to endorse or promote products
  20.  *    derived from this software without specific prior written permission.
  21.  *
  22.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
  23.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  24.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  25.  * IN NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY
  26.  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  27.  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  28.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  29.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  30.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  31.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32.  *
  33.  * @category  Internationalization
  34.  * @package   Translation2
  35.  * @author    Lorenzo Alberton <l.alberton@quipo.it>
  36.  * @author    Ian Eure <ieure@php.net>
  37.  * @copyright 2004-2007 Lorenzo Alberton, Ian Eure
  38.  * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
  39.  * @version   CVS: $Id: db.php,v 1.40 2008/05/03 09:17:59 quipo Exp $
  40.  * @link      http://pear.php.net/package/Translation2
  41.  */
  42.  
  43. /**
  44.  * require Translation2_Container_db class
  45.  */
  46. require_once 'Translation2/Container/db.php';
  47.  
  48. /**
  49.  * Storage driver for storing/fetching data to/from a database
  50.  *
  51.  * This storage driver can use all databases which are supported
  52.  * by the PEAR::DB abstraction layer to store and fetch data.
  53.  *
  54.  * @category  Internationalization
  55.  * @package   Translation2
  56.  * @author    Lorenzo Alberton <l.alberton@quipo.it>
  57.  * @author    Ian Eure <ieure@php.net>
  58.  * @copyright 2004-2007 Lorenzo Alberton, Ian Eure
  59.  * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
  60.  * @link      http://pear.php.net/package/Translation2
  61.  */
  62. {
  63.  
  64.     // {{{ class vars
  65.  
  66.     // }}}
  67.     // {{{ addLang()
  68.  
  69.     /**
  70.      * Creates a new table to store the strings in this language.
  71.      * If the table is shared with other langs, it is ALTERed to
  72.      * hold strings in this lang too.
  73.      *
  74.      * @param array $langData language data
  75.      * @param array $options  options
  76.      *
  77.      * @return true|PEAR_Error
  78.      */
  79.     function addLang($langData$options = array())
  80.     {
  81.         $tables $this->db->getListOf('tables');
  82.         if (PEAR::isError($tables)) {
  83.             return $tables;
  84.         }
  85.  
  86.         $lang_col $this->_getLangCol($langData['lang_id']);
  87.  
  88.         if (in_array($langData['table_name']$tables)) {
  89.             // table exists
  90.             $query sprintf('ALTER TABLE %s ADD %s%s TEXT',
  91.                             $this->db->quoteIdentifier($langData['table_name']),
  92.                             $this->db->phptype == 'mssql' '' 'COLUMN ',
  93.                             $this->db->quoteIdentifier($lang_col)
  94.             );
  95.             ++$this->_queries;
  96.             return $this->db->query($query);
  97.         }
  98.  
  99.         //table does not exist
  100.         $queries   = array();
  101.         $queries[sprintf('CREATE TABLE %s ( '
  102.                              .'%s VARCHAR(%d) default NULL, '
  103.                              .'%s TEXT NOT NULL, '
  104.                              .'%s TEXT )',
  105.              $this->db->quoteIdentifier($langData['table_name']),
  106.              $this->db->quoteIdentifier($this->options['string_page_id_col']),
  107.              (int)$this->options['string_page_id_col_length'],
  108.              $this->db->quoteIdentifier($this->options['string_id_col']),
  109.              $this->db->quoteIdentifier($lang_col)
  110.         );
  111.         $mysqlClause ($this->db->phptype == 'mysql''(255)' '';
  112.  
  113.         $index_name sprintf('%s_%s_%s_index',
  114.             $langData['table_name'],
  115.             $this->options['string_page_id_col'],
  116.             $this->options['string_id_col']
  117.         );
  118.         $queries[]  sprintf('CREATE UNIQUE INDEX %s ON %s (%s, %s%s)',
  119.              $this->db->quoteIdentifier($index_name),
  120.              $this->db->quoteIdentifier($langData['table_name']),
  121.              $this->db->quoteIdentifier($this->options['string_page_id_col']),
  122.              $this->db->quoteIdentifier($this->options['string_id_col']),
  123.              $mysqlClause
  124.         );
  125.  
  126.         $index_name sprintf('%s_%s_index',
  127.             $langData['table_name'],
  128.             $this->options['string_page_id_col']
  129.         );
  130.         $queries[]  sprintf('CREATE INDEX %s ON %s (%s)',
  131.              $this->db->quoteIdentifier($index_name),
  132.              $this->db->quoteIdentifier($langData['table_name']),
  133.              $this->db->quoteIdentifier($this->options['string_page_id_col'])
  134.         );
  135.  
  136.         $index_name sprintf('%s_%s_index',
  137.             $langData['table_name'],
  138.             $this->options['string_id_col']
  139.         );
  140.         $queries[]  sprintf('CREATE INDEX %s ON %s (%s%s)',
  141.              $this->db->quoteIdentifier($index_name),
  142.              $this->db->quoteIdentifier($langData['table_name']),
  143.              $this->db->quoteIdentifier($this->options['string_id_col']),
  144.              $mysqlClause
  145.         );
  146.  
  147.         foreach ($queries as $query{
  148.             ++$this->_queries;
  149.             $res $this->db->query($query);
  150.             if (PEAR::isError($res)) {
  151.                 return $res;
  152.             }
  153.         }
  154.         return true;
  155.     }
  156.  
  157.     // }}}
  158.     // {{{ addLangToList()
  159.  
  160.     /**
  161.      * Creates a new entry in the langsAvail table.
  162.      * If the table doesn't exist yet, it is created.
  163.      *
  164.      * @param array $langData array('lang_id'    => 'en',
  165.      *                               'table_name' => 'i18n',
  166.      *                               'name'       => 'english',
  167.      *                               'meta'       => 'some meta info',
  168.      *                               'error_text' => 'not available',
  169.      *                               'encoding'   => 'iso-8859-1');
  170.      *
  171.      * @return true|PEAR_Error
  172.      */
  173.     function addLangToList($langData)
  174.     {
  175.         $tables $this->db->getListOf('tables');
  176.         if (PEAR::isError($tables)) {
  177.             return $tables;
  178.         }
  179.  
  180.         if (!in_array($this->options['langs_avail_table']$tables)) {
  181.             $queries   = array();
  182.             $queries[sprintf('CREATE TABLE %s ('
  183.                                 .'%s VARCHAR(16), '
  184.                                 .'%s VARCHAR(200), '
  185.                                 .'%s TEXT, '
  186.                                 .'%s VARCHAR(250), '
  187.                                 .'%s VARCHAR(16) )',
  188.                 $this->db->quoteIdentifier($this->options['langs_avail_table']),
  189.                 $this->db->quoteIdentifier($this->options['lang_id_col']),
  190.                 $this->db->quoteIdentifier($this->options['lang_name_col']),
  191.                 $this->db->quoteIdentifier($this->options['lang_meta_col']),
  192.                 $this->db->quoteIdentifier($this->options['lang_errmsg_col']),
  193.                 $this->db->quoteIdentifier($this->options['lang_encoding_col'])
  194.             );
  195.             $queries[sprintf('CREATE UNIQUE INDEX %s_%s_index ON %s (%s)',
  196.                 $this->options['langs_avail_table'],
  197.                 $this->options['lang_id_col'],
  198.                 $this->db->quoteIdentifier($this->options['langs_avail_table']),
  199.                 $this->db->quoteIdentifier($this->options['lang_id_col'])
  200.             );
  201.  
  202.             foreach ($queries as $query{
  203.                 ++$this->_queries;
  204.                 $res $this->db->query($query);
  205.                 if (PEAR::isError($res)) {
  206.                     return $res;
  207.                 }
  208.             }
  209.         }
  210.  
  211.         $query sprintf('INSERT INTO %s (%s, %s, %s, %s, %s) VALUES (%s, %s, %s, %s, %s)',
  212.             $this->db->quoteIdentifier($this->options['langs_avail_table']),
  213.             $this->db->quoteIdentifier($this->options['lang_id_col']),
  214.             $this->db->quoteIdentifier($this->options['lang_name_col']),
  215.             $this->db->quoteIdentifier($this->options['lang_meta_col']),
  216.             $this->db->quoteIdentifier($this->options['lang_errmsg_col']),
  217.             $this->db->quoteIdentifier($this->options['lang_encoding_col']),
  218.             $this->db->quote($langData['lang_id']),
  219.             $this->db->quote($langData['name']),
  220.             $this->db->quote($langData['meta']),
  221.             $this->db->quote($langData['error_text']),
  222.             $this->db->quote($langData['encoding'])
  223.         );
  224.  
  225.         ++$this->_queries;
  226.         $success $this->db->query($query);
  227.         $this->options['strings_tables'][$langData['lang_id']] $langData['table_name'];
  228.         return $success;
  229.     }
  230.  
  231.     // }}}
  232.     // {{{ removeLang()
  233.  
  234.     /**
  235.      * Remove the lang from the langsAvail table and drop the strings table.
  236.      * If the strings table holds other langs and $force==false, then
  237.      * only the lang column is dropped. If $force==true the whole
  238.      * table is dropped without any check
  239.      *
  240.      * @param string  $langID language ID
  241.      * @param boolean $force  if true, the whole table is dropped without checks
  242.      *
  243.      * @return true|PEAR_Error
  244.      */
  245.     function removeLang($langID$force)
  246.     {
  247.         //remove from langsAvail
  248.         $query sprintf('DELETE FROM %s WHERE %s = %s',
  249.             $this->db->quoteIdentifier($this->options['langs_avail_table']),
  250.             $this->db->quoteIdentifier($this->options['lang_id_col']),
  251.             $this->db->quote($langID)
  252.         );
  253.         ++$this->_queries;
  254.         $res $this->db->query($query);
  255.         if (PEAR::isError($res)) {
  256.             return $res;
  257.         }
  258.  
  259.         $lang_table $this->_getLangTable($langID);
  260.         if ($force{
  261.             //remove the whole table
  262.             ++$this->_queries;
  263.             return $this->db->query('DROP TABLE ' $this->db->quoteIdentifier($lang_table));
  264.         }
  265.  
  266.         //drop only the column for this lang
  267.         $query sprintf('ALTER TABLE %s DROP COLUMN %s',
  268.             $lang_table,
  269.             $this->_getLangCol($langID)
  270.         );
  271.         ++$this->_queries;
  272.         return $this->db->query($query);
  273.     }
  274.  
  275.     // }}}
  276.     // {{{ updateLang()
  277.  
  278.     /**
  279.      * Update the lang info in the langsAvail table
  280.      *
  281.      * @param array $langData language data
  282.      *
  283.      * @return true|PEAR_Error
  284.      */
  285.     function updateLang($langData)
  286.     {
  287.         $allFields = array(
  288.             //'lang_id'    => 'lang_id_col',
  289.             'name'       => 'lang_name_col',
  290.             'meta'       => 'lang_meta_col',
  291.             'error_text' => 'lang_errmsg_col',
  292.             'encoding'   => 'lang_encoding_col',
  293.         );
  294.         $updateFields array_keys($langData);
  295.         $langSet = array();
  296.         foreach ($allFields as $field => $col{
  297.             if (in_array($field$updateFields)) {
  298.                 $langSet[$this->db->quoteIdentifier($this->options[$col]' = ' .
  299.                              $this->db->quote($langData[$field]);
  300.             }
  301.         }
  302.         $query sprintf('UPDATE %s SET %s WHERE %s=%s',
  303.             $this->db->quoteIdentifier($this->options['langs_avail_table']),
  304.             implode(', '$langSet),
  305.             $this->db->quoteIdentifier($this->options['lang_id_col']),
  306.             $this->db->quote($langData['lang_id'])
  307.         );
  308.  
  309.         ++$this->_queries;
  310.         $success $this->db->query($query);
  311.         $this->fetchLangs();  //update memory cache
  312.         return $success;
  313.     }
  314.  
  315.     // }}}
  316.     // {{{ add()
  317.  
  318.     /**
  319.      * Add a new entry in the strings table.
  320.      *
  321.      * @param string $stringID    string ID
  322.      * @param string $pageID      page/group ID
  323.      * @param array  $stringArray Associative array with string translations.
  324.      *                Sample format:  array('en' => 'sample', 'it' => 'esempio')
  325.      *
  326.      * @return true|PEAR_Error
  327.      */
  328.     function add($stringID$pageID$stringArray)
  329.     {
  330.         $langs array_intersect(
  331.             array_keys($stringArray),
  332.             $this->getLangs('ids')
  333.         );
  334.  
  335.         if (!count($langs)) {
  336.             //return error: no valid lang provided
  337.             return true;
  338.         }
  339.  
  340.         // Langs may be in different tables - we need to split up queries along
  341.         // table lines, so we can keep DB traffic to a minimum.
  342.  
  343.         $unquoted_stringID $stringID;
  344.         $unquoted_pageID   $pageID;
  345.         $stringID $this->db->quote($stringID);
  346.         $pageID   is_null($pageID'NULL' $this->db->quote($pageID);
  347.         // Loop over the tables we need to insert into.
  348.         foreach ($this->_tableLangs($langsas $table => $tableLangs{
  349.             $exists $this->_recordExists($unquoted_stringID$unquoted_pageID$table);
  350.             if (PEAR::isError($exists)) {
  351.                 return $exists;
  352.             }
  353.             $func  $exists '_getUpdateQuery' '_getInsertQuery';
  354.             $query $this->$func($table$tableLangs$stringID$pageID$stringArray);
  355.  
  356.             ++$this->_queries;
  357.             $res $this->db->query($query);
  358.             if (PEAR::isError($res)) {
  359.                 return $res;
  360.             }
  361.         }
  362.  
  363.         return true;
  364.     }
  365.  
  366.     // }}}
  367.     // {{{ update()
  368.  
  369.     /**
  370.      * Update an existing entry in the strings table.
  371.      *
  372.      * @param string $stringID    string ID
  373.      * @param string $pageID      page/group ID
  374.      * @param array  $stringArray Associative array with string translations.
  375.      *                Sample format:  array('en' => 'sample', 'it' => 'esempio')
  376.      *
  377.      * @return true|PEAR_Error
  378.      */
  379.     function update($stringID$pageID$stringArray)
  380.     {
  381.         return $this->add($stringID$pageID$stringArray);
  382.     }
  383.  
  384.     // }}}
  385.     // {{{ _getInsertQuery()
  386.  
  387.     /**
  388.      * Build a SQL query to INSERT a record
  389.      *
  390.      * @param string $table        table name
  391.      * @param array  &$tableLangs  tables containing the languages
  392.      * @param string $stringID     string ID
  393.      * @param string $pageID       page/group ID
  394.      * @param array  &$stringArray array of strings
  395.      *
  396.      * @return string INSERT query
  397.      * @access private
  398.      */
  399.     function _getInsertQuery($table&$tableLangs$stringID$pageID&$stringArray)
  400.     {
  401.         $tableCols $this->_getLangCols($tableLangs);
  402.         $langData  = array();
  403.         foreach ($tableLangs as $lang{
  404.             $langData[$lang$this->db->quote($stringArray[$lang]);
  405.         }
  406.         foreach (array_keys($tableColsas $k{
  407.             $tableCols[$k$this->db->quoteIdentifier($tableCols[$k]);
  408.         }
  409.  
  410.         return sprintf('INSERT INTO %s (%s, %s, %s) VALUES (%s, %s, %s)',
  411.             $this->db->quoteIdentifier($table),
  412.             $this->db->quoteIdentifier($this->options['string_id_col']),
  413.             $this->db->quoteIdentifier($this->options['string_page_id_col']),
  414.             implode(', '$tableCols),
  415.             $stringID,
  416.             $pageID,
  417.             implode(', '$langData)
  418.         );
  419.     }
  420.  
  421.     // }}}
  422.     // {{{ _getUpdateQuery()
  423.  
  424.     /**
  425.      * Build a SQL query to UPDATE a record
  426.      *
  427.      * @param string $table        table name
  428.      * @param array  &$tableLangs  tables containing the languages
  429.      * @param string $stringID     string ID
  430.      * @param string $pageID       page/group ID
  431.      * @param array  &$stringArray array of strings
  432.      *
  433.      * @return string UPDATE query
  434.      * @access private
  435.      */
  436.     function _getUpdateQuery($table&$tableLangs$stringID$pageID&$stringArray)
  437.     {
  438.         $tableCols $this->_getLangCols($tableLangs);
  439.         $langSet   = array();
  440.         foreach ($tableLangs as $lang{
  441.             $langSet[$this->db->quoteIdentifier($tableCols[$lang]' = ' .
  442.                          $this->db->quote($stringArray[$lang]);
  443.         }
  444.  
  445.         return sprintf('UPDATE %s SET %s WHERE %s = %s AND %s = %s',
  446.             $this->db->quoteIdentifier($table),
  447.             implode(', '$langSet),
  448.             $this->db->quoteIdentifier($this->options['string_id_col']),
  449.             $stringID,
  450.             $this->db->quoteIdentifier($this->options['string_page_id_col']),
  451.             $pageID
  452.         );
  453.     }
  454.  
  455.     // }}}
  456.     // {{{ remove()
  457.  
  458.     /**
  459.      * Remove an entry from the strings table.
  460.      *
  461.      * @param string $stringID string ID
  462.      * @param string $pageID   page/group ID
  463.      *
  464.      * @return true|PEAR_Error
  465.      */
  466.     function remove($stringID$pageID)
  467.     {
  468.         $tables array_unique($this->_getLangTables());
  469.  
  470.         $stringID $this->db->quote($stringID);
  471.         // get the tables and skip the non existent ones
  472.         $dbTables $this->db->getListOf('tables');
  473.         foreach ($tables as $table{
  474.             if (!in_array($table$dbTables)) {
  475.                 continue;
  476.             }
  477.             $query sprintf('DELETE FROM %s WHERE %s = %s AND %s',
  478.                  $this->db->quoteIdentifier($table),
  479.                  $this->db->quoteIdentifier($this->options['string_id_col']),
  480.                  $stringID,
  481.                  $this->db->quoteIdentifier($this->options['string_page_id_col'])
  482.             );
  483.             if (is_null($pageID)) {
  484.                 $query .= ' IS NULL';
  485.             else {
  486.                 $query .= ' = ' $this->db->quote($pageID);
  487.             }
  488.  
  489.             ++$this->_queries;
  490.             $res $this->db->query($query);
  491.             if (PEAR::isError($res)) {
  492.                 return $res;
  493.             }
  494.         }
  495.  
  496.         return true;
  497.     }
  498.  
  499.     // }}}
  500.     // {{{ removePage
  501.  
  502.     /**
  503.      * Remove all the strings in the given page/group
  504.      *
  505.      * @param string $pageID page/group ID
  506.      *
  507.      * @return mixed true on success, PEAR_Error on failure
  508.      */
  509.     function removePage($pageID = null)
  510.     {
  511.         $tables array_unique($this->_getLangTables());
  512.  
  513.         // get the tables and skip the non existent ones
  514.         $dbTables $this->db->getListOf('tables');
  515.         foreach ($tables as $table{
  516.             if (!in_array($table$dbTables)) {
  517.                 continue;
  518.             }
  519.             $query sprintf('DELETE FROM %s WHERE %s',
  520.                  $this->db->quoteIdentifier($tabletrue),
  521.                  $this->db->quoteIdentifier($this->options['string_page_id_col'])
  522.             );
  523.             if (is_null($pageID)) {
  524.                 $query .= ' IS NULL';
  525.             else {
  526.                 $query .= ' = ' $this->db->quote($pageID'text');
  527.             }
  528.  
  529.             ++$this->_queries;
  530.             $res $this->db->query($query);
  531.             if (PEAR::isError($res)) {
  532.                 return $res;
  533.             }
  534.         }
  535.  
  536.         return true;
  537.     }
  538.  
  539.     // }}}
  540.     // {{{ getPageNames()
  541.  
  542.     /**
  543.      * Get a list of all the pageIDs in any table.
  544.      *
  545.      * @return array 
  546.      */
  547. &n