root

Changeset 659

Show
Ignore:
Timestamp:
07/21/09 09:38:52 (1 year ago)
Author:
wbond
Message:

Fixed tickets #225 and #270 - Loading fActiveRecord objects by multi-column primary key now works even if the columns are in a different order, one-to-one relationships now are properly detected the ORM API was improved to handle them

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • fActiveRecord.php

    r648 r659 Hide Line Numbers
    1616 * @link       http://flourishlib.com/fActiveRecord 
    1717 *  
    18  * @version    1.0.0b30 
     18 * @version    1.0.0b31 
     19 * @changes    1.0.0b31  Fixed a bug with loading a record by a multi-column primary key, fixed one-to-one relationship API [wb, 2009-07-21] 
    1920 * @changes    1.0.0b30  Updated ::reflect() for new fORM::callReflectCallbacks() API [wb, 2009-07-13] 
    2021 * @changes    1.0.0b29  Updated to use new fORM::callInspectCallbacks() method [wb, 2009-07-13] 
     
    520521            // Related data methods 
    521522            case 'associate': 
    522                 $subject = fGrammar::singularize($subject); 
     523                $table   = fORM::tablize($class); 
     524                $records = $parameters[0]; 
     525                $route   = isset($parameters[1]) ? $parameters[1] : NULL; 
     526                $plural  = FALSE; 
     527                 
     528                // one-to-many relationships need to use plural forms 
     529                if (in_array($subject, fORMSchema::retrieve()->getTables())) { 
     530                    if (fORMSchema::isOneToOne($table, $subject, $route)) { 
     531                        throw new fProgrammerException( 
     532                            'The table %1$s is not in a %2$srelationship with the table %3$s', 
     533                            $table, 
     534                            '*-to-many ', 
     535                            $subject 
     536                        );       
     537                    } 
     538                    $subject = fGrammar::singularize($subject); 
     539                    $plural  = TRUE; 
     540                } 
    523541                $subject = fGrammar::camelize($subject, TRUE); 
    524542                 
    525                 if (isset($parameters[1])) { 
    526                     return fORMRelated::associateRecords($class, $this->related_records, $subject, $parameters[0], $parameters[1]); 
    527                 } 
    528                 return fORMRelated::associateRecords($class, $this->related_records, $subject, $parameters[0]); 
     543                // This handles one-to-many and many-to-many relationships 
     544                if ($plural) { 
     545                    return fORMRelated::associateRecords($class, $this->related_records, $subject, $records, $route); 
     546                } 
     547                 
     548                // This handles one-to-one relationships 
     549                return fORMRelated::associateRecord($class, $this->related_records, $subject, $records, $route); 
    529550             
    530551            case 'build': 
     
    550571                 
    551572                if (isset($parameters[0])) { 
    552                     return fORMRelated::createRecord($class, $this->values, $subject, $parameters[0]); 
    553                 } 
    554                 return fORMRelated::createRecord($class, $this->values, $subject); 
     573                    return fORMRelated::createRecord($class, $this->values, $this->related_records, $subject, $parameters[0]); 
     574                } 
     575                return fORMRelated::createRecord($class, $this->values, $this->related_records, $subject); 
    555576              
    556577            case 'inject': 
     
    582603             
    583604            case 'populate': 
    584                 $subject = fGrammar::singularize($subject); 
     605                $table = fORM::tablize($class); 
     606                $route = isset($parameters[0]) ? $parameters[0] : NULL; 
     607                 
     608                // one-to-many relationships need to use plural forms 
     609                if (in_array($subject, fORMSchema::retrieve()->getTables())) { 
     610                    if (fORMSchema::isOneToOne($table, $subject, $route)) { 
     611                        throw new fProgrammerException( 
     612                            'The table %1$s is not in a %2$srelationship with the table %3$s', 
     613                            $table, 
     614                            'one-to-many ', 
     615                            $subject 
     616                        );       
     617                    } 
     618                    $subject = fGrammar::singularize($subject); 
     619                } 
     620                 
    585621                $subject = fGrammar::camelize($subject, TRUE); 
    586622                 
    587                 if (isset($parameters[0])) { 
    588                     return fORMRelated::populateRecords($class, $this->related_records, $subject, $parameters[0]); 
    589                 } 
    590                 return fORMRelated::populateRecords($class, $this->related_records, $subject); 
     623                return fORMRelated::populateRecords($class, $this->related_records, $subject, $route); 
    591624             
    592625            case 'tally': 
     
    721754            // If the primary key does not look properly formatted, check to see if it is a UNIQUE key 
    722755            $is_unique_key = FALSE; 
    723             if (is_array($key) && (sizeof($pk_columns) == 1 || array_keys($key) != $pk_columns)) { 
     756            if (is_array($key) && (sizeof($pk_columns) == 1 || array_diff(array_keys($key), $pk_columns))) { 
    724757                $unique_keys = fORMSchema::retrieve()->getKeys($table, 'unique'); 
    725758                $key_keys    = array_keys($key); 
     
    731764            } 
    732765             
    733             $wrong_keys = is_array($key) && array_keys($key) != $pk_columns
     766            $wrong_keys = is_array($key) && array_diff(array_keys($key), $pk_columns)
    734767            $wrong_type = !is_array($key) && (sizeof($pk_columns) != 1 || !is_scalar($key)); 
    735768             
  • fORMRelated.php

    r616 r659 Hide Line Numbers
    1313 * @link       http://flourishlib.com/fORMRelated 
    1414 *  
    15  * @version    1.0.0b10 
     15 * @version    1.0.0b11 
     16 * @changes    1.0.0b11  Fixed some bugs with one-to-one relationships [wb, 2009-07-21] 
    1617 * @changes    1.0.0b10  Fixed a couple of bugs with validating related records [wb, 2009-06-26] 
    1718 * @changes    1.0.0b9   Fixed a bug where ::store() would not save associations with no related records [wb, 2009-06-23] 
     
    5253     
    5354    /** 
     55     * A generic cache for the class 
     56     *  
     57     * @var array 
     58     */ 
     59    static private $cache = array(); 
     60     
     61    /** 
    5462     * Rules that control what order related data is returned in 
    5563     *  
     
    6472     */ 
    6573    static private $related_record_names = array(); 
     74     
     75     
     76    /** 
     77     * Creates associations for one-to-one relationships 
     78     *  
     79     * @internal 
     80     *  
     81     * @param  string                             $class             The class to get the related values for 
     82     * @param  array                              &$related_records  The related records existing for the fActiveRecord class 
     83     * @param  string                             $related_class     The class we are associating with the current record 
     84     * @param  fActiveRecord|array|string|integer $record            The record (or primary key of the record) to be associated 
     85     * @param  string                             $route             The route to use between the current class and the related class 
     86     * @return void 
     87     */ 
     88    static public function associateRecord($class, &$related_records, $related_class, $record, $route=NULL) 
     89    { 
     90        $table         = fORM::tablize($class); 
     91        $related_table = fORM::tablize($related_class); 
     92         
     93        if (!$record instanceof fActiveRecord) { 
     94            $record = new $related_class($record);   
     95        } 
     96         
     97        $records = fRecordSet::buildFromRecords($related_class, array($record));     
     98        $route   = fORMSchema::getRouteName($table, $related_table, $route, 'one-to-one'); 
     99         
     100        self::setRecordSet($class, $related_records, $related_class, $records, $route); 
     101        self::flagForAssociation($class, $related_records, $related_class, $route); 
     102    } 
    66103     
    67104     
     
    246283     * @internal 
    247284     *  
    248      * @param  string $class          The class to create the related record for 
    249      * @param  array  $values         The values existing in the fActiveRecord class 
    250      * @param  string $related_class  The related class name 
     285     * @param  string $class             The class to create the related record for 
     286     * @param  array  $values            The values existing in the fActiveRecord class 
     287     * @param  array  &$related_records  The related records for the record 
     288     * @param  string $related_class     The related class name 
     289     * @param  string $route             The route to the related class 
     290     * @return fActiveRecord  An instace of the class specified 
     291     */ 
     292    static public function createRecord($class, $values, &$related_records, $related_class, $route=NULL) 
     293    { 
     294        $table         = fORM::tablize($class); 
     295        $related_table = fORM::tablize($related_class); 
     296         
     297        $relationship = fORMSchema::getRoute($table, $related_table, $route, '*-to-one'); 
     298        $route        = $relationship['column']; 
     299         
     300        // Determine if the relationship is one-to-one 
     301        if (isset(self::$cache['one-to-one::' . $table . '::' . $related_table . '::' . $route])) { 
     302            $one_to_one = self::$cache['one-to-one::' . $table . '::' . $related_table . '::' . $route];     
     303         
     304        } else { 
     305            $one_to_one = FALSE; 
     306            $one_to_one_relationships = fORMSchema::getRoutes($table, $related_table, 'one-to-one'); 
     307            foreach ($one_to_one_relationships as $one_to_one_relationship) { 
     308                if ($relationship['column'] == $one_to_one_relationship['column']) { 
     309                    $one_to_one = TRUE; 
     310                    break;   
     311                } 
     312            }    
     313             
     314            self::$cache['one-to-one::' . $table . '::' . $related_table . '::' . $route] = $one_to_one; 
     315        } 
     316         
     317        // One-to-one records are stored in the related records array to support populating 
     318        if ($one_to_one) { 
     319            if (isset($related_records[$related_table][$route]['record_set'])) { 
     320                if ($related_records[$related_table][$route]['record_set']->count()) { 
     321                    return $related_records[$related_table][$route]['record_set']->current(); 
     322                } 
     323                return new $related_class(); 
     324            } 
     325             
     326            // If the value is NULL, don't pass it to the constructor because an fNotFoundException will be thrown 
     327            if ($values[$relationship['column']] !== NULL) { 
     328                $records = array(new $related_class(array($relationship['column'] => $values[$relationship['column']]))); 
     329            } else { 
     330                $records = array(); 
     331            }    
     332            $record_set = fRecordSet::buildFromRecords($related_class, $records); 
     333            self::setRecordSet($class, $related_records, $related_class, $record_set, $route); 
     334             
     335            if ($record_set->count()) { 
     336                return $record_set->current();       
     337            } 
     338            return new $related_class();     
     339        } 
     340         
     341        return new $related_class($values[$relationship['column']]); 
     342    } 
     343     
     344     
     345     
     346    /** 
     347     * Figures out the first primary key column for a related class that is not the related column 
     348     * 
     349     * @internal 
     350     *  
     351     * @param  string $class          The class name of the main class 
     352     * @param  string $related_class  The related class being filtered for 
    251353     * @param  string $route          The route to the related class 
    252      * @return fActiveRecord  An instace of the class specified 
    253      */ 
    254     static public function createRecord($class, $values, $related_class, $route=NULL) 
    255     { 
    256         $table         = fORM::tablize($class); 
    257         $related_table = fORM::tablize($related_class); 
    258          
    259         $relationship = fORMSchema::getRoute($table, $related_table, $route, '*-to-one'); 
    260          
    261         return new $related_class($values[$relationship['column']]); 
     354     * @return string  The first primary key column in the related class 
     355     */ 
     356    static public function determineFirstPKColumn($class, $related_class, $route) 
     357    { 
     358        $table         = fORM::tablize($class); 
     359        $related_table = fORM::tablize($related_class); 
     360         
     361        $pk_columns    = fORMSchema::retrieve()->getKeys($related_table, 'primary'); 
     362         
     363        // If there is a multi-fiend primary key we want to populate based on any field BUT the foreign key to the current class 
     364        if (sizeof($pk_columns) > 1) { 
     365         
     366            $first_pk_column = NULL; 
     367            $relationships   = fORMSchema::getRoutes($related_table, $table, '*-to-one'); 
     368            foreach ($pk_columns as $pk_column) { 
     369                foreach ($relationships as $relationship) { 
     370                    if ($pk_column == $relationship['column']) { 
     371                        continue; 
     372                    } 
     373                    $first_pk_column = $pk_column; 
     374                    break 2; 
     375                }    
     376            } 
     377             
     378            if (!$first_pk_column) { 
     379                $first_pk_column = $pk_columns[0]; 
     380            } 
     381             
     382        } else { 
     383            $first_pk_column = $pk_columns[0]; 
     384        } 
     385         
     386        return $first_pk_column;     
    262387    } 
    263388     
     
    270395     * @param  string $class          The class name of the main class 
    271396     * @param  string $related_class  The related class being filtered for 
    272      * @param  string $route          The route to the related table 
     397     * @param  string $route          The route to the related class 
    273398     * @return string  The prefix to filter the request fields by 
    274399     */ 
     
    314439        $related_table = fORM::tablize($related_class); 
    315440         
    316         $route = fORMSchema::getRouteName($table, $related_table, $route, '*-to-many'); 
     441        try { 
     442            $route = fORMSchema::getRouteName($table, $related_table, $route, '*-to-many'); 
     443        } catch (fProgrammerException $e) { 
     444            $route = fORMSchema::getRouteName($table, $related_table, $route, 'one-to-one'); 
     445        }    
    317446         
    318447        if (!isset($related_records[$related_table][$route]['record_set']) && !isset($related_records[$related_table][$route]['primary_keys'])) { 
     
    460589        $related_table = fORM::tablize($related_class); 
    461590         
    462         $route = fORMSchema::getRouteName($table, $related_table, $route, '*-to-many'); 
     591        $route = fORMSchema::getRouteName($table, $related_table, $route); 
    463592         
    464593        if (!isset(self::$related_record_names[$table]) || 
     
    588717        $pk_columns      = fORMSchema::retrieve()->getKeys($related_table, 'primary'); 
    589718         
    590         // If there is a multi-fiend primary key we want to populate based on any field BUT the foreign key to the current class 
    591         if (sizeof($pk_columns) > 1) { 
    592          
    593             $first_pk_column = NULL; 
    594             $relationships   = fORMSchema::getRoutes($related_table, $table, '*-to-one'); 
    595             foreach ($pk_columns as $pk_column) { 
    596                 foreach ($relationships as $relationship) { 
    597                     if ($pk_column == $relationship['column']) { 
    598                         continue; 
    599                     } 
    600                     $first_pk_column = $pk_column; 
    601                     break 2; 
    602                 }    
    603             } 
    604              
    605             if (!$first_pk_column) { 
    606                 $first_pk_column = $pk_columns[0]; 
    607             } 
    608              
    609         } else { 
    610             $first_pk_column = $pk_columns[0]; 
    611         } 
     719        $first_pk_column = self::determineFirstPKColumn($class, $related_class, $route); 
    612720         
    613721        $filter          = self::determineRequestFilter($class, $related_class, $route); 
     
    708816             
    709817            $to_one_created[$related_class] = TRUE; 
     818        } 
     819         
     820        $one_to_one_created = array(); 
     821         
     822        foreach ($one_to_one_relationships as $relationship) { 
     823            $related_class = fORM::classize($relationship['related_table']); 
     824             
     825            if (isset($one_to_one_created[$related_class])) { 
     826                continue; 
     827            } 
     828             
     829            $routes = fORMSchema::getRoutes($table, $relationship['related_table'], 'one-to-one'); 
     830            $route_names = array(); 
     831             
     832            foreach ($routes as $route) { 
     833                $route_names[] = fORMSchema::getRouteNameFromRelationship('one-to-one', $route); 
     834            } 
     835             
     836            $signature = ''; 
     837            if ($include_doc_comments) { 
     838                $signature .= "/**\n"; 
     839                $signature .= " * Populates the related " . $related_class . "\n"; 
     840                $signature .= " * \n"; 
     841                if (sizeof($route_names) > 1) { 
     842                    $signature .= " * @param  string \$route  The route to the related class. Must be one of: '" . join("', '", $route_names) . "'.\n"; 
     843                } 
     844                $signature .= " * @return void\n"; 
     845                $signature .= " */\n"; 
     846            } 
     847            $populate_method = 'populate' . $related_class; 
     848            $signature .= 'public function ' . $populate_method . '('; 
     849            if (sizeof($route_names) > 1) { 
     850                $signature .= '$route'; 
     851            } 
     852            $signature .= ')'; 
     853             
     854            $signatures[$populate_method] = $signature; 
     855             
     856            $signature = ''; 
     857            if ($include_doc_comments) { 
     858                $signature .= "/**\n"; 
     859                $signature .= " * Associates the related " . $related_class . " to this record\n"; 
     860                $signature .= " * \n"; 
     861                $signature .= " * @param  fActiveRecord|array|string|integer \$record  The record, or the primary key of the record, to associate\n"; 
     862                if (sizeof($route_names) > 1) { 
     863                    $signature .= " * @param  string \$route  The route to the related class. Must be one of: '" . join("', '", $route_names) . "'.\n"; 
     864                } 
     865                $signature .= " * @return void\n"; 
     866                $signature .= " */\n"; 
     867            } 
     868            $associate_method = 'associate' . $related_class; 
     869            $signature .= 'public function ' . $associate_method . '('; 
     870            if (sizeof($route_names) > 1) { 
     871                $signature .= '$route'; 
     872            } 
     873            $signature .= ')'; 
     874             
     875            $signatures[$associate_method] = $signature; 
     876             
     877            $one_to_one_created[$related_class] = TRUE;      
    710878        } 
    711879         
     
    8681036    static public function reset() 
    8691037    { 
     1038        self::$cache                = array(); 
    8701039        self::$order_bys            = array(); 
    8711040        self::$related_record_names = array(); 
     
    9901159        $related_table = fORM::tablize($related_class); 
    9911160         
    992         $route = fORMSchema::getRouteName($table, $related_table, $route, '*-to-many'); 
     1161        try { 
     1162            $route = fORMSchema::getRouteName($table, $related_table, $route, '*-to-many'); 
     1163        } catch (fProgrammerException $e) { 
     1164            $route = fORMSchema::getRouteName($table, $related_table, $route, 'one-to-one');     
     1165        } 
    9931166         
    9941167        if (!isset($related_records[$related_table])) { 
     
    10201193        $table = fORM::tablize($class); 
    10211194         
    1022         $one_to_many_relationships  = fORMSchema::retrieve()->getRelationships($table, 'one-to-many'); 
    1023         $many_to_many_relationships = fORMSchema::retrieve()->getRelationships($table, 'many-to-many'); 
    1024          
    1025         foreach ($related_records as $related_table => $relationship) { 
    1026             foreach ($relationship as $route => $related_info) { 
     1195        foreach ($related_records as $related_table => $relationships) { 
     1196            foreach ($relationships as $route => $related_info) { 
    10271197                if (!$related_info['associate']) { 
    10281198                    continue; 
     
    10331203                    fORMRelated::storeManyToMany($values, $relationship, $related_info); 
    10341204                } else { 
    1035                     fORMRelated::storeOneToMany($values, $relationship, $related_info); 
     1205                    fORMRelated::storeOneToStar($class, $values, $related_records, fORM::classize($related_table), $route); 
    10361206                } 
    10371207            } 
     
    11111281     * @internal 
    11121282     *  
    1113      * @param  array &$values       The current values for the main record being stored 
    1114      * @param  array $relationship  The information about the relationship between this object and the records in the record set 
    1115      * @param  array $related_info  An array containing the keys `'record_set'`, `'count'`, `'primary_keys'` and `'associate'` 
     1283     * @param  string $class             The class to store the related records for 
     1284     * @param  array  &$values           The current values for the main record being stored 
     1285     * @param  array  &$related_records  The related records array 
     1286     * @param  string $related_class     The related class being stored 
     1287     * @param  string $route             The route to the related class 
    11161288     * @return void 
    11171289     */ 
    1118     static public function storeOneToMany(&$values, $relationship, $related_info) 
    1119     { 
     1290    static public function storeOneToStar($class, &$values, &$related_records, $related_class, $route) 
     1291    { 
     1292        $table         = fORM::tablize($class); 
     1293        $related_table = fORM::tablize($related_class); 
     1294         
     1295        $relationship = fORMSchema::getRoute($table, $related_table, $route); 
    11201296        $column_value = $values[$relationship['column']]; 
    11211297         
    1122         $record_set = $related_info['record_set']; 
     1298        if (!empty($related_records[$related_table][$route]['record_set'])) { 
     1299            $record_set = $related_records[$related_table][$route]['record_set']; 
     1300        } else { 
     1301            $record_set = self::buildRecords($class, $values, $related_records, $related_class, $route);     
     1302        } 
    11231303         
    11241304        $where_conditions = array( 
     
    11261306        ); 
    11271307         
    1128         $related_class    = $record_set->getClass(); 
     1308         
    11291309        $existing_records = fRecordSet::build($related_class, $where_conditions); 
    11301310         
     
    11411321        $set_method_name = 'set' . fGrammar::camelize($relationship['related_column'], TRUE); 
    11421322         
    1143         $record_number = 0; 
    1144         $filter        = self::determineRequestFilter(fORM::classize($relationship['table']), $related_class, $relationship['related_column']); 
    1145          
    1146         foreach ($record_set as $record) { 
    1147             fRequest::filter($filter, $record_number); 
     1323        $first_pk_column = self::determineFirstPKColumn($class, $related_class, $route); 
     1324        $filter          = self::determineRequestFilter(fORM::classize($relationship['table']), $related_class, $relationship['related_column']); 
     1325        $pk_field        = $filter . $first_pk_column; 
     1326        $input_keys      = array_keys(fRequest::get($pk_field, 'array', array())); 
     1327         
     1328        foreach ($record_set as $i => $record) { 
     1329            fRequest::filter($filter, isset($input_keys[$i]) ? $input_keys[$i] : $i); 
    11481330            $record->$set_method_name($column_value); 
    11491331            $record->store(); 
    11501332            fRequest::unfilter(); 
    1151             $record_number++; 
    11521333        } 
    11531334    } 
     
    11831364                    $related_messages = self::validateManyToMany($class, $related_class, $route, $related_info); 
    11841365                } else { 
    1185                     $related_messages = self::validateOneToMany($class, $values, $related_records, $related_class, $route); 
     1366                    $related_messages = self::validateOneToStar($class, $values, $related_records, $related_class, $route); 
    11861367                } 
    11871368                 
     
    11951376     
    11961377    /** 
    1197      * Validates one-to-many related records 
     1378     * Validates one-to-* related records 
    11981379     * 
    1199      * @internal 
    1200      *  
    12011380     * @param  string $class             The class to validate the related records for 
    12021381     * @param  array  &$values           The values for the object 
     
    12061385     * @return array  An array of validation messages 
    12071386     */ 
    1208     static private function validateOneToMany($class, &$values, &$related_records, $related_class, $route) 
     1387    static private function validateOneToStar($class, &$values, &$related_records, $related_class, $route) 
    12091388    { 
    12101389        $table               = fORM::tablize($class); 
    12111390        $related_table       = fORM::tablize($related_class); 
    1212         $route_name          = fORMSchema::getRouteName($table, $related_table, $route, 'one-to-many'); 
     1391         
     1392        $first_pk_column     = self::determineFirstPKColumn($class, $related_class, $route); 
    12131393        $filter              = self::determineRequestFilter($class, $related_class, $route); 
     1394        $pk_field            = $filter . $first_pk_column; 
     1395        $input_keys          = array_keys(fRequest::get($pk_field, 'array', array())); 
     1396         
    12141397        $related_record_name = self::getRelatedRecordName($class, $related_class, $route); 
    12151398         
    1216         $record_number = 1; 
    1217          
    12181399        $messages = array(); 
    12191400         
    1220         $record_set = self::buildRecords($class, $values, $related_records, $related_class, $route); 
    1221          
    1222         foreach ($record_set as $record) { 
    1223             fRequest::filter($filter, $record_number-1); 
     1401        $one_to_one = fORMSchema::isOneToOne($table, $related_table, $route); 
     1402        if ($one_to_one) { 
     1403            $records = array(self::createRecord($class, $values, $related_records, $related_class, $route)); 
     1404 
     1405        } else { 
     1406            $records = self::buildRecords($class, $values, $related_records, $related_class, $route); 
     1407        } 
     1408         
     1409        foreach ($records as $i => $record) { 
     1410            fRequest::filter($filter, isset($input_keys[$i]) ? $input_keys[$i] : $i); 
    12241411            $record_messages = $record->validate(TRUE); 
    12251412             
    12261413            foreach ($record_messages as $record_message) { 
    12271414                // Ignore validation messages about the primary key since it will be added 
    1228                 if (strpos($record_message, fValidationException::formatField(fORM::getColumnName($related_class, $route_name))) === 0) { 
     1415                if (strpos($record_message, fValidationException::formatField(fORM::getColumnName($related_class, $route))) === 0) { 
    12291416                    continue; 
    12301417                } 
     
    12341421                preg_match($extract_message_regex, $record_message, $matches); 
    12351422                 
     1423                if ($one_to_one) { 
     1424                    $column_name = self::compose( 
     1425                        '%1$s %2$s', 
     1426                        $related_record_name, 
     1427                        $matches[1] 
     1428                    ); 
     1429                     
     1430                } else { 
     1431                    $column_name = self::compose( 
     1432                        '%1$s #%2$s %3$s', 
     1433                        $related_record_name, 
     1434                        $i+1, 
     1435                        $matches[1] 
     1436                    );   
     1437                } 
     1438                 
    12361439                $messages[] = self::compose( 
    12371440                    '%1$s%2$s', 
    1238                     fValidationException::formatField( 
    1239                         self::compose( 
    1240                             '%1$s #%2$s %3$s', 
    1241                             $related_record_name, 
    1242                             $record_number, 
    1243                             $matches[1] 
    1244                         ) 
    1245                     ), 
     1441                    fValidationException::formatField($column_name), 
    12461442                    $matches[2] 
    12471443                ); 
    12481444            } 
    1249             $record_number++; 
    12501445            fRequest::unfilter(); 
    12511446        } 
     
    12581453     * Validates many-to-many related records 
    12591454     * 
    1260      * @internal 
    1261      *  
    12621455     * @param  string $class          The class to validate the related records for 
    12631456     * @param  string $related_class  The name of the class for this record set 
  • fORMSchema.php

    r603 r659 Hide Line Numbers
    1010 * @link       http://flourishlib.com/fORMSchema 
    1111 *  
    12  * @version    1.0.0b3 
     12 * @version    1.0.0b4 
     13 * @changes    1.0.0b4  Added ::isOneToOne() [wb, 2009-07-21] 
    1314 * @changes    1.0.0b3  Added routes caching for performance [wb, 2009-06-15] 
    1415 * @changes    1.0.0b2  Backwards Compatiblity Break - removed ::enableSmartCaching(), fORM::enableSchemaCaching() now provides equivalent functionality [wb, 2009-05-04] 
     
    2324    const getRouteNameFromRelationship = 'fORMSchema::getRouteNameFromRelationship'; 
    2425    const getRoutes                    = 'fORMSchema::getRoutes'; 
     26    const isOneToOne                   = 'fORMSchema::isOneToOne'; 
    2527    const reset                        = 'fORMSchema::reset'; 
    2628    const retrieve                     = 'fORMSchema::retrieve'; 
     
    272274     
    273275    /** 
     276     * Indicates if the relationship specified is a one-to-one relationship 
     277     *  
     278     * @internal 
     279     *  
     280     * @param  string $table          The main table we are searching on behalf of 
     281     * @param  string $related_table  The related table we are trying to find the routes for 
     282     * @param  string $route          The route between the two tables 
     283     * @return boolean  If the table is in a one-to-one relationship with the related table over the route specified 
     284     */ 
     285    static public function isOneToOne($table, $related_table, $route=NULL) 
     286    { 
     287        $relationships = self::getRoutes($table, $related_table, 'one-to-one', $route); 
     288         
     289        if ($route === NULL && sizeof($relationships) > 1) { 
     290            throw new fProgrammerException( 
     291                'There is more than one route for the %1$srelationship between %2$s and %3$s', 
     292                'one-to-one ', 
     293                $table, 
     294                $related_table 
     295            ); 
     296        } 
     297        if (!$relationships) { 
     298            return FALSE;    
     299        } 
     300         
     301        foreach ($relationships as $relationship) { 
     302            if ($route === NULL || $route == $relationship['column']) { 
     303                return TRUE; 
     304            }        
     305        } 
     306         
     307        return FALSE; 
     308    } 
     309     
     310     
     311    /** 
    274312     * Resets the configuration of the class 
    275313     *  
  • fSchema.php

    r634 r659 Hide Line Numbers
    1010 * @link       http://flourishlib.com/fSchema 
    1111 *  
    12  * @version    1.0.0b22 
     12 * @version    1.0.0b23 
     13 * @changes    1.0.0b23  Fixed a bug where one-to-one relationships were being listed as many-to-one [wb, 2009-07-21] 
    1314 * @changes    1.0.0b22  PostgreSQL UNIQUE constraints that are created as indexes and not table constraints are now properly detected [wb, 2009-07-08] 
    1415 * @changes    1.0.0b21  Added support for the UUID data type in PostgreSQL [wb, 2009-06-18] 
     
    148149     */ 
    149150    private function checkForSingleColumnUniqueKey($table, $column) 
    150     { 
     151    {         
    151152        foreach ($this->merged_keys[$table]['unique'] as $key) { 
    152153            if (array($column) == $key) { 
     
    16941695    { 
    16951696        foreach ($this->merged_keys[$table]['foreign'] as $key) { 
     1697            $type = ($this->checkForSingleColumnUniqueKey($table, $key['column'])) ? 'one-to-one' : 'one-to-many'; 
    16961698            $temp = array(); 
    16971699            $temp['table']          = $key['foreign_table']; 
     
    16991701            $temp['related_table']  = $table; 
    17001702            $temp['related_column'] = $key['column']; 
    1701             $temp['on_delete']      = $key['on_delete']; 
    1702             $temp['on_update']      = $key['on_update']; 
    1703             $this->relationships[$key['foreign_table']]['one-to-many'][] = $temp; 
     1703            if ($type == 'one-to-many') { 
     1704                $temp['on_delete']      = $key['on_delete']; 
     1705                $temp['on_update']      = $key['on_update']; 
     1706            } 
     1707            $this->relationships[$key['foreign_table']][$type][] = $temp; 
    17041708        } 
    17051709    }