Variable on findBy parameter return an error

I’m trying to retrieve a page url from a structure field.
Works well when the value of the key is hardcoded, but not when I replace it with a vraiable.

Code:

<?php $relatedthread = page('eets')->children()->findBy('firsttweetid', '902476448149250048')->url() ?>

= Is working

<?php $thread = $article->relatedthread()->value() ?>
<?php $relatedthread = page('eets')->children()->findBy('firsttweetid', $thread)->url() ?>

= Error Call to a member function url() on boolean

$thread is a string and it echoes / dump as intended.

How can I put a vraiable in findBy() parameters? Why this code doesn’t work?

thanks!

<?php echo gettype($thread) ?>

Returns a string ? Without the value() or the toString() method it would indeed fail, but I see no reason it wouldn’t work fine with one of those. :thinking:

This is not a good thing to to, because you will run into an error if the page does not exist. Try to separate both:

<?php $relatedthread = page('eets')->children()->findBy('firsttweetid', $thread);?><?php 
<?php if($relatedthread) { echo $relatedthread->url(); } ?>

Apart from that, what kind of field is relatedthread()? Is that the structure field?

relatedthread() is a standard field.

oddly,

<?php $relatedthread = page('eets')->children()->findBy('firsttweetid', $thread);?><?php 
<?php if($relatedthread) { echo $relatedthread->url(); } ?>

works, but I don’t know why

<?php $relatedthread = page('eets')->children()->findBy('firsttweetid', $thread)->url();?><?php 

Throws me the boolean error even if the field is populated

I planned to add the checking of the field later and I still don’t understand why the second solution wont work, tell me if you know.

Thx!

Are you using that code snippet within a loop maybe, where the field may or may not be filled? Even if the field is populated, if the variable is not a page object, you can’t call the url() method on that. It is good practice to get into a habit of checking if an object exists before you try to call a method on it, you never know what happens to fields or pages later on.

I don’t understand what <?php $relatedthread = page('eets')->children()->findBy('firsttweetid', $thread);?> returns. Is it a string, a page object? (var_dump says it’s a page object, but why I can’t chain url() to it ?)

I think that this precision is missing in documentation, the parameters format and the return format are always missing, it’s not easy to understand the expected behaviour.

If the page you are trying to find exists, it will return a page object. Otherwise it will return false. The return value is usually given in the cheatsheet, e.g. here: https://getkirby.com/docs/cheatsheet/pages/find-by (see return)

Use dump() or var_dump() to check what you get.

Ok, thanks for the doc, it’s not clear for a noob like me tha $page is an object (I’m not a dev)
Var dump says it’s a page object and display it, although ->url() throw me an error (Call to a member function url() on boolean)

<? var_dump($relatedthread) ?> = OK (dump the correct page object)
<? var_dump($relatedthread->url()) ?> = boolean error

I’m sorry I dont really understand your last message. Even toPage() throws me an error. How can I get the URL (or any other page related fields) of the founded page then ? What is the point of findBy() if I can’t extract anything.

Well, yes, forget it, what I posted above did not make sense.

I don’t know, maybe you can post the whole context, something seems to be wrong. Or send me a download link to your project.

Here’s the full context

This code works:

        <ul class="postMeta">
          <?php /* takes the value of ID filled in the article */ $threadid = $article->relatedthread()->value() ?>
          <?php /* search for this ID in the field firsttweetid of all tweets page */ $relatedthread = page('eets')->children()->findBy('firsttweetid', $threadid);?>
          <li><span class="postMeta">Date : </span>le <?= $article->date('%A %u %B %Y') ?></li>
          <?php if($relatedthread): ?>
          <li><span class="postMeta">Fil Twitter relatif : </span><a href="https://twitter.com/<?= $relatedthread->twitterusername() ?>/status/<?= $relatedthread->firsttweetid(); ?>">Live</a><a href="<?= $relatedthread->url(); ?>">Archive</a></li>
          <?php endif ?>
          <li><span class="postMeta">Permalien : </span><a href="<?php echo $article->url() ?>">/<? echo $article->slug() ?></a></li>
        </ul>

Now, if I skip the if/endif statement, it throws me an error despite the fact the page exists (as the previous code is working)

This code doesn’t work (error: Call to a member function twitterusername() on boolean):

        <ul class="postMeta">
          <?php /* takes the value of ID filled in the article */ $threadid = $article->relatedthread()->value() ?>
          <?php /* search for this ID in the field firsttweetid of all tweets page */ $relatedthread = page('eets')->children()->findBy('firsttweetid', $threadid);?>
          <li><span class="postMeta">Date : </span>le <?= $article->date('%A %u %B %Y') ?></li>
          <li><span class="postMeta">Fil Twitter relatif : </span><a href="https://twitter.com/<?= $relatedthread->twitterusername() ?>/status/<?= $relatedthread->firsttweetid(); ?>">Live</a><a href="<?= $relatedthread->url(); ?>">Archive</a></li>
          <li><span class="postMeta">Permalien : </span><a href="<?php echo $article->url() ?>">/<? echo $article->slug() ?></a></li>
        </ul>

The only difference is the verification, which (if i’m correct) doesn’t affect the variable type.

Sorcery! :slight_smile:

And this happens on a page for this single article?

Good call!
This doesn’t happen in the sigle page of the article, it happens on the homepage where this article is called. It’s exactly the same code as I use a snippet for the article render.

My structure:

homepage -> calls articles via controller (the kirby starterkit controller) -> article rendered in article.php snippet
<?php snippet('article', array('article' => $article)) ?>

single article -> article rendered by the same snippet with other parameter
<?php snippet('article', array('article' => $page)) ?>

result: article page: with or without the ifit works, homepage: without the if it fails.

I can’t explain this, but I thinks that’s a lead.

As I already said above, this problem often occurs if people call pages in a foreach loop. It might work for a single page that has all the information needed, but fails in a loop, because not all the articles (projects, whatever) in the loop return a page object (or whatever else it is they are looping through). That’s why I was asking for the bigger context… And that’s why it is so important check if the object exists.

Yes I’m sorry I was working on the snippet so I don’t see that the bug occurs only on the homepage as it was the same code everywhere. I still don’t understand how the if statement makes a difference.

Well, I can’t tell you without actually seeing your project, I’m afraid. But believe me, the error occurs for a reason. There’s nothing wrong with the findBy() method.

OK after a re-reading I think I understand the problem, as you said maybe sometime the field of one of the subpage is empty, then it return false (boolean) the the error occurs for this entry, marking a “wrong” line for the error.

Thank you very much for your help, I am very sorry that I don’t see that the snippet was in a loop as I was working in the snippet in different contexts, and that all was working fine except in the special home case.

At least I understood the problem know. Thanks again.

Yes, this is a general problem, just make sure to always check if an object exists before you call a method on it, be it a page object, an image object or anything else. You can never be sure that you get what you expect to get. Often, in a controlled environment during development, everything seems to work fine. But then later, when pages/images/etc. are deleted or renamed or moved, you will run into errors if you don’t check the truthiness of your objects.