List all files in the asset folder

Is there any easy “Kirby like” solution to list all files in a folder, for example the assets? I tried with

dump(Dir::read($kirby->url('assets')));

But that doesn’t seem to work (of course, assets has no files in it). But also this isn’t working

dump(Dir::read($kirby->url('assets') . '/js/'));

Almost.

dump(Dir::read($kirby->root('assets')));

That’s working :smiley:

Quick extra question about this. How do I turn this (the files contained within an assets subfolder) into a files collection?

Files are by default objects that live in the content folder, so if you really want a Files collection, you would have to create virtual files from those assets folder files: Virtual files | Kirby CMS

What is your use case?

Maybe it would be good enough to create a new Assets object from each file and pass that to a standard Collection object?

Ah that makes sense. My use case was this:

On my site there is a certain type of subpages that can be created from frontend. Each of these created subpages receives a randomly assigned 3D object. I now wanted to store these 3D files in the assets folder and on each page creation move one random one of them to the newly created subpage.

But this now seems quite complicated to me, I think I will rather create a hidden subpage that stores all these 3d files in its content folder and then they get picked and moved from there. I guess that would be much easier.

But why would these files have to be in a files collection just to pick a random one?

Not just to pick a random one, but also to have access to all the other methods. But I guess, there should be nothing wrong with moving them into the content folder altogether, right?

No, nothing wrong with that. But instead of moving them (and thub duplication them), you might as well assign a random object via a files field programmatically.

I don’t think, I quite understand …? How would I do that?

My plan is to move them without duplicating. Basically, I have a folder with a lot of files and whenever a subpage is created a random file is moved out of this folder into the subpages content folder.

Ah, ok, then forget what I wrote. Nevertheless it would be another option to have all files in a central folder and just assign them to page via a pages field. But that’s up to you.

Thanks @texnixe, that would be if I am using the panel, right? Because I want all this to happen without the use of the panel.

It doesn’t matter if you use the Panel or not. You can store the reference to the file in the content file just as the Panel would.

Ah, okay, now I understand. But how would I do this programmatically?
I currently pick a random file like this:

$meshes = $kirby->page('objects/meshes')->files();
$randomIx = random_int(1, $meshes->count());

$randomMesh = $meshes->nth($randomIx - 1);

How could I then assign it to the current page via a pages field?

The $kirby in front it is useless. At least as far as I can see at the moment. I’m not sure if this helps in this case but at least a first approach

$meshes = page('objects/meshes')->files();

But to be sure that the code runs cleanly, some queries should be made in advance.

$meshes = page('objects/meshes');

if ( $meshes ) {
  if ( $meshes->hasFiles() ) {
    echo 'Page was found and it has files, now make sure that the extension is correct ...';
  } else {
    echo 'Page was found but it has no files ...';
  }
} else {
  echo 'No page with that URL found';
}

Come to think about it, it probably makes more sense to move the file, because you want to get a random one out of the ones left in the folder.

@Oli1 Those if statements should be merged into one.

I wouldn’t subscribe to that. It’s two different things altogether. page() is a helper function, while in the case of $kirby->page(), page() is a method of the App class. The function and the method accept different parameters and their return values are also different.

In this case, using the page() helper is of course fine, if the page in question is no a draft.

Ah ok, that was also new for me. Sure, statements can be merged

I ended up doing this now:

$meshes = $kirby->page('objects/meshes')->files();
$randomIx = random_int(1, $meshes->count());
$randomMesh = $meshes->nth($randomIx - 1);
$newMesh = $randomMesh->move($targetPage->root() . '/' . $randomMesh->filename());

$fileArray = A::wrap($newMesh->filename());

$targetPage->update([
  'mesh' => Data::encode($fileArray, 'yaml')
]);

That way I end up writing the file to a field, so I can later easily access it on my page. Not sure if this method makes sense. If it is too complicated, I would be very happy about hints how to improve it / make it easier!

Methods like $file->move() or $page->update() throw an error if the action fails for some reason. So you should wrap your code in a try/catch statement and handle the potential exception, for example. return an error message.

1 Like

Thanks, will take care of that!