Copy images to newly created pages

Hi,
I am working on importing a load of content from a CSV to Kirby. I have created pages, and then done the following to update them from the CSV:

<?php

function csv(string $file, string $length, string $delimiter = ','): array {

  $fh = fopen($file, 'r');
  $header_line = fgets($fh);
  $header_line = str_replace("\xEF\xBB\xBF", '', $header_line);
  $keys = str_getcsv($header_line);
  $csv = [];

  while ($row = fgetcsv($fh, 2000, $delimiter)) {
     $csv[] = array_combine($keys, $row);
  }

  return $csv;

}

$csv      = csv($page->root() . '/businesses.csv', ',');

$kirby->impersonate('kirby');
foreach ($csv as $business) {

  $newPage = page('business-directory')->find($business['slug'])->update([
      'title' => $business['title'],
      'biography' => $business['biography'],
      'phone' => $business['telephone_number'],
      'website' => $business['website'],
  ]);

};
?>

Which as worked great. I now need to get the images into the correct folders, and also into the page content. The image paths in the CSV look like this:

/directory/i-am-an-image.jpg

I have all the images in a directory folder which I can put anywhere that is necessary to copy from.

I am not sure where to start with this.

1 Like

You can do this with file system level method F::move() | Kirby CMS

Hi,

Thanks so much for the pointer, that has got me a lot closer. Each of my new page folders now has the correct image in it. I have also used File::factory to create a .txt for each one, with a uuid.

I am now struggling with the very last part - updating the page content file to link to this file. The field is called thumbnailimage, I have tried the following (using the data from the CSV file):

$kirby->impersonate('kirby');
foreach ($csv as $business) { // This is reading in each entry in the csv

  $imagefile = $business['thumbnail_image']; //this gets the filename e.g. logo.jpg

  $newPage = page('business-directory')->find($business['slug'])->update([
    'thumbnailimage' => page('business-directory')->find($business['slug'])->files()->findBy('filename', $imagefile)
  ]);

};

But the thumbnailimage field is staying empty. I did try adding ->uuid() to the end of the update but that returned the error Call to a member function uuid() on null. The files are definitely there, and match the filename I am using, but I can’t seem to get this to work.

Wondering why you are looping through the csv again. Now that your pages already exist with the files in it, you could loop through the pages instead?

And note that if you are using a files field, you need to store the file uuids as array.

Hi,

Thanks for the quick reply.
I am looping through CSV again as that is the only place where I can find the slug for the page and the filename together, I can’t think of another way to do that.

I have done a dump of

page('business-directory')->find($business['slug'])->files()->findBy('filename', $imagefile)

and it is a file object with everything in there, so I am not sure why

page('business-directory')->find($business['slug'])->files()->findBy('filename', $imagefile)->uuid()

is giving the error Call to a member function uuid() on null

Thanks for the tip about the array - am I going about getting the uuid wrong?

Well, you are in a loop, so it might be that not every page has a file. And if that is the case, then you will of course get this error message. Therefore, you always (always, always) need to check if what you expect to have does actually exist, before you call any member method.

On a side note, uuid() returns a UUID object, not the UUID as string. You would have to call uuid()->id().

In PHP 8 you can prevent the error by using the null-safe operator ?->:

page('business-directory')?->find($business['slug'])?->files()->findBy('filename', $imagefile)?->uuid()?->id()

As you can see from the code snippet above, there are actually several places where the code can potentially throw an error.

Thanks for all your help - the pointer about checking with the null-safe operator was a good reminder to be careful how I write my code!

Every entry had an image, so I assumed I wouldn’t need to check for existence. However what I hadn’t realised is that Kirby had skipped the images with an underscore at the start of their name, and not created a .txt file, so then couldn’t use them on the page. I guess this is to do with how Kirby handles drafts.

Anyway, all working now and thanks for your patient advice as always