Creating Virtual Pages with Virtual Files at the same time

I’ve been using page model to create children that are virtual pages pulled from a CSV. It works great. But I’d like to at the same time create virtual files, so I can see the images in the panel.


class mygalleryPage extends Page
{

    public function subpages()
        {
            return Pages::factory($this->inventory()['children'], $this);
        }

    public function children()
    {
        $children = [];
        if ($this->hasFiles()) {
            $csv      = csv($this->root() . '/myCSV.csv', ',');
                $children = array_map(function ($entrant) {

                    $slug = Str::slug($entrant['lastname'] );
                    $page = $this->subpages()->find($slug);
                    return [
                        'slug'     => $slug,
                'template' => 'my-entry',
                'model'    => 'my-entry',
                'num'      => 0,
                'content'  => [
                    'fullname' => $entrant['fullname'],
                    'category' => $entrant['category'],
                    'credit1' => $entrant['credit1'],
                    'image1' => $entrant['image1'],
                    'image2' => $entrant['image2'],
                    'image3' => $entrant['image3'],
                ]
                    ];
                }, $csv);

                return Pages::factory($children, $this);
        } 
        else {
            return $this->children = Pages::factory($this->inventory()['children'], $this);
        }
    }

}

Do i need to create a new model for the virtual files? Or can I append to this page model?

Thanks for any help!

This should help: Virtual files | Kirby CMS You can define them in the same child page model. It should actually also be possible to add the files via the files key in your children method.

So I was able get the virtual images to work on that sample. But I’m trying to update another site and running into trouble. In my CSV, each entry has multiple image files.
I can return all the images in the entire CSV. Or I can return just the first image.

<?php

class AnnualEntryPage extends Page
{

    public function files()
    {

        if ($this->files !== null) {
             return $this->files;
           }

        $csv = csv($this->parent()->root() . '/myCSV.csv', ',');

        $files = array_map(function ($entry) {
          $url = 'https://url.com';

                
               return [
                    [
                    'filename' => $entry['image1'],
                    'url' => $url . $entry['image1'],
                    'template' => 'virtual-file',
                    'content'  => [
                        'alt' => 'Artwork by ' . $entry['fullname'] ,
                        'idno' => $entry['idno']
                        ]
                    ],
                    [
                    'filename' => $entry['image2'],
                    'url' => $url . $entry['image2'],
                    'template' => 'virtual-file',
                    'content'  => [
                        'alt' => 'Artwork by ' . $entry['fullname'],
                        'idno' => $entry['idno']
                    ],
                    ]

                ];
            


        }, $csv);

        return $this->files = Files::factory($files, $this);
    }

}

What is your actual question?

Sorry I wasn’t clear. I am unable to get the multiple images by $entry. I either get the first image of the $entry or I get images from all the $entry in the csv file.

I hope this is more clear.

How are the images stored in your csv file?

it’s stored as the file name:

image1: MyImage1.jpg.
image2: MyImage2.jpg.

So multiple image columns per row?

yes, exactly!

From this array, you have to get the item that corresponds to the current page. Then get the files from this item.

Yes, but that is where I am being tripped up. I try to get the item that corresponds to the page, but it doesn’t work.

$csv = csv($this->parent()->root() . '/myCSV.csv', ',');
$csv = array_map(function(&$item) {
    $item['lastname'] = Str::slug($item['lastname']);
    return $item;
}, $csv);
// find the entry with the page id
$key = array_search($page->id(), array_column($csv, 'lastname'));
$pageData = $csv[$key] ?? null;
dump($pageData);

Sorry for dragging this out. I tried out the code above and it did not work. But it gave me something to work form.

I made changes so the code reads as this:

 $csv = csv($this->parent()->root() . '/annual.csv', ',');

        $csv = array_map(function(&$item) {
       $item['id'] = Str::slug($item['id'] ;
       $imgs = array($item['image1'],$item['image2'],$item['image3']);
       
          return 
            [
                'slug' => $item['id'],
                'filename' => $imgs,
                'template' => 'virtual-file',
                'content' => [
                        'alt' => 'Artwork by ' . $item['firstname'] . " " . $item['lastname'],
                    ]
        ];
        
    }, $csv);
// find the entry with the page id
$key = array_search($this->id(), array_column($csv, 'id'));
$pageData = $csv[$key] ?? null;
dump($pageData);

      return $this->files = Files::factory($csv, $this);

Here is what I get on the dump:

The JSON response could not be parsed 

Array
(
    [slug] => 78571
    [filename] => Array
        (
            [0] => 78571-01.jpg
            [1] => 78571-02.jpg
            [2] => 78571-03.jpg
        )

    [template] => virtual-file
    [content] => Array
        (
            [alt] => Artwork by Firstname Lastname
        )

)

{"status":"error","message":"Argument 1 passed to Kirby\\Cms\\File::setFilename() must be of the type string, array given, called in \/Users\/sarah\/Sites\/3x3new\/kirby\/src\/Toolkit\/Properties.php on line 138","code":500,"exception":"TypeError","key":null,"file":"File.php","line":511,"details":[],"route":"pages\/([a-zA-Z0-9\\.\\-_%= \\+\\@\\(\\)]+)\/sections\/([a-zA-Z0-9\\.\\-_%= \\+\\@\\(\\)]+)"}

Sorry for dragging this out.