Can't get Images or Image on a user page from the user account

Hey there.

I allready found help in this entry:
Continuing the discussion from Building user profile pages in Kirby 3:

In the model I added fields like addresses and links, but how do I get images, that were uploaded in the user account?

<?php

class RaeumePage extends Page
{
public function children()
{
$usersPages = [];
$users      = kirby()->users();
foreach ($users as $key => $user) {
  $userPages[] = [
    'slug'     => Str::slug($user->id()), // or username if unique
    'num'      => $user->indexOf($users),
    'template' => 'user',
    'model'    => 'user',
    'content'  => [
      ...
      'avatar'    => $user->avatar(),
      'image'    => $user->image(),
       ...
       ]

These fields are files ^^ one or many

When I want to call them in the template, I get no content.

<?php if($avatar = $page->avatar()): ?>
  <img src="<?= $avatar() ?>" alt="">
<?php endif ?>
<?php foreach ($page->image() as $image): ?>
  <img src="<?= $image() ?>" alt="">
<?php endforeach; ?>

I am allways losing trake about the format of the field. Is $user->image() an object or do I need to convert ->toFile() or ->toFiles() somewhere?
Or do I need to manipulate the route somehow to get the images?
config:

<?php
return [
'routes' => [
     [
       'pattern' => 'user/(:any)',
       'language' => 'de',
       'action'  => function($user) {
         $site = kirby()->site()->find("raume");
         return tpl::load(kirby()->roots()->templates() . DS . 'user.php', array('user' => $user, 'site' => $site), false);
       }
     ]
     ],
'debug' => true,
'languages' => true,
];

I highly appreciate your support.
Thanks in advance.

  1. The files field expects a yaml encoded array of file ids, however, in your model you are passing a file object.
'avatar' => ($avatar = $user->avatar()) ? Data::encode([$avatar()->id()], 'yaml') ? null,
  1. $user->image() returns a single image, same problem as above, but additionally, you try to loop through $page->image() in your template.

However, $page->image() will return the first image in the page folder, not the one stored in the image field (see field names: https://getkirby.com/docs/guide/content/fields#naming-fields)

  1. Then rendering the field content in your template, you have to convert to a file object

2 . Ok, thought so too. Thanks.

1 .

This is going in the model content array, right?
Because it is throwing a syntax error there:

$page->image() … Yeah, sure! Forgot about this function. I will rename the field.
But passing/encoding an array of files would work the same way as you posted for a singel one? (I can not test it now, because of the error)

Thanks for the quick answer?

Should be $avatar->id()

mh unfortunately still the same error. :slightly_frowning_face:

'avatar' => ($avatar = $user->avatar()) ? Data::encode($avatar->id(), 'yaml') ? null,

In the Reverence, there is a string after the encode round braces… But there is nothing missing, right? mh

Ok, my mistake:

'avatar' => ($avatar = $user->avatar()) ? Data::encode($avatar->id(), 'yaml') : null,
1 Like

Ah that was it! Sorry, still learning php…
Thanks for sticking with me!

But now there is follow-up error: :see_no_evil:

Bildschirmfoto 2022-09-06 um 09.24.02

Is that a local host problem, or do I have to specify the max size of data that get routed, somehow?

I found this post that should solve the problem, but I am not sure that increasing the memory is the
the goal.

I can also prohibit to upload large files in this case.

Multiple images:
For testing I took very small images now. The error is a different one:
What is happening now is that the page takes forever to load until the timeout hits.
This is only happening with the array of images.

So could it be, that

'bilder' => ($bilder = $user->bilder()) ? Data::encode($bilder->id(), 'yaml') : null,

which should deliver an array of images, need a different encoding here?

Single images:
With a single image “avatar” it also does not work as I expaced it.

When I call the avatar like this:

<?= $page->avatar()->toFile()->url()?>

in the template, after I encode it in the model like this:

'avatar' => ($avatar = $user->avatar()) ? Data::encode($avatar->id(), 'yaml') : null,

the outcome is null even if the account has an avatar. Looks like I am still doing stuff wrong here…

If the problem is the uploaded file size, I’d limit what the user can upload. After all, you never need huge images, and it’s just a waste of resources.

Well, the original error as before above (you are not converting the field value), but also you would have to pluck the ideas

$images = $user->bilder()->toFiles();
'bilder' => $images->isNotEmpty() ? Data::encode($images->pluck('id', ','), 'yaml') : null,

Yeah, sure! What I mean.

At least there is no error anymore. Now it delivers this:

- > B8Shzv2W/img-one-name.jpg - B8Shzv2W/img-two-name.jpg 

I don’t understand were the - > and the - in front and between the two strings is coming from.
And since it looks like a part on an url… I don’t know where I can find the images now. :innocent:
I tried, the page url + string and some other combinations –> always 404

I think we are going wrong somewhere, and I think I got confused.

Where do you get this result?

Ok. Sorry for any confusion @texnixe.

I will start over:
I have users with an avatar and another field for multiple images.

I want to list all the users on a page: users
Every user should get a subpage of this users page: user

user blueprint:

avatar:
   type: files
   multiple: false
bilder:
   label: Bilder Deiner Performance/Kunst
   type: files

users model:

<?php

 class RaeumePage extends Page
 {

 public function children()
 {
$usersPages = [];
$users      = kirby()->users();

foreach ($users as $key => $user) {
  $images     = $user->bilder()->toFiles();
  $userPages[] = [
    'slug'     => Str::slug($user->id()), // or username if unique
    'num'      => $user->indexOf($users),
    'template' => 'user',
    'model'    => 'user',
    'content'  => [
      ...
      'avatar' => ($avatar = $user->avatar()) ? Data::encode($avatar->id(), 'yaml') : null,
      'bilder' =>  $images->isNotEmpty() ? Data::encode($images->pluck('id', ','), 'yaml') : null,
      ...
    ]
  ];
}
return Pages::factory($userPages, $this);

}
}

then here is the user page template: user.php

<img src="<?= $page->avatar()->toFile()->url() ?>" alt="">

<?php foreach ($page->bilder()->toFiles() as $bild): ?>
  <img src="<?= $bild->url() ?>" alt="">
<?php endforeach; ?>

This leads to an error calling member function url() on null
However. For testing what the outcome of those fields look like I wrote:

<?= $page->bilder()?> </br>
<?= $page->avatar()?>

and this is the output, where I have no idea what to do with it :dotted_line_face:

- > B8Shzv2W/img-one-name.jpg - B8Shzv2W/img-two-name.jpg
- B8Shzv2W/profile.webp 

Hope that clarifies the problem.

Sorry, haven’t found the time yet to set up a little test. Will do asap.

1 Like

Ok, finally got round to it and the problem are the user images. Take a look at this example:

    public function children()
    {
        $usersPages = [];
        $users      = kirby()->users();
        foreach ($users as $key => $user) {
            $images  = page('photography')->children()->first()->images()->pluck('id', ',');
            $uImages = $user->images()->pluck('id', ',');
            $userPages[] = [
                'slug'     => Str::slug($user->id()), // or username if unique
                'num'      => $user->indexOf($users),
                'template' => 'user',
                'model'    => 'user',
                'content'  => [
                    'avatar'    => Data::encode($images, 'yaml'),
                    'userimages'    => Data::encode($uImages, 'yaml'),

                ]
            ];
        }
        return $this->children = Pages::Factory($userPages, $this);
    }

This works well for the avatar field which contains a simple set of page files:

In the template in my example:

<?php foreach($page->children() as $child): ?>
  <h2><?= $child->title()  ?></h2>
  <img src="<?php echo $child->avatar()->toFile()?->url() ?>" alt="">
  <img src="<?php echo $child->userimages()->toFile()?->url() ?>" alt="">
<?php endforeach ?>

While $child->avatar()->toFile() (which now stores a page file id) return the file as expected, calling toFile()/toFiles() on the userimages field has no effect whatsoever.

The only way to solve this problem is to fetch the images from the user object:

$userImages = $kirby->user($child->userId())->files()->filter(fn ($file) => in_array($file->id(), $child->userimages()->yaml()));
dump($userImages);

For this to work, the user id needs to be stored in the content in your model as well.

2 Likes

Hey Sonja, Thanks for taking your time to help.

Your use case seems to not fit mine exactly.

Your model:
It looks like you are catching the $images from a page named photography. In my case the images or the one image (avatar) is uploaded in each user. And there is no child of the user.
Also, the page for that I am working on the template has no children…

I will try to tweak it to my use case.

...
foreach ($users as $key => $user) {
$avatar        = $user->avatar()->first()->pluck('id', ',');
$userPages[] = [
    'slug'     => Str::slug($user->id()), // or username if unique
    'num'      => $user->indexOf($users),
    'template' => 'user',
    'model'    => 'user',
    'content'  => [
            'avatar' =>  Data::encode($avatar, 'yaml'),
              ]
       ];
    }

Your Template:
In the template, I am on the user Page itself.
So calling children here wouldn’t make any sense – there are none.

<img src="<?php echo  $page->avatar()->toFile()?->url() ?>" alt="">

That is crashing. No Error just the hole page is not loading anything.

Guess that is what you are meaning here, right?

Accept that it is also not working with a single image (avatar) directly from the user.

Your solution would be this:

$userImages = $kirby->user($child->userId())
->files()->filter(fn ($file) => in_array($file->id(),  
$child->userimages()->yaml()));

dump($userImages);

So I’m trying to understand your code here:
You are calling the kirby->user()
In the brackets $child->userId() –> why? Where is the child coming from? Or is that the actual user?

userId is a field in your example?
The user id is already in the model – we are using it in slug, don’t we?

Then you are filtering from through an array of files in user? Or the child page?
The filter method I don’t understand…

Mh. Sorry.
I am really trying, but I don’t get it yet. :face_with_spiral_eyes:

As I tried to explain, this was for a test. I compared fetching images from a page vs from a user to make sure the syntax is correct.

That is a child defined in the model. Only I’m not in the virtual page but in the parent, as you can see, I’m looping through the children.

And userId is a field I additionally defined in the model to have access to the user id, as explained above. Quoting myself >

But the slug sluggifys the user id, so it is useless to fetch the user (e.g. 8Ng0DaaC != 8ng0daac)