4

I'm working on a project where I need to export a spreadsheet, populate it manually and then import it again back in to the system. I'm using PHPExcel to do all the hard work.

The spreadsheet is basically a set of questions which need answering. (You can download an example of the spreadsheet here). The answers to each question are in a Data Validation List which come from another sheet (Answers) using named ranges. Both questions and answers come with unique IDs so that I can read the results back into the database with ease.

The questionID is stored in column B and is inserted when I create the spreadsheet. The answerID however is done via a lookup (in column C) because the answerID will change depending on the answer that is chosen. Each set of answers have two named ranges 1 for the answers in the list and one for the lookups. These named ranges are labelled answers_questionID and answers_lookup_questionID. The formula used in column C for getting the lookup values is:

=INDEX(answers_lookup_1, MATCH(E6, answers_1, 0),2)

I'm using INDEX and MATCH instead of VLOOKUP because I don't want to sort the data alphabetically.

This all works fine in the spreadsheet, it's when I try to read it back in that I have the problem. When I try reading the values back in, I either get 0 (they should all be positive integers) or #REF!

Here's what I'm doing when I read the data back in:

$objPHPExcel = new PHPExcel();

// Set a read filter so that we can restrict what we're loading in
class MyReadFilter implements PHPExcel_Reader_IReadFilter {
    private $_iStartRow = 0;
    private $_iEndRow = 0;
    private $_aColumns = array();

    public function __construct($iStartRow, $iEndRow, $aColumns) {
        $this->_iStartRow   = $iStartRow;
        $this->_iEndRow     = $iEndRow;
        $this->_aColumns    = $aColumns;
    }

    public function readCell($iCol, $iRow, $sWorksheetName = '') {
        if ($iRow >= $this->_iStartRow && $iRow <= $this->_iEndRow) {
            if (in_array($iCol, $this->_aColumns)) {
                return true;
            }
        }
        return false;
    }
}

$objFilterSubset = new MyReadFilter(5, 500, range('B', 'L'));

// Which type of reader do we need.
if (!extension_loaded('zip')) dl('php_zip.dll');
$objReader = new PHPExcel_Reader_Excel2007();

// Set the read filter so we don't get EVERYTHING
$objReader->setReadFilter($objFilterSubset);

// Load the actual data
$objPHPExcel = $objReader->load($sFilename);

// Store the data in an array
$aSheetNames = $objPHPExcel->getSheetNames();

foreach ($aSheetNames as $iSheetNum => $sSheetName) {
    $objPHPExcel->setActiveSheetIndex($iSheetNum);
    $aSheetData[$sSheetName] = $objPHPExcel->getActiveSheet()->toArray(null,true,true,false);
}

So I get a nice big array with all my data in, only column C is wrong.

  • There doesn't seem to be anything wrong with my formula as it works in excel.
  • I've tried simpler versions of formulas and they work i.e. summing multiple cells together.
  • Both sheets are present at the time of reading.
  • All named ranges are set fine at the time of reading.
  • I'm using v 1.7.4 but I've tried all versions up to 1.7.9 (1.8.0 doesn't even read in the spreadsheet).

Mark Baker asked me to run a formula test which can be found here which gives the following debug if anyone can make sense of it.

Formula Value is =INDEX(answers_lookup_1, MATCH(E6, answers_1, 0),2)
Expected Value is 7 Parser Stack :-

Array (
[0] => Array
    (
        [type] => Value
        [value] => answers_lookup_1
        [reference] =>
    )

[1] => Array
    (
        [type] => Cell Reference
        [value] => E6
        [reference] => E6
    )

[2] => Array
    (
        [type] => Value
        [value] => answers_1
        [reference] => 
    )

[3] => Array
    (
        [type] => Value
        [value] => 0
        [reference] => 
    )

[4] => Array
    (
        [type] => Operand Count for Function MATCH()
        [value] => 3
        [reference] => 
    )

[5] => Array
    (
        [type] => Function
        [value] => MATCH(
        [reference] => 
    )

[6] => Array
    (
        [type] => Value
        [value] => 2
        [reference] => 
    )

[7] => Array
    (
        [type] => Operand Count for Function INDEX()
        [value] => 3
        [reference] => 
    )

[8] => Array
    (
        [type] => Function
        [value] => INDEX(
        [reference] => 
    )

)

Calculated Value is 0

Evaluation Log:
Array
(
    [0] => Questions!C6 -> Evaluating Named Range answers_lookup_1
    [1] => Questions!C6 -> Evaluation Result for named range A4:B6 is a matrix with a value of { , ; , 7; , 8 }
    [2] => Questions!C6 -> Evaluating Cell E6 in current worksheet
    [3] => Questions!C6 -> Evaluation Result for cell Questions!E6 is a string with a value of Yes
    [4] => Questions!C6 -> Evaluating Named Range answers_1
    [5] => Questions!C6 -> Evaluation Result for named range A4:A6 is a matrix with a value of { ; ;  }
    [6] => Questions!C6 -> Evaluating Function MATCH() with 3 arguments
    [7] => Questions!C6 -> Evaluating MATCH( Yes, { ; ;  }, 0 )
    [8] => Questions!C6 -> Evaluation Result for MATCH() function call is a #N/A error
    [9] => Questions!C6 -> Evaluating Function INDEX() with 3 arguments
    [10] => Questions!C6 -> Evaluating INDEX( { , ; , 7; , 8 }, #N/A, 2 )
    [11] => Questions!C6 -> Evaluation Result for INDEX() function call is a null value
)

I've tried multiple variations of formulas and ways of reading the data in. I've looped over the data and used getCalculatedValue() instead of toArray() and still got the same results.

I can only think that this may be a bug within the INDEX function in Functions.php and that the formula is not being interpreted correctly when being read in using named ranges. If I print out the passed array to INDEX() the result is:

INDEX: Array
(
    [12] => Array
    (
        [A] =>
        [B] => 6
    )
    [13] => Array
    (
        [A] =>
        [B] => 7
    )
    [14] => Array
    (
        [A] =>
        [B] => 8
    )
)

which are the right values (although I'm not sure if the A column should be populated as it is in my spreadsheet) i.e. Yes, No and N/A...

If you've got this far, thanks and hopefully you can help or point me in the right direction.

Much appreciated,

Adam.

pnuts
  • 58,317
  • 11
  • 87
  • 139
Adam Holmes
  • 1,783
  • 3
  • 20
  • 32

1 Answers1

-1

Looks like function INDEX cannot handle cell references as second parameters

@@ -604,10 +604,13 @@ class PHPExcel_Calculation_LookupRef
         }

         if (!is_array($arrayValues)) {
             return PHPExcel_Calculation_Functions::REF();
         }
+        
+        $lrow = PHPExcel_Calculation_Functions::flattenSingleValue($rowNum); 
+        $rowNum = $lrow;

         $rowKeys = array_keys($arrayValues);
         $columnKeys = @array_keys($arrayValues[$rowKeys[0]]);

         if ($columnNum > count($columnKeys)) {