<p>Looks like you have to do a bit of fudging if your running the $model->validate() function in your controller. assetId has to be set correctly before it jumps over to Service.</p>

<p>I still run the following in my <strong>Controller</strong></p>

<pre><code>$reorder = craft()-&gt;request-&gt;getPost('assetId', $model-&gt;assetId);
$model-&gt;assetId = (!empty($reorder) ? $reorder[0] : null);
</code></pre>

<p>Then I run this in my <strong>Service</strong></p>

<pre><code>$record-&gt;assetId = $model-&gt;assetId;
</code></pre>

<p>Tell me if I've missed something here.</p>

CC BY-SA 3.0
2014-07-28T00:33:28.847Z
2014-07-28T00:33:28.847Z
Adam McCombs
<p>I did this recently with my <a href="https://www.doublesecretagency.com/plugins/ad-wizard" rel="nofollow noreferrer">Ad Wizard</a> plugin... There are several different parts which need to be brought together to make it work:</p>

<hr>

<p>In your <strong>Record</strong> file, add this to <code>defineRelations</code>:</p>

<pre><code>'asset' =&gt; array(static::BELONGS_TO, 'AssetFileRecord')
</code></pre>

<hr>

<p>In your <strong>Model</strong> file, add this to <code>defineAttributes</code>:</p>

<pre><code>'assetId' =&gt; AttributeType::Number
</code></pre>

<hr>

<p>Whichever <strong>template</strong> is responsible for editing that data will need something like this:</p>

<pre><code>&lt;div class="field" id="assetId-field"&gt;
    &lt;div class="heading"&gt;
        &lt;label for="assetId"&gt;Image&lt;/label&gt;
    &lt;/div&gt;
    &lt;div class="input"&gt;
        {% if assetsSourceExists %}
            {{ forms.elementSelect({
                elements: elements,
                id: 'assetId',
                name: 'assetId',
                elementType: elementType,
                criteria: {"kind":[],"localeEnabled":null,"locale":"en_us"},
                sourceElementId: assetId,
                jsClass: 'Craft.AssetSelectInput',
                addButtonLabel: 'Select Image',
                limit: 1,
            }) }}
        {% else %}
            &lt;p class="error"&gt;No assets sources currently exist. &lt;a href="{{ newAssetsSourceUrl }}"&gt;Create one now...&lt;/a&gt;&lt;/p&gt;
        {% endif %}
    &lt;/div&gt;
&lt;/div&gt;
</code></pre>

<p>You'll notice in the Twig code above, I set references to the following variables:</p>

<ul>
<li><code>assetId</code></li>
<li><code>elements</code></li>
<li><code>elementType</code></li>
<li><code>assetsSourceExists</code></li>
<li><code>newAssetsSourceUrl</code></li>
</ul>

<p>These variable were set in the <code>actionEditMyElement</code> method of the <strong>Controller</strong> prior to loading the template:</p>

<pre><code>// Set assetId
$variables['assetId'] = $myModel-&gt;assetId;

// Set elements
if ($variables['assetId']) {
    $asset = craft()-&gt;elements-&gt;getElementById($variables['assetId']);
    $variables['elements'] = array($asset);
} else {
    $variables['elements'] = array();
}

// Set elementType
$variables['elementType'] = craft()-&gt;elements-&gt;getElementType(ElementType::Asset);

// Set assetsSourceExists
$sources = craft()-&gt;assets-&gt;findFolders();
$variables['assetsSourceExists'] = count($sources);

// Set newAssetsSourceUrl
$variables['newAssetsSourceUrl'] = UrlHelper::getUrl('settings/assets/sources/new');

// Render the template!
$this-&gt;renderTemplate('myplugin/_edit', $variables);
</code></pre>

<hr>

<p>Your <strong>Controller</strong> will probably have something like this in your <code>actionSaveMyElement</code> method:</p>

<pre><code>$myModel-&gt;assetId = craft()-&gt;request-&gt;getPost('assetId', $myModel-&gt;assetId);
</code></pre>

<hr>

<p>Your <strong>Service</strong> file will probably have something like this to save your record:</p>

