After create adding images via update

Hey there.

Im sending appended data over a dropzone form. Now I got a problem with creating the file and adding it to the post.
I’m adding data via fetch over a routing and collection all filesname in an array. (createdImages)
Now when i press once submit all other values are updated but not the images.
When im checking the folder of i see all images and all txt files but the field “image” is empty in this post → When I press a second time the submit button in the fronted it works - image shows no in the backend of the post all files.

                       $createdImages = [];
        
                        foreach($images as $image){
        
                            $filename = $image['name'];
                            $filenameSafeName = F::safeName($filename);
                            $filecaption = $image['caption'];
                            $filepath = $submissionDirectory.'/'.$filenameSafeName;
                            $file = explode( ',', $image['dataURL']);
                            $decode = base64_decode($file[1]);
        
                            $metaCaption = $image['caption'];
        
                            // Meta File
                            $metafilename = $filenameSafeName . '.txt';
                            $metafilepath = $submissionDirectory.'/'.$metafilename;
                            $metacontent['title'] =  $filename;
                            $metacontent['credits'] =  $filecaption;
                            $metacontent['template'] = 'image';

                            // Create Meta
                            F::write($metafilepath, data::encode($metacontent, 'txt'));
        
                            // Create File
                            F::write($filepath, $decode);
        
                            // Build array for update submission
                            $createdImages[] =  $filenameSafeName;
        
                        }
  $submission->update([
                            ...other
                            "image" => $createdImages,
                        ]);

on print_r($createdImages);
i see all images in an array.
Array ( [0] => bildschirmfoto-2022-08-24-um-10.09.46.png )

Bildschirmfoto 2022-08-29 um 18.18.52
Bildschirmfoto 2022-08-29 um 18.19.01

I think the problem is that the $submission page knows nothing of these files without a reload because you are using low level methods to save these files to disk without attaching them to the page inventory. And since Kirby doesn’t store images in a files field that do not exist, nothing is saved.

Why should kirby not knowing my field?

columns:
  - width: 1/3
    sections:
      filesSection:
        type: fields
        fields:
          image:
            label: Bilder
            type: files
            sortable: true

The “problem” is im getting the image as base64 and im creating the image on the fly.
So what I can do there? And why it attached it right on the second submit?

Is there any change to use base64 and $submission->createFile()

It’s not about not knowing your field, is about the page object being aware of the files.

I’d try to load the files via $page->files()->find() after you save them to disk.

So do i need do it after each create? Or after all?

When the files you want to save to the content file are created. You can pass multiple keys to find()

Maybe im doing it wrong?

 // Create Images
                        $submissionDirectory = $submission->contentFileDirectory();
        
                        foreach($images as $image){
        
                            $filename = $image['name'];
                            $filenameSafeName = F::safeName($filename);
                            $filecaption = $image['caption'];
                            $filepath = $submissionDirectory.'/'.$filenameSafeName;
                            $file = explode( ',', $image['dataURL']);
                            $decode = base64_decode($file[1]);
                
                            // Meta File
                            $metafilename = $filenameSafeName . '.txt';
                            $metafilepath = $submissionDirectory.'/'.$metafilename;
                            $metacontent['title'] =  $filename;
                            $metacontent['credits'] =  $filecaption;
                            $metacontent['template'] = 'image';

                            // Create Meta
                            F::write($metafilepath, data::encode($metacontent, 'txt'));
        
                            // Create File
                            F::write($filepath, $decode);
        
                            $submission->files()->find($filenameSafeName);

                        }

Bildschirmfoto 2022-08-29 um 20.21.35
Bildschirmfoto 2022-08-29 um 20.21.45

So if i do.

print_r($createdImages);
$imageItems = $submission->files()->find($createdImages);             
 print_r($imageItems);

I got this back

Array
(
    [0] => bildschirmfoto-2022-08-26-um-07.34.44.png
)
Kirby\Cms\Files Object
(
    [0] => test-projekt-05-08-2022-05-28/bildschirmfoto-2022-08-26-um-07.34.44.png
)

But it not showing the image in the backend.
Bildschirmfoto 2022-08-29 um 20.40.41

columns:
  - width: 1/3
    sections:
      filesSection:
        type: fields
        fields:
          image:
            label: Bilder
            type: files
            sortable: true

Bildschirmfoto 2022-08-29 um 20.41.31

