<h1>Preamble</h1>

<ul>
<li>Craft 3.1.26</li>
<li>PHP 7.2.8 on Mamp Pro 5.1.1</li>
</ul>

<p>I browsed to my <code>storage/reports</code> folder and made sure in Finder than full read/write privileges are granted.</p>

<h1>What's goin on</h1>

<p>I have a module with a service that has two methods currently:</p>

<ul>
<li><code>generateScriptPdf()</code>: gets information from a given entry and generates a PDF with its data,</li>
<li><code>savePdfAsAsset()</code>: called by the former and takes some data about that PDF file and uses it to create a new Asset.</li>
</ul>

<p><code>generateScriptPdf()</code> is working fine and it saves the PDF in <code>storage/reports</code>.</p>

<p><code>savePdfAsAsset()</code>, however, responds with a 500 status and this error message:</p>

<pre><code>PHP Warning 'yii\base\ErrorException' with message 'unlink(/Users/steven/Code/vetscripts/storage/reports/): Operation not permitted' 
</code></pre>

<h1>My real question</h1>

<p>This is my first time trying to generate a file and then save/upload that file as a Craft Asset, so I'm sure I'm doing something a little off and I know that right now my code is not very defensive. <strong>Are there any important parts or steps I am missing when trying to save my file as an Asset?</strong></p>

<h1>Service</h1>

<pre class="lang-php prettyprint-override"><code>&lt;?php
namespace modules\vetscripts\services;

use Craft;
use craft\elements\Asset;
use craft\elements\Entry;
use craft\base\Component;
use Fpdf\Fpdf;

class Scripts extends Component
{
    /**
     * Generate Script PDF
     *
     * @param $scriptId
     * @return array
     */
    public function generateScriptPdf($scriptId)
    {
        $script = Entry::find()
            -&gt;section('scripts')
            -&gt;id($scriptId)
            -&gt;one();

        $pdf = new Fpdf('P','in','Letter');
        $pdf-&gt;SetFont('Times');
        $pdf-&gt;AddPage();
        $pdf-&gt;Cell(40,10,$script-&gt;title);

        $filepath = CRAFT_BASE_PATH . '/storage/reports/';
        if (!file_exists($filepath)) {
            mkdir($filepath, 0777, true);
        }
        $filename = "Script_Report_$script-&gt;title.pdf";

        $success = $pdf-&gt;Output('F', $filepath.$filename, false);
        if (!$success) {
            Craft::error("Could not save the report $filepath.$filename", __METHOD__);
        }

        $this-&gt;savePdfAsAsset($filepath, $filename, 7, 3);

        return [
            'success' =&gt; true
        ];
    }

    public function savePdfAsAsset($tempPath, $filename, $folderId, $volumeId)
    {
        $asset = new Asset();
        $asset-&gt;tempFilePath = $tempPath;
        $asset-&gt;filename = $filename;
        $asset-&gt;newFolderId = $folderId;
        $asset-&gt;volumeId = $volumeId;
        $asset-&gt;avoidFilenameConflicts = true;
        $asset-&gt;setScenario(Asset::SCENARIO_CREATE);

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

        if (!$result) {
            return ['message' =&gt; 'Error'];
        }

        return ['success' =&gt; true];
    }
}
</code></pre>

<h1>Stack trace</h1>