<pre><code>$assetId = (!empty($myModel-&gt;assetId) ? $myModel-&gt;assetId[0] : null);
$myRecord-&gt;assetId = $assetId;
...
$myRecord-&gt;save();
</code></pre>

<hr>

<p>Hope that helps, let me know if I missed anything!</p>

CC BY-SA 3.0
2014-06-25T01:00:59.320Z
Thanks Lindsey. This is great. I'll need to contemplate this for a moment!  Are you allowing the user to select any asset folder?  Do you have any Asset field settings in your own plugin, or just let the user interact with all asset folders and such via the Asset Element Selector Modal?
Ben Parizek
CC BY-SA 3.0
2014-06-25T05:22:28.757Z
The way I've got it setup, the user can select from any existing assets folder. I didn't need to lock it to a single folder for this plugin. Other than borrowing the Twig code which triggers the Asset Element Selector Modal, I tried to let Craft deal with the assets as natively as possible.
Lindsey D
CC BY-SA 3.0
2014-06-25T08:58:30.437Z
@LindseyD Is there a technical reason you specify it in the php-file, or is it just preference? I tried to keep it as much in Twig as possible: http://craftb.in/xepeqosupa are there any downsides to this?
Victor
CC BY-SA 3.0
2014-06-25T16:15:30.947Z
@VictorIn It's a little bit of personal preference... I generally try to put as much logic as reasonably possible into the PHP, to save Twig the hassle of parsing it later.
Lindsey D
CC BY-SA 3.0
2014-06-30T11:49:12.387Z
Thanks for the detailed description Lindsey. This came together nicely and I've now got multiple image fields working as needed.
Ben Parizek
CC BY-SA 3.0
2014-06-30T16:15:12.517Z
Excellent, glad to hear it Ben! There was a lot to include, glad I didn't miss anything. :)
Lindsey D
CC BY-SA 3.0
2014-07-27T23:54:53.547Z
@LindseyD wins the internet again.
Adam McCombs
CC BY-SA 3.0
2014-06-25T00:55:32.043Z
2018-02-20T22:43:53.443Z
2018-02-20T22:43:53.443Z
Lindsey D
<p>We've got a plugin.  It doesn't have the ability to add custom field types.  We're pre-defining all of the fields.  One of the fields needs to be an Asset field.  A user should be able to upload an Asset using the native Craft Asset UI, store that Asset locally or on Amazon or any supported cloud platforms.</p>

<p>How do we do this?</p>

<p>Where do we create the relationship between the uploaded Asset and the database record we want the Asset related to?</p>

<p>If we were allowing custom fields we could have our custom table relate to a Field Layout ID, and have any number of fields relate to that Field Layout.  But in our case, we're defining all of the columns we need in our template, in our own record, and don't really need to create any fields within Craft's fields table as we're setting them all up beforehand.</p>

<p>Do we need a Field Layout in this situation?  Do we need to create a Field within Craft under our own context (like Matrix blocks) to be able to control the settings such as where to upload the assets to, and whether to restrict the upload to a single folder, or single image?</p>

<p>I feel I have lots of pieces of the puzzle, but can't yet see how they fit together.</p>

<plugin-development><assets><field>
How do we create a pre-defined Asset upload field in a plugin that integrates with the native Craft Assets file manager?
# How do we create a pre-defined Asset upload field in a plugin that integrates with the native Craft Assets file manager?

(Asked by: username_0 on 2014-06-24)

We've got a plugin. It doesn't have the ability to add custom field types. We're pre-defining all of the fields. One of the fields needs to be an Asset field. A user should be able to upload an Asset using the native Craft Asset UI, store that Asset locally or on Amazon or any supported cloud platforms.

How do we do this?

Where do we create the relationship between the uploaded Asset and the database record we want the Asset related to?

If we were allowing custom fields we could have our custom table relate to a Field Layout ID, and have any number of fields relate to that Field Layout. But in our case, we're defining all of the columns we need in our template, in our own record, and don't really need to create any fields within Craft's fields table as we're setting them all up beforehand.

Do we need a Field Layout in this situation? Do we need to create a Field within Craft under our own context (like Matrix blocks) to be able to control the settings such as where to upload the assets to, and whether to restrict the upload to a single folder, or single image?

