Solved

PHP Coding layout question.

Posted on 2003-11-10
10
310 Views
Last Modified: 2006-11-17
Hi.

I have just finished creating a class to show a 12 month calendar (primarily to be used as an Absence Map from our HR system).

This is the first real class I have written.

Effectively, you create an instance of the class, use the Add_Legend and Add_Data methods to inject suitable data and then call Show_Calendar to extract the HTML to show it. The HTML contains no formatting, all colouring, etc is CSS based.

All fine and everyone likes it.

My question is about coding the HTML generation.

At the moment, there are a lot of ...

$sResult .= <<< END_HTML
some_html_goes_here
and_here
and_here
END_HTML;

Which is fine, but overall, looks rather messy.

I tried ...

      function Kalendar_ShowLegend()
            {
            if ($this->_bInitialized)
                  {
                  ksort($this->_aLegends);
                  $sResult = "<table class=\"KKey\" cellspacing=\"0\" cellpadding=\"0\"><caption class=\"KKeyCap\">{$this->sLegendTitle}</caption>";
                  $sKeyRow = '';
                  $sValueRow = '';
                  foreach($this->_aLegends as $k => $v)
                        {
                        if ($k != '')
                              {
                              $sKeyValue = "<div class=\"KKeyValIn\" style=\"background-color:{$v['Colour']};\">{$v['Additional']}</div>";
                              if ($this->bLegendPortrait == True)
                                    {
                                    $sResult .= "<tr><th class=\"KKeyKey\">$k</th><td class=\"KKeyValOut\">$sKeyValue</td></tr>";
                                    }
                              else
                                    {
                                    $sKeyRow .= "<th class=\"KKeyKey\">$k</th>";
                                    $sValueRow .= "<td class=\"KKeyValOut\">$sKeyValue</td>";
                                    }
                              }
                        }
                  if ($this->bLegendPortrait == False)
                        {
                        $sResult .= "<tr>$sKeyRow</tr><tr>$sValueRow</tr>";
                        }
                  $sResult .= "</table>";
                  return $sResult;
                  }
            }


which is a little neater, but having to do all the escapes was a pain.

I was considering using some sort of templating system, but that, for this project, is overkill and not appropriate. How many ways can you show a year calendar? Months along the top and date down the side looks REALLY strange!

Basically, coding designs for code which generates fixed HTML output.

Suggestions please.

Regards,

Richard Quadling.
0
Comment
Question by:RQuadling
  • 3
  • 3
  • 2
  • +2
10 Comments
 
LVL 3

Expert Comment

by:ashoooo
ID: 9716571
I would escape out of the <?php ?> tag and write the HTML directly... something like this...

<?php
...
   if(...)
   {
   }
   else
   {
?>

   <p align="center"> This is NOT inside the PHP tag</p>

<?php
   }
?>
0
 
LVL 9

Accepted Solution

by:
AlanJDM earned 50 total points
ID: 9717045
Im not sure my way is any better, but at least I don't have to escape anything. By using single quotes for your PHP strings, you then dont have to escape the double quotes in the string, of course, now you must concatenate all of the variables. Just another way of doing it.

function Kalendar_ShowLegend()
{
  if ($this->_bInitialized)
  {
    ksort($this->_aLegends);
    $sResult = '<table class="KKey" cellspacing="0" cellpadding="0"><caption class="KKeyCap">'.{$this->sLegendTitle}.'</caption>';
    $sKeyRow = '';
    $sValueRow = '';
    foreach($this->_aLegends as $k => $v)
    {
      if ($k != '')
      {
        $sKeyValue = '<div class="KKeyValIn" style="background-color:'.{$v['Colour']}.';\">'.{$v['Additional']}.'</div>';
        if ($this->bLegendPortrait == True)
        {
          $sResult .= '<tr><th class="KKeyKey">'.$k.'</th><td class="KKeyValOut">'.$sKeyValue.'</td></tr>';
        }
        else
        {
          $sKeyRow .= '<th class="KKeyKey">'.$k.'</th>';
          $sValueRow .= '<td class="KKeyValOut">'.$sKeyValue.'</td>';
        }
      }
    }
    if ($this->bLegendPortrait == False)
    {
      $sResult .= '<tr>'.$sKeyRow.'</tr><tr>'.$sValueRow.'</tr>';
    }
    $sResult .= '</table>';
    return $sResult;
  }
}


