<p>Not an answer directly to your question but a general function to upload an asset in PHP. In my case <code>$file</code> is an uploaded file in the <code>$_FILES</code> array. You can <a href="https://stackoverflow.com/questions/3938534/download-file-to-server-from-url">download a file per url</a> and insert it's <code>tmp_name</code> and <code>name</code> manually</p>

<pre><code>/**
 * Upload a file
 *
 * @param $file
 * @return int|null|string
 * @throws \Throwable
 * @throws \craft\errors\ElementNotFoundException
 * @throws \yii\base\Exception
 */
public function uploadImage($file)
{
    $assets = Craft::$app-&gt;getAssets();
    $folderId = 1; //&lt;- insert your folder id

    /** @var \craft\models\VolumeFolder $folder */
    $folder = $assets-&gt;findFolder(['id' =&gt; $folderId]);

    $asset = new Asset();
    $asset-&gt;tempFilePath = $file['tmp_name'];
    $asset-&gt;filename = $file['name'];
    $asset-&gt;newFolderId = $folder-&gt;id;
    $asset-&gt;volumeId = $folder-&gt;volumeId;
    $asset-&gt;avoidFilenameConflicts = true;
    $asset-&gt;setScenario(Asset::SCENARIO_CREATE);

    $result = Craft::$app-&gt;getElements()-&gt;saveElement($asset);

    // In case of error, let user know about it.
    if ($result === false) {
        throw new Exception('Error while upload asset');
    }

    return $asset-&gt;id;
}
</code></pre>

CC BY-SA 3.0
2018-03-27T11:43:14.727Z
2018-03-27T11:43:14.727Z
Robin Schambach
<p>I ran into this problem too, and isolated it to AssetLocationValidator.php on line 110 or so.  </p>

<pre><code>// If nothing has changed, just null-out the newLocation attribute
if (!$hasNewFolderId &amp;&amp; !$hasNewFilename) {
    $model-&gt;$attribute = null;

    return;
}
</code></pre>

<p>but the problem is, having a null newLocation throws a validation error.</p>

<p>My solution was to set the folderId as 0, and the newFolderId as the destination folder.  This keeps the "null out the newLocation..." from firing, and keeps the newLocation populated.</p>

<pre><code>$asset = new Asset();
$asset-&gt;tempFilePath = $tempPath;
$asset-&gt;filename = $filename;
$asset-&gt;folderId = 0;
$asset-&gt;newFolderId = $folder-&gt;id;
$asset-&gt;volumeId = $folder-&gt;volumeId;
$asset-&gt;avoidFilenameConflicts = true;
$asset-&gt;setScenario(Asset::SCENARIO_CREATE);

$result = Craft::$app-&gt;getElements()-&gt;saveElement($asset);
</code></pre>

CC BY-SA 4.0
2018-07-02T17:53:29.263Z
2018-07-02T17:53:29.263Z
Mark Middleton
<p>I'm working on a plugin in Craft 3 that is fetching a file reference (URL) via an API.</p>

<p>I want to fetch the file and save it locally as an Asset. I've tried to do this via <code>Craft::$app-&gt;getElements()-&gt;saveElement()</code> but am getting the following error:</p>

<p><code>New Location cannot be blank.</code></p>

<p>Any thoughts on this issue or where to dig a bit deeper to resolve?</p>

<p>Cole </p>

<plugin-development><assets><craft3><plugin-elementapi>
Saving asset programatically, eg via API
# Saving asset programatically, eg via API

(Asked by: username_0 on 2018-03-27)

I'm working on a plugin in Craft 3 that is fetching a file reference (URL) via an API.

I want to fetch the file and save it locally as an Asset. I've tried to do this via `Craft::$app->getElements()->saveElement()` but am getting the following error:

`New Location cannot be blank.`

Any thoughts on this issue or where to dig a bit deeper to resolve?

Cole

**Tags:** plugin-development, assets, craft3, plugin-elementapi


---

## 2 answers

### Answer by username_1 on 2018-03-27. Score: 4

Not an answer directly to your question but a general function to upload an asset in PHP. In my case $file is an uploaded file in the $_FILES array. You can download a file per url and insert it's tmp_name and name manually
/**
 * Upload a file
 *
 * @param $file
 * @return int|null|string
 * @throws \Throwable
 * @throws \craft\errors\ElementNotFoundException
 * @throws \yii\base\Exception
 */
public function uploadImage($file)
{
    $assets = Craft::$app->getAssets();
    $folderId = 1; //<- insert your folder id

    /** @var \craft\models\VolumeFolder $folder */
    $folder = $assets->findFolder(['id' => $folderId]);

    $asset = new Asset();
    $asset->tempFilePath = $file['tmp_name'];
    $asset->filename = $file['name'];
    $asset->newFolderId = $folder->id;
    $asset->volumeId = $folder->volumeId;
    $asset->avoidFilenameConflicts = true;
    $asset->setScenario(Asset::SCENARIO_CREATE);

    $result = Craft::$app->getElements()->saveElement($asset);

    // In case of error, let user know about it.
    if ($result === false) {
        throw new Exception('Error while upload asset');
    }

    return $asset->id;
}


---

### Answer by username_2 on 2018-07-02. Score: 1

I ran into this problem too, and isolated it to AssetLocationValidator.php on line 110 or so.  
// If nothing has changed, just null-out the newLocation attribute
if (!$hasNewFolderId && !$hasNewFilename) {
    $model->$attribute = null;

    return;
}

but the problem is, having a null newLocation throws a validation error.
My solution was to set the folderId as 0, and the newFolderId as the destination folder.  This keeps the "null out the newLocation..." from firing, and keeps the newLocation populated.
$asset = new Asset();
$asset->tempFilePath = $tempPath;
$asset->filename = $filename;
$asset->folderId = 0;
$asset->newFolderId = $folder->id;
$asset->volumeId = $folder->volumeId;
$asset->avoidFilenameConflicts = true;
$asset->setScenario(Asset::SCENARIO_CREATE);

$result = Craft::$app->getElements()->saveElement($asset);


---

