コード例 #1
0
 protected function populateRelated($recursive = false)
 {
     if ($recursive) {
         $one_to_many_relationships = $schema->getRelationships($table, 'one-to-many');
         foreach ($one_to_many_relationships as $relationship) {
             $route_name = fORMSchema::getRouteNameFromRelationship('one-to-many', $relationship);
             $related_class = fORM::classize($relationship['related_table']);
             $method = 'populate' . fGrammar::pluralize($related_class);
             $this->{$method}(TRUE, $route_name);
         }
         $one_to_one_relationships = $schema->getRelationships($table, 'one-to-one');
         foreach ($one_to_one_relationships as $relationship) {
             $route_name = fORMSchema::getRouteNameFromRelationship('one-to-one', $relationship);
             $related_class = fORM::classize($relationship['related_table']);
             $this->__call('populate' . $related_class, array(TRUE, $route_name));
         }
     }
     return $this;
 }
コード例 #2
0
ファイル: fActiveRecord.php プロジェクト: mrjwc/printmaster
 /**
  * Stores a record in the database, whether existing or new
  * 
  * This method will start database and filesystem transactions if they have
  * not already been started.
  * 
  * @throws fValidationException  When ::validate() throws an exception
  * 
  * @param  boolean $force_cascade  When storing related records, this will force deleting child records even if they have their own children in a relationship with an RESTRICT or NO ACTION for the ON DELETE clause
  * @return fActiveRecord  The record object, to allow for method chaining
  */
 public function store($force_cascade = FALSE)
 {
     $class = get_class($this);
     if (fORM::getActiveRecordMethod($class, 'store')) {
         return $this->__call('store', array());
     }
     fORM::callHookCallbacks($this, 'pre::store()', $this->values, $this->old_values, $this->related_records, $this->cache);
     $db = fORMDatabase::retrieve($class, 'write');
     $schema = fORMSchema::retrieve($class);
     try {
         $table = fORM::tablize($class);
         // New auto-incrementing records require lots of special stuff, so we'll detect them here
         $new_autoincrementing_record = FALSE;
         if (!$this->exists()) {
             $pk_columns = $schema->getKeys($table, 'primary');
             $pk_column = $pk_columns[0];
             $pk_auto_incrementing = $schema->getColumnInfo($table, $pk_column, 'auto_increment');
             if (sizeof($pk_columns) == 1 && $pk_auto_incrementing && !$this->values[$pk_column]) {
                 $new_autoincrementing_record = TRUE;
             }
         }
         $inside_db_transaction = $db->isInsideTransaction();
         if (!$inside_db_transaction) {
             $db->translatedQuery('BEGIN');
         }
         fORM::callHookCallbacks($this, 'post-begin::store()', $this->values, $this->old_values, $this->related_records, $this->cache);
         $this->validate();
         fORM::callHookCallbacks($this, 'post-validate::store()', $this->values, $this->old_values, $this->related_records, $this->cache);
         // Storing main table
         if (!$this->exists()) {
             $params = $this->constructInsertParams();
         } else {
             $params = $this->constructUpdateParams();
         }
         $result = call_user_func_array($db->translatedQuery, $params);
         // If there is an auto-incrementing primary key, grab the value from the database
         if ($new_autoincrementing_record) {
             $this->set($pk_column, $result->getAutoIncrementedValue());
         }
         // Fix cascade updated columns for in-memory objects to prevent issues when saving
         $one_to_one_relationships = $schema->getRelationships($table, 'one-to-one');
         $one_to_many_relationships = $schema->getRelationships($table, 'one-to-many');
         $relationships = array_merge($one_to_one_relationships, $one_to_many_relationships);
         foreach ($relationships as $relationship) {
             $type = in_array($relationship, $one_to_one_relationships) ? 'one-to-one' : 'one-to-many';
             $route = fORMSchema::getRouteNameFromRelationship($type, $relationship);
             $related_table = $relationship['related_table'];
             $related_class = fORM::classize($related_table);
             $related_class = fORM::getRelatedClass($class, $related_class);
             if ($relationship['on_update'] != 'cascade') {
                 continue;
             }
             $column = $relationship['column'];
             if (!fActiveRecord::changed($this->values, $this->old_values, $column)) {
                 continue;
             }
             if (!isset($this->related_records[$related_table][$route]['record_set'])) {
                 continue;
             }
             $record_set = $this->related_records[$related_table][$route]['record_set'];
             $related_column = $relationship['related_column'];
             $old_value = fActiveRecord::retrieveOld($this->old_values, $column);
             $value = $this->values[$column];
             if ($old_value === NULL) {
                 continue;
             }
             foreach ($record_set as $record) {
                 if (isset($record->old_values[$related_column])) {
                     foreach (array_keys($record->old_values[$related_column]) as $key) {
                         if ($record->old_values[$related_column][$key] === $old_value) {
                             $record->old_values[$related_column][$key] = $value;
                         }
                     }
                 }
                 if ($record->values[$related_column] === $old_value) {
                     $record->values[$related_column] = $value;
                 }
             }
         }
         // Storing *-to-many and one-to-one relationships
         fORMRelated::store($class, $this->values, $this->related_records, $force_cascade);
         fORM::callHookCallbacks($this, 'pre-commit::store()', $this->values, $this->old_values, $this->related_records, $this->cache);
         if (!$inside_db_transaction) {
             $db->translatedQuery('COMMIT');
         }
         fORM::callHookCallbacks($this, 'post-commit::store()', $this->values, $this->old_values, $this->related_records, $this->cache);
     } catch (fException $e) {
         if (!$inside_db_transaction) {
             $db->translatedQuery('ROLLBACK');
         }
         fORM::callHookCallbacks($this, 'post-rollback::store()', $this->values, $this->old_values, $this->related_records, $this->cache);
         if ($new_autoincrementing_record && self::hasOld($this->old_values, $pk_column)) {
             $this->values[$pk_column] = self::retrieveOld($this->old_values, $pk_column);
             unset($this->old_values[$pk_column]);
         }
         throw $e;
     }
     fORM::callHookCallbacks($this, 'post::store()', $this->values, $this->old_values, $this->related_records, $this->cache);
     $was_new = !$this->exists();
     // If we got here we succefully stored, so update old values to make exists() work
     foreach ($this->values as $column => $value) {
         $this->old_values[$column] = array($value);
     }
     // If the object was just inserted into the database, save it to the identity map
     if ($was_new) {
         $hash = self::hash($this->values, $class);
         if (!isset(self::$identity_map[$class])) {
             self::$identity_map[$class] = array();
         }
         self::$identity_map[$class][$hash] = $this;
     }
     return $this;
 }