Alan
0
 
LVL 6

Expert Comment

by:aolXFT
ID: 9717396
Does this have to be XHTML Complant? If not, you can put the attributes in single quotes, instead of double quotes.

Your first assignment becomes:
 $sResult = "<table class='KKey' cellspacing='0' cellpadding='0'><caption class='KKeyCap'>{$this->sLegendTitle}</caption>";

Alternatively you could map some other character instead of the double quote, it would have to be a character that had no other use, lets say for example the | symbol.

Your first assignment would then become

 $sResult = map("<table class=|KKey| cellspacing=|0| cellpadding=|0|><caption class=|KKeyCap|>{$this->sLegendTitle}</caption>");

you would define the function map as follows:

function map(&$my_string){
     strtr($map, "\"", "|");
}
0
 
LVL 6

Expert Comment

by:aolXFT
ID: 9717468
Correction: Passing a constant string, shouldn't be done by reference.

change the above map function to

function map($my_string){
     strtr($map, "\"", "|");
     return $map;
}

Actually come to think of it even if this DOES have to be XHTML Compliant you could map the single quotes to double quotes. It would be different from the above map though, because you would have to only map quotes that are inside tags, and not map quotes that are escaped.

That would require regex

I'm not sure of the exact syntax, but you want to match any single quotes inside between '<' and '>'  that is not escaped.

Having that said if this is for an internal project, chances are that it won't need to be XHTML compliant, and you can just use the single quotes.
0
 
LVL 3

Expert Comment

by:ashoooo
ID: 9717574
Or download a small tool which takes an HTML statement as input and gives out PHP echo statements as output. You can even write one on your own, just replace " by \"
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
LVL 3

Expert Comment

by:ashoooo
ID: 9717592
0
 
LVL 3

Expert Comment

by:red010knight
ID: 9718308
Well my prefered method is this --

create a page that is pure PHP
Create a page that is pure HTML with a php variable for a placeholder for the dynamic string data

Then at the end of your php page, make use of the eval() function in php and presto chango - a dynamic page is generated with out having complex php in the middle of your HTML.

And whala no need to keep escaping in and out of PHP to generate a good webpage - for code

For more information on doing this, check out this question as I go a bit more detailed into ways to set the code up.
http://www.experts-exchange.com/Web/Web_Languages/PHP/Q_20785310.html

Thanks and have fun making your PHP files cleaner,
red010knight
0
 
LVL 11

Expert Comment

by:shmert
ID: 9719265
Hey richard,
fun question.  First off, I agree with Alan, use single-quotes when you're outputting HTML, and just use the concat dot to group things together.  Single quotes are a teeny bit faster than double-quotes anyway, since there is no interpretation going on in there.  Only annoying thing is if you like to output newlines.

Also, you might consider echoing the HTML instead of returning it.  I know, I know, a big golden rule used to be "always return, never output" but I think output buffering has negated that, since if you really need the output of a script you can make a buffer to get it.  Again, this is a little cleaner, and can also give you a small speed boost.

Last idea:
Maybe you could use a domxml-style API for generating your HTML.  So instead of building up a big HTML string, you create a tree object with tag nodes in it.  One caveat:  this pretty effectively negates any previous speed benefit from my first 2 ideas ;)

Maybe you could make dumbed-down html_tag function that you pass the args in to, which outputs an HTML tag.  I could see this being useful in tons of places.  Something like this:

<?php
function html_tag($tagName, $attrs) {
        $args = func_get_args();
        $out = '<' . array_shift($args);
        while ($args) {
                $out .= ' ' . array_shift($args) . '="' . array_shift($args) . '"';
        }
        $out .= '>';
        return $out;
}

echo html_tag('table', 'border', 1, 'cellpadding', 2, 'cellspacing', 123, 'name', 'foo');
?>

0
 
LVL 11

Expert Comment

by:shmert
ID: 9723975
I've been fooling around with a node-based HTML-building class after my post yesterday.  Here's the code that you'd use to generate the table using this system (apologies for mangling your brace style).  I'll post the class separately.

function Kalendar_ShowLegend() {
        if ($this->_bInitialized) {
                ksort($this->_aLegends);
                $sResult = new HtmlNode('table', null, 'class', 'KKey', 'cellspacing', 0, 'cellpadding', 0);
                $sResult->addNode('caption', $this->sLegendTitle, 'class', 'KKeyCap');
                $keyRow =& $sResult->addNode('tr');
                if ($this->bLegendPortrait) {
                        $valueRow =& $sResult->addNode('tr'); // append value stuff to a new row
                } else {
                        $valueRow =& $keyRow; // append value stuff to the same row as the keys
                }
                foreach($this->_aLegends as $k => $v) {
                        if ($k == '') continue;
                        $keyRow->addNode('th', $k, 'class', 'KKeyKey');
                        $valueCell =& $valueRow->addNode('td', null, 'class', 'KKeyValout');
                        $valueCell->addNode('div', $v['Additional'], 'class', 'KKeyValIn', 'style', 'background-color:' . $v['Colour']);
                }      
                return $sResult->toString();
        }      
}      
0
 
LVL 11

Expert Comment

by:shmert
ID: 9723988
There's no documentation in place yet, but the key function is addNode(), which takes the same arguments as the constructor.  First param is tag name, second is any cdata content, and any remaining args are used to build the attr array.

<?php
class HtmlNode {
      var $_tagName;
      var $_attrs;
      var $_contents;

      function HtmlNode($tagName, $cdata=null, $attrs=null) {
            $this->_tagName = $tagName;
            $this->_contents = array();
            if ($cdata!==null) $this->addCdata($cdata);
            if (is_array($attrs)) {
                  $this->_attrs = $attrs;
            } else if ($attrs !== null) {
                  $this->_attrs = HtmlNode::_attributesFromArgs(func_get_args());
            }
      }

      function _attributesFromArgs($args) {
            array_shift($args);
            array_shift($args);
            $attrs = array();
            while($args) {
                  $attrs[array_shift($args)] = array_shift($args);
            }
            return $attrs;
      }

      function &addNode($childNode) {
            if (!is_object($childNode)) {
                  // use function arguments to call constructor for a new HtmlNode object
                  $args = func_get_args();
                  $cdata = $args[1];
                  $attrs = HtmlNode::_attributesFromArgs($args);
                  $childNode = new HtmlNode($childNode, $cdata, $attrs);
            }
            $this->_contents[] =& $childNode;
            return $childNode;
      }

      function addCdata($cdata) {
            $this->_contents[] = $cdata;
      }

      function toString() {
            $out = '<' . $this->_tagName;
            if ($this->_attrs) {
                  foreach($this->_attrs AS $key=>$value) {
                        $out .= ' ' . $key . '="' . $value . '"';
                  }
            }
            if (count($this->_contents) == 0) {
                  $out .= ' />';
            } else {
                  $out .= '>';
                  foreach($this->_contents AS $child) {
                        if (is_object($child)) {
                              $out .= $child->toString();
                        } else {
                              $out .= $child;
                        }
                  }
                  $out .= '</' . $this->_tagName . '>';
            }
            return $out;
      }
}
?>
0

Featured Post

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

Suggested Solutions

Author Note: Since this E-E article was originally written, years ago, formal testing has come into common use in the world of PHP.  PHPUnit (http://en.wikipedia.org/wiki/PHPUnit) and similar technologies have enjoyed wide adoption, making it possib…
These days socially coordinated efforts have turned into a critical requirement for enterprises.
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
The viewer will learn how to create a basic form using some HTML5 and PHP for later processing. Set up your basic HTML file. Open your form tag and set the method and action attributes.: (CODE) Set up your first few inputs one for the name and …

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now