5

I have a basic understanding of PHP, but I feel like what I am trying to do could by done in a much simpler way. I am using PHP to display HTML content for a Wordpress theme. I want users to be able to determine the order in which HTML "blocks" are displayed. Currently I am using an if/elseif setup. Here is an overly simplified example:

if ( $layout == 'layout_one' ) {
   echo '<div class="header">Header</div>';
   echo '<div class="content">Content</div>';
   echo '<div class="footer">Footer</div>';
} elseif ( $layout == 'layout_two' ) {
   echo '<div class="content">Content</div>';
   echo '<div class="header">Header</div>';
   echo '<div class="footer">Footer</div>';
} elseif ( $layout == 'layout_three' ) {
   echo '<div class="footer">footer</div>';
   echo '<div class="header">Header</div>';
   echo '<div class="content">Content</div>';
}

Now, this technique becomes an absolute bear due to the shear number of layout options (permutations). So in my mind you would write a separate function for each HTML content block, and then in some way have another function that presents them in the order specified by the user. Or maybe putting all the blocks into an array and then reordering the array based on the layout selection...

Anyway, I have hit a wall on how to actually do this. Any guidance would be greatly appreciated. Thanks

ndiego
  • 88
  • 1
  • 7
  • The general approach (prepare the block content, then order the blocks) seems reasonable. What is the problem--you don't know how to write the functions to prepare the block contents? Or you're not sure whether it would be better to use an if/else loop or something else? – i alarmed alien Aug 23 '14 at 15:01
  • Another quick comment -- if you have a bewildering selection of different layouts to deal with in your code, the users may also find the number of different layout choices bewildering too. – i alarmed alien Aug 23 '14 at 15:02

4 Answers4

6

This is not a trivial question; as the number of layout parts grows, it becomes more and more difficult to maintain. However I'm going to try to provide a "simple" solution for this.

Let's assume you have 3 parts, as in your example. However this should work for N parts. You set them in an array:

$parts = [
  0 => '<div class="header">Header</div>',
  1 => '<div class="content">Content</div>',
  2 => '<div class="footer">Footer</div>'
  ]

Then you want the combinations in a deterministic way. This is what I came up with, although I'm sure there's some algorithm to do all possible combinations (one example of an algorithm) so this step is automatic:

$layout_combinations = [
  0 => [0, 1, 2],
  1 => [0, 2, 1],
  2 => [1, 0, 2],
  3 => [1, 2, 0],
  4 => [2, 0, 1],
  5 => [2, 1, 0]
  ];

Do you really have $layout == 'layout_one'? We'll have to convert it:

$layout_number = [
  'layout_one'   => 0,
  'layout_two'   => 1,
  'layout_three' => 2,
  'layout_four'  => 3,
  'layout_five'  => 4,
  'layout_six'   => 5
  ];

To use it, after defining the parts above, simply do:

$layout = 'layout_four';

if (!array_key($layout, $layout_number))
  throw new Exception('Invalid layout');

$layout_number = $layout_number[$layout];

$layout_structure = $layout_combinations[$layout_number];

foreach ($layout_structure as $part_number) {
  echo $parts[$part_number];
  }

The main advantage is that it's very easily extensible. If you want to put another part, simply add it to the $parts array, add the corresponding new $layout_combinations and to the "english => number" conversion.

Note: a step could be prevented if $layout = 4 instead of $layout = 'layout_four'. This is highly preferable since it allow you to make it automatic, simply adding an element at the end of your $parts array.

Community
  • 1
  • 1
Francisco Presencia
  • 8,732
  • 6
  • 46
  • 90
  • 2
    This is really nice! Maybe ndiego should think about making it even simpler: No need for the $layout_number array, he should use integers as layout_numbers. For example: `$layout = 1` instead of `$layout = 'layout_one'`. Then he does not need the array layout_number anymore. What do you think about that? – Bluedayz Aug 23 '14 at 15:10
  • I completely agree, I just added a note. It makes the process of adding a new part to the layout as simple as adding a new element in `$parts` (: – Francisco Presencia Aug 23 '14 at 15:13
  • This is exactly what I was thinking! Thank you so much. I was just having trouble putting it all together. And yea, I like your ideas for simplifying the process. Thanks again! – ndiego Aug 23 '14 at 15:15
  • 1
    This is probably overcomplicating things -- you could generate the different combinations and layout numbers programmatically. – i alarmed alien Aug 23 '14 at 15:23
  • Thanks @girlwithglasses, I noted it in `I'm sure there's some algorithm to do the same so it doesn't become difficult to maintain for N > 3` and I was hoping for the `$layout` to be able to be a number from the beginning by changing some previous code from the OP, so no need for that step also. – Francisco Presencia Aug 23 '14 at 15:25
  • It would be more efficient to encode the order of the sections in the identifier you're using for each layout -- then you don't need to maintain `layout_combinations`. – i alarmed alien Aug 23 '14 at 15:46
2

What about this:

<?php
$h = '<div class="header">Header</div>';
$c = '<div class="content">Content</div>';
$f = '<div class="footer">Footer</div>';

if ($layout == 'layout_one') {
    echo $h.$c.$f;
} elseif($layout == 'layout_two') {
    echo $c.$h.$f;
} elseif($layout == 'layout_three') {
    echo $f.$h.$c;
}
Bluedayz
  • 599
  • 5
  • 17
2

Create an identifier for each layout that dictates the order of the components, e.g. h_c_f means header, content, footer, and c_f_h is content, footer, header.

Store the contents of your sections in an array indexed by the appropriate letter:

$section_stuff = array(
   'h' => '<div>Header</div>',
   'c' => '<div>Contents</div>',
   'f' => '<div>Footer</div>',
);

Assemble your output using the layout identifier to work out the order:

// $order is the layout name, e.g. c_f_h, f_c_h, etc.
// split $order by "_" to get the appropriate order

$ordered = explode( '_', $order );
foreach ($ordered as $section) {
    echo $section_stuff[$section];
}

Obviously you'd need to add in error checking, etc.

The advantage with this method is that you could use something like a drag-and-drop interface to set up the order of the sections; the identifier name dictates the layout, rather than being an arbitrary value.

If you want to generate all the possible layouts in advance, the PHP cookbook has some suitable suggestions.

i alarmed alien
  • 9,412
  • 3
  • 27
  • 40
1

Switch case can be used to instead of long elseif conditions. Because switch is efficient than elseif and will support large amount of condition. The exact replacement of your code will be like follows for switch.

switch ($layout) {
    case 'layout_one':

        echo '<div class="header">Header</div>';
        echo '<div class="content">Content</div>';
        echo '<div class="footer">Footer</div>';

        break;
    case 'layout_two':

        echo '<div class="content">Content</div>';
        echo '<div class="header">Header</div>';
        echo '<div class="footer">Footer</div>';

        break;
    case 'layout_three':

        echo '<div class="footer">footer</div>';
        echo '<div class="header">Header</div>';
        echo '<div class="content">Content</div>';

        break;
}

additionally a tricky work cane done by php include function. You can create template as php file with the same name used on the if statement and use the variable in include statement. Sample code would be like follows.

include("/path_to/layout/".$layout.".php");

Sample HTML layout will be like follows with related names.

layout_one.php

<div class="header">Header</div>
<div class="content">Content</div>
<div class="footer">Footer</div>
sugunan
  • 4,408
  • 6
  • 41
  • 66
  • Yeah, but I will still have to replicate the order manually for each case. Maybe there is no way around the replication...hmmmm – ndiego Aug 23 '14 at 15:04