function &_add($oFolder, $sFilename, $oUser, $aOptions)
 {
     global $default;
     //$oContents = KTUtil::arrayGet($aOptions, 'contents');
     $aMetadata = KTUtil::arrayGet($aOptions, 'metadata', null, false);
     $oDocumentType = KTUtil::arrayGet($aOptions, 'documenttype');
     $sDescription = KTUtil::arrayGet($aOptions, 'description', '');
     if (empty($sDescription)) {
         // If no document name is provided use the filename minus the extension
         $aFile = pathinfo($sFilename);
         $sDescription = isset($aFile['filename']) && !empty($aFile['filename']) ? $aFile['filename'] : $sFilename;
     }
     $oUploadChannel =& KTUploadChannel::getSingleton();
     if ($oDocumentType) {
         $iDocumentTypeId = KTUtil::getId($oDocumentType);
     } else {
         $iDocumentTypeId = 1;
     }
     $oUploadChannel->sendMessage(new KTUploadGenericMessage(_kt('Creating database entry')));
     $oDocument =& Document::createFromArray(array('name' => $sDescription, 'description' => $sDescription, 'filename' => $sFilename, 'folderid' => $oFolder->getID(), 'creatorid' => $oUser->getID(), 'documenttypeid' => $iDocumentTypeId));
     $oUploadChannel->sendMessage(new KTUploadGenericMessage(_kt('Storing contents')));
     $res = KTDocumentUtil::storeContents($oDocument, '', $aOptions);
     if (PEAR::isError($res)) {
         if (!PEAR::isError($oDocument)) {
             $oDocument->delete();
         }
         return $res;
     }
     if (is_null($aMetadata)) {
         $res = KTDocumentUtil::setIncomplete($oDocument, 'metadata');
         if (PEAR::isError($res)) {
             $oDocument->delete();
             return $res;
         }
     } else {
         $oUploadChannel->sendMessage(new KTUploadGenericMessage(_kt('Saving metadata')));
         $res = KTDocumentUtil::saveMetadata($oDocument, $aMetadata, $aOptions);
         if (PEAR::isError($res)) {
             $oDocument->delete();
             return $res;
         }
     }
     // setIncomplete and storeContents may change the document's status or
     // storage_path, so now is the time to update
     $oDocument->update();
     return $oDocument;
 }