Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

We've moved the forum!

Please use forum.silverstripe.org for any new questions (announcement).
The forum archive will stick around, but will be read only.

You can also use our Slack channel or StackOverflow to ask for help.
Check out our community overview for more options to contribute.

Form Questions /

Moderators: martimiz, Sean, Ed, biapar, Willr, Ingo, swaiba

[SOLVED] Saving uploaded file from front-end into assets/database & has_many relation


Go to End


4 Posts   6976 Views

Avatar
micschk

Community Member, 22 Posts

16 January 2013 at 10:27am

Hi, I have a front-end form which allows attaching multiple files:

public function myform(){
	...
	$fields->insertBefore($att=new FileField("Attachments[]", "Attachments"), "Title");
	$att->setFolderName('fileattachments');
	...
}

I save the uploaded files into the record in this function:

public function project_save($data, $form){
	...
		// save file attachments into record;
		$i = 0;
		while(isset($data['Attachments']['tmp_name'][$i])) {
			if (!empty($data['Attachments']['name'][$i])) { 
				// create new single file array from file uploads array
				$file = array();
				$file['name'] = $data['Attachments']['name'][$i];
				$file['type'] = $data['Attachments']['type'][$i];
				$file['tmp_name'] = $data['Attachments']['tmp_name'][$i];
				$file['error'] = $data['Attachments']['error'][$i];
				$file['size'] = $data['Attachments']['size'][$i];
				
				// create & write uploaded file in DB
				try {
					$fileClass = File::get_class_for_file_extension(pathinfo($file['name'], PATHINFO_EXTENSION));
					$newfile = new $fileClass();
					$upload = new Upload();
					// get folder from form upload field
					$folder = $form->Fields()->fieldByName('Attachments[]')->getFolderName();
					$folderObj = Folder::find_or_make($folder);
					$upload->loadIntoFile($file, $newfile, $folder);
					$fileObj = $upload->getFile();
					// for some reason the Filename is off...
//					$fileObj->setFilename( "assets/$folder/".$fileObj->Name );
//					$fileObj->setParentID( $folderObj->ID );
//					$fileObj->write();
					$this->Record->Attachments()->add($fileObj);
				} catch(ValidationException $e) {
					$form->sessionMessage('Extension not allowed...','bad');
					return $this->redirectBack();
				}
			}
			$i++;
		}
		$this->Record->write();
	...
}

This works OK, the relation gets added. The problem is that the resulting File/Image object has the wrong Filename & ParentID (folder ID) set. The actual files do get saved into the right folder ('fileattachments'), but the database record for the file always says it's in assets/Uploads/file.jpg instead.

I guess the problem's in Upload::loadIntoFile(), but I cannot seem to figure out what's going wrong;

$upload->loadIntoFile($file, $newfile, $folder);
$fileObj = $upload->getFile();

Avatar
micschk

Community Member, 22 Posts

17 January 2013 at 2:47am

OK, so as it turns out, the files get auto-saved as well upon $form->saveinto(), causing the wrong Filename & link issue. I managed to fix this by saving the files manualy & adding them into the has_many relation, and then saving the rest of the form fields into the datarecord, filtering out the uploadfields.

Avatar
lozhowlett

Community Member, 151 Posts

11 January 2014 at 12:53am

I would be interested to see your final code that has it working...

Avatar
micschk

Community Member, 22 Posts

8 April 2014 at 1:01am

The code's still a first working version, never actually revisited this project (and sorry for the delay lozhowlett):


	public function project_save($data, $form){
		//Debug::dump($data['Attachments']);
		$new = false;
		// save existing or create new;
		if( !$data['ID'] ){
			$this->Project = new Project();
			$new = true;
		} else {
			$this->Project = Project::get()->byID($data['ID']);
		}
		
		// save file attachments into project;
		$i = 0;
		while(!empty($data['Attachments-'.$i]) && !empty($data['Attachments-'.$i]['tmp_name'])) {
			$file = $data['Attachments-'.$i];
			if ($file && !empty($file['tmp_name']) && !empty($file['name'])) {
//				$fileClass = File::get_class_for_file_extension(pathinfo($file['name'], PATHINFO_EXTENSION));
//				$newfile = new $fileClass(); // instead, we use a subclass so we can later add data to the record
				$newfile = new Project_Attachment();
				// create & write uploaded file in DB
				try {
					$upload = new Upload();
					// get folder from form upload field
					$folder = $form->Fields()->fieldByName('Attachments-0')->getFolderName();
//					$folderObj = Folder::find_or_make($folder);
					$upload->loadIntoFile($file, $newfile, $folder);
					//$fileObj = $upload->getFile();
					$newfile->write();
					$this->Project->Attachments()->add($newfile);
				} catch(ValidationException $e) {
					$form->sessionMessage('Extension not allowed...','bad');
					return $this->redirectBack();
				}
			}
			$i++;
		}
		
		// prevent saving attachments twice (auto saved upon $form->saveinto()), by filtering them out after saving;
		$fieldsToSave = array_keys($data);
		foreach($fieldsToSave as $i => $val){
			if( strpos($val, 'Attachments')===0 ){ unset( $fieldsToSave[$i] ); }
		}
//		Debug::dump($fieldsToSave);
		// load further submitted data into project (has to be done after saving attachments, or they'll be saved twice...
		$form->saveInto($this->Project, $fieldsToSave);
	
		// if new client, create:
		if( $data['ClientID']=='new' ){
			$newClient = new Client();
			$newClient->Company = $data['NewClientName'];
			$newClient->write();
			$this->Project->ClientID = $newClient->ID;
		}
		
		$this->Project->write();
//		Debug::dump($this->Project->Attachments());
		$form->sessionMessage('Project saved!','good');
		// Someday maybe... (redirect happens too fast, 
		if( $new ){
			return $this->redirect($this->Link().'project_edit/'.$this->Project->ID.'/#Todotable');
		}
		return $this->redirectBack();
		//return $this->redirect($this->Link().'projects');
	}