weedave
weedave

Reputation: 237

Comparing two multi-dimensional arrays in CakePHP - struggling to get logic correct

Scenario

I am developing an internal CakePHP company application that has a despatch screen, which has three lists:

  1. Available items for despatch (Shown below on the left - "Items Available for Packing")
  2. Already packed items pulled from the database (Shown below on the right - "Packed Items")
  3. Changes to the packed items list (Form submission after changes have been made)

The user can drag items from the left list to the right list and vice versa. Once the click the Save button, the form is submitted with the items on the right list.

Original state of lists

Desired Result

As part of the save, I need to compare (using PHP) the updated list with the saved list from the database.

With any additions, I need to update the items record with the despatch ID.

Additions - from left to right

With any removals, I need to update the items record to sell the despatch ID to NULL.

Removals - from right to left

This would allow users to drag and drop items in both directions, then click Save and expect the page to load with the state they left the page in.

Current State

I am able to save items to be added to the list and, separately, save items being removed. However, I cannot get them working together. When I try this, one item being added to the list completely replace all the other items on the "Packed Items" list.

Code so far...

function edit() {       
 $this->Despatch->recursive = -1; 
 if (!empty($this->data)) { 
  if($this->Despatch->save($this->data)) {
   /* NEED TO RETRIEVE CURRENT REPAIR IDs ASSOCIATED 
   WITH THE DESPATCH ID AND COMPARE WITH FORM SUBMISSION LIST TO 
   REMOVE THE DIFFERENCES */
   # Retrieve current repair records where despatch_id = $this->id.
   $this->Despatch->Repair->recursive = -1;
   $current_associated_repairs = $this->Despatch->Repair->find('all', array(
    'fields' => array('id', 'despatch_date', 'despatch_id'),
    'conditions' => array('Repair.despatch_id =' => $this->data['Despatch']['id'])));
   # Create array with repair IDs
   $repairs = explode(",", $this->data['Repair']['ids']);
   $i = 0;
   foreach($repairs as $repair) {
    $repairupdates[$i]['Repair']['id'] = $repair;
    $i++;
   }
   # Delete array index to prevent it interfering with form saving later
   unset($this->data['Repair']['ids']);

   # 2. Find unmatched IDs between current records and form submission list of repairs
   $length1 = sizeof($current_associated_repairs);
   $length2 = sizeof($this->data['Repair']);

   for ($i = 0; $i < $length1; $i++) { 
    for ($j = 0; $j < $length2; $j++) {
 ### LOGIC NOT CORRECT HERE !!! ###
 ### THIS WORKS FOR REMOVING PACKED INSTRUMENTS - FROM RIGHT TO LEFT ###
 ### BUT ACTUALLY BEING TRIGGERED WHEN ADDING FROM LEFT TO RIGHT TOO ###
     if ($current_associated_repairs[$i]['Repair']['id'] == $this->data['Repair'][$j]['id'] 
     && !in_array($current_associated_repairs[$i]['Repair']['id'], $this->data['Repair'][$j])) {
     # if it's in current repairs and not in form submission, set to null...
     # otherwise, it must be an addition if there's no matches
     # 3. Set the despatch_date and despatch_id fields of those records to NULL
     $this->data['Repair'][$j+1]['id'] = $current_associated_repairs[$i]['Repair']['id'];
     $this->data['Repair'][$j+1]['despatch_date'] = null;
     $this->data['Repair'][$j+1]['despatch_id'] = null;
 }
    }
   }
   # 4. Save the new list of repairs to the current despatch
   if($this->Despatch->save($this->data) && $this->Despatch->Repair->saveAll($this->data['Repair'])) {
    $this->Session->setFlash(__('The despatch has been saved.', true), 'default', array('class' => 'success-scheme message'));
   } else {
    $this->Session->setFlash(__('The repair could not be updated with the despatch number. Please try again.', true), 'default', array('class' => 'error-scheme message'));
   }
  } else {
   $this->Session->setFlash(__('The despatch could not be saved. Please try again.', true), 'default', array('class' => 'error-scheme message'));       
  }
 $this->redirect($this->referer(array('action' => 'view', $this->data['Despatch']['id'])));
 }
}

I think I've included all the detail anyone should need, but just ask if you need to know more. The main problem I'm having is understanding the logic the code for achieving this.

Many thanks in advance.

PS - JavaScript Code

// click handler for saving despatch - required to save sortable lists properly
$('#save_despatch').click(function(e) {
    e.preventDefault();
    // gives comma-separated array of instrument IDs, e.g. 12345, 56789...
    var result = $('#sortable2').sortable('toArray');
    $('#RepairIds').val(result);
    $('form').submit();
});

Upvotes: 0

Views: 655

Answers (1)

Derk Arts
Derk Arts

Reputation: 3460

I can not really figure out what you are doing now in your logic, but I will suggest an approach that should work without a doubt.

You have two lists, for simplicity: left and right. This code is sort of pseudocode because I do not fully understand what you need, but this way, the lists should remain updated, and it cant go wrong.

Logic before displaying the lists (in PHP):

//Retrieve records from mysql into two arrays->aLeft and aRight
//Create an MD5 hash to easily compare current en future lists.
$sCheckSum = md5(implode(",",$aLeft));
$_SESSION['checkSum'] = $sCheckSum;

//Generate your lists now 
//Display output

JS:

$('#save_despatch').click(function(e) {
    e.preventDefault();
    // gives comma-separated array of instrument IDs, e.g. 12345, 56789...
    var leftResult = $('#sortable2').sortable('toArray');
    var rightResult = $('#sortableX').sortable('toArray'); //Make sure this matches your lists, as I have not seen your HTML
    $('#Left').val(leftResult);
    $('#Right').val(rightResult);
    $('form').submit();
});

Then on the receiving end:

//Get the values of the #Left and #Right inputs in to $aLeft and $aRight
$sNewCheckSum = md5($aLeft);
if($sNewCheckSum  != $_SESSION['checkSum'] ) //Left list is not the same, so the right is neither
{
   foreach(explode(",",$aLeft) as $iRepairId){
      //Not sure what should happen here, but thats up to you.
      //Mysql update table SET  ID = NULL WHERE repairdId = $iRepairId
   }
   foreach(explode(",",$aRight) as $iRepairId){
      //Not sure what should happen here, but thats up to you.
      //Mysql update table SET  ID = xxx WHERE repairdId = $iRepairId
   }

}

Upvotes: 2

Related Questions