/** * Creates the objects for related records that are in a one-to-one or many-to-one relationship with the current class in a single DB query * * @param string $related_class This should be the name of a related class * @param string $route This should be the column name of the foreign key and is only required when there are multiple routes to a related table. If there are multiple routes and this is not specified, an fProgrammerException will be thrown. * @return fRecordSet The record set object, to allow for method chaining */ private function precreate($related_class, $route = NULL) { if (!$this->records) { return $this; } $this->validateSingleClass('precreate'); // If there are no primary keys we can just exit if (!array_merge($this->getPrimaryKeys())) { return $this; } fActiveRecord::validateClass($related_class); fActiveRecord::forceConfigure($related_class); $relationship = fORMSchema::getRoute(fORMSchema::retrieve($this->class), fORM::tablize($this->class), fORM::tablize($related_class), $route, '*-to-one'); $values = $this->call('get' . fGrammar::camelize($relationship['column'], TRUE)); $values = array_unique($values); self::build($related_class, array($relationship['related_column'] . '=' => $values)); return $this; }
/** * Validates one-to-* related records * * @param string $class The class to validate the related records for * @param array &$values The values for the object * @param array &$related_records The related records for the object * @param string $related_class The name of the class for this record set * @param string $route The route between the table and related table * @return array An array of validation messages */ private static function validateOneToStar($class, &$values, &$related_records, $related_class, $route) { $schema = fORMSchema::retrieve($class); $table = fORM::tablize($class); $related_table = fORM::tablize($related_class); $relationship = fORMSchema::getRoute($schema, $table, $related_table, $route); $first_pk_column = self::determineFirstPKColumn($class, $related_class, $route); $filter = self::determineRequestFilter($class, $related_class, $route); $pk_field = $filter . $first_pk_column; $input_keys = array_keys(fRequest::get($pk_field, 'array', array())); $related_record_name = self::getRelatedRecordName($class, $related_class, $route); $messages = array(); $one_to_one = fORMSchema::isOneToOne($schema, $table, $related_table, $route); if ($one_to_one) { $records = array(self::createRecord($class, $values, $related_records, $related_class, $route)); } else { $records = self::buildRecords($class, $values, $related_records, $related_class, $route); } foreach ($records as $i => $record) { fRequest::filter($filter, isset($input_keys[$i]) ? $input_keys[$i] : $i); $record_messages = $record->validate(TRUE); foreach ($record_messages as $column => $record_message) { // Ignore validation messages about the primary key since it will be added if ($column == $relationship['related_column']) { continue; } if ($one_to_one) { $token_field = fValidationException::formatField('__TOKEN__'); $extract_message_regex = '#' . str_replace('__TOKEN__', '(.*?)', preg_quote($token_field, '#')) . '(.*)$#D'; preg_match($extract_message_regex, $record_message, $matches); $column_name = self::compose('%1$s %2$s', $related_record_name, $matches[1]); $messages[$related_table . '::' . $column] = self::compose('%1$s%2$s', fValidationException::formatField($column_name), $matches[2]); } else { $main_key = $related_table . '[' . $i . ']'; if (!isset($messages[$main_key])) { if (isset(self::$validation_name_methods[$class][$related_class][$route])) { $name = $record->{self::$validation_name_methods[$class][$related_class][$route]}($i + 1); } else { $name = $related_record_name . ' #' . ($i + 1); } $messages[$main_key] = array('name' => $name, 'errors' => array()); } $messages[$main_key]['errors'][$column] = $record_message; } } fRequest::unfilter(); } return $messages; }
/** * Validates any many-to-many associations or any one-to-many records that have been flagged for association * * @internal * * @param string $class The class to validate the related records for * @param array &$values The values for the object * @param array &$related_records The related records for the object * @return void */ public static function validate($class, &$values, &$related_records) { $table = fORM::tablize($class); $validation_messages = array(); // Find the record sets to validate foreach ($related_records as $related_table => $routes) { foreach ($routes as $route => $related_info) { if (!$related_info['count'] || !$related_info['associate']) { continue; } $related_class = fORM::classize($related_table); $relationship = fORMSchema::getRoute($table, $related_table, $route); if (isset($relationship['join_table'])) { $related_messages = self::validateManyToMany($class, $related_class, $route, $related_info); } else { $related_messages = self::validateOneToStar($class, $values, $related_records, $related_class, $route); } $validation_messages = array_merge($validation_messages, $related_messages); } } return $validation_messages; }