Title: Bildschirmfoto 2022-08-26 um 07.34.44.png

----

Credits: 

----

Template: image

So did you now update the page content with this file data?

$imageItems = $submission->files()->find($createdImages);   
$submission->update([
    'image' => $imageItems->toArray(),
]);

Hmm - i think i got something in the cache before - but now i got on first click this array back
Could it be something cause im local dev?

Array
(
    [0] => bildschirmfoto-2022-08-25-um-09.39.37.png
    [1] => bildschirmfoto-2022-08-25-um-14.28.32.png
    [2] => bildschirmfoto-2022-08-25-um-14.28.35.png
)
Kirby\Cms\Files Object
(
)

and on the second submit click i got this back :confused:

Array
(
    [0] => bildschirmfoto-2022-08-25-um-09.39.37.png
    [1] => bildschirmfoto-2022-08-25-um-14.28.32.png
    [2] => bildschirmfoto-2022-08-25-um-14.28.35.png
)
Kirby\Cms\Files Object
(
    [0] => test-projekt-05-08-2022-05-28/bildschirmfoto-2022-08-25-um-09.39.37.png
    [1] => test-projekt-05-08-2022-05-28/bildschirmfoto-2022-08-25-um-14.28.32.png
    [2] => test-projekt-05-08-2022-05-28/bildschirmfoto-2022-08-25-um-14.28.35.png
)
                        //Images

                        $images = json_decode($data["images"], true);

                        // Create Images
                        $submissionDirectory = $submission->contentFileDirectory();
                        $createdImages = [];
        
                        foreach($images as $image){
        
                            $filename = $image['name'];
                            $filenameSafeName = F::safeName($filename);
                            $filecaption = $image['caption'];
                            $filepath = $submissionDirectory.'/'.$filenameSafeName;
                            $file = explode( ',', $image['dataURL']);
                            $decode = base64_decode($file[1]);
                
                            // Meta File
                            $metafilename = $filenameSafeName . '.txt';
                            $metafilepath = $submissionDirectory.'/'.$metafilename;
                            $metacontent['title'] =  $filename;
                            $metacontent['credits'] =  $filecaption;
                            $metacontent['template'] = 'image';

                            // Create Meta
                            F::write($metafilepath, data::encode($metacontent, 'txt'));
        
                            // Create File
                            F::write($filepath, $decode);
        
                            // Build array for update submission
                            $createdImages[] =  $filenameSafeName;
        
                        }
                        
                        print_r($createdImages);

                        $imageItems = $submission->files()->find($createdImages); 

                        print_r($imageItems);

                        $submission->update([
                            "image" => $imageItems->toArray(),
                        ]);
                              

Maybe I can use there after file create hook?

Ok, here is a basic working example, adapt to your code:

$createdFiles = [];
// the loop here is just for testing purposes
foreach([1,2] as $counter) {
  $b64 = 'iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAYAAAA6/NlyAAAAVElEQVR42u3PAQEAAAgCoPw/2h50IHhApu08EmFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYeHLAikKs4nmjczXAAAAAElFTkSuQmCC';
  $decode = base64_decode($b64);
  $props = [
    'filename' => 'pixel' . $counter .'.jpg',
    'parent'   => $page,
  ];
  // create a file object via the factory method
  $file = File::factory($props);
  // write content to this file
  F::write($file->root(), $decode);
  // add the file to the siblings collection
  $file->siblings()->append($file->id(), $file);
  
  // add id to array of created files
  $createdFiles[] = $file->id();
}

// update page with array of file ids
$page->update(['image' => $createdFiles]); 

I can confirm your code works.
So I though I could pass after i read this → File::factory() | Kirby CMS
more props.

$props = [
                                'filename' => $filenameSafeName,
                                'parent'   => $submission,
                                'template' => 'image',
                                'content' => [
                                    'title' => $filename,
                                    'credits' => $filecaption
                                ]
                            ];

It uploads the file but don’t create the txt file where the content should be based.
I can use a second write function but I thought i could also pass it here - or I’m wrong?

Yes, you can define the content there, but you still have to call

  $file->save($file->content()->toArray());

to save the content txt file to disk.

Ah - I see, I thought save was in the write included :smiley: . Now it works perfect as I want :slight_smile: @texnixe as usual thanks a lot :slight_smile: