I have an array of objects (goals) that I want to sort based on 2 of their properties, the Status and the DueDate.

Here are the rules:

Statuses:

  1. Design
  2. Approved
  3. In Progress
  4. Completed
  5. Archived

If a goal has a status of 4 (completed) or 5 (archived) then the DueDate doesn't matter.

If a goal is neither 4 nor 5 and its DueDate is less than now then it is "Overdue" and should be at the top

If a goal is not "Overdue" then the order of statuses determines it's position (lowest to highest)

If $a and $b are both "Overdue" then the one with the earliest DueDate is more important

The order should be:

  1. Overdue
  2. Design
  3. Approved
  4. In Progress
  5. Completed
  6. Archived

Here is the last thing I tried:

function cmp($a, $b)
{
    $now = new DateTime("now");
    $aDueDate = new DateTime($a->GetDueDate());
    $bDueDate = new DateTime($b->GetDueDate());

if($a->GetStatus() != 4 && $a->GetStatus() != 5 && $b->GetStatus() != 4 && $b->GetStatus() != 5){
    if($aDueDate < $now || $bDueDate < $now){
        if($aDueDate == $bDueDate){
        return 0;
    }

    return ($aDueDate < $bDueDate) ? -1 : 1;
    }
}
elseif(($a->GetStatus() == 4 || $a->GetStatus() == 5) && ($b->GetStatus() != 4 && $b->GetStatus() != 5)) {
    return -1;
}
elseif(($a->GetStatus() != 4 && $a->GetStatus() != 5) && ($b->GetStatus() == 4 || $b->GetStatus() == 5)){
    return 1;
}

if ($a->GetStatus() == $b->GetStatus()) {
        return 0;
    }
    return ($a->GetStatus() < $b->GetStatus()) ? -1 : 1;
}

Which orders the array like so:

  1. Completed
  2. Archived
  3. Overdue
  4. Design
  5. Approved
  6. In Progress
有帮助吗?

解决方案

The following should meet your requirements:

function cmp($a, $b) {
    $now = new DateTime("now");
    $aDueDate = new DateTime($a->GetDueDate());
    $bDueDate = new DateTime($b->GetDueDate());
    $aStatus = $a->GetStatus();
    $bStatus = $b->GetStatus();
    $incompleteStatuses = array(1, 2, 3); 

    // use date if same status (might not be needed)    
    if ($aStatus == $bStatus) {
        return ($aDueDate < $bDueDate ? -1 : 1); 
    }   

    // if A is overdue:
    if (in_array($aStatus, $incompleteStatuses) && $aDueDate < $now) {
        // if B is overdue too, only consider dates
        if (in_array($bStatus, $incompleteStatuses) && $bDueDate < $now) {
            return ($aDueDate < $bDueDate ? -1 : 1); 
        }   

        return -1; // A definitely first
    }   
    // if B is overdue:
    elseif (in_array($bStatus, $incompleteStatuses) && $bDueDate < $now) {
        return 1; // B definitely first (we know A is not overdue from above)
    }   

    // both A and B are not overdue; order by status
    return $aStatus - $bStatus;
}

Here's a test codepad.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top