Mixing PHP function call and HTML in a template foreach loop

ahundiak,

I’m going to stop trying to simplify code for these posts. Better just to post exactly what’s there…

For your benefit (and others) here’s the version version (the opening):

<ul>
    <?php foreach ($vertical_groups as $vertical_group) : ?>
        <li>
            <h6><?= $vertical_group->title; ?></h6>  *(This line DOES display the correct title)*
            <!--Featured image-->
            <div>
                <img src="/img/raster/vertical_groups/<?= $vertical_group->vertical_group_id ?>.jpg">
            </div>
            <!--Featured image-->

And here’s a pic from XDebug at the crucial moment…

SO, the value is there to be used. Just a matter oh how???

It’s Friday and I am bored. Here is another self-contained test file:

<?php

class VerticalGroup
{
    public $vertical_group_id;
    public $title;

    public function __construct($id,$title)
    {
        $this->vertical_group_id = $id;
        $this->title = $title;
    }
}
$vertical_groups = [
    new VerticalGroup(1,'VT 1'),
    new VerticalGroup(2,'VT 2'),
];
?>
<ul>
    <?php foreach ($vertical_groups as $vertical_group) : ?>
    <li>
        <h6><?= $vertical_group->title; ?></h6>
        <div>
            <img src="/img/raster/vertical_groups/<?= $vertical_group->vertical_group_id ?>.jpg">
        </div>
    </li>
    <?php endforeach; ?>
</ul>

Ru it from the command line and the output shows the expected result:

<img src="/img/raster/vertical_groups/1.jpg">

I actually suspect that when you say “it does not work” then you mean that your javascript does not work when you click on it. First thing to do is to check the actual generated html by using control-u in the browser. I suspect it was just a missing slash all along.

1 Like

ahundiak,

Thanks again for the effort you’re putting into this. That really helps when you have a piece of code that should work but doesn’t.

You’re quite right, see image.
php_script

However, using your element in my code still does not work. When debugging, the debugger stops debugging at this line with no explanation and I get only one of the six links that appear when I hard code a 1 instead. And that link is not clickable: no mega menu functionality on it.

ahundiak (and all others who’ve chipped in),

Solved. Stupid, stupid, stupid. Learnt a lesson today.

The difference between your code and mine (apart from the origin of the class)… your vertical_group_id is public. I’d mistakenly coded mine as private. Why? What’s the point of private properties in an Entity class whose purpose is to provide information? Nada. Stupid.

I’m an idiot.

Right, enough, apologies to all and very sincere thanks for your input without which I would not have seen my stupid mistake.

You might be relying too much on that debugger tool you keep mentioning. It appears you are not seeing php generated error messages. If I change id to private in my example I get:

Fatal error:  Uncaught Error: 
Cannot access private property 
VerticalGroup::$vertical_group_id in ...

Pretty obvious. Investigate what is happening to your error messages.

I might add that my IDE (PHPStorm) also flags this as an error even before I try to run it.

And just to save a bit of typing, id should work fine instead of vertical_group_id.

It might help if you add:

error_reporting(E_ALL);

To the top of your main file. But you really should get the error somewhere regardless.

Well …

If this really is a database entity then I should not have public properties, because then everyone and everything can just change them and save the entity - which is not what you’d want!

It would be better to make the properties private and then add getters to the object:

public function getVerticalGroupId()
{
    return $this->vertical_group_id;
}

6 posts were split to a new topic: Problems with HEREDOC

Just wondering, have you ever considered sprintf?

return sprintf(
    '<img src="/img/%s.jpg">%s</img>',
    $group["id"],
    $group["name"]
);

I think it’s easier to read because your brain doesn’t have to parse all kinds of single and double quotes all over.

1 Like

I use sprintf quite a bit when I feel it is appropriate. However, once you have more than a few variables it can become difficult to figure out which %s belongs to which variable.

Agreed wholeheartedly.

I am currently working on a PHP snippet rendered in an AJAX loop. The snippet could be rendered up to about forty times (depending on MySqli LIMIT 0, 42).

If there is a better way then I would be grateful for an example.

<?php 

