PHPExcel
[ class tree: PHPExcel ] [ index: PHPExcel ] [ all elements ]

Source for file ReferenceHelper.php

Documentation is available at ReferenceHelper.php

  1. <?php
  2. /**
  3.  * PHPExcel
  4.  *
  5.  * Copyright (c) 2006 - 2009 PHPExcel
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  *
  12.  * This library is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with this library; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  20.  *
  21.  * @category   PHPExcel
  22.  * @package    PHPExcel
  23.  * @copyright  Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel)
  24.  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
  25.  * @version    1.6.7, 2009-04-22
  26.  */
  27.  
  28.  
  29. /** PHPExcel_Worksheet */
  30. require_once 'PHPExcel/Worksheet.php';
  31.  
  32. /** PHPExcel_Cell */
  33. require_once 'PHPExcel/Cell.php';
  34.  
  35. /** PHPExcel_Cell_DataType */
  36. require_once 'PHPExcel/Cell/DataType.php';
  37.  
  38. /** PHPExcel_Style */
  39. require_once 'PHPExcel/Style.php';
  40.  
  41. /** PHPExcel_Worksheet_Drawing */
  42. require_once 'PHPExcel/Worksheet/Drawing.php';
  43.  
  44. /** PHPExcel_Calculation_FormulaParser */
  45. require_once 'PHPExcel/Calculation/FormulaParser.php';
  46.  
  47. /** PHPExcel_Calculation_FormulaToken */
  48. require_once 'PHPExcel/Calculation/FormulaToken.php';
  49.  
  50.  
  51. /**
  52.  * PHPExcel_ReferenceHelper (Singleton)
  53.  *
  54.  * @category   PHPExcel
  55.  * @package    PHPExcel
  56.  * @copyright  Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel)
  57.  */
  58. {
  59.     /**
  60.      * Instance of this class
  61.      *
  62.      * @var PHPExcel_ReferenceHelper 
  63.      */
  64.     private static $_instance;
  65.  
  66.     /**
  67.      * Get an instance of this class
  68.      *
  69.      * @return PHPExcel_ReferenceHelper 
  70.      */
  71.     public static function getInstance({
  72.         if (!isset(self::$_instance|| is_null(self::$_instance)) {
  73.             self::$_instance new PHPExcel_ReferenceHelper();
  74.         }
  75.  
  76.         return self::$_instance;
  77.     }
  78.  
  79.     /**
  80.      * Create a new PHPExcel_Calculation
  81.      */
  82.     protected function __construct({
  83.     }
  84.  
  85.     /**
  86.      * Insert a new column, updating all possible related data
  87.      *
  88.      * @param     int    $pBefore    Insert before this one
  89.      * @param     int    $pNumCols    Number of columns to insert
  90.      * @param     int    $pNumRows    Number of rows to insert
  91.      * @throws     Exception
  92.      */
  93.     public function insertNewBefore($pBefore 'A1'$pNumCols 0$pNumRows 0PHPExcel_Worksheet $pSheet null{
  94.         // Get a copy of the cell collection
  95.         /*$aTemp = $pSheet->getCellCollection();
  96.         $aCellCollection = array();
  97.         foreach ($aTemp as $key => $value) {
  98.             $aCellCollection[$key] = clone $value;
  99.         }*/
  100.         $aCellCollection $pSheet->getCellCollection();
  101.  
  102.         // Get coordinates of $pBefore
  103.         $beforeColumn     'A';
  104.         $beforeRow        1;
  105.         list($beforeColumn$beforeRowPHPExcel_Cell::coordinateFromString$pBefore );
  106.  
  107.  
  108.         // Remove cell styles?
  109.         $highestColumn     $pSheet->getHighestColumn();
  110.         $highestRow     $pSheet->getHighestRow();
  111.  
  112.         if ($pNumCols && PHPExcel_Cell::columnIndexFromString($beforeColumn$pNumCols 0{
  113.             for ($i 1$i <= $highestRow 1++$i{
  114.                 $pSheet->duplicateStyle(
  115.                     new PHPExcel_Style(),
  116.                     (PHPExcel_Cell::stringFromColumnIndexPHPExcel_Cell::columnIndexFromString($beforeColumn$pNumCols $i':' (PHPExcel_Cell::stringFromColumnIndexPHPExcel_Cell::columnIndexFromString($beforeColumn$i)
  117.                 );    
  118.             }
  119.         }
  120.  
  121.         if ($pNumRows && $beforeRow $pNumRows 0{
  122.             for ($i PHPExcel_Cell::columnIndexFromString($beforeColumn1$i <= PHPExcel_Cell::columnIndexFromString($highestColumn1++$i{
  123.                 $pSheet->duplicateStyle(
  124.                     new PHPExcel_Style(),
  125.                     PHPExcel_Cell::stringFromColumnIndex($i($beforeRow $pNumRows)) ':' PHPExcel_Cell::stringFromColumnIndex($i($beforeRow 1))
  126.                 );
  127.             }
  128.         }
  129.  
  130.  
  131.            // Loop trough cells, bottom-up, and change cell coordinates
  132.         while ( ($cell ($pNumCols || $pNumRows 0array_shift($aCellCollectionarray_pop($aCellCollection)) ) {
  133.             // New coordinates
  134.             $newCoordinates PHPExcel_Cell::stringFromColumnIndexPHPExcel_Cell::columnIndexFromString($cell->getColumn()) $pNumCols ($cell->getRow($pNumRows);
  135.  
  136.             // Should the cell be updated?
  137.             if (
  138.                     (PHPExcel_Cell::columnIndexFromString$cell->getColumn() ) >= PHPExcel_Cell::columnIndexFromString($beforeColumn)) &&
  139.                      ($cell->getRow(>= $beforeRow)
  140.                  {
  141.  
  142.                 // Update cell styles
  143.                 $pSheet->duplicateStyle$pSheet->getStyle($cell->getCoordinate())$newCoordinates ':' $newCoordinates );
  144.                 $pSheet->duplicateStyle$pSheet->getDefaultStyle()$cell->getCoordinate(':' $cell->getCoordinate() );
  145.  
  146.                 // Insert this cell at its new location
  147.                 if ($cell->getDataType(== PHPExcel_Cell_DataType::TYPE_FORMULA{
  148.                     // Formula should be adjusted
  149.                     $pSheet->setCellValue(
  150.                           $newCoordinates
  151.                         $this->updateFormulaReferences($cell->getValue()$pBefore$pNumCols$pNumRows)
  152.                     );
  153.                 else {
  154.                     // Formula should not be adjusted
  155.                     $pSheet->setCellValue($newCoordinates$cell->getValue());
  156.                 }
  157.  
  158.                 // Clear the original cell
  159.                 $pSheet->setCellValue($cell->getCoordinate()'');
  160.             }
  161.         }
  162.  
  163.  
  164.         // Duplicate styles for the newly inserted cells
  165.         $highestColumn     $pSheet->getHighestColumn();
  166.         $highestRow     $pSheet->getHighestRow();
  167.  
  168.         if ($pNumCols && PHPExcel_Cell::columnIndexFromString($beforeColumn0{
  169.             for ($i $beforeRow$i <= $highestRow 1++$i{
  170.  
  171.                 // Style
  172.                 $pSheet->duplicateStyle(
  173.                     $pSheet->getStyle(
  174.                         (PHPExcel_Cell::stringFromColumnIndexPHPExcel_Cell::columnIndexFromString($beforeColumn$i)
  175.                     ),
  176.                     ($beforeColumn $i':' (PHPExcel_Cell::stringFromColumnIndexPHPExcel_Cell::columnIndexFromString($beforeColumn$pNumCols $i)
  177.                 );
  178.  
  179.             }
  180.         }
  181.  
  182.         if ($pNumRows && $beforeRow 0{
  183.             for ($i PHPExcel_Cell::columnIndexFromString($beforeColumn1$i <= PHPExcel_Cell::columnIndexFromString($highestColumn1++$i{
  184.  
  185.                 // Style
  186.                 $pSheet->duplicateStyle(
  187.                     $pSheet->getStyle(
  188.                         (PHPExcel_Cell::stringFromColumnIndex($i($beforeRow 1))
  189.                     ),
  190.                     (PHPExcel_Cell::stringFromColumnIndex($i$beforeRow':' (PHPExcel_Cell::stringFromColumnIndex($i($beforeRow $pNumRows))
  191.                 );
  192.  
  193.             }
  194.         }
  195.  
  196.  
  197.         // Update worksheet: column dimensions
  198.         $aColumnDimensions array_reverse($pSheet->getColumnDimensions()true);
  199.         if (count($aColumnDimensions0{
  200.             foreach ($aColumnDimensions as $objColumnDimension{
  201.                 $newReference $this->updateCellReference($objColumnDimension->getColumnIndex('1'$pBefore$pNumCols$pNumRows);
  202.                 list($newReferencePHPExcel_Cell::coordinateFromString($newReference);
  203.                 if ($objColumnDimension->getColumnIndex(!= $newReference{
  204.                     $objColumnDimension->setColumnIndex($newReference);
  205.                 }
  206.             }
  207.             $pSheet->refreshColumnDimensions();
  208.         }
  209.  
  210.  
  211.         // Update worksheet: row dimensions
  212.         $aRowDimensions array_reverse($pSheet->getRowDimensions()true);
  213.         if (count($aRowDimensions0{
  214.             foreach ($aRowDimensions as $objRowDimension{
  215.                 $newReference $this->updateCellReference('A' $objRowDimension->getRowIndex()$pBefore$pNumCols$pNumRows);
  216.                 list($newReferencePHPExcel_Cell::coordinateFromString($newReference);
  217.                 if ($objRowDimension->getRowIndex(!= $newReference{
  218.                     $objRowDimension->setRowIndex($newReference);
  219.                 }
  220.             }
  221.             $pSheet->refreshRowDimensions();
  222.     
  223.             $copyDimension $pSheet->getRowDimension($beforeRow 1);
  224.             for ($i $beforeRow$i <= $beforeRow $pNumRows++$i{
  225.                 $newDimension $pSheet->getRowDimension($i);
  226.                 $newDimension->setRowHeight($copyDimension->getRowHeight());
  227.                 $newDimension->setVisible($copyDimension->getVisible());
  228.                 $newDimension->setOutlineLevel($copyDimension->getOutlineLevel());
  229.                 $newDimension->setCollapsed($copyDimension->getCollapsed());
  230.             }
  231.         }
  232.  
  233.  
  234.         // Update worksheet: breaks
  235.         $aBreaks array_reverse($pSheet->getBreaks()true);
  236.         foreach ($aBreaks as $key => $value{
  237.             $newReference $this->updateCellReference($key$pBefore$pNumCols$pNumRows);
  238.             if ($key != $newReference{
  239.                 $pSheet->setBreak$newReference$value );
  240.                 $pSheet->setBreak$keyPHPExcel_Worksheet::BREAK_NONE );
  241.             }
  242.         }
  243.  
  244.  
  245.         // Update worksheet: merge cells
  246.         $aMergeCells array_reverse($pSheet->getMergeCells()true);
  247.         foreach ($aMergeCells as $key => $value{
  248.             $newReference $this->updateCellReference($key$pBefore$pNumCols$pNumRows);
  249.             if ($key != $newReference{
  250.                 $pSheet->mergeCells$newReference );
  251.                 $pSheet->unmergeCells$key );
  252.             }
  253.         }
  254.  
  255.  
  256.         // Update worksheet: protected cells
  257.         $aProtectedCells array_reverse($pSheet->getProtectedCells()true);
  258.         foreach ($aProtectedCells as $key => $value{
  259.             $newReference $this->updateCellReference($key$pBefore$pNumCols$pNumRows);
  260.             if ($key != $newReference{
  261.                 $pSheet->protectCells$newReference$valuetrue );
  262.                 $pSheet->unprotectCells$key );
  263.             }
  264.         }
  265.  
  266.  
  267.         // Update worksheet: autofilter
  268.         if ($pSheet->getAutoFilter(!= ''{
  269.             $pSheet->setAutoFilter$this->updateCellReference($pSheet->getAutoFilter()$pBefore$pNumCols$pNumRows) );
  270.         }
  271.  
  272.  
  273.         // Update worksheet: freeze pane
  274.         if ($pSheet->getFreezePane(!= ''{
  275.             $pSheet->freezePane$this->updateCellReference($pSheet->getFreezePane()$pBefore$pNumCols$pNumRows) );
  276.         }
  277.  
  278.  
  279.         // Page setup
  280.         if ($pSheet->getPageSetup()->isPrintAreaSet()) {
  281.             $pSheet->getPageSetup()->setPrintArea$this->updateCellReference($pSheet->getPageSetup()->getPrintArea()$pBefore$pNumCols$pNumRows) );
  282.         }
  283.  
  284.  
  285.         // Update worksheet: drawings
  286.         $aDrawings $pSheet->getDrawingCollection();
  287.         foreach ($aDrawings as $objDrawing{
  288.             $newReference $this->updateCellReference($objDrawing->getCoordinates()$pBefore$pNumCols$pNumRows);
  289.             if ($objDrawing->getCoordinates(!= $newReference{
  290.                 $objDrawing->setCoordinates($newReference);
  291.             }
  292.         }
  293.  
  294.  
  295.         // Update workbook: named ranges
  296.         if (count($pSheet->getParent()->getNamedRanges()) 0{
  297.             foreach ($pSheet->getParent()->getNamedRanges(as $namedRange{
  298.                 if ($namedRange->getWorksheet()->getHashCode(== $pSheet->getHashCode()) {
  299.                     $namedRange->setRange(
  300.                         $this->updateCellReference($namedRange->getRange()$pBefore$pNumCols$pNumRows)
  301.                     );
  302.                 }
  303.             }
  304.         }
  305.  
  306.  
  307.         // Garbage collect
  308.         $pSheet->garbageCollect();
  309.     }
  310.  
  311.     /**
  312.      * Update references within formulas
  313.      *
  314.      * @param     string    $pFormula    Formula to update
  315.      * @param     int        $pBefore    Insert before this one
  316.      * @param     int        $pNumCols    Number of columns to insert
  317.      * @param     int        $pNumRows    Number of rows to insert
  318.      * @return     string    Updated formula
  319.      * @throws     Exception
  320.      */
  321.     public function updateFormulaReferences($pFormula ''$pBefore 'A1'$pNumCols 0$pNumRows 0{
  322.         // Formula stack
  323.         $executableFormulaArray array();
  324.  
  325.         // Parse formula into a tree of tokens
  326.         $objParser new PHPExcel_Calculation_FormulaParser($pFormula);
  327.  
  328.         // Loop trough parsed tokens and create an executable formula
  329.         $inFunction false;
  330.         $token         null;
  331.         $tokenCount $objParser->getTokenCount();
  332.         for ($i 0$i $tokenCount++$i{
  333.             $token $objParser->getToken($i);
  334.  
  335.             // Is it a cell reference? Not a cell range?
  336.             if ( ($token->getTokenType(== PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND&&
  337.                  ($token->getTokenSubType(== PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_RANGE) ) {
  338.                      // New cell reference
  339.                      $newCellReference $this->updateCellReference($token->getValue()$pBefore$pNumCols$pNumRows);
  340.  
  341.                      // Add adjusted cell coordinate to executable formula array
  342.                      $executableFormulaArray[$newCellReference;
  343.  
  344.                      continue;
  345.             }
  346.  
  347.             // Is it a subexpression?
  348.             if ($token->getTokenType(== PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION{
  349.                 // Temporary variable
  350.                 $tmp '';
  351.                 switch($token->getTokenSubType()) {
  352.                     case PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START:
  353.                         $tmp '(';
  354.                         break;
  355.                     case PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP:
  356.                         $tmp ')';
  357.                         break;
  358.                 }
  359.  
  360.                 // Add to executable formula array
  361.                 $executableFormulaArray[$tmp;
  362.  
  363.                 continue;
  364.             }
  365.  
  366.             // Is it a function?
  367.             if ($token->getTokenType(== PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION{
  368.                 // Temporary variable
  369.                 $tmp '';
  370.  
  371.                 // Check the function type
  372.                 if ($token->getValue(== 'ARRAY' || $token->getValue(== 'ARRAYROW'{
  373.                     // An array or an array row...
  374.                     $tmp '(';
  375.                 else {
  376.                     // A regular function call...
  377.                     switch($token->getTokenSubType()) {
  378.                         case PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START:
  379.                             $tmp strtoupper($token->getValue()) '(';
  380.                             $inFunction true;
  381.                             break;
  382.                         case PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP:
  383.                             $tmp ')';
  384.                             break;
  385.                     }
  386.                 }
  387.  
  388.                 // Add to executable formula array
  389.                 $executableFormulaArray[$tmp;
  390.  
  391.                 continue;
  392.             }
  393.  
  394.             // Is it text?
  395.             if ( ($token->getTokenType(== PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND&&
  396.                  ($token->getTokenSubType(== PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_TEXT) ) {
  397.                      // Add to executable formula array
  398.                      $executableFormulaArray['"'.$token->getValue().'"';
  399.  
  400.                      continue;
  401.             }
  402.  
  403.             // Is it something else?
  404.             $executableFormulaArray[$token->getValue();
  405.         }
  406.  
  407.         // Return result
  408.         return '=' implode(' '$executableFormulaArray);
  409.     }
  410.  
  411.     /**
  412.      * Update cell reference
  413.      *
  414.      * @param     string    $pCellRange            Cell range
  415.      * @param     int        $pBefore            Insert before this one
  416.      * @param     int        $pNumCols            Number of columns to increment
  417.      * @param     int        $pNumRows            Number of rows to increment
  418.      * @return     string    Updated cell range
  419.      * @throws     Exception
  420.      */
  421.     public function updateCellReference($pCellRange 'A1'$pBefore 'A1'$pNumCols 0$pNumRows 0{
  422.         // Is it a range or a single cell?
  423.         if (strpos($pCellRange':'=== false && strpos($pCellRange','=== false{
  424.             // Single cell
  425.             return $this->_updateSingleCellReference($pCellRange$pBefore$pNumCols$pNumRows);
  426.         else {
  427.             // Range
  428.             return $this->_updateCellRange($pCellRange$pBefore$pNumCols$pNumRows);
  429.         }
  430.     }
  431.     
  432.     /**
  433.      * Update named formulas (i.e. containing worksheet references / named ranges)
  434.      *
  435.      * @param PHPExcel $pPhpExcel    Object to update
  436.      * @param string $oldName        Old name (name to replace)
  437.      * @param string $newName        New name
  438.      */
  439.     public function updateNamedFormulas(PHPExcel $pPhpExcel$oldName ''$newName ''{
  440.         foreach ($pPhpExcel->getWorksheetIterator(as $sheet{
  441.             foreach ($sheet->getCellCollection(as $cell{
  442.                 if (!is_null($cell&& $cell->getDataType(== PHPExcel_Cell_DataType::TYPE_FORMULA{
  443.                     $formula $cell->getValue();
  444.                     if (strpos($formula$oldName!== false{
  445.                         $formula str_replace("'" $oldName "'!""'" $newName "'!"$formula);
  446.                         $formula str_replace($oldName "!"$newName "!"$formula);
  447.                         $cell->setValue($formulafalse);
  448.                     }
  449.                 }
  450.             }
  451.         }
  452.     }
  453.  
  454.     /**
  455.      * Update cell range
  456.      *
  457.      * @param     string    $pCellRange            Cell range
  458.      * @param     int        $pBefore            Insert before this one
  459.      * @param     int        $pNumCols            Number of columns to increment
  460.      * @param     int        $pNumRows            Number of rows to increment
  461.      * @return     string    Updated cell range
  462.      * @throws     Exception
  463.      */
  464.     private function _updateCellRange($pCellRange 'A1:A1'$pBefore 'A1'$pNumCols 0$pNumRows 0{
  465.         if (strpos($pCellRange,':'!== false || strpos($pCellRange','!== false{
  466.             // Update range
  467.             $range PHPExcel_Cell::splitRange($pCellRange);
  468.             for ($i 0$i count($range)$i++{
  469.                 for ($j 0$j count($range[$i])$j++{
  470.                     $range[$i][$j$this->_updateSingleCellReference($range[$i][$j]$pBefore$pNumCols$pNumRows);
  471.                 }
  472.             }
  473.             
  474.             // Recreate range string
  475.             return PHPExcel_Cell::buildRange($range);
  476.         else {
  477.             throw new Exception("Only cell ranges may be passed to this method.");
  478.         }
  479.     }
  480.  
  481.     /**
  482.      * Update single cell reference
  483.      *
  484.      * @param     string    $pCellReference        Single cell reference
  485.      * @param     int        $pBefore            Insert before this one
  486.      * @param     int        $pNumCols            Number of columns to increment
  487.      * @param     int        $pNumRows            Number of rows to increment
  488.      * @return     string    Updated cell reference
  489.      * @throws     Exception
  490.      */
  491.     private function _updateSingleCellReference($pCellReference 'A1'$pBefore 'A1'$pNumCols 0$pNumRows 0{
  492.         if (strpos($pCellReference':'=== false && strpos($pCellReference','=== false{
  493.             // Get coordinates of $pBefore
  494.             $beforeColumn     'A';
  495.             $beforeRow        1;
  496.             list($beforeColumn$beforeRowPHPExcel_Cell::coordinateFromString$pBefore );
  497.  
  498.             // Get coordinates
  499.             $newColumn     'A';
  500.             $newRow     1;
  501.             list($newColumn$newRowPHPExcel_Cell::coordinateFromString$pCellReference );
  502.  
  503.             // Verify which parts should be updated
  504.             $updateColumn (PHPExcel_Cell::columnIndexFromString($newColumn>= PHPExcel_Cell::columnIndexFromString($beforeColumn))
  505.                             && (strpos($newColumn'$'=== false)
  506.                             && (strpos($beforeColumn'$'=== false);
  507.  
  508.             $updateRow ($newRow >= $beforeRow)
  509.                             && (strpos($newRow'$'=== false)
  510.                             && (strpos($beforeRow'$'=== false);
  511.  
  512.             // Create new column reference
  513.             if ($updateColumn{
  514.                 $newColumn     PHPExcel_Cell::stringFromColumnIndexPHPExcel_Cell::columnIndexFromString($newColumn$pNumCols );
  515.             }
  516.  
  517.             // Create new row reference
  518.             if ($updateRow{
  519.                 $newRow     $newRow $pNumRows;
  520.             }
  521.  
  522.             // Return new reference
  523.             return $newColumn $newRow;
  524.         else {
  525.             throw new Exception("Only single cell references may be passed to this method.");
  526.         }
  527.     }
  528.  
  529.     /**
  530.      * __clone implementation. Cloning should not be allowed in a Singleton!
  531.      *
  532.      * @throws    Exception
  533.      */
  534.     public final function __clone({
  535.         throw new Exception("Cloning a Singleton is not allowed!");
  536.     }
  537. }

Documentation generated on Wed, 22 Apr 2009 09:01:44 +0200 by phpDocumentor 1.4.1