/**
  * Copy one object into another including has-one fields
  *
  * @param DataObject $copyFrom
  * @param DataObject $newObject
  * @param Boolean $overwriteValues - overwrite values that exist
  *
  * @return CopyFactory
  */
 public function copyObject($copyFrom, $newObject, $overwriteValues = true)
 {
     //get ignore fields
     if ($newObject->hasMethod("getIgnoreInCopyFields")) {
         $this->setIgnoreFields($newObject->getIgnoreInCopyFields());
     } elseif ($array = Config::inst()->get($newObject->ClassName, "ignore_in_copy_fields")) {
         if (is_array($array) && count($array)) {
             $this->setIgnoreFields($array);
         }
     }
     //get copy field
     $this->addIgnoreField($newObject->CopyFromFieldName($withID = true));
     $this->addIgnoreField($newObject->CopiedFromFieldName($withID = true));
     //get copy-able fields
     $dbFields = Config::inst()->get($copyFrom->ClassName, "db");
     $hasOneFields = Config::inst()->get($copyFrom->ClassName, "has_one");
     //has-one fields fixup
     foreach ($hasOneFields as $key => $field) {
         $hasOneFields[$key . "ID"] = $field;
         unset($hasOneFields[$key]);
     }
     $fields = $dbFields + $hasOneFields;
     //remove ignore fields ...
     foreach ($this->ignoreFields as $ignoreField) {
         unset($fields[$ignoreField]);
     }
     //flip
     $fields = array_keys($fields);
     if ($this->recordSession) {
         self::add_to_session("\n\t\t\t\t\t====================================\n\t\t\t\t\t*** COPYING INTO\n\t\t\t\t\t" . ($this->myClassName != $copyFrom->ClassName ? "ERROR: ClassName mismatch: " . $this->myClassName . " != " . $copyFrom->ClassName : "") . "\n\t\t\t\t\tValues will " . ($overwriteValues ? "" : "NOT") . " be overridden.\n\t\t\t\t\tDB Fields: " . implode(", ", array_keys($dbFields)) . "\n\t\t\t\t\tHAS ONE Fields: " . implode(", ", array_keys($hasOneFields)) . "\n\t\t\t\t\tIGNORE Fields: " . implode(", ", $this->ignoreFields) . "\n\t\t\t\t\tFINAL Fields: " . implode(", ", $fields) . "\n\t\t\t\t\t====================================\n\t\t\t\t", $copyFrom, $newObject);
     }
     if ($this->recordSession) {
         $copySessionRecording = "";
     }
     foreach ($fields as $field) {
         if (!$newObject->{$field} || $overwriteValues) {
             $value = $copyFrom->{$field};
             if (is_object($value)) {
                 $value = $value->raw();
             }
             if ($this->recordSession) {
                 $copySessionRecording .= "\r\nSetting '{$field}' to '{$value}'";
             }
             if ($this->isForReal) {
                 $newObject->{$field} = $value;
             }
         }
     }
     $copyField = $newObject->CopyFromFieldName($withID = true);
     $copyFieldCompleted = $newObject->CopiedFromFieldName($withID = true);
     //important - reset, so that it does not get into a loop.
     if ($this->recordSession) {
         self::add_to_session("\n\t\t\t{$copySessionRecording}\n\t\t\tsetting '{$copyField}' to zero\n\t\t\tsetting '{$copyFieldCompleted}' to '" . $copyFrom->ID . "'", $copyFrom, $newObject);
     }
     if ($this->isForReal) {
         $newObject->{$copyFieldCompleted} = $copyFrom->ID;
         if ($newObject->exists()) {
             $newObject->{$copyField} = 0;
         }
         $newObject->write();
     }
     //now we do all the other methods ...
     if ($newObject->hasMethod("doCopyFactory")) {
         if ($this->recordSession) {
             self::add_to_session("Now calling doCopyFactory ... ", $copyFrom, $newObject);
         }
         $newObject->doCopyFactory($this, $copyFrom);
     }
     return $this;
 }