I feel I have lots of pieces of the puzzle, but can't yet see how they fit together.

**Tags:** plugin-development, assets, field

---

## 2 answers

### Answer by username_2 on 2014-06-25. Score: 16 | Accepted answer

I did this recently with my Ad Wizard plugin... There are several different parts which need to be brought together to make it work:

In your Record file, add this to defineRelations:
'asset' => array(static::BELONGS_TO, 'AssetFileRecord')


In your Model file, add this to defineAttributes:
'assetId' => AttributeType::Number


Whichever template is responsible for editing that data will need something like this:

    
        Image
    
    
        {% if assetsSourceExists %}
            {{ forms.elementSelect({
                elements: elements,
                id: 'assetId',
                name: 'assetId',
                elementType: elementType,
                criteria: {"kind":[],"localeEnabled":null,"locale":"en_us"},
                sourceElementId: assetId,
                jsClass: 'Craft.AssetSelectInput',
                addButtonLabel: 'Select Image',
                limit: 1,
            }) }}
        {% else %}
            No assets sources currently exist. Create one now...
        {% endif %}
    


You'll notice in the Twig code above, I set references to the following variables:

assetId
elements
elementType
assetsSourceExists
newAssetsSourceUrl

These variable were set in the actionEditMyElement method of the Controller prior to loading the template:
// Set assetId
$variables['assetId'] = $myModel->assetId;

// Set elements
if ($variables['assetId']) {
    $asset = craft()->elements->getElementById($variables['assetId']);
    $variables['elements'] = array($asset);
} else {
    $variables['elements'] = array();
}

// Set elementType
$variables['elementType'] = craft()->elements->getElementType(ElementType::Asset);

// Set assetsSourceExists
$sources = craft()->assets->findFolders();
$variables['assetsSourceExists'] = count($sources);

// Set newAssetsSourceUrl
$variables['newAssetsSourceUrl'] = UrlHelper::getUrl('settings/assets/sources/new');

// Render the template!
$this->renderTemplate('myplugin/_edit', $variables);


Your Controller will probably have something like this in your actionSaveMyElement method:
$myModel->assetId = craft()->request->getPost('assetId', $myModel->assetId);


Your Service file will probably have something like this to save your record:
$assetId = (!empty($myModel->assetId) ? $myModel->assetId[0] : null);
$myRecord->assetId = $assetId;
...
$myRecord->save();


Hope that helps, let me know if I missed anything!

> **Comments:**
> **username_0**: Thanks Lindsey. This is great. I'll need to contemplate this for a moment!  Are you allowing the user to select any asset folder?  Do you have any Asset field settings in your own plugin, or just let the user interact with all asset folders and such via the Asset Element Selector Modal?  
> **username_2**: The way I've got it setup, the user can select from any existing assets folder. I didn't need to lock it to a single folder for this plugin. Other than borrowing the Twig code which triggers the Asset Element Selector Modal, I tried to let Craft deal with the assets as natively as possible.  
> **username_3**: @LindseyD Is there a technical reason you specify it in the php-file, or is it just preference? I tried to keep it as much in Twig as possible: http://craftb.in/xepeqosupa are there any downsides to this?  
> **username_2**: @VictorIn It's a little bit of personal preference... I generally try to put as much logic as reasonably possible into the PHP, to save Twig the hassle of parsing it later.  
> **username_0**: Thanks for the detailed description Lindsey. This came together nicely and I've now got multiple image fields working as needed.  
> **username_2**: Excellent, glad to hear it Ben! There was a lot to include, glad I didn't miss anything. :)  
> **username_1**: @LindseyD wins the internet again.  

---

### Answer by username_1 on 2014-07-28. Score: 2

Looks like you have to do a bit of fudging if your running the $model->validate() function in your controller. assetId has to be set correctly before it jumps over to Service.
I still run the following in my Controller
$reorder = craft()->request->getPost('assetId', $model->assetId);
$model->assetId = (!empty($reorder) ? $reorder[0] : null);

Then I run this in my Service
$record->assetId = $model->assetId;

Tell me if I've missed something here.


---

