Пример #1
0
 /**
  * Takes information from a method call and determines the subject, route and if subject was plural
  * 
  * @param string $class    The class the method was called on
  * @param string $subject  An underscore_notation subject - either a singular or plural class name
  * @param string $route    The route to the subject
  * @return array  An array with the structure: array(0 => $subject, 1 => $route, 2 => $plural)
  */
 private static function determineSubject($class, $subject, $route)
 {
     $schema = fORMSchema::retrieve($class);
     $table = fORM::tablize($class);
     $type = '*-to-many';
     $plural = FALSE;
     // one-to-many relationships need to use plural forms
     $singular_form = fGrammar::singularize($subject, TRUE);
     if ($singular_form && fORM::isClassMappedToTable($singular_form)) {
         $subject = $singular_form;
         $plural = TRUE;
     } elseif (!fORM::isClassMappedToTable($subject) && in_array(fGrammar::underscorize($subject), $schema->getTables())) {
         $subject = fGrammar::singularize($subject);
         $plural = TRUE;
     }
     $related_table = fORM::tablize($subject);
     $one_to_one = fORMSchema::isOneToOne($schema, $table, $related_table, $route);
     if ($one_to_one) {
         $type = 'one-to-one';
     }
     if ($one_to_one && $plural || !$plural && !$one_to_one) {
         throw new fProgrammerException('The table %1$s is not in a %2$srelationship with the table %3$s', $table, $type, $related_table);
     }
     $route = fORMSchema::getRouteName($schema, $table, $related_table, $route, $type);
     return array($subject, $route, $plural);
 }
Пример #2
0
 /**
  * Handles all method calls for columns, related records and hook callbacks
  * 
  * Dynamically handles `get`, `set`, `prepare`, `encode` and `inspect`
  * methods for each column in this record. Method names are in the form
  * `verbColumName()`.
  * 
  * This method also handles `associate`, `build`, `count` and `link` verbs
  * for records in many-to-many relationships; `build`, `count` and
  * `populate` verbs for all related records in one-to-many relationships
  * and the `create` verb for all related records in *-to-one relationships.
  * 
  * Method callbacks registered through fORM::registerActiveRecordMethod()
  * will be delegated via this method.
  * 
  * @param  string $method_name  The name of the method called
  * @param  array  $parameters   The parameters passed
  * @return mixed  The value returned by the method called
  */
 public function __call($method_name, $parameters)
 {
     $class = get_class($this);
     if (!isset(self::$callback_cache[$class][$method_name])) {
         if (!isset(self::$callback_cache[$class])) {
             self::$callback_cache[$class] = array();
         }
         $callback = fORM::getActiveRecordMethod($class, $method_name);
         self::$callback_cache[$class][$method_name] = $callback ? $callback : FALSE;
     }
     if ($callback = self::$callback_cache[$class][$method_name]) {
         return call_user_func_array($callback, array($this, &$this->values, &$this->old_values, &$this->related_records, &$this->cache, $method_name, $parameters));
     }
     if (!isset(self::$method_name_cache[$method_name])) {
         list($action, $subject) = fORM::parseMethod($method_name);
         self::$method_name_cache[$method_name] = array('action' => $action, 'subject' => $subject);
     } else {
         $action = self::$method_name_cache[$method_name]['action'];
         $subject = self::$method_name_cache[$method_name]['subject'];
     }
     switch ($action) {
         // Value methods
         case 'get':
             return $this->get($subject);
         case 'encode':
             if (isset($parameters[0])) {
                 return $this->encode($subject, $parameters[0]);
             }
             return $this->encode($subject);
         case 'prepare':
             if (isset($parameters[0])) {
                 return $this->prepare($subject, $parameters[0]);
             }
             return $this->prepare($subject);
         case 'inspect':
             if (isset($parameters[0])) {
                 return $this->inspect($subject, $parameters[0]);
             }
             return $this->inspect($subject);
         case 'set':
             if (sizeof($parameters) < 1) {
                 throw new fProgrammerException('The method, %s(), requires at least one parameter', $method_name);
             }
             return $this->set($subject, $parameters[0]);
             // Related data methods
         // Related data methods
         case 'associate':
             if (sizeof($parameters) < 1) {
                 throw new fProgrammerException('The method, %s(), requires at least one parameter', $method_name);
             }
             $table = fORM::tablize($class);
             $records = $parameters[0];
             $route = isset($parameters[1]) ? $parameters[1] : NULL;
             $plural = FALSE;
             // one-to-many relationships need to use plural forms
             if (in_array($subject, fORMSchema::retrieve()->getTables())) {
                 if (fORMSchema::isOneToOne($table, $subject, $route)) {
                     throw new fProgrammerException('The table %1$s is not in a %2$srelationship with the table %3$s', $table, '*-to-many ', $subject);
                 }
                 $subject = fGrammar::singularize($subject);
                 $plural = TRUE;
             }
             $subject = fGrammar::camelize($subject, TRUE);
             // This handles one-to-many and many-to-many relationships
             if ($plural) {
                 return fORMRelated::associateRecords($class, $this->related_records, $subject, $records, $route);
             }
             // This handles one-to-one relationships
             return fORMRelated::associateRecord($class, $this->related_records, $subject, $records, $route);
         case 'build':
             $subject = fGrammar::singularize($subject);
             $subject = fGrammar::camelize($subject, TRUE);
             if (isset($parameters[0])) {
                 return fORMRelated::buildRecords($class, $this->values, $this->related_records, $subject, $parameters[0]);
             }
             return fORMRelated::buildRecords($class, $this->values, $this->related_records, $subject);
         case 'count':
             $subject = fGrammar::singularize($subject);
             $subject = fGrammar::camelize($subject, TRUE);
             if (isset($parameters[0])) {
                 return fORMRelated::countRecords($class, $this->values, $this->related_records, $subject, $parameters[0]);
             }
             return fORMRelated::countRecords($class, $this->values, $this->related_records, $subject);
         case 'create':
             $subject = fGrammar::camelize($subject, TRUE);
             if (isset($parameters[0])) {
                 return fORMRelated::createRecord($class, $this->values, $this->related_records, $subject, $parameters[0]);
             }
             return fORMRelated::createRecord($class, $this->values, $this->related_records, $subject);
         case 'inject':
             if (sizeof($parameters) < 1) {
                 throw new fProgrammerException('The method, %s(), requires at least one parameter', $method_name);
             }
             $subject = fGrammar::singularize($subject);
             $subject = fGrammar::camelize($subject, TRUE);
             if (isset($parameters[1])) {
                 return fORMRelated::setRecordSet($class, $this->related_records, $subject, $parameters[0], $parameters[1]);
             }
             return fORMRelated::setRecordSet($class, $this->related_records, $subject, $parameters[0]);
         case 'link':
             $subject = fGrammar::singularize($subject);
             $subject = fGrammar::camelize($subject, TRUE);
             if (isset($parameters[0])) {
                 return fORMRelated::linkRecords($class, $this->related_records, $subject, $parameters[0]);
             }
             return fORMRelated::linkRecords($class, $this->related_records, $subject);
         case 'list':
             $subject = fGrammar::singularize($subject);
             $subject = fGrammar::camelize($subject, TRUE);
             if (isset($parameters[0])) {
                 return fORMRelated::getPrimaryKeys($class, $this->values, $this->related_records, $subject, $parameters[0]);
             }
             return fORMRelated::getPrimaryKeys($class, $this->values, $this->related_records, $subject);
         case 'populate':
             $table = fORM::tablize($class);
             $route = isset($parameters[0]) ? $parameters[0] : NULL;
             // one-to-many relationships need to use plural forms
             if (in_array($subject, fORMSchema::retrieve()->getTables())) {
                 if (fORMSchema::isOneToOne($table, $subject, $route)) {
                     throw new fProgrammerException('The table %1$s is not in a%2$srelationship with the table %3$s', $table, ' one-to-many ', $subject);
                 }
                 $subject = fGrammar::singularize($subject);
             }
             $subject = fGrammar::camelize($subject, TRUE);
             return fORMRelated::populateRecords($class, $this->related_records, $subject, $route);
         case 'tally':
             if (sizeof($parameters) < 1) {
                 throw new fProgrammerException('The method, %s(), requires at least one parameter', $method_name);
             }
             $subject = fGrammar::singularize($subject);
             $subject = fGrammar::camelize($subject, TRUE);
             if (isset($parameters[1])) {
                 return fORMRelated::setCount($class, $this->related_records, $subject, $parameters[0], $parameters[1]);
             }
             return fORMRelated::setCount($class, $this->related_records, $subject, $parameters[0]);
             // Error handler
         // Error handler
         default:
             throw new fProgrammerException('Unknown method, %s(), called', $method_name);
     }
 }
Пример #3
0
 /**
  * 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;
 }
Пример #4
0
 /**
  * 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)
 {
     $table = fORM::tablize($class);
     $related_table = fORM::tablize($related_class);
     $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($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);
     }
     // Ignore validation messages about the primary key since it will be added
     $primary_key_name = fValidationException::formatField(fORM::getColumnName($related_class, $route));
     $primary_key_regex = '#^' . preg_quote($primary_key_name, '#') . '.*$#D';
     fORMValidation::addRegexReplacement($related_class, $primary_key_regex, '');
     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 $record_message) {
             $token_field = fValidationException::formatField('__TOKEN__');
             $extract_message_regex = '#' . str_replace('__TOKEN__', '(.*?)', preg_quote($token_field, '#')) . '(.*)$#D';
             preg_match($extract_message_regex, $record_message, $matches);
             if ($one_to_one) {
                 $column_name = self::compose('%1$s %2$s', $related_record_name, $matches[1]);
             } else {
                 $column_name = self::compose('%1$s #%2$s %3$s', $related_record_name, $i + 1, $matches[1]);
             }
             $messages[] = self::compose('%1$s%2$s', fValidationException::formatField($column_name), $matches[2]);
         }
         fRequest::unfilter();
     }
     fORMValidation::removeRegexReplacement($related_class, $primary_key_regex, '');
     return $messages;
 }