//==================================================================
function render
(
  object $row, 
  string $tog, 
  string $search = '',
  bool   $gooRvw = FALSE 
)
:string
{
  $qqq = empty('') ? '&nbsp;.&nbsp;' : $row->qqq;  
  $RVW = '';

  if($gooRvw):
    $GBK  = 'author=' .$row->author .'&amp;' .'title=' .$row->memo;
    $JSC  = $row->ref     .'^' 
          . $row->author  .'^' 
          . $row->memo    .'^' 
          . $row->baht    .'^' 
          . $row->type
          ;
    $JSC = htmlspecialchars($JSC); 
    $RVW =  '
              <form action="?" method="post">
                <div class="tac p42 fwb fsl bdT"> 
                  <input type="hidden"
                    name="author" value="{$row->author}"
                  />
                  <input type="hidden"
                    name="title" value="{$row->memo}"
                  />

                  <input
                    class = "fll bga" 
                    type  = "submit" name = "submit" 
                    value = "Google_Review" 
                  />                    
              </form>  

              <form 
                action="#" 
                name="ShoppingList" 
                method="get" 
                onsubmit="myFunction()" >
          
                <input type="text" name="$JSC">

                <input
                    class = "flr bgl" 
                    type  = "submit" name = "add2cart" 
                    value = "Add to cart" 
                />
                  <br>                    
                </div>  
              </form>  
            ';
  endif;            

  $book = <<< ____TMP
      <div class="$tog rad p42 fss bdr bd1">
        <span class="flr ooo">
          <b class="fgb"> Ref: {$row->ref} </b>
        </span>

        <span>
          Title: <b class="fg0"> {$row->memo} </b>
        </span>
        <br>
        <span>
          by: <i class="fg0"> <b>{$row->author} </b></i>
        </span>
        <br>

        <span class="fll"> 
          Baht: <b> {$row->baht} </b> 
        </span>
        <span class="flr">
          Type: <b class="fgr0"> {$row->type} </b>
        </span>
        <br>

        $RVW
      </div>

      <!-- SPACER -->
      <p> &nbsp; </p>
____TMP;

  return $book;
}//


An example from the Free PHP Online manual:

<?php

class foo
{
    var $foo;
    var $bar;

    function __construct()
    {
        $this->foo = 'Foo';
        $this->bar = array('Bar1', 'Bar2', 'Bar3');
    }
}



$foo = new foo();
$name = 'MyName';

echo <<<EOT
My name is "$name". I am printing some $foo->foo.
Now, I am printing some {$foo->bar[1]}.
This should print a capital 'A': \x41
EOT;
?>

The above example will output:

It looks as though the curly braces are only essential with array elements.

You can number them if you like:

return sprintf(
    '<img src="/img/%1$s.jpg">%2$s</img>',
    $group["id"],
    $group["name"]
);

That way %1$s refers to argument 1 and %2$s refers to argument 2. And yes you can swap those around in the template without changing the order of the arguments. You can also re-use them.

echo sprintf(
    '<img src="/img/%1$s.jpg" alt="%2$s">%2$s</img>',
    $group["id"],
    $group["name"]
);

‘Better’ of course can be highly subjective and often depends on what a given developer is used to.

Your example is really the sort of thing that template engines excel at. If you like, I could make a simple Twig based example which I suspect would be easier to read and maintain once the learning curve was overcome.

If you want to stick with php’s templating then I would consider moving to the concept of templating classes. More or less off the top of my head, I might try:

class BooksTemplate {
    public function render($books) : string {}
    private function renderBook($book) : string {}
    private function renderBookForms($book) : string {}
    private function escape(string $data) : string {} // Wrapper for htmlspecialchars
}

This approach would break things up a bit and might be easier to maintain.

I am confused with:

$JSC  = $row->ref .'^'  . $row->author  .'^'  ...
<input type="text" name="$JSC">

$JSC seems to be some sort of unique identifier being used as an input element name?

You probably need to do a bit more htmlspecialchars escaping as well. Pretty much all string data should be escaped including author and title. You never know where special characters might sneak in and end up breaking your html. Which actually brings me back to templating engines as they tend to escape automatically.

As mentioned the script is work in progress. The idea is to first make it work then makes it better.

The $JSC string is supposed to be passed to a JavaScript function. The function does not accept parameters and only activates an alert if there is no parameter passed.

It is late here and if I cannot solve the problem tomorrow will seek advice.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.