Separating view from logic?

I am really scratching my head about how to go about finding a way to separate view from logic for dynamically generated tables. how can this be accomplish? I have tried for a few days but every time I try a different approach I always have to stick some php logic in the view, otherwise I won’t be able to echo nothing?

Try enforcing this on yourself:

In your View, you may only use the “echo” command while inside PHP tags. Anything outside of the PHP tags is fair.

Now code your page. [Hint: Variables can contain anything, including HTML.]

i can’t really force myself to use only “echo” since I have to use a foreach() function to retrieve and view data and put this data in a table or list with a few if statements in between.???

maybe what I am not understanding is not the script itself but what separating logic and view mean?

<table>
<?php echo $thetable; ?>
</table>

Now define $thetable in your logic file instead.

You do not put anything in the View that isnt an echo. (This is a bit of an over-exaggeration of seperating logic and view, but if you are having trouble understanding, then it’s good to overdo it, then ease back a little.)

yes, this is the method that I use; so I guess I am already separating logic from view then. ok good to know lol.

the reason why I was asking is because I am trying to echo a dynamically generated php value from the bottom of hte page and echo it on top of the page. I read that the only way to accomplish that is to separate my logic and write the logic on top of the page and then nest every element into it so I can echo what I want on top of the page. but the thing that still escape me is no matter if I totally separate everything and even put my logic in another file. the php result that I am after will always come after the fact and will never be able to echo this value on top.

I then learned that I can use javascript to do this for me but elas I have absolutely no knowledge in javascript so I rather stick to php if it is at all possible. can this be accomplished in php you figure?

There is no such thing as ‘the bottom of the page’ until you output the bottom of the page to the browser.

The lesson to impart with separating logic and view is that you can do every bit of data processing before you even START to output any HTML. The HTML doesnt change anything; so there isn’t data “at the bottom of the page” - the data exists whenever you create it. You just choose to put it at the bottom of the page when you render it to the browser.

If i say:
Logic.php:

<?php $thetable = "<tr><td>A thing.</td></tr>"; 
include_once('View.php'); 
?>

I can now put $thetable in… anywhere in the View that I want. (granted, with that HTML, it only really makes sense to stick it between some <table> tags… but the point is still there.)

View.php:

<table>
<?php echo $thetable; ?>
</table>
<p>And because I can</p>
<table>
<?php echo $thetable; ?>
</table>

And to reinforce the idea of “there’s no such thing as the bottom of the page…”

Logic.php:

<?php $thebottom = "<tr><td>A thing.</td></tr>";  //So this goes at the bottom.
$thetop = $thebottom."<tr><td>And Double</td></tr>"; //And this goes at the top, but we defined it AFTER the bottom, because it uses the bottom.
include_once('View.php'); 
?>

View.php:

<table>
<?php echo $thetop; ?>
</table>
<p>And because I can</p>
<table>
<?php echo $thebottom; ?>
</table>

i see what you are saying and I agree with you. The only thing is I have to run 2 queries and count records for each and then make a percentage calculation of the 2 queries. That can only happen after I have ran both my queries. Unless I apply some sort of neat CSS trick that would shift everything around I don’t see how I can produce what I want in the way you are trying to explain it to me. Maybe if I duplicate the queries up at the top and get my value from that I can see it working but I was trying to maybe understand better what I am doing and find a better solution than duplicating the same code in two different places.

THe thing I don’t understand is from what I have researched everyone say it is cleaner and easier to separate logic and views; makes thing easier to maintain. THe way I see it, it is much much harder to nest functions within functions and have scripts all over the place in other files or somewhere else in the page when you can neatly combine everything together in a clean and orderly fashion that is so much easier to follow and maintain if thing change along the way. Am I completely missing the point ? I just don’t get it.

Why?

<?php $query1 = $db->query("I'ma Query");
while($query1->doarow() {
 //Do The Things
}
$query2 = $db->query("Imanother Query");
while($query2->doarow() {
 //Do The Things
}
$percent = $stuffFrom1 / $stuffFrom2;
//Note at this point I have done absolutely ZERO HTML output - I dont need CSS, I dont need javascript... I just have the raw data.
include_once('View.php'); 
?>

I see that, but how are you going to echo the data? The data needs to be in between curly braces which mean I am going to have to nest a bunch of stuff together which will make thing really hard to figure out if I want to change stuff around therafter, no?

So you show me what your data looks like, and what you need it to look like, and i’ll show you how you can write it to a variable that you can echo later.

    	<?php 
///completed fire training
		$userid = Input::get('user');
		$rs = DB::getInstance()->get('fsattendances LEFT JOIN firesafety ON fsattendances.fireSafetyId = firesafety.id LEFT JOIN fstraining LEFT JOIN fscomponents ON fstraining.FSComponentId = fscomponents.id ON firesafety.id = fstraining.fireSafetyId', array( 'fsattendances.attendee', '=', $userid));
		if($rs->count()){
			echo '<table>';
				echo '<th class="th">Fire Safety Component</th><th class="th">Completed On</th>';
				echo '<tr>';
					  foreach($rs->results() as $list){
						  echo	'<td class="tdLeft"> <a  href="firesafety.php?id='.escape($list->id).'">'.escape($list->componentTitle).'</a></td>';
						  echo	'<td class="tdLeft">'.escape(date ("F d, Y",strtotime($list->FSDate))).'</td>';
				echo '</tr>';	
						}	
		}
		else
		  {echo '<span class="error">No Fire Safety Training has been completed yet.</span>';}
		echo'</table>';
		
		$rsCount= count($rs->results());
		?>
        <hr>
    </section>
  
  
      <section class="sectionLeft">
    	<h3 class="pow">Fire Safety Training NOT yet completed</h3>
    	<?php 
		$rss = DB::getInstance()->query(" SELECT fscomponents.componentTitle, fscomponents.id, a.attendee FROM (SELECT fscomponents.componentTitle,fsattendances.attendee 
			FROM fscomponents LEFT JOIN fstraining 	ON fscomponents.id = fstraining.FSComponentId 
			LEFT JOIN fsattendances ON fstraining.fireSafetyId = fsattendances.fireSafetyId 
			WHERE fsattendances.attendee = $userid) AS a RIGHT JOIN fscomponents ON a.componentTitle = fscomponents.componentTitle");
		
		if($rss->count()){
			
			echo '<table>';
					echo '<tr>';
					  foreach($rss->results() as $lists){
						  if($lists->attendee == NULL){
						  echo	'<td class="tdLeft"> <a  href="firesafety.php?id='.escape($lists->id).'">'.escape($lists->componentTitle).'</a></td>';
						  }
					echo '</tr>';	
					  }	
		}else{
			echo 'There is no existing Fire Training Component at the monent';}
		echo'</table>';
		$rssCount= count($rss->results());
		
		$percentage= ($rsCount / $rssCount);
		
		?>
        <hr>
    </section>
    
<div class="sectionLeft">
//////the line below is what I want to show above both table result////////////////////////////////////////////////////////////////////////
<span id="completed" class="outputHeading">Fire Safety Training is <?php echo round( $percentage * 100 );?>% Completed</span>">

</div>

Logic.php

   	<?php 
///completed fire training
		$userid = Input::get('user');
		$rs = DB::getInstance()->get('fsattendances LEFT JOIN firesafety ON fsattendances.fireSafetyId = firesafety.id LEFT JOIN fstraining LEFT JOIN fscomponents ON fstraining.FSComponentId = fscomponents.id ON firesafety.id = fstraining.fireSafetyId', array( 'fsattendances.attendee', '=', $userid));
                $table = "";
		if($rs->count()){
                        $table .= '<table><tr><th class="th">Fire Safety Component</th><th class="th">Completed On</th></tr>';
					  foreach($rs->results() as $list){
						  $table .= '<tr><td class="tdLeft"> <a  href="firesafety.php?id='.escape($list->id).'">'.escape($list->componentTitle).'</a></td><td class="tdLeft">'.escape(date ("F d, Y",strtotime($list->FSDate))).'</td></tr>';	
		else
		  { $table .= '<tr><td colspan='2'><span class="error">No Fire Safety Training has been completed yet.</span></td></tr>';}
		$table .= '</table>';
					}	
		$rsCount= count($rs->results());
            $table2 = "";
 		$rss = DB::getInstance()->query(" SELECT fscomponents.componentTitle, fscomponents.id, a.attendee FROM (SELECT fscomponents.componentTitle,fsattendances.attendee 
			FROM fscomponents LEFT JOIN fstraining 	ON fscomponents.id = fstraining.FSComponentId 
			LEFT JOIN fsattendances ON fstraining.fireSafetyId = fsattendances.fireSafetyId 
			WHERE fsattendances.attendee = $userid) AS a RIGHT JOIN fscomponents ON a.componentTitle = fscomponents.componentTitle");
		
		if($rss->count()){
			
			$table2 .= '<table>';
			  foreach($rss->results() as $lists){
				  if($lists->attendee == NULL){
			        	  $table2 .= '<tr><td class="tdLeft"> <a  href="firesafety.php?id='.escape($lists->id).'">'.escape($lists->componentTitle).'</a></td></tr>';
				  }
			  }	
		} else{
			$table2 .= '<tr><td>There is no existing Fire Training Component at the moment</tr></td>';
            }
		$table2 .= '</table>';
		$rssCount= count($rss->results());
		
		$percentage= round($rsCount / $rssCount*100);
            include_once("View.php");

View.php:

<div class="sectionLeft">
<span id="completed" class="outputHeading">Fire Safety Training is <?php echo $percentage; ?>% Completed</span>">

</div>

//Whatever came before the code section posted....
<?php echo $table; ?>
        <hr />
</section>
  
  
  <section class="sectionLeft">
	<h3 class="pow">Fire Safety Training NOT yet completed</h3>
   <?php echo $table2; ?>
    <hr />
</section>

OOOOOKKK now I get it… Done this way as you demonstrated totally can work without even me trying it first I can see that. That is a pretty neat method of getting things done, I never seen this done that way before. very Cool indeed! I can see myself using this style of writing code in the remainder of my app. thanks so much!!! x100

Though, there definitely shouldn’t be any HTML in the logic section. None at all. That’s a pretty big violation of separating view and logic.

1 Like

So you are saying that if I wanted to use the same data for, say, an RSS feed, XML file, PDF, API JSON, whatever, ie. any non-HTML use, that having HTML in the logic it could make more work.I get that.

But it seems to MVC newbie me there’s bound to be some view in the logic or some logic in the view.

How do you suggest to get past that over-lapping?
The Controller?

You’ll need to be a bit more specific. Is there a specific example you have in mind?

I’m referring to this discussion.

So I’m guessing this is where the Controller steps in for both the correct logic and correct output.
Or is “logic” and Contoller the same?

It’s actually both common and proper to have "if"s and "foreach"es and even some formatting calls inside the view. We’re not limited to just echo.

Not sure if that satisfies the concern you had.

1 Like

Here’s how I would write that code to separate the view and logic.

###firesafety_logic.php

<?php

$userid = Input::get('user');

// also important: use meaningful variable names
// clarity is better than brevity
// for example, I don't know what "rs" is short for
$rs = DB::getInstance()->get(
    'fsattendances 
    LEFT JOIN firesafety ON fsattendances.fireSafetyId = firesafety.id 
    LEFT JOIN fstraining 
        LEFT JOIN fscomponents ON fstraining.FSComponentId = fscomponents.id 
    ON firesafety.id = fstraining.fireSafetyId', 
    array('fsattendances.attendee', '=', $userid)
);

$rss = DB::getInstance()->query("
    SELECT fscomponents.componentTitle, fscomponents.id, a.attendee 
    FROM (
        SELECT fscomponents.componentTitle,fsattendances.attendee 
        FROM fscomponents 
        LEFT JOIN fstraining ON fscomponents.id = fstraining.FSComponentId 
        LEFT JOIN fsattendances ON fstraining.fireSafetyId = fsattendances.fireSafetyId 
        WHERE fsattendances.attendee = $userid
    ) AS a RIGHT JOIN fscomponents ON a.componentTitle = fscomponents.componentTitle
");

require 'firesafety_view.html.php';

###firesafety_view.html.php

<section class="sectionLeft">
    <?php if ($rs->count()): ?>
        <span id="completed" class="outputHeading">Fire Safety Training is <?php echo round($rs->count() / $rss->count() * 100) ?>% Completed</span> <!-- this one is flirting with the line between view and logic -->

        <table>
            <th class="th">Fire Safety Component</th><th class="th">Completed On</th> <!-- I think even TH's need their own TR -->
            <tr>
                <?php foreach ($rs->results() as $list): ?>
                    <td class="tdLeft"><a href="firesafety.php?id=<?php echo escape($list->id) ?>"><?php echo escape($list->componentTitle) ?></a></td>
                    <td class="tdLeft"><?php echo escape(date("F d, Y", strtotime($list->FSDate))) ?></td> <!-- this one is flirting with the line between view and logic -->
                <?php endforeach ?>
            </tr>
        </table>
    <?php else: ?>
        <span class="error">No Fire Safety Training has been completed yet.</span>
    <?php endif ?>
</section>

<hr>

<section class="sectionLeft">
    <h3 class="pow">Fire Safety Training NOT yet completed</h3>

    <?php if ($rss->count()): ?>
        <span id="completed" class="outputHeading">Fire Safety Training is <?php echo round($rs->count() / $rss->count() * 100) ?>% Completed</span> <!-- this one is flirting with the line between view and logic -->

        <table>
            <tr>
                <?php foreach ($rss->results() as $lists): ?>
                    <?php if ($lists->attendee == NULL): ?>
                        <td class="tdLeft"><a href="firesafety.php?id=<?php echo escape($lists->id) ?>"><?php echo escape($lists->componentTitle) ?></a></td>
                    <?php endif ?>
                <?php endforeach ?>
            </tr>
        </table>
    <?php else: ?>
        There is no existing Fire Training Component at the monent
    <?php endif ?>
</section>

EDIT: I didn’t run this, so hopefully there aren’t any typos.

1 Like