Link to home
Start Free TrialLog in
Avatar of Bruce Gust
Bruce GustFlag for United States of America

asked on

How does this "for" loop break down (Part II)?

This is "Part II" of a two part question. Part I is at https://www.experts-exchange.com/questions/28966558/How-does-this-for-loop-break-down-Part-I.html. I've got a couple of graphics that provide some background that you might want to refer to.

We're at line 11 of the following code:

$data = pf::getAppData('/app/accounttimeline');
$timeline = AccountTimelines::getAccountTimeline($accountid); //the SELECT statement that produces the sample data I've got listed above
$data['timeline'] = array();
$txnGroup = array();
 for ($i=0; $i < count($timeline); $i++) {
	$event = $timeline[$i];
	$event['demo'] = ($data['badge']['practiceid'] == '63'?$accountid : false);
	if ($event['eventtype']=='transaction') {
		$thisDate = Date('mdy', strToTime($event['eventdate']));
		$nextDate = (isset($timeline[$i+1])&&$timeline[$i+1]['eventtype']=='transaction')?Date('mdy', strToTime($timeline[$i+1]['eventdate'])):null;
		array_push($txnGroup, $event);
		if ($thisDate != $nextDate) {
			//add to data
			if (count($txnGroup)!=1) {
				array_push($data['timeline'], array(
					'eventdate'=>Date('m/d/Y', strToTime($event['eventdate'])),
					'eventtype'=>'transactions',
					'runningbal'=>$event['runningbal'],
					'transactions'=>$txnGroup
				));
			} else {
				array_push($data['timeline'], $event);
			}
			$txnGroup = array();
		}

Open in new window


Line 11 is crucial to the project that I'm working on. We've got a multi-dimensional array that's being enhanced with the data coming from a SELECT statement. We're setting up some additional indices to hold more data and we're a point now where we're checking the eventtype to see if it's a "transaction:"

if ($event['eventtype']=='transaction') {//if the eventtype is a "transaction," then...
		$thisDate = Date('mdy', strToTime($event['eventdate'])); //set up $thisDate as a strtotime variable
		$nextDate = (isset($timeline[$i+1])&&$timeline[$i+1]['eventtype']=='transaction')?Date('mdy', strToTime($timeline[$i+1]['eventdate'])):null;//[b]if the next eventtype in the recordset is also a "transaction," then...not sure what this is doing[/b]
		array_push($txnGroup, $event);// you're using array_push to add everything that's currently compiled in the $event index to the $txnGroup array
 if ($thisDate != $nextDate) {//[b]if $thisData is not equal to $nextDate, then you've got a potential group of transactions as opposed to something that's flying solo[/b]
                        //add to data
                        if (count($txnGroup)!=1) {//if the there's more than one transaction in the $txnGroup, then we're going to make the eventtype "transactions," rather than "transaction"
                            array_push($data['timeline'], array(//push all of the following into the $txnGroup array
                                'eventdate'=>Date('m/d/Y', strToTime($event['eventdate'])),
                                'eventtype'=>'transactions',
                                'runningbal'=>$event['runningbal'],
                                'transactions'=>$txnGroup
                            ));
                        }

Open in new window


This is the last part of the "for" loop, but it represents something that I'm suspecting, but I'm not certain about...

}else {//if the eventtype is not a "transaction," then simply push what's there into the $event
array_push($data['timeline'], $event);
 }
 $txnGroup = array();//I think what's happening here is that I'm resetting the $txnGroup array to "". Rather than it being populated with anything, I'm starting fresh with the next round of $I in my "for" loop

Open in new window


Am I close?
SOLUTION
Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
greetings  brucegust , , , In looking at your code with your comments, , I do not believe u are seeing what this code tries to do.  It is true that the only "IF TEST" you have in this for the $event "eventtype" is the value of  'transaction'  as this line shows -
               if ($event['eventtype']=='transaction') {

but in many data SELECTS there are times that some ROWS need to be grouped or marked as being similar, and this code tries to use the  'eventdate'     to set an EXTRA array entry when the date changes detected by this line -
          if ($thisDate != $nextDate) {

and these lines get the current event date and the next SELECT ROW  event date -
       $thisDate = Date('mdy', strToTime($event['eventdate']));
       $nextDate = Date('mdy', strToTime($timeline[$i+1]['eventdate']));    // shortened code

so if the two ROWS eventdate are the same then it just adds the event to the array
    $data['timeline'][] = $event;

if the dates are different in the   -
     if ($thisDate != $nextDate) {

then this array is placed in the $data['timeline'][ ]  - --
    array( 'eventdate'=>Date('m/d/Y', strToTime($event['eventdate'])),
      'eventtype'=>'transactions',
      'runningbal'=>$event['runningbal'],
      'transactions'=>$txnGroup
      )

as a MARKER to show that the previous added events are grouped by DATE, all of the $event  with the same dates are in the  $txnGroup, in the  'transactions' of the added array

SOOOO, then the if test for -
         if ($thisDate != $nextDate) {
is TRUE then the  $txnGroup  array is emptied with -
     $txnGroup = array();

and the next data ROWS as $event are added to the $txnGroup until the date is not equal.

Hope this helps some how? but you failed to place the end    }    for the -
          for ($i=0; $i < count($timeline);    ) {
LOOP, and the
          if ($event['eventtype']=='transaction') {

So there may be other operations below the code you have shown. . .

- - - - - - - - -
I must say that almost NO DEVELOPERS in PHP use your  array_push( ) , instead they use the common array  [ ]   as -
      ///  array_push($data['timeline'], $event); // not good to use
    $data['timeline'][ ] = $event; // a more common PHP usage.

But maybe this code was "Translated" from another coding language ? ?
Avatar of Bruce Gust

ASKER

Gentlemen!

As a quick aside, I've got a buddy who's taking some classes in an effort to become a PHP developer. I spend far too much time asking questions to feel like an "authority," but he seeks me out nevertheless for some help with some basic code.

He's taking a class in Java and he asked me if I could help. I know nothing about Java, but I encouraged him to subscribe to EE if for no other reason than with Google you can get the WHAT, but you very rarely get the WHY. And when you're seeking to understand something and not just get something done, EE is an invaluable resource and this question reinforces that point.

Thank you!

Slick, I've posed several questions, as Ray can attest, pertaining to this project that demonstrates several fallacies when it comes to healthy code. The client is migrating everything over to a third party software that promises to meet their needs and my role is to simply plug the holes in their current app and add some additional features until they've moved everyone over to the new system.

It's a bear. But... it's a healthy exercise in stretching my knowledge and it's resources such as yourself, Ray and several others, who keep things moving forward as opposed to getting stuck.

With that said:

I'm tracking with you on everything with the exception of the MARKER.

When I think of an array, rather than a series of rows, I'm thinking of a single row with multiple columns. It sounds as though the ONLY time "transactions" shows up as a value within the eventtype column is in the aftermath of a series of rows ($event being the index) with the same date.

Take a look at some sample data as it's coming from the database:

User generated image
So, you've got several rows in the database that have the same date. As it's being processed by the above code, I would THINK that those rows that have the same date would be categorized as "transactions," yes?

On the page that's actually displaying the data, I see this:

  break;
        case "transaction":
        ?>
        <div class='amount'><?=GlobalFunctions::formatMoney($amount)?><span class='float'>
          <span class='payer <?=$payer?>'><?=$payer?></span><span class='transtype <?=$transactiontype?>'><?=$transactiontype?></span>
        </div>
        <?if($dos !== null && $dos !=='1900-01-01'){?><div class="dos"><?='DOS : ' . date('M d, Y',strtotime($dos))?></div><?}?>
        <div class='encounter'><?if($encountercode != null){?>Encounter Code <?=$encountercode?><?}else{?>No encounter<?}?></div>
        <div class='description'>
          <?=$content?>
        </div>
        <?
          break;
        case "transactions":
        ?>
        <ul>
        <?foreach($transactions as $txn){
        ?>
        <li>
          <div class='amount'><?=GlobalFunctions::formatMoney($txn['amount'])?><span class='float'>
            <span class='payer <?=$txn['payer']?>'><?=$txn['payer']?></span><span class='transtype <?=$txn['transactiontype']?>'><?=$txn['transactiontype']?></span>
          </div>
          <?if($txn['dos'] !== null && $txn['dos'] !=='1900-01-01'){?><div class="dos"><?='DOS : ' . date('M d, Y',strtotime($txn['dos']))?></div><?}?>
          <div class='encounter'><?if($txn['encountercode'] != null){?>Encounter Code <?=$txn['encountercode']?><?}else{?>No encounter<?}?></div>
          <div class='description'>
            <?=$txn['content']?>
          </div>
          <div class='txntime'><?=Date('h:i A',strtotime($txn['eventdate']))?></div>
          <?/*if(isset($txn['runningbal'])){?>
           <div class='runningbal'>Running balance : <span><?=$txn['runningbal']?></span></div>
          <?}*/?>
        </li>
        <?}

Open in new window


On line 2, you have "transaction," which would be a single row. But then on line #14, you've got "transactions." A few lines down, you've got a "foreach," which makes perfect sense in that you've got several rows worth of data, each having the same date.

But I'm thinking that every one of those rows that's getting ready to be spit out by that "foreach" would have to have an eventtype of "transactions," and it sounds like, from your explanation, "transactions" only shows up once - kind of like an exclamation point - after a series of rows with the same date.

That doesn't sound right. Where am I falling short in my understanding?
You ask - "As it's being processed by the above code, I would THINK that those rows that have the same date would be categorized as "transactions," yes? "

This is the Idea, but Not to close to the "Code" logic processing, , as you have a TEST of some variable in a PHP Switch and Case operation, and the OUTPUT display Changes with different matches in the   CASE:



OK, you did NOT seem to notice that the TWO case types of -
       case "transaction":
       case "transactions":

give DIFFERENT HTML groupings as the "transaction" case will do 4 <div> output, ,
BUT the "transactions" do an HTML LIST, that begins with a <ul> , and then a <li> is added for each of the $event that was added to the $txnGroup array in the PREVIOUS PHP building of arrays. Each <li> has 5 <div> output, very similar to the "transaction" case HTML output. Please consider WHY development staff wants to show a list <ul> grouping for time-date related data rows.

- - - - - - - - - - - - - - - - - -  - - - -
You say - "But I'm thinking that every one of those rows that's getting ready to be spit out by that "foreach" would have to have an eventtype of "transactions," and it sounds like, from your explanation, "transactions" only shows up once - kind of like an exclamation point - after a series of rows with the same date. "

Yess to the Last part, ,  an exclamation point is a MARKER in english writing, that signifies the END of sentence, and Special Importance for that sentence. BUT you do NOT see what is going on in the building of the $data['timeline'] Array used for OUTPUT with the SWITCH-CASE ,

You say - "I'm thinking that every one of those rows that's getting ready to be spit out by that "foreach" would have to have an eventtype of "transactions," ", , , , , but this is not what can work, because the OUTPUT has to be changed to a list <ul> for grouping for an INNER array (not the $data['timeline'] array) that has all of the stored $event from the  $txnGroup array, all of the $event (a data ROW) is in the $transactions array in your SWITCH-CASE code, and are NOT tested for their eventtype,
the added ARRAY entry in the build code as -
array_push($data['timeline'], 
  array('eventdate'=>Date('m/d/Y', strToTime($event['eventdate'])),
  'eventtype'=>'transactions',
  'runningbal'=>$event['runningbal'],
  'transactions'=>$txnGroup
  ));

Open in new window


is tested for the 'eventtype', BUT in that array there is sub-array, the -
    'transactions'=>$txnGroup
which is what operates in the OUTPUT CASE as the foreach -
<?foreach($transactions as $txn){ ?>

, , I am not trying to comment on how this code, to me, seems inefficient and CONFUSING. BUT the developers should NEVER have used the database table  ROW field name  "eventtype" value as  'transaction' and  'transactions'  as the $data['timeline'] eventtype, , it just TOO CONFUSING, they would do better at use eventtype value as "single" and "dategroup", or some other. the image you gave for SELECT results has all eventtypes as "transaction", so I wonder what happens if in the database SELECT a eventtypes is NOT a "transaction"? ? ?

I have tried to get you to re analyze the code operations in your presentation here, so you have a better understanding of the "WHY" this was set as the code used to get a database read, and then output to HTML with PHP to have a display with sections and groupings for many ROWS of data.
Slick!

I built a "sandbox" in order to better isolate the code and view the results.

I was puzzled as to why the MARKER would come after the rows that had been identified as a group. But then I saw the last part of the function: $data['timeline'] = array_reverse($data['timeline']); and it made perfect sense. We're going in reverse order so putting the MARKER at the tail end of the grouped variables will work when it's run from the back to the front.

I get it!

But I wanted you to see this.

Here's my code:

		 $set = AccountTimelines::getAccountTimeline(11128265);
		 
		 //var_dump($timeline);
		   $runningbal = 0;
		 foreach($set as &$item){
		  if($item['eventtype'] == 'transaction'){
			$runningbal += pfmoney::toCents($item['amount']);
			$item['runningbal'] = pfmoney::fromCents($runningbal);
		  }
		} //adding the runningbal index to the array if the eventtype is a transaction
		
		 $data['timeline'] = array();
		 $txnGroup = array();
		 
		  for ($i=0; $i < count($set); $i++) {
                $event = $set[$i]; //changing what would otherwise be a cumbersome key to something a little more intuitive 
				if($event['eventtype']=='transaction')
				{
					$thisDate = Date('mdy', strToTime($event['eventdate']));
					$nextDate = (isset($timeline[$i+1])&&$timeline[$i+1]['eventtype']=='transaction' AND $timeline[$i+1]['payer']=='I' AND $timeline[$i+1]['transactiontype']=='P' )?Date('mdy', strToTime($timeline[$i+1]['eventdate'])):null;
					array_push($txnGroup, $event); //pushing anything with an eventtype of "transaction" to its own array
					if ($thisDate != $nextDate) //looking to see if the next row has a date that is not equal to the current row's date. If not, then
					{
						//add to data
						if (count($txnGroup)!=1) 
						{
							array_push($data['timeline'], array(
								'eventdate'=>Date('m/d/Y', strToTime($event['eventdate'])),
								'eventtype'=>'transactions',
								'runningbal'=>$event['runningbal'],
								'transactions'=>$txnGroup//I don't understand this
							));
						} 
						else 
						{
							array_push($data['timeline'], $event); //anything that's not a transaction event type gets put into the $data['timeline'] array as a regular $event
						}
					}
				}
		  }
		  
		  //var_dump($data['timeline']);
		  
		 foreach($data['timeline'] as $txn)
		  {
			  echo $txn['transactions'].'<br>';
		  }

Open in new window


And here's a screen shot of what I get in my sandbox as well as what I get when I run the actual page.

Sandbox...

User generated image
Actual page...

User generated image
Why do I get the error in my sandbox, and then get the "arrays." I'm thinking the arrays should the 'transactions'=>$txnGroup//I don't understand this" part of the code.

Bottom line: The new array that serves as a marker makes total sense now that I've been able to understand the flow of the data (reversed), but what's the significance of the "transactions" index? That last line: "transactions=?$txnGroup" is the last piece of the puzzle.

What do you think?

Thanks!
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Slick, you've written a book for me, man! Thank you! Ray...as always, it's a treat. Consider yourselves the recipient of a digital Diet Coke on me! Rock on and Happy Friday!