コード例 #3
0
 /**
  * Adds information about methods provided by this class to fActiveRecord
  *
  * @internal
  *
  * @param  string  $class                 The class to reflect the related record methods for
  * @param  array   &$signatures           The associative array of `{method_name} => {signature}`
  * @param  boolean $include_doc_comments  If the doc block comments for each method should be included
  * @return void
  */
 public static function reflect($class, &$signatures, $include_doc_comments)
 {
     $table = fORM::tablize($class);
     $schema = fORMSchema::retrieve($class);
     $one_to_one_relationships = $schema->getRelationships($table, 'one-to-one');
     $one_to_many_relationships = $schema->getRelationships($table, 'one-to-many');
     $many_to_one_relationships = $schema->getRelationships($table, 'many-to-one');
     $many_to_many_relationships = $schema->getRelationships($table, 'many-to-many');
     $to_one_relationships = array_merge($one_to_one_relationships, $many_to_one_relationships);
     $to_many_relationships = array_merge($one_to_many_relationships, $many_to_many_relationships);
     $to_one_created = array();
     foreach ($to_one_relationships as $relationship) {
         $related_class = fORM::classize($relationship['related_table']);
         $related_class = fORM::getRelatedClass($class, $related_class);
         if (isset($to_one_created[$related_class])) {
             continue;
         }
         $routes = fORMSchema::getRoutes($schema, $table, $relationship['related_table'], '*-to-one');
         $route_names = array();
         foreach ($routes as $route) {
             $route_names[] = fORMSchema::getRouteNameFromRelationship('*-to-one', $route);
         }
         $signature = '';
         if ($include_doc_comments) {
             $signature .= "/**\n";
             $signature .= " * Creates the related " . $related_class . "\n";
             $signature .= " * \n";
             if (sizeof($route_names) > 1) {
                 $signature .= " * @param  string \$route  The route to the related class. Must be one of: '" . join("', '", $route_names) . "'.\n";
             }
             $signature .= " * @return " . $related_class . "  The related object\n";
             $signature .= " */\n";
         }
         $create_method = 'create' . $related_class;
         $signature .= 'public function ' . $create_method . '(';
         if (sizeof($route_names) > 1) {
             $signature .= '$route';
         }
         $signature .= ')';
         $signatures[$create_method] = $signature;
         $to_one_created[$related_class] = TRUE;
     }
     $one_to_one_created = array();
     foreach ($one_to_one_relationships as $relationship) {
         $related_class = fORM::classize($relationship['related_table']);
         $related_class = fORM::getRelatedClass($class, $related_class);
         if (isset($one_to_one_created[$related_class])) {
             continue;
         }
         $routes = fORMSchema::getRoutes($schema, $table, $relationship['related_table'], 'one-to-one');
         $route_names = array();
         foreach ($routes as $route) {
             $route_names[] = fORMSchema::getRouteNameFromRelationship('one-to-one', $route);
         }
         $signature = '';
         if ($include_doc_comments) {
             $signature .= "/**\n";
             $signature .= " * Populates the related " . $related_class . "\n";
             $signature .= " * \n";
             if (sizeof($route_names) > 1) {
                 $signature .= " * @param  string \$route  The route to the related class. Must be one of: '" . join("', '", $route_names) . "'.\n";
             }
             $signature .= " * @return fActiveRecord  The record object, to allow for method chaining\n";
             $signature .= " */\n";
         }
         $populate_method = 'populate' . $related_class;
         $signature .= 'public function ' . $populate_method . '(';
         if (sizeof($route_names) > 1) {
             $signature .= '$route';
         }
         $signature .= ')';
         $signatures[$populate_method] = $signature;
         $signature = '';
         if ($include_doc_comments) {
             $signature .= "/**\n";
             $signature .= " * Associates the related " . $related_class . " to this record\n";
             $signature .= " * \n";
             $signature .= " * @param  fActiveRecord|array|string|integer \$record  The record, or the primary key of the record, to associate\n";
             if (sizeof($route_names) > 1) {
                 $signature .= " * @param  string \$route  The route to the related class. Must be one of: '" . join("', '", $route_names) . "'.\n";
             }
             $signature .= " * @return fActiveRecord  The record object, to allow for method chaining\n";
             $signature .= " */\n";
         }
         $associate_method = 'associate' . $related_class;
         $signature .= 'public function ' . $associate_method . '($record';
         if (sizeof($route_names) > 1) {
             $signature .= ', $route';
         }
         $signature .= ')';
         $signatures[$associate_method] = $signature;
         $signature = '';
         if ($include_doc_comments) {
             $signature .= "/**\n";
             $signature .= " * Indicates if a related " . $related_class . " exists\n";
             $signature .= " * \n";
             if (sizeof($route_names) > 1) {
                 $signature .= " * @param  string \$route  The route to the related class. Must be one of: '" . join("', '", $route_names) . "'.\n";
             }
             $signature .= " * @return boolean  If a related record exists\n";
             $signature .= " */\n";
         }
         $has_method = 'has' . $related_class;
         $signature .= 'public function ' . $has_method . '($record';
         if (sizeof($route_names) > 1) {
             $signature .= ', $route';
         }
         $signature .= ')';
         $signatures[$has_method] = $signature;
         $one_to_one_created[$related_class] = TRUE;
     }
     $to_many_created = array();
     foreach ($to_many_relationships as $relationship) {
         $related_class = fORM::classize($relationship['related_table']);
         $related_class = fORM::getRelatedClass($class, $related_class);
         if (isset($to_many_created[$related_class])) {
             continue;
         }
         $routes = fORMSchema::getRoutes($schema, $table, $relationship['related_table'], '*-to-many');
         $route_names = array();
         $many_to_many_route_names = array();
         $one_to_many_route_names = array();
         foreach ($routes as $route) {
             if (isset($route['join_table'])) {
                 $route_name = fORMSchema::getRouteNameFromRelationship('many-to-many', $route);
                 $route_names[] = $route_name;
                 $many_to_many_route_names[] = $route_name;
             } else {
                 $route_name = fORMSchema::getRouteNameFromRelationship('one-to-many', $route);
                 $route_names[] = $route_name;
                 $one_to_many_route_names[] = $route_name;
             }
         }
         if ($one_to_many_route_names) {
             $signature = '';
             if ($include_doc_comments) {
                 $related_table = fORM::tablize($related_class);
                 $signature .= "/**\n";
                 $signature .= " * Calls the ::populate() method for multiple child " . $related_class . " records. Uses request value arrays in the form " . $related_table . "::{column_name}[].\n";
                 $signature .= " * \n";
                 if (sizeof($one_to_many_route_names) > 1) {
                     $signature .= " * @param  string \$route  The route to the related class. Must be one of: '" . join("', '", $one_to_many_route_names) . "'.\n";
                 }
                 $signature .= " * @return fActiveRecord  The record object, to allow for method chaining\n";
                 $signature .= " */\n";
             }
             $populate_related_method = 'populate' . fGrammar::pluralize($related_class);
             $signature .= 'public function ' . $populate_related_method . '(';
             if (sizeof($one_to_many_route_names) > 1) {
                 $signature .= '$route';
             }
             $signature .= ')';
             $signatures[$populate_related_method] = $signature;
         }
         if ($many_to_many_route_names) {
             $signature = '';
             if ($include_doc_comments) {
                 $related_table = fORM::tablize($related_class);
                 $signature .= "/**\n";
                 $signature .= " * Creates entries in the appropriate joining table to create associations with the specified " . $related_class . " records. Uses request value array(s) in the form " . $related_table . "::{primary_key_column_name(s)}[].\n";
                 $signature .= " * \n";
                 if (sizeof($many_to_many_route_names) > 1) {
                     $signature .= " * @param  string \$route  The route to the related class. Must be one of: '" . join("', '", $many_to_many_route_names) . "'.\n";
                 }
                 $signature .= " * @return fActiveRecord  The record object, to allow for method chaining\n";
                 $signature .= " */\n";
             }
             $link_related_method = 'link' . fGrammar::pluralize($related_class);
             $signature .= 'public function ' . $link_related_method . '(';
             if (sizeof($many_to_many_route_names) > 1) {
                 $signature .= '$route';
             }
             $signature .= ')';
             $signatures[$link_related_method] = $signature;
             $signature = '';
             if ($include_doc_comments) {
                 $related_table = fORM::tablize($related_class);
                 $signature .= "/**\n";
                 $signature .= " * Creates entries in the appropriate joining table to create associations with the specified " . $related_class . " records\n";
                 $signature .= " * \n";
                 $signature .= " * @param  fRecordSet|array \$records_to_associate  The records to associate - should be an fRecords, an array of records or an array of primary keys\n";
                 if (sizeof($many_to_many_route_names) > 1) {
                     $signature .= " * @param  string           \$route  The route to the related class. Must be one of: '" . join("', '", $many_to_many_route_names) . "'.\n";
                 }
                 $signature .= " * @return fActiveRecord  The record object, to allow for method chaining\n";
                 $signature .= " */\n";
             }
             $associate_related_method = 'associate' . fGrammar::pluralize($related_class);
             $signature .= 'public function ' . $associate_related_method . '($records_to_associate';
             if (sizeof($many_to_many_route_names) > 1) {
                 $signature .= ', $route';
             }
             $signature .= ')';
             $signatures[$associate_related_method] = $signature;
         }
         $signature = '';
         if ($include_doc_comments) {
             $signature .= "/**\n";
             $signature .= " * Builds an fRecordSet of the related " . $related_class . " objects\n";
             $signature .= " * \n";
             if (sizeof($route_names) > 1) {
                 $signature .= " * @param  string \$route  The route to the related class. Must be one of: '" . join("', '", $route_names) . "'.\n";
             }
             $signature .= " * @return fRecordSet  A record set of the related " . $related_class . " objects\n";
             $signature .= " */\n";
         }
         $build_method = 'build' . fGrammar::pluralize($related_class);
         $signature .= 'public function ' . $build_method . '(';
         if (sizeof($route_names) > 1) {
             $signature .= '$route';
         }
         $signature .= ')';
         $signatures[$build_method] = $signature;
         $signature = '';
         if ($include_doc_comments) {
             $signature .= "/**\n";
             $signature .= " * Indicates if related " . $related_class . " objects exist\n";
             $signature .= " * \n";
             if (sizeof($route_names) > 1) {
                 $signature .= " * @param  string \$route  The route to the related class. Must be one of: '" . join("', '", $route_names) . "'.\n";
             }
             $signature .= " * @return boolean  If related " . $related_class . " objects exist\n";
             $signature .= " */\n";
         }
         $has_method = 'has' . fGrammar::pluralize($related_class);
         $signature .= 'public function ' . $has_method . '(';
         if (sizeof($route_names) > 1) {
             $signature .= '$route';
         }
         $signature .= ')';
         $signatures[$has_method] = $signature;
         $signature = '';
         if ($include_doc_comments) {
             $signature .= "/**\n";
             $signature .= " * Returns an array of the primary keys for the related " . $related_class . " objects\n";
             $signature .= " * \n";
             if (sizeof($route_names) > 1) {
                 $signature .= " * @param  string \$route  The route to the related class. Must be one of: '" . join("', '", $route_names) . "'.\n";
             }
             $signature .= " * @return array  The primary keys of the related " . $related_class . " objects\n";
             $signature .= " */\n";
         }
         $list_method = 'list' . fGrammar::pluralize($related_class);
         $signature .= 'public function ' . $list_method . '(';
         if (sizeof($route_names) > 1) {
             $signature .= '$route';
         }
         $signature .= ')';
         $signatures[$list_method] = $signature;
         $signature = '';
         if ($include_doc_comments) {
             $signature .= "/**\n";
             $signature .= " * Counts the number of related " . $related_class . " objects\n";
             $signature .= " * \n";
             if (sizeof($route_names) > 1) {
                 $signature .= " * @param  string \$route  The route to the related class. Must be one of: '" . join("', '", $route_names) . "'.\n";
             }
             $signature .= " * @return integer  The number related " . $related_class . " objects\n";
             $signature .= " */\n";
         }
         $count_method = 'count' . fGrammar::pluralize($related_class);
         $signature .= 'public function ' . $count_method . '(';
         if (sizeof($route_names) > 1) {
             $signature .= '$route';
         }
         $signature .= ')';
         $signatures[$count_method] = $signature;
         $to_many_created[$related_class] = TRUE;
     }
 }
