Page models, returning a string

Hello.

I have a structure field setup on the site level for ‘team_members’. This contains a person’s name, job title and photo ( file field ).

I’ve got a blog setup, with a page template called article.

In the blog article the user can select a team member in a select field, blueprint below:

              author:
                label: Author
                type: select
                options:
                  type: query
                  query: site.team_members.toStructure
                  text: "{{ item.name }}"
                  value: "{{ item.name }}"

I’m trying to create a model, that adds a team_member_image() method. But whenever I call $article->team_member_image()->toFile() on the page template, I get an error of ‘Call to a member function toFile() on string’. If I don’t call toFile() an img tag is echo’d to the page.

If I print_r what I’m returning from the model, in the article.php model file, it’s a Kirby\Content\Field Object.

Model code is below.

<?php

use Kirby\Cms\Page;

class ArticlePage extends Page
{

    public function team_member_image(): string
    {
        $page_id = $this->id();
        $team_member_image = false;

        if ($this->author()->isNotEmpty()) {
    
            // Get all team members
            $team_members = kirby()->site()->team_members()->toStructure();

            foreach ($team_members as $member) {
                
                // Does this match our article author?
                if ( $member->name() == $this->author()->value() ) {
                    return $member->photo();
                }
            }
        }

        return $team_member_image;
    }
}

What am I missing, or is there a better way to do this?

Thanks for the help

Ian.

  1. You’re type-hinting a string, but you are either returning false or a field object.

  2. $member->photo() returns a field object, so this is fine, but you probably want to call toFile() here to directly return a file object.

  3. Instead of the rather ugly construct of looping through all structure items and the nested if, use

    if ($member = $team_members->findBy('name', $this->author()->value())) {
        return $member->photo()->toFile();
    }
    

so complete method would look like this

	public function team_member_image(): ?Kirby\Cms\File
	{
		if ($this->author()->isNotEmpty()) {
			
			// Get all team members
			$team_members = kirby()->site()->team_members()->toStructure();
			
			if ($member = $team_members->findBy('name', $this->author()->value())) {
				return $member->photo()->toFile();
			}
		}
		
		return null;
	}

Amazing, thanks for the rapid reply @texnixe , that’s working perfectly now.

Damn copilot autocompleting, I didn’t spot the type hinting and didn’t expect that to be there.

Thanks for the heads up re the findBy method, indeed much cleaner and more elegant - like Kirby as a whole :grinning_face: