0

This is a continuation of my previous question.

UPDATE: Thank you Rasclatt for the cleaner script. It is overall better than my original so I'll be using that instead.

This is what's inside the db, showing the records for ACOL. The query used is the same one I used in the script. ACOL's DATEIN ends at 2015/01/30 and started back on 2015/03/04
what's in db

This is the output. The row with the orange times indicates TIMEIN while red represents TIMEOUT (not shown on the db). Notice how ACOL have records for February even though there is none in the db.
the output

As you can see, some time for the correct existing dates matches those in the db (4th, 17th) but some are completely missing.
ACOL's march records

No other instances of ACOL exist that might have caused the inaccuracies. I've queried to see if the TIMEIN/OUT pairs matched someone else's but there's no result. I have no idea where the time came from.

The script

<?php
function is_weekend($date = false)
    {
        return (date("D",strtotime($date)) == 'Sun' || date("D",strtotime($date)) == 'Sat')? true : false;
    }
// Make a function for on time, makes that part changeable
// gives the ability to change start times ($default) in the future
function on_time($timein = false, $default = '09:30')
    {
        if($timein == false)
            return true;

        return (strtotime($timein) > strtotime($default))? false : true;
    }

function early($timeout = false, $default = '18:00')
    {
        if($timeout == false)
            return true;

        return (strtotime($timeout) < strtotime($default))? false : true;
    }   

$staff = $dome = array();

while($row = ibase_fetch_assoc($result))
{   $dome[] = $row; }

foreach($dome as &$value)
    if (ctype_upper(substr($value['NAME'],0,2))== TRUE)
        $staff[] = $value['NAME'];
$staff = array_values(array_unique($staff,SORT_REGULAR));

$m = $_POST['month'];
$y = $_POST['year'];

//reorganize the array by day
foreach($dome as $user) {
        if(!preg_match('/^'.$y.'\/'.$m.'/',$user['DATEIN']))
            continue;

        $new[ltrim(substr($user['DATEIN'],-2),"0")][strtolower($user['NAME'])][] =   $user['TIMEIN'];
        $newto[ltrim(substr($user['DATEIN'],-2),"0")][strtolower($user['NAME'])][] =   $user['TIMEOUT'];
    } 

if ($m != '' || $y != '')
    echo "<br><u>Attendance for ".date("F", mktime(null, null, null, $m, 1)).", ".$y."</u>";
else
    break;
?>

<table id="caltable" cellpadding="0" cellspacing="0" border="0">
    <tr>
        <td>
            NAME
        </td>
<?php
// Set header row
$day_in_mo  =   cal_days_in_month(CAL_GREGORIAN,$m,$y);
for($i = 1; $i <= $day_in_mo; $i++) { ?>
        <td><?php echo $i; ?></td>
        <?php
    } ?>
    </tr>
<?php
// Loop through staff
foreach($staff as $name) { ?>
    <tr>
        <td rowspan=2><?php echo $name; ?></td>
        <?php
        $keyname    =   strtolower($name);
        for($i = 1; $i <= $day_in_mo; $i++) {
                $timein =   (!empty($new[$i][$keyname][0]))? $new[$i][$keyname][0] : false;?>

        <td class="<?php if(!is_weekend("{$y}-{$m}-{$i}")) { echo 'weekday'; if(!on_time($timein)) echo ' late'; echo '"'; } else echo 'weekend' ?>"><?php
                // Match keys and see if user is listed in that day
                echo ($timein != false)? $timein : '<div class="absent">-</div>'; ?></td>
        <?php
            } ?>
    </tr>
    <tr>
        <td style="display:none"></td>
        <?php
        $keyname    =   strtolower($name);
        for($i = 1; $i <= $day_in_mo; $i++) {
                $timeout = (!empty($newto[$i][$keyname][0]))? $newto[$i][$keyname][0] : false; ?>

        <td class="<?php if(!is_weekend("{$y}-{$m}-{$i}")) { echo 'weekday'; if(!early($timeout)) echo ' early'; echo '"'; } else echo 'weekend' ?>"><?php
                echo ($timeout != false)? $timeout : '<div class="absent">-</div>'; ?></td>
        <?php
            } ?>
    </tr>
    <?php
} ?>

</table>
5
  • Is the DATEIN for key 3 supposed to be 2012 or 2015? Commented Jul 28, 2015 at 3:48
  • Also, are the uppercase staff and STAFF interchangeable (ie represent the same entity)? Commented Jul 28, 2015 at 3:51
  • @Rasclatt 2012. $dome contains all the data from 2012 to 2015. The reason it's below the newer dates is because of the group by name in the SQL. As for the cases, I coded for the system to completely ignore the non-all caps username because I can't find a way to filter them through SQL. Commented Jul 28, 2015 at 3:51
  • But you wouldn't display anything but Jan 2015 in your example (it would skip if it hits it)? Commented Jul 28, 2015 at 3:52
  • Yes, if the user selects January and 2015, it won't display any attendance for the other dates Commented Jul 28, 2015 at 3:54

2 Answers 2

1

I think maybe I am not being very articulate on what I am suggesting. Where I think you are going wrong is how you are approaching this table. Because it's primarily a date-based table, I think reorganizing your data array by date right off the start is a good plan. Secondly, if you break your script down by isolated functions you will be better-able to customize the table layout. If you notice, I added functionality to the table without extensive altering of the original table-generation script:

Create some simple functions (include at top of page):

<?php
// Make a function for the weekend to isolate that condition
// makes it much cleaner
function is_weekend($date = false)
    {
        return (date("D",strtotime($date)) == 'Sun' || date("D",strtotime($date)) == 'Sat')? true : false;
    }
// Make a function for on time, makes that part changeable
// by giving you the ability to change start times ($default) in the future
function on_time($timein = false, $default = '09:10')
    {
        if($timein == false)
            return true;

        return (strtotime($timein) > strtotime($default))? false : true;
    }

CSS for changing look based on your prefs:

<!-- Just some quick styling -->
<style>
#caltable td    {
    width: 50px;
    padding: 5px;
    font-family: Arial, Helvetica, sans-serif;
    font-size: 13px;
    text-align: center;
    border-bottom: 1px solid #CCC;
}
#caltable td:first-child    {
    width: 150px;   
}
.weekend    {
    background-color: #FFFF00;
}
.late   {
    background-color: orange;
    color: #FFF;
}
.weekday    {
    background-color: #EBEBEB;
}
.absent {
    color: #888;
    font-weight: bold;
}
</style>

Script algorithm:

$y  =   '2015';
$m  =   '01';

// I think it's important to reorganize the array by day
foreach($dome as $user) {
        if(!preg_match('/^'.$y.'\/'.$m.'/',$user['DATEIN']))
            continue;

        $new[ltrim(substr($user['DATEIN'],-2),"0")][strtolower($user['NAME'])][] =   $user['TIMEIN'];
    } ?>


<table id="caltable" cellpadding="0" cellspacing="0" border="0">
    <tr>
        <td>
            NAME
        </td>
<?php
// Set header row
$day_in_mo  =   cal_days_in_month(CAL_GREGORIAN,$m,$y);
for($i = 1; $i <= $day_in_mo; $i++) { ?>
        <td><?php echo $i; ?></td>
        <?php
    } ?>
    </tr>
<?php
// Loop through staff
foreach($staff as $name) { ?>
    <tr>
        <td><?php echo $name; ?></td>
        <?php
        $keyname    =   strtolower($name);
        for($i = 1; $i <= $day_in_mo; $i++) {
                $timein =   (!empty($new[$i][$keyname][0]))? $new[$i][$keyname][0] : false; ?>

        <td class="<?php if(is_weekend("{$y}-{$m}-{$i}")) { echo 'weekend'; if(!on_time($timein)) echo ' late'; echo '"'; } else echo 'weekday' ?>"><?php
                // Match keys and see if user is listed in that day
                echo ($timein != false)? $timein : '<div class="absent">-</div>'; ?></td>
        <?php
            } ?>
    </tr>
    <?php
    } ?>
</table>
Sign up to request clarification or add additional context in comments.

17 Comments

Thank you for the code but I apologize for not being clear enough: What troubles me is the if/else statements. I tried numerous ways to get the output, but I simply don't know where I've started going wrong. Your code is really nice and gives beautiful output, so an upvote for that.
Check my revisions. I have adjusted the script to accommodate your preferences in the table.
Also, a note for this comment: To clarify: The problem is that I keep getting mismatched time and blank cells, which I know are controlled by the if statements. which is 100% correct and the reason you are getting this is because you have too many places in your nested conditions that if a condition is not met, will carry on without building a cell. In my example, the <td>s are always built because they are not conditional. The look of them is conditional. Anyway, take a look at my script again, see if it works closer to what yours should.
Has to do with the date converter. Try modifying the $new[trim( to $new[ltrim( (notice the "l" on trim( -> ltrim( for "left trim"
Just so you know, what I ended up doing by accident is turning this: 2015/02/10 to this 2015/02/1 because I trimmed the 0 off both sides, I just wanted to trim off the left side so that the array key would be [1] instead of [01]. That's why it was messed up. It should be good now!
|
1

Doesn't look too wrong (although the many nested ifs will guarantee headaches when it comes to maintaining the code, but that's not your question).

Check these:

  • The gray cell else case outputs nothing in the <td>, which might account for empty cells.
  • Setting $cond = TRUE should probably be set one level above its current place, though I doubt that would make too much of a difference now.
  • If the NAME of the staff in your array isn't in correct case, you obviously have to compare something like strtoupper($value) == strtoupper(...array...).
  • Your Sun/Sat comparison seems odd; wouldn't that be more like == 'Sun' and == 'Sat'?

Besides those, it's hard to tell what might be wrong. You'd have to provide a complete array of your data, the wrong output and the desired output, otherwise it's impossible to see which values lead to which output.

Edit: And what's the initial assignment to $inidate via print_r supposed to mean? I guess you would want to have the same assignment as at the end of your main loop, the strftime business?

After all, this is an example of way too complex and thus error-prone code. Consider renaming variables to something meaningful, not $value, and extract methods instead of nesting too deep.

Edit 2: Perhaps I didn't make myself clear. This is the code after my suggestions. Is the output better now?

$inidate = "$y/$m/01"; //$y and $m chosen by user
$count=0; 
foreach ($staff as $key => $team) //row or use count on staff
{
    $j=0;
    echo "<tr><td>".($count+1).".</td><td>".$team."</td>";
    for ($i=0;$i<cal_days_in_month(CAL_GREGORIAN,$m,$y);$i++) //column
    {
        $cond = FALSE;
        while (($dome[$j]['DATEIN'] != "") && ($cond == FALSE))
        {
            if ($dome[$j]['DATEIN'] == $inidate)
            {
                if (strtoupper($team) == strtoupper($dome[$j]['NAME']))
                {
                    if ($dome[$j]['TIMEIN'] != "")
                    {
                        $cond = TRUE;
                        if (date("D",strtotime($getdate)) == 'Sun' || date("D",strtotime($getdate)) == 'Sat')
                        {   
                            //if late output time in yellow cell
                            if (strtotime($dome[$j]['TIMEIN']) > strtotime('09:10'))
                                echo "<td BGCOLOR='#ffff00'>".$dome[$j]['TIMEIN']."</td>";
                            else //output time normally
                                echo "<td>".$dome[$j]['TIMEIN']."</td>";
                        }
                        else //if its weekday outputs gray cell
                            echo "<td BGCOLOR='#525266'>".$dome[$j]['TIMEIN']."</td>";
                    }
                    else
                        echo "<td>AB</td>";
                }
            $j++;
            }
        }
        $inidate = strftime("%Y/%m/%d", strtotime("$inidate +1 day"));
        echo "</tr>";
    }
    $count++;
}

Edit 3: Ok, the code's more messed up than I originally thought. I PhpFiddled it to this, which works as expected (I suppose) for the given input. I didn't care about coloring or other trivial changes. Moreover, I won't point out the changes, you can see them if you compare this to your original code. And you should extract methods, as I pointed out before and as was done in the other answer. "Extract methods" refers to a refactoring term (http://refactoring.com/catalog/extractMethod.html) and is not a PHP function.

<?php
$month = "01";
$year = "2015";

$staff=array('STAFF A-Full Name',
             'STAFF B-Full Name',
             'STAFF C-Full Name');

$dome[]=array('NAME' => 'STAFF A-Full Name',
              'DATEIN' => '2015/01/01' ,
              'TIMEIN' => '09:02');
$dome[]=array('NAME' => 'STAFF A-Full Name',
              'DATEIN' => '2015/01/02',
              'TIMEIN' => '08:30');
$dome[]=array('NAME' => 'STAFF B-Full Name',
              'DATEIN' => '2015/01/01',
              'TIMEIN' => '08:43');
$dome[]=array('NAME' => 'Staff B-Full Name',
              'DATEIN' => '2015/01/03',
              'TIMEIN' => '09:11');

echo "<table>";
$countTeam = 0;
foreach ($staff as $key => $team) //row or use count on staff
{
    $inidate = "$year/$month/01"; //$year and $month chosen by user

    echo "<tr><td>".($countTeam + 1).".</td><td>".$team."</td>";
    for ($i = 0; $i < cal_days_in_month(CAL_GREGORIAN, $month, $year); $i++) //column
    {
        $found = false;

        foreach($dome as $domeKey => $staffAssignment){
            if($found){
                break;
            }

            if ($staffAssignment['DATEIN'] == $inidate)
            {
                if (strtoupper($team) == strtoupper($staffAssignment['NAME']))
                {
                    if ($staffAssignment['TIMEIN'] != "")
                    {
                        $found = true;
                        if (date("D", strtotime($inidate)) == 'Sun' || date("D", strtotime($inidate)) == 'Sat')
                        {   
                            //if late output time in yellow cell
                            if (strtotime($staffAssignment['TIMEIN']) > strtotime('09:10')){
                                echo "<td BGCOLOR='#ffff00'>".$staffAssignment['TIMEIN']."</td>";
                            }
                            else { //output time normally
                                echo "<td>".$staffAssignment['TIMEIN']."</td>";
                            }
                        }
                        else { //if its weekday outputs gray cell
                            echo "<td BGCOLOR='#525266'>".$staffAssignment['TIMEIN']."</td>";
                        }
                    }
                    else {
                        echo "<td>AB</td>";
                    }
                }
            }
        }

        if(!$found){
            echo "<td></td>";
        }       

        $inidate = strftime("%Y/%m/%d", strtotime("$inidate +1 day"));
    }

    $countTeam++;
    echo "</tr>";
}
echo "</table>";
?>

6 Comments

1. The empty cells are not colored. 2. You're right; the table is all messed up. 3. I disregard them for now because they are old datas. 4. I want to make sure that the date is a weekday, not a weekend. For $inidate is user defined. If the user chooses Jan 2015, it becomes a string '2015/01/01'. In the loop it increments the date so the system will look for the attendance time of the next day. I don't know how to use extract() because I'm not very experienced with php, and I've been pretty much spoiled by compilers that I can't even detect where I went wrong.
Ok, the print_r actually works as intended, just tried it. But I don't get the rest of what you're trying to say, sorry. Clearly, you wanrt a gray cell when it's weekday: //if its weekday outputs gray cell. Hence, you want the if condition to match a weekend, and that's why you use == 'Sun' and not != 'Sun'. If you wanted it to be the other way round, you'd use && and not || in this condition. Finally, I didn't say "the table is all messed up", I provided some aspects to consider / to change and see if the output's better afterwards. Did you try those?
I'm really sorry, I meant gray cells for the weekends instead of weekdays. About the table is messed up, I was agreeing with you about not getting a noticeable difference regarding the level of $cond. Yes, I've tried it.
Ok, at this point, I don't know what to suggest. You have to either narrow down your question (is it about not understanding if statements at all? Is it about one specific if statement? what is it about?), or you have to provide your (preferrably shortened) real data array, the real output, and the output you want to receive. The output of course in HTML, not an ASCII art table. Take an array of perhaps three entries producing a wrong output, show the array and HTML, and let us know what the desired output should look like. The level of $cond is the most irrelevant part in all of this.
PHPFiddled and came up with one final version. HTML output looked good to me. I wonder where you had that code from, since it contained so many errors? E.g., you use a variable $getdate which is nowhere defined, so I guess this isn't your real code at all? Doesn't make things much easier when trying to answer your questions.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.