Problems to update a files field with an image

Hello,

I try to scrap a json file and CLI import as pages in Kirby V4.
the import works like a charme but I have a problem to fill a files field with an image.

 foreach($news['images'] as $newsImageURL){
                    // cURL verwenden, um nur die HTTP-Header zu erhalten
                    $newsImageDownload = curl_init($newsImageURL);
                    curl_setopt($newsImageDownload, CURLOPT_RETURNTRANSFER, true);
                    $newsImageData = curl_exec($newsImageDownload);

                    // Hole den HTTP-Header
                    curl_close($newsImageDownload); 

                    if ($newsImageData === false) {
                        $cli->dump('Fehler beim Abrufen des Bildes.');
                        continue;
                    }

                    $tempFile = tempnam(sys_get_temp_dir(), 'img');
                    file_put_contents($tempFile, $newsImageData);

                    // MIME-Typ mit finfo_file() ermitteln
                    $finfo = finfo_open(FILEINFO_MIME_TYPE);
                    $mimeType = finfo_file($finfo, $tempFile);
                    finfo_close($finfo);

                    // Extrahiere den MIME-Typ aus den HTTP-Headern
                    function getExtensionFromMimeType($mimeType) {
                        $mimeTypes = [
                            'image/jpeg' => 'jpg',
                            'image/png' => 'png',
                            'image/gif' => 'gif',
                            'image/webp' => 'webp',
                            'image/svg+xml' => 'svg',
                            'image/bmp' => 'bmp',
                            'image/tiff' => 'tiff',
                        ];

                        return isset($mimeTypes[$mimeType]) ? $mimeTypes[$mimeType] : 'jpg'; // Standard auf jpg setzen
                    }

                    $newsImageFiletype = getExtensionFromMimeType($mimeType);

                    try{
                        $imageCreation = File::create([
                            'source' => $tempFile,
                            'parent' => $newsEntry, 
                            'filename' => $newsAuthorName.'-'.$news['postedAtISO'].'_'.$n.'.'.$newsImageFiletype
                        ]);

                        // Überprüfen, ob das Bild erfolgreich erstellt wurde
                        if (!$imageCreation) {
                            $cli->dump('Fehler beim Erstellen des Bildes.');
                            continue;
                        }

                        $cli->dump($imageCreation);

                        $n++;

                        $newsEntry->update([
                           'newsarticleheaderimage'	=> $imageCreation->filename(),
                        ]);

                        // Temporäre Datei löschen
                        unlink($tempFile);

                    } catch (Exception $e) {
                        $cli->dump('Fehler beim Erstellen der Datei: ' . $e->getMessage());
                        continue;
                    }
                }
          newsarticleheaderimage:
            label: Headerimage for the Newsarticle
            type: files
            multiple: false
            layout: cards
            query: page.images

I have also tried to use $imageCreation->url()or [$imageCreation]. The image is in the created page folder but will not be added to the field in the page txt file.

What did I wrong?

Best

You need to store the files as array, ie. either the file id or the file uuid (by default, the files field stores the uuids).

Thanks for your answer.
I used now ['newsarticleheaderimage' => $imageCreation->uuid()]but now I have to different UUIDs. The one which is printen inside the field is another than which is printed in the image txt file. Could it be that I recreate the image on the $imageCreation call in the fieldupdate. So that I have a new object?

If the file already exists, the uuid should not be recreated. However, instead of passing the uuid object, you need to convert to string, i.e. $file->uuid()->toString().

The file doesn’t exist before. It was only a idea why I got two different uuids.
The toString()change also nothing.

And agin the complete CLI importscript. The break on the end is there only for development.
The imageimport is at the end of the script. Hopefull someone see something or had an Idea whats my mistake is.

<?php

