• 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?


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()

        $pdf = new Fpdf('P','in','Letter');

        $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;

        $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}
  • 2
    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 May 20 at 12:53
  • 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 May 20 at 15:24

Your Answer

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

Browse other questions tagged or ask your own question.