5

I'm trying to do something very simple - but I've yet to find documentation to cover this basic scenario.

I'm writing a plugin. In a controller, I want to create a new entry, and assign an uploaded file to an Assets field on the entry.

I can create an entry using the example code:

$entry = new EntryModel();
$entry->getContent()->title = 'Title of thing';
// set some custom fields
craft()->entries->saveEntry($entry);

One of the fields is an Assets type; I have image data in a variable - I want to create an asset and associate it to the relevant property of the entry.

7

Assets fields are capable of storing newly uploaded files into assets folders, and then automatically relating them to the entry (making this feature possible).

When you’re saving the entry yourself rather than using the entries/saveEntry controller action, there are two things you need to do in order to take advantage of this feature:

  1. Make sure your form is set up correctly.

    The form should be submitting with a POST request, and encoding with multipart/form-data:

    <form method="post" enctype="multipart/form-data">
    

    And the file input needs to have an input name based on the Assets field’s handle:

    <input type="file" name="fields[myAssetsFieldHandle]">
    
  2. Your controller needs to tell the entry where to find the uploaded file.

    You can do this with setContentFromPost() if you want all custom field values in the POST data to be assigned to the entry automatically, or setContentPostLocation() if you want to assign the custom field values to the entry manually.

    setContentFromPost() example:

    $entry = new EntryModel();
    $entry->getContent()->title = 'My New Entry';
    
    // Look through $_POST['fields'] for any custom field values
    // and assign them to the entry's content automatically
    $entry->setContentFromPost('fields');
    
    craft()->entries->saveEntry($entry);
    

    setContentPostLocation() example:

    $entry = new EntryModel();
    $entry->getContent()->title = 'My New Entry';
    
    // Assign the custom field values manually
    $entry->getContent()->summary = craft()->request->getPost('fields.summary');
    $entry->getContent()->body = craft()->request->getPost('fields.body');
    
    // Tell the entry where these custom fields are coming from in the POST data
    // so that the Assets field will know where to look for an uploaded file
    $entry->setContentPostLocation('fields');
    
    craft()->entries->saveEntry($entry);
    

Alternatively, you can manually store the uploaded file into an asset folder using AssetsService::insertFileByLocalPath(), get the resulting file ID, and assign that file ID directly onto the Assets field.

$fileIds = array();

$uploadedFile = UploadedFile::getInstanceByName('fields.myAssetsFieldHandle');

if ($uploadedFile)
{
    $response = craft()->assets->insertFileByLocalPath(
        $uploadedFile->tempName,
        $uploadedFile->name,
        $folderId,
        AssetConflictResolution::KeepBoth
    );

    if ($response->isSuccess())
    {
        $fileIds[] = $response->getDataItem('fileId');
    }
}

$entry = new EntryModel();
$entry->getContent()->title = 'My New Entry';

// Assign the custom field values manually
$entry->getContent()->summary = craft()->request->getPost('fields.summary');
$entry->getContent()->body = craft()->request->getPost('fields.body');
$entry->getContent()->myAssetsFieldHandle = $fileIds;

craft()->entries->saveEntry($entry);

Note that in this approach, the name of the file input doesn’t matter, since you’re the one that’s telling UploadedFile where to look for it in $_FILES.

  • I was using insertFileByLocalPath, as I'm not taking input from a form (it's handling data from an API) - but the bit that I couldn't find documented was that I needed to set the assets field with an array of file IDs (which I already had from a call to getDataItem('fileId') on the response from insertFileByLocalPath). It probably seems incredibly basic - but I just couldn't find documentation or an example which showed this. – Tom Oct 16 '14 at 14:20
  • @Tom Yeah, I think this calls for us adding a new section to all the field type pages in the docs, explaining how their data should be formatted when saving elements, and also showing an example HTML form and PHP code. – Brandon Kelly Oct 16 '14 at 14:59
  • @Tom Also hope you don’t mind that I edited your question to focus on the file being uploaded. It wasn’t entirely clear whether it was getting uploaded or not (thanks for the clarification), but I figured freshly-uploaded files are the majority use case, and answering that question kills both birds with one stone. – Brandon Kelly Oct 16 '14 at 15:02
  • 2
    Just to update on this; sometimes this comes back with the error: "Integrity constraint violation: 1048 Column 'targetId' cannot be null. The SQL statement executed was: INSERT INTO craft_relations..." But not consistently. Any ideas? – Tom Oct 17 '14 at 15:58
  • 1
    @Tom You’re probably passing some blank values into the relation field’s array value. – Brandon Kelly Oct 17 '14 at 17:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.