return [
	'description' => 'Import Linkedin News',
	'args' => [],
	'command' => static function ($cli): void {
        $jsonurl = $cli->prompt('Please enter a json url:');
        $kirby = $cli->kirby();
        $kirby->impersonate('kirby');

        //$jsonfile = 'dataset.json';
        //$json = Json::read($jsonfile);
        
        $json = Remote::get($jsonurl)->json();
        //$cli->dump($json); exit;

        $newsPages = $kirby->page('news');
               
        foreach($json as $news){
            //finetuning output content
            $newsAuthorName = str_replace(' ','', strtolower($news['authorName']));
            $creationDate = date('Y-m-d', strtotime($news['postedAtISO']));
            $link = '(link: '. $news['url'] .' text: › Linkedin Reference target: _blank rel: nofollow)';
            
            //linkedin Hashtags aus dem Text löschen
            $newsText = preg_replace('/\s?#\w+/', '', $news['text']);

            //Generate Tags Array
            $nameArray = [$news['author']['name'],$news['author']['universalName']];

            preg_match_all('/#\w+/', $news['text'], $hashes);

            $hashesWithout = array_map(function($tag) {
                return ltrim($tag, '#');
            }, $hashes[0]);

            $allTags = array_merge($hashesWithout, $nameArray);
            $allTagsLower = array_map('strtolower', $allTags);
            $newsTagsArray = array_unique($allTagsLower);
            $newsTags =  implode(', ', $newsTagsArray);

            //build the pageObject
            $newsEntry = $newsPages->createChild([
                'slug' => $newsAuthorName.'-'.$news['postedAtISO'],
                'draft' => false,
                'template' => 'news-article',
                'content' => [
                    'title' => 'Linkedin News from '.$news['authorName'] . ' on ' .$creationDate,
                    //'newsarticleheaderimage' => $newsImage[0],
                    'newsarticleheaderimage' => '',
                    'newsarticletags' => $newsTags, 
                    'date' => $creationDate,
                    'newsarticleauthor' => '',
                    'newsarticletext' => $newsText . $link,
                    'loginpage' => 'true',
                    'setallowedroles' => 'Admin, Investors', 
                    'logintarget' => '',
                    'titleoverride' => '', 
                    'showshare' => 'true',
                    'showfooterdivider' => 'false',
                    'startwhitenav' => 'false',
                ]
            ]);

            $n = 1;

            foreach($news['images'] as $newsImageURL){
                // cURL verwenden, um nur die HTTP-Header zu erhalten
                $newsImageDownload = curl_init($newsImageURL);
                curl_setopt($newsImageDownload, CURLOPT_RETURNTRANSFER, true);
                $newsImageData = curl_exec($newsImageDownload);

                // Hole die HTTP-Header
                curl_close($newsImageDownload); 

                if ($newsImageData === false) {
                    $cli->dump('Fehler beim Abrufen des Bildes.');
                    continue;
                }

                $tempFile = tempnam(sys_get_temp_dir(), 'img');
                file_put_contents($tempFile, $newsImageData);

                // MIME-Typ mit finfo_file() ermitteln
                $finfo = finfo_open(FILEINFO_MIME_TYPE);
                $mimeType = finfo_file($finfo, $tempFile);
                finfo_close($finfo);

                // Extrahiere den MIME-Typ aus den HTTP-Headern
                function getExtensionFromMimeType($mimeType) {
                    $mimeTypes = [
                        'image/jpeg' => 'jpg',
                        'image/png' => 'png',
                        'image/gif' => 'gif',
                        'image/webp' => 'webp',
                        'image/svg+xml' => 'svg',
                        'image/bmp' => 'bmp',
                        'image/tiff' => 'tiff',
                    ];

                    return isset($mimeTypes[$mimeType]) ? $mimeTypes[$mimeType] : 'jpg'; // Standard auf jpg setzen
                }

                $newsImageFiletype = getExtensionFromMimeType($mimeType);

                try{
                    $imageCreation = File::create([
                        'source' => $tempFile,
                        'parent' => $newsEntry, 
                        'filename' => $newsAuthorName.'-'.$news['postedAtISO'].'_'.$n.'.'.$newsImageFiletype
                    ]);

                    // Überprüfen, ob das Bild erfolgreich erstellt wurde
                    if (!$imageCreation) {
                        $cli->dump('Fehler beim Erstellen des Bildes.');
                        continue;
                    }

                    $newsEntry->update([
                       'newsarticleheaderimage'	=> [$imageCreation->uuid()->toString()],
                    ]);

                    // Temporäre Datei löschen
                    unlink($tempFile);

                    $n++;

                } catch (Exception $e) {
                    $cli->dump('Fehler beim Erstellen der Datei: ' . $e->getMessage());
                    continue;
                }
            }

            break;
        }

        $cli->success('linkedin News imported!');
    }
];

Hm, you are updating one page with possibly multiple images, but the way you do it, every new image file will overwrite the value in the files field with the latest value. So to make this work properly with multiple images, you would have to merge the existing values with the new ones.

But it exists at the time you create it. And the File::create() command should generate a file with a UUID.

Okay, I understand that I have actually a mistake if it have multiple images. But I don‘t understand further why I get another UUID on the field update. In the image .txt is stored another as in the field of the page .txt.
I test actually the script with an entry with one image.

Best

Is there an easy way to test your code? Like, can you share a JSON file with some data (via PM)?