コード例 #4
0
ファイル: fActiveRecord.php プロジェクト: jsuarez/MyDesign
 /**
  * Deletes a record from the database, but does not destroy the object
  * 
  * This method will start a database transaction if one is not already active.
  * 
  * @return fActiveRecord  The record object, to allow for method chaining
  */
 public function delete()
 {
     $class = get_class($this);
     if (fORM::getActiveRecordMethod($class, 'delete')) {
         return $this->__call('delete', array());
     }
     if (!$this->exists()) {
         throw new fProgrammerException('This %s object does not yet exist in the database, and thus can not be deleted', fORM::getRecordName($class));
     }
     fORM::callHookCallbacks($this, 'pre::delete()', $this->values, $this->old_values, $this->related_records, $this->cache);
     $table = fORM::tablize($class);
     $inside_db_transaction = fORMDatabase::retrieve()->isInsideTransaction();
     try {
         if (!$inside_db_transaction) {
             fORMDatabase::retrieve()->translatedQuery('BEGIN');
         }
         fORM::callHookCallbacks($this, 'post-begin::delete()', $this->values, $this->old_values, $this->related_records, $this->cache);
         // Check to ensure no foreign dependencies prevent deletion
         $one_to_many_relationships = fORMSchema::retrieve()->getRelationships($table, 'one-to-many');
         $many_to_many_relationships = fORMSchema::retrieve()->getRelationships($table, 'many-to-many');
         $relationships = array_merge($one_to_many_relationships, $many_to_many_relationships);
         $records_sets_to_delete = array();
         $restriction_messages = array();
         foreach ($relationships as $relationship) {
             // Figure out how to check for related records
             $type = isset($relationship['join_table']) ? 'many-to-many' : 'one-to-many';
             $route = fORMSchema::getRouteNameFromRelationship($type, $relationship);
             $related_class = fORM::classize($relationship['related_table']);
             $related_objects = fGrammar::pluralize($related_class);
             $method = 'build' . $related_objects;
             // Grab the related records
             $record_set = $this->{$method}($route);
             // If there are none, we can just move on
             if (!$record_set->count()) {
                 continue;
             }
             if ($type == 'one-to-many' && $relationship['on_delete'] == 'cascade') {
                 $records_sets_to_delete[] = $record_set;
             }
             if ($relationship['on_delete'] == 'restrict' || $relationship['on_delete'] == 'no_action') {
                 // Otherwise we have a restriction
                 $related_class_name = fORM::classize($relationship['related_table']);
                 $related_record_name = fORM::getRecordName($related_class_name);
                 $related_record_name = fGrammar::pluralize($related_record_name);
                 $restriction_messages[] = self::compose("One or more %s references it", $related_record_name);
             }
         }
         if ($restriction_messages) {
             throw new fValidationException(self::compose('This %s can not be deleted because:', fORM::getRecordName($class)), $restriction_messages);
         }
         // Delete this record
         $sql = 'DELETE FROM ' . $table . ' WHERE ' . fORMDatabase::createPrimaryKeyWhereClause($table, $table, $this->values, $this->old_values);
         $result = fORMDatabase::retrieve()->translatedQuery($sql);
         // Delete related records
         foreach ($records_sets_to_delete as $record_set) {
             foreach ($record_set as $record) {
                 if ($record->exists()) {
                     $record->delete();
                 }
             }
         }
         fORM::callHookCallbacks($this, 'pre-commit::delete()', $this->values, $this->old_values, $this->related_records, $this->cache);
         if (!$inside_db_transaction) {
             fORMDatabase::retrieve()->translatedQuery('COMMIT');
         }
         fORM::callHookCallbacks($this, 'post-commit::delete()', $this->values, $this->old_values, $this->related_records, $this->cache);
     } catch (fException $e) {
         if (!$inside_db_transaction) {
             fORMDatabase::retrieve()->translatedQuery('ROLLBACK');
         }
         fORM::callHookCallbacks($this, 'post-rollback::delete()', $this->values, $this->old_values, $this->related_records, $this->cache);
         // Check to see if the validation exception came from a related record, and fix the message
         if ($e instanceof fValidationException) {
             $message = $e->getMessage();
             $search = self::compose('This %s can not be deleted because:', fORM::getRecordName($class));
             if (stripos($message, $search) === FALSE) {
                 $regex = self::compose('This %s can not be deleted because:', '__');
                 $regex_parts = explode('__', $regex);
                 $regex = '#(' . preg_quote($regex_parts[0], '#') . ').*?(' . preg_quote($regex_parts[0], '#') . ')#';
                 $message = preg_replace($regex, '\\1' . strtr(fORM::getRecordName($class), array('\\' => '\\\\', '$' => '\\$')) . '\\2', $message);
                 $find = self::compose("One or more %s references it", '__');
                 $find_parts = explode('__', $find);
                 $find_regex = '#' . preg_quote($find_parts[0], '#') . '(.*?)' . preg_quote($find_parts[1], '#') . '#';
                 $replace = self::compose("One or more %s indirectly references it", '__');
                 $replace_parts = explode('__', $replace);
                 $replace_regex = strtr($replace_parts[0], array('\\' => '\\\\', '$' => '\\$')) . '\\1' . strtr($replace_parts[1], array('\\' => '\\\\', '$' => '\\$'));
                 $message = preg_replace($find_regex, $replace_regex, $regex);
                 throw new fValidationException($message);
             }
         }
         throw $e;
     }
     fORM::callHookCallbacks($this, 'post::delete()', $this->values, $this->old_values, $this->related_records, $this->cache);
     // If we just deleted an object that has an auto-incrementing primary key,
     // lets delete that value from the object since it is no longer valid
     $pk_columns = fORMSchema::retrieve()->getKeys($table, 'primary');
     if (sizeof($pk_columns) == 1 && fORMSchema::retrieve()->getColumnInfo($table, $pk_columns[0], 'auto_increment')) {
         $this->values[$pk_columns[0]] = NULL;
         unset($this->old_values[$pk_columns[0]]);
     }
     return $this;
 }