Very easy to reproduce. E.g. for a site with a field dummy, call $site->dummy()->parent() in the template. Then you get the error Return value of Kirby\Cms\Model::__toString() must be of the type string, null returned, which occurs at
public function __toString(): string
Is this a general issue? I guess it could be fixed by checking whether $this->id() is really a string before returning and otherwise return the empty string or throw an exception.
For a field on a regular page the call succeeds as expected: $page->dummy()->parent() returns the page id.
Short explanation: In the example given above it’s not very useful to call the parent() method as the parent is known in this case. In the end I want to call this in a custom field method, in order to check where the field is defined and access the parent later.
This only happens if you actually echo $site->dummy()->parent(), I think, which IMO you shouldn’t do anyway, because it’s not a good idea to rely on the magic __string() method as this implementation could change.
However, could you please create an issue on GitHub for this?
Yes, you’re right. I thought it should be caused by my echo (which was only for test purposes; I’m not going to use this in production). So I removed the echo and the error persisted. The problem was: I got caught up in my test templates and actually removed the echo from the wrong one…
I will create an issue on GitHub for the type check before the return statement in __toString(), anyway.
As explained in the first post: Of course it is trivial in my dummy example. What I want to do (and am doing; it is working now) is get the parent() in a custom field method. In the custom field method I just call $field->parent() not knowing what the actual parent is (might be any page or $site). Is this clearer?
The use-case is as follows: My field contains the settings for a contact form (fields, validation settings etc.). The custom field method outputs the html for the contact form. However, there may be more contact forms on the site, maybe within $site or in different pages, with different fields and validation settings. So I need to know, which contact form exactly was addressed in the blueprint in order to be able to validate everything correctly etc. So I send this information in a hidden field in the contact form for later use. The $page variable is not enough for this as the contact form used on a page called ‘contact’ might be defined in site.yml or similar and I need the real origin, where the contact form is defined.
I hope this is a bit clearer.
P.S.: I might as well force the site editor to add a site-wide unique id for each form, but this might go wrong and means unnecessary work for the editor. Another solution would be to pass information about the origin to the custom field method, but in this case you have to remember which parameter to pass and so on. When I can automize it, I prefer the automized solution. Then I just need to call $fieldname->toContactform() in the template and that’s it. Easy and no need to think about it too much. Thinking has been done before. Maybe I’m overcomplicating things, but I like it this way.
Unless you don’t try to echo it $field->parent() should return the model, either a page model or the site model. So you could act on that. I’m currently moving devices so I don’t have my dev environment ready for testing, but that should be the way to go, no matter what the magic __toString() method returns.
@texnixe Yes, correct, $field->parent() returns a model as expected. I only experienced the issue due to my debugging. There is actually no problem for my project. I can work with the model without echoing it and thus invoking __toString(). So everything is fine. I just opened the GitHub issue because __toString() shouldn’t return null. That’s all. @anon77445132 I don’t need to use either $site or site() and of course $site is not a $page. The whole issue is just due to my debugging. It’s not a big issue, anyway, and I think it can be solved easily.