<pre><code>#0 /Users/steven/Code/vetscripts/vendor/yiisoft/yii2/helpers/BaseFileHelper.php(407): ::unlink('???')
#1 /Users/steven/Code/vetscripts/vendor/craftcms/cms/src/elements/Asset.php(1516): yii\helpers\BaseFileHelper::unlink('???')
#2 /Users/steven/Code/vetscripts/vendor/craftcms/cms/src/elements/Asset.php(1275): craft\elements\Asset-&gt;_relocateFile()
#3 /Users/steven/Code/vetscripts/vendor/craftcms/cms/src/services/Elements.php(515): craft\elements\Asset-&gt;afterSave('???')
#4 /Users/steven/Code/vetscripts/modules/craft-vetscripts/src/services/Scripts.php(82): craft\services\Elements-&gt;saveElement('???', '???', '???')
#5 /Users/steven/Code/vetscripts/modules/craft-vetscripts/src/services/Scripts.php(65): modules\vetscripts\services\Scripts-&gt;savePdfAsAsset('???', '???', '???', '???')
#6 /Users/steven/Code/vetscripts/modules/craft-vetscripts/src/controllers/ScriptsController.php(46): modules\vetscripts\services\Scripts-&gt;generateScriptPdf('???')
#7 /Users/steven/Code/vetscripts/vendor/yiisoft/yii2/base/InlineAction.php(57): modules\vetscripts\controllers\ScriptsController-&gt;actionPdf()
#8 /Users/steven/Code/vetscripts/vendor/yiisoft/yii2/base/InlineAction.php(57): ::call_user_func_array:{/Users/steven/Code/vetscripts/vendor/yiisoft/yii2/base/InlineAction.php:57}('???', '???')
#9 /Users/steven/Code/vetscripts/vendor/yiisoft/yii2/base/Controller.php(157): yii\base\InlineAction-&gt;runWithParams('???')
#10 /Users/steven/Code/vetscripts/vendor/craftcms/cms/src/web/Controller.php(109): modules\vetscripts\controllers\ScriptsController-&gt;runAction('???', '???')
#11 /Users/steven/Code/vetscripts/vendor/yiisoft/yii2/base/Module.php(528): modules\vetscripts\controllers\ScriptsController-&gt;runAction('???', '???')
#12 /Users/steven/Code/vetscripts/vendor/craftcms/cms/src/web/Application.php(297): craft\web\Application-&gt;runAction('???', '???')
#13 /Users/steven/Code/vetscripts/vendor/craftcms/cms/src/web/Application.php(565): craft\web\Application-&gt;runAction('???', '???')
#14 /Users/steven/Code/vetscripts/vendor/craftcms/cms/src/web/Application.php(281): craft\web\Application-&gt;_processActionRequest('???')
#15 /Users/steven/Code/vetscripts/vendor/yiisoft/yii2/base/Application.php(386): craft\web\Application-&gt;handleRequest('???')
#16 /Users/steven/Code/vetscripts/web/index.php(21): craft\web\Application-&gt;run()
#17 {main}
</code></pre>

CC BY-SA 4.0
2019-05-20T12:53:58.417Z
Your sending the folder path without the filename to the `savePdfAsAsset` method. If you add the filename to the path, your example should work.
Fred Carlsen
CC BY-SA 4.0
2019-05-20T15:24:23.563Z
Awesome, it works now! However two copies of the pdf are saved as an asset with one of them having a datetime stamp appended to the filename, e.g. `Script_Report_8804_190520_152057.pdf`. Any idea why that might be happening? In any case, post an answer and I'll mark it as accepted. Thanks!
Steven Thate
<plugin-development><assets><modules><pdf><files>
How do I correctly upload a new Asset from a temp file I generated from a service method?
# How do I correctly upload a new Asset from a temp file I generated from a service method?

(Asked by: username_0 on 2019-05-19)

Preamble

Craft 3.1.26
PHP 7.2.8 on Mamp Pro 5.1.1

I browsed to my storage/reports folder and made sure in Finder than full read/write privileges are granted.
What's goin on
I have a module with a service that has two methods currently:

generateScriptPdf(): gets information from a given entry and generates a PDF with its data,
savePdfAsAsset(): called by the former and takes some data about that PDF file and uses it to create a new Asset.

generateScriptPdf() is working fine and it saves the PDF in storage/reports.
savePdfAsAsset(), however, responds with a 500 status and this error message:
PHP Warning 'yii\base\ErrorException' with message 'unlink(/Users/steven/Code/vetscripts/storage/reports/): Operation not permitted' 

My real question
This is my first time trying to generate a file and then save/upload that file as a Craft Asset, so I'm sure I'm doing something a little off and I know that right now my code is not very defensive. Are there any important parts or steps I am missing when trying to save my file as an Asset?
Service
section('scripts')
            ->id($scriptId)
            ->one();

        $pdf = new Fpdf('P','in','Letter');
        $pdf->SetFont('Times');
        $pdf->AddPage();
        $pdf->Cell(40,10,$script->title);

        $filepath = CRAFT_BASE_PATH . '/storage/reports/';
        if (!file_exists($filepath)) {
            mkdir($filepath, 0777, true);
        }
        $filename = "Script_Report_$script->title.pdf";

        $success = $pdf->Output('F', $filepath.$filename, false);
        if (!$success) {
            Craft::error("Could not save the report $filepath.$filename", __METHOD__);
        }

        $this->savePdfAsAsset($filepath, $filename, 7, 3);

        return [
            'success' => true
        ];
    }

    public function savePdfAsAsset($tempPath, $filename, $folderId, $volumeId)
    {
        $asset = new Asset();
        $asset->tempFilePath = $tempPath;
        $asset->filename = $filename;
        $asset->newFolderId = $folderId;
        $asset->volumeId = $volumeId;
        $asset->avoidFilenameConflicts = true;
        $asset->setScenario(Asset::SCENARIO_CREATE);

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

        if (!$result) {
            return ['message' => 'Error'];
        }

        return ['success' => true];
    }
}

Stack trace
#0 /Users/steven/Code/vetscripts/vendor/yiisoft/yii2/helpers/BaseFileHelper.php(407): ::unlink('???')
#1 /Users/steven/Code/vetscripts/vendor/craftcms/cms/src/elements/Asset.php(1516): yii\helpers\BaseFileHelper::unlink('???')
#2 /Users/steven/Code/vetscripts/vendor/craftcms/cms/src/elements/Asset.php(1275): craft\elements\Asset->_relocateFile()
#3 /Users/steven/Code/vetscripts/vendor/craftcms/cms/src/services/Elements.php(515): craft\elements\Asset->afterSave('???')
#4 /Users/steven/Code/vetscripts/modules/craft-vetscripts/src/services/Scripts.php(82): craft\services\Elements->saveElement('???', '???', '???')
#5 /Users/steven/Code/vetscripts/modules/craft-vetscripts/src/services/Scripts.php(65): modules\vetscripts\services\Scripts->savePdfAsAsset('???', '???', '???', '???')
#6 /Users/steven/Code/vetscripts/modules/craft-vetscripts/src/controllers/ScriptsController.php(46): modules\vetscripts\services\Scripts->generateScriptPdf('???')
#7 /Users/steven/Code/vetscripts/vendor/yiisoft/yii2/base/InlineAction.php(57): modules\vetscripts\controllers\ScriptsController->actionPdf()
#8 /Users/steven/Code/vetscripts/vendor/yiisoft/yii2/base/InlineAction.php(57): ::call_user_func_array:{/Users/steven/Code/vetscripts/vendor/yiisoft/yii2/base/InlineAction.php:57}('???', '???')
#9 /Users/steven/Code/vetscripts/vendor/yiisoft/yii2/base/Controller.php(157): yii\base\InlineAction->runWithParams('???')
#10 /Users/steven/Code/vetscripts/vendor/craftcms/cms/src/web/Controller.php(109): modules\vetscripts\controllers\ScriptsController->runAction('???', '???')
#11 /Users/steven/Code/vetscripts/vendor/yiisoft/yii2/base/Module.php(528): modules\vetscripts\controllers\ScriptsController->runAction('???', '???')
#12 /Users/steven/Code/vetscripts/vendor/craftcms/cms/src/web/Application.php(297): craft\web\Application->runAction('???', '???')
#13 /Users/steven/Code/vetscripts/vendor/craftcms/cms/src/web/Application.php(565): craft\web\Application->runAction('???', '???')
#14 /Users/steven/Code/vetscripts/vendor/craftcms/cms/src/web/Application.php(281): craft\web\Application->_processActionRequest('???')
#15 /Users/steven/Code/vetscripts/vendor/yiisoft/yii2/base/Application.php(386): craft\web\Application->handleRequest('???')
#16 /Users/steven/Code/vetscripts/web/index.php(21): craft\web\Application->run()
#17 {main}

**Tags:** plugin-development, assets, modules, pdf, files

> **Comments:**
> **username_1**: Your sending the folder path without the filename to the `savePdfAsAsset` method. If you add the filename to the path, your example should work.  
> **username_0**: Awesome, it works now! However two copies of the pdf are saved as an asset with one of them having a datetime stamp appended to the filename, e.g. `Script_Report_8804_190520_152057.pdf`. Any idea why that might be happening? In any case, post an answer and I'll mark it as accepted. Thanks!  

---

## 0 answers

