Optional file upload

Hi,

I have a form and last option in the form is to upload a file. When I attach file, everything works. When I do not attach file, I always get this error:

Uploaded file is saved in my src/uploads folder and the path to the file is saved in my varchar(255) field.

Validator for the field with path is set as as follows:

    > $validator
        ->scalar('report_scan')
        ->maxLength('report_scan', 255)
        ->allowEmptyString('report_scan');

Is there any way to change validator in the way that it would allow optional file upload?

This is part of my controller which is handling the file upload:

Thnak you a lot.

try ->allowEmptyFile() instead of ->allowEmptyString()

Thank you @KevinPfeifer . Unfortunately, it did not help. The same error continues to appear:

Untitled

When I attach file, I have no problem and new record is created.

In the past, in other project (CakePHP 4.1), I did not have any problem with similar job. When user dod not attach the file, the record was created without file. Nevertheles, even in that project the same error occured when user edited the record in edit action and did not upload new file. Then, I fixed this by loading the old file path and saving it again as new record.

Does anybody has working entity/table/controller and action with optional file upload? Could you please upload the corresponding lines here? I do not know where I am making mistake and I am unable to find it.

Thank you very much in advance.

I tried to remove validator for my file upload field, i.e.:

echo $this->Form->control(‘report_scan’, [‘type’ => ‘file’]);

In my MeasurementsTable.php I set:

$validator->remove(‘report_scan’);

Nevertheless, I am still getting the same error when I submit my form with empty file:

(click to enlarge the picture)

Maybe it is a bug … please can anyone help me with this? Today it is my 3rd day with this error and I desparately need help.

Finally, if I comment this in marshal.php:

I get this error:

Why cake can not convert empty object of Laminas\Diactoros\UploadedFile into a empty string?

Any idea how to fix this issue please?

Aren’t scalar and maxLength also both things that would look for their inputs to be strings, not file objects? What are those trying accomplish for you?

Thank you @Zuluru. Yes, they are but Inthoyght they verify that filename and the length of the filename have to be verified before saving them into DB columb report_scan, which is varchar(255). When I attach a file I do not encounter with any problem and the file upload works properly.

Nevertheless, this error occurs also when I turn off validator

$validator->remove(‘report_scan’);

for the report_scan column.

Simply, the problem is that the CakePHP tries to convert empty Laminas file object into a string (see my last post with screenshots).

I believe that CakePHP should skip this check for empty Laminas objects and save nothing into the report_scan column.

So what to do with this? Is there any simple solution?

Are you saying that simply using $validator->allowEmptyFile('report_scan'), it still causes the error?

Unfortunately yes. It looks like a bug. In other cske project with cake 4.1, the same code works. In the latest cake not.

So the report_scan column of your table is a varchar I guess?

I just tried the following in the latest CakePHP version:

Created a migration with a simple table containing just a text column and timestamps:

<?php
declare(strict_types=1);

use Migrations\AbstractMigration;

class Test extends AbstractMigration
{
    public function change(): void
    {
        $table = $this->table('test');
        $table->addColumn('myfile', 'text');
        $table->addTimestamps('created', 'modified');
        $table->save();
    }
}

baked all the CRUD operations with

bin/cake bake all test

The I adjusted the templates/Test/add.php to have

<?= $this->Form->create($test) ?>
<fieldset>
    <legend><?= __('Add Test') ?></legend>
    <?php
        echo $this->Form->control('myfile', [
            'type' => 'file'
        ]);
    ?>
</fieldset>
<?= $this->Form->button(__('Submit')) ?>
<?= $this->Form->end() ?>

and finally I adjusted the Model/Table/TestTable.php to have

    public function validationDefault(Validator $validator): Validator
    {
        $validator
            ->allowEmptyFile('myfile');

        return $validator;
    }

Which now lets me create a new Test entity via http://localhost:8765/test/add without providing a file.

So I am not able to reproduce your problem.

Thank you very much @KevinPfeifer . My code is written in similar manner. I will create new Cake installation and let you all know. Once more thank you!

Once more thank you for your help @KevinPfeifer. I created new cakephp installation, new DB test with varchar(255) filed named myfile and baked templates exactly as you did.

At the first sight your code is working but the result of form submit is that I have only file name added into my database.

I do not know how to get uploaded file object, because your add.php template does not set form type as required here in Cookbook: Form - 4.x

echo $this->Form->create($document, [‘enctype’ => ‘multipart/form-data’]);
// OR
echo $this->Form->create($document, [‘type’ => ‘file’]);

When I change form type, like this:

and do file upload and submit the form, I immediately get the same error. The error is shown not only when I am not attaching the file, but also in case when I attach file.

So please could you try to change form type in your code and tell me, if you get the same error?

Thank you very much.

I know what you are trying to achieve but again: You can’t save files inside databases. You can only create entries inside your table to reference the files which you save on your server.

I’d recommend you take a look at GitHub - brandcom/cakephp-assets: Backend Asset Management for CakePHP which is a ready made, very simple asset management.

If you want to have even more control you can build your own asset management based upon Examples — CakePHP Upload (which the cakephp-assets plugin from above also uses) but doesn’t contain any tables or logic since you have to build it yourself)

Hope this helps you get to the result you desire.

Thank you very much @KevinPfeifer again. I can upload the file easily when the “add form field” has other name then my DB column, then I can get the file like e.g.

In my add.php

<?= $this->Form->create($measurement, ['id'=>'measurement-form']) ?>


echo $this->Form->control(‘report_scan_add_form_field’, [‘type’ => ‘file’]);

<?= $this->Form->button(__('Submit')) ?> <?= $this->Form->end() ?>

In my MeasurementsController.php


$measurement = $this->Measurements->patchEntity($measurement, >$this->request->getData());
$attachment = $this->request->getUploadedFile(‘report_scan_add_form_field’);

Then I will move file to destination folder, extract file name from my $attachment laminas object and save it into

$measurement->report_scan

varchar(255) column so that I could later build the path to the file.

Nevertheless, is this case I can not use validator to validate file properties becuase the add form field differs from the name of the column for file name / path in the DB.

So I was curious and wanted to find proper way how to upload the file in CakePHP without using any plugin.

Obviously, CakePHP is trying to convert the uploaded object into the string before I start to work with it in the controller.

Once more thank you very much for your help. You helped me a lot and I appreciate it very much. I hope to fix this problem after studying the links you sent.