1

I'm making several HTML popups that always follows a defined template.

Since there is a template (header,content,example table,more button), I thought I can save a lot of recurring html by passing the data to a wrapper function like so:

$device_popup_data = array(
    'header' => 'Header text',
    'content' => 'some text<span style ="bold"> Some more text</span>',
    'example' => '<table><tbody><tr><td> A lot of text here, multi lined and messy',
    'more' => '',
);

echo theme_uxt_expanded_popup($device_popup_data);

function theme_uxt_expanded_popup($data){
    $head = isset($data['head'])?$data['head']:'';
    $content = isset($data['content'])?$data['content']:'';
    $example = isset($data['example'])?$data['example']:'';
    $more_html = isset($data['more'])?$data['more']:'';

    $output= '<div class = "expandedTooltip">';
    $output.=   '<h1>'.$head.'</h1>';
    $output.=   '<p>'.$content.'</p>';
    if(!empty($more)){
        $output.=   '<a class = "popupShowMore"><p>'.$more.'</p></a>';
    }
    $output .= '</div>';
    return $output;
}

This seemed like a great idea, until I have seen that some of these fields, like the example field, may contain around 100 lines of HTML.

Pushing these long strings into the example variable seems to make very unreadable code. Something like this :

$device_popup_data = array(
    'header' => 'Header text',
    'content' => 'some text<span style ="bold"> Some more text</span>',
    'example' => '<table><tbody><tr><td> A lot of text here</td>,<td> multi lined and 
    messy, and if any one</td>
 <td>wants to change this string it will be very hard</td> 
Real string is much longer ... </table>',
    'more' => '',
);

Do you know of an efficient and readable way of doing something like this?

Skarlinski
  • 2,419
  • 11
  • 28
  • Well as you don't read those strings, you don't have to care if they are long or small. They will be always same way readable, by their variable name. If you're concerned about the final HTML output, you can just run it through a beautifier, like tidy http://php.net/tidy . – hakre Aug 20 '13 at 17:34
  • @hakre, edited my question, trying to be clearer. I am worried about these long strings will make the code flow unreadeble – Skarlinski Aug 20 '13 at 17:48
  • well that indeed looks a bit burdensome. Also I now better see what you actually want to ask about. That long or even longer? – hakre Aug 20 '13 at 17:51
  • 1
    You can do this by abstracting template logic and using `OB` tricks – Yang Aug 20 '13 at 18:41
  • Yes like including a template and just injecting some other variables. See here for some more anonymous [`include_helper()`](http://stackoverflow.com/a/7697490/367456) and combine it with output buffering for example as outlined here: [Modify an Existing PHP Function to Return a String](http://stackoverflow.com/a/8730878/367456). – hakre Aug 20 '13 at 19:07

1 Answers1

1

Do you know of an efficient and readable way of doing something like this?

The only readable, maintainable way of doing this is to adhere to the Separation of Concerns. The points here are 1) Decoupling HTML from PHP 2) Implementing a container, like name => HTML content

You should really wrap that into a class, in order to take full advantage of DI and SRP (see below). So, a class itself would look like as:

class TemplateBlockManager
{
     private $blocks = array(); 

     public function define($name, $file, array $vars = array())
     {
          ob_start();

          if (!empty($vars)) {
              extract($vars);
          }

          require($file);

          $content = ob_get_clean();

          $this->blocks[$name] = $content;
     }

     public function getBlock($name)
     {
         return $this->blocks[$name];
     }

}

File : test.phtml

<p>
   <b>Welcome to <?php echo $foo; ?></b>
</p>

Usage:

<?php

$blockManager = new TemplateBlockManager();
$blockManager->define('header', '/path/to/test.phtml', array('foo' => 'bar'));

// Should output "Welcome to bar"
echo $blockManager->getBlock('header');

This approach has a number of advantages:

  • You can prepare several blocks at a bootstrap stage, thus your blocks can be shared across your pages. This reduces code duplication

  • You can inject an instance of a $blockManager to another classes that generate an output. This is good for unit-testing, as it adheres to the Dependency Injection

  • You also adhere to the Single-Responsibility Principle

  • You totally decouple HTML from PHP, since your templates contain basic (or none) php logic

  • Since your templates are totally decoupled you don't have to worry if they are long or small. You would simply define a path to the one

  • And finally, both HTML and PHP code are easy to maintain

Yang
  • 8,580
  • 8
  • 33
  • 58
  • I think it should be possible in the define to define default variables and when the block is returned with getBlock you should be also able to specify variables. – hakre Aug 20 '13 at 19:23
  • Thanks for the excellent answer, I will definitely use this instead of my procedural version, but still I am left with the same issue : Where you write array('foo' => 'bar')); I will still have to enter a huge html table instead of 'bar'. – Skarlinski Aug 20 '13 at 21:14
  • No no, you got it a bit wrong. The 3-rd optional argument `array('foo' => 'bar')` is only for template variables. As you can see it has default empty value, so that you can omit that. As for huge table, this would be : `$blockManager->define('huge_table', '/path/to/huge/table.phtml'); echo $blockManager->getBlock('huge_table');` – Yang Aug 20 '13 at 21:23