Example #1
0
 /**
  * Returns an SQL query that will obtain the domain of this relationship.  The Domain
  * is slightly different than the actual relationship, in that it returns all eligible
  * rows that can be added to the relationship (and rows already in the relationship).
  */
 function getDomainSQL()
 {
     $relationship =& $this->_schema;
     // obtain reference to the relationship in question
     // The 'domain_sql' attribute of a relationship defines the SQL select statement that
     // is used to obtain the set of candidates for a relationship.  This can be specified
     // in the ini file using the __domain__ attribute of a relationship, or it can be parsed
     // from the existiing 'sql' attribute.
     if (!isset($relationship['domain_sql'])) {
         import('SQL/Compiler.php');
         // compiles SQL tree structure into query strings
         import('SQL/Parser/wrapper.php');
         // utility methods for dealing with SQL structures
         $compiler = new SQL_Compiler();
         // the compiler we will use to generate the eventual SQL
         $parsed_sql = unserialize(serialize($relationship['parsed_sql']));
         // we make a deep copy of the existing 'parsed_sql' structure that was
         // created in the "readRelationshipsIniFile" method.  We deep copy, because
         // some of the methods in SQL_Parser_wrapper work directly on the
         // datastructure - but we want to leave it unchanged.
         $wrapper = new SQL_Parser_wrapper($parsed_sql);
         // create a new wrapper to operate on the sql data structure.
         $wrapper->removeWhereClausesWithTable($this->_sourceTable->tablename);
         $wrapper->removeJoinClausesWithTable($this->_sourceTable->tablename);
         // We remove all Where and Join clauses that use columns from the current table.
         // This is because portions of the sql pertaining to the current table
         // likely represent specifications within the domain to mark that an
         // element of the domain is related to the current table.
         $wrapper->removeWhereClausesWithPattern('/\\$\\w+/');
         $wrapper->removeJoinClausesWithPattern('/\\$\\w+/');
         // Similarly we need to remove any clauses containing variables which
         // get filled in by the current table.  The rationale is the same as
         // for removing clauses pertaining to the current table.
         $fkVals = $this->getForeignKeyValues();
         // We obtain the foreign key values for this relationship because they
         // will help us to decide which columns in the remaining query are
         // helpful for obtaining the domain.
         $uselessTables = array();
         // will hold list of tables that we don't need
         $fkTables = array_keys($fkVals);
         // list of tables that are involved in foreign key relationships in this
         // relationship.
         foreach ($fkVals as $fkTable => $fkFields) {
             $foundVal = 0;
             $foundLink = 0;
             // keep track of which tables actually have real values assigned.
             foreach ($fkFields as $fieldVal) {
                 //if ( !preg_match('/^__(\w+)_auto_increment__$/', $fieldVal) ){
                 //	// A field with a value of the form __Tablename__auto_increment__ is a placeholder
                 //	// for an auto generated id.  If the only values specified for a table are placeholders
                 //	// then that table is pretty much useless as a domain query... it can be eliminated.
                 //	$foundVal++;
                 //
                 //
                 //}
                 if (is_scalar($fieldVal) and strpos($fieldVal, '$') === 0) {
                     // This table is linked directly to the current table... hence it is only a join
                     // table.
                     $foundLink++;
                 }
             }
             if ($foundLink) {
                 // no real valus found.. mark table as useless.
                 $uselessTables[] = $fkTable;
             }
         }
         foreach ($uselessTables as $table_name) {
             // Remove all useless tables from the query's where and join clauses.
             $wrapper->removeWhereClausesWithTable($table_name);
             $wrapper->removeJoinClausesWithTable($table_name);
             $wrapper->removeColumnsFromTable($table_name);
         }
         $domain_tables = array_diff($relationship['selected_tables'], $uselessTables);
         if (!$domain_tables) {
             $domain_tables = $relationship['selected_tables'];
         }
         $table_ranks = array();
         foreach ($this->_schema['columns'] as $col) {
             list($tname) = explode('.', $col);
             if (!isset($table_ranks[$tname])) {
                 $table_ranks[$tname] = 0;
             }
             $table_ranks[$tname]++;
         }
         $high = null;
         $high_score = 0;
         foreach ($domain_tables as $dt) {
             if ($table_ranks[$dt] > $high_score) {
                 $high = $dt;
                 $high_score = $table_ranks[$dt];
             }
         }
         $domain_tables = array($high);
         if (count($domain_tables) !== 1) {
             return PEAR::raiseError("Error calculating domain tables for relationship '" . $this->_name . "'.  Selected tables are {" . implode(',', $relationship['selected_tables']) . "} and Useless tables are {" . implode(',', $uselessTables) . "}.", null, null, null, 1);
         }
         $relationship['domain_table'] = array_pop($domain_tables);
         $wrapper->packTables();
         // Previous steps have only eliminated useless tables with respect to query
         // parameters.  There may still be some tables listed in the query that don't
         // offer anything.  Notice that we pass the list of selected tables to this
         // method to indicate that tables whose columns are selected need to be there
         // and should be left intact.
         $relationship['domain_sql'] = $compiler->compile($parsed_sql);
     }
     return $relationship['domain_sql'];
 }