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 - 2008 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 - 2008 PHPExcel (http://www.codeplex.com/PHPExcel)
  24.  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
  25.  * @version    1.6.4, 2008-10-27
  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 - 2008 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.  
  115.                 $pSheet->duplicateStyle(
  116.                     new PHPExcel_Style(),
  117.                     (PHPExcel_Cell::stringFromColumnIndexPHPExcel_Cell::columnIndexFromString($beforeColumn$pNumCols $i':' (PHPExcel_Cell::stringFromColumnIndexPHPExcel_Cell::columnIndexFromString($beforeColumn$i)
  118.                 );
  119.  
  120.             }
  121.         }
  122.  
  123.         if ($pNumRows && $beforeRow $pNumRows 0{
  124.             for ($i PHPExcel_Cell::columnIndexFromString($beforeColumn1$i <= $highestColumn 1++$i{
  125.                 $pSheet->duplicateStylenew PHPExcel_Style()($i.($beforeRow $pNumRows)).':'.($i.($beforeRow 1)));
  126.             }
  127.         }
  128.  
  129.  
  130.            // Loop trough cells, bottom-up, and change cell coordinates
  131.         while ( ($cell ($pNumCols || $pNumRows 0array_shift($aCellCollectionarray_pop($aCellCollection)) ) {
  132.             // New coordinates
  133.             $newCoordinates PHPExcel_Cell::stringFromColumnIndexPHPExcel_Cell::columnIndexFromString($cell->getColumn()) $pNumCols ($cell->getRow($pNumRows);
  134.  
  135.             // Should the cell be updated?
  136.             if (
  137.                     (PHPExcel_Cell::columnIndexFromString$cell->getColumn() ) >= PHPExcel_Cell::columnIndexFromString($beforeColumn)) &&
  138.                      ($cell->getRow(>= $beforeRow)
  139.                  {
  140.  
  141.                 // Update cell styles
  142.                 $pSheet->duplicateStyle$pSheet->getStyle($cell->getCoordinate())$newCoordinates ':' $newCoordinates );
  143.                 $pSheet->duplicateStyle$pSheet->getDefaultStyle()$cell->getCoordinate(':' $cell->getCoordinate() );
  144.  
  145.                 // Insert this cell at its new location
  146.                 if ($cell->getDataType(== PHPExcel_Cell_DataType::TYPE_FORMULA{
  147.                     // Formula should be adjusted
  148.                     $pSheet->setCellValue(
  149.                           $newCoordinates
  150.                         $this->updateFormulaReferences($cell->getValue()$pBefore$pNumCols$pNumRows)
  151.                     );
  152.                 else {
  153.                     // Formula should not be adjusted
  154.                     $pSheet->setCellValue($newCoordinates$cell->getValue());
  155.                 }
  156.  
  157.                 // Clear the original cell
  158.                 $pSheet->setCellValue($cell->getCoordinate()'');
  159.             }
  160.         }
  161.  
  162.  
  163.         // Duplicate styles for the newly inserted cells
  164.         $highestColumn     $pSheet->getHighestColumn();
  165.         $highestRow     $pSheet->getHighestRow();
  166.  
  167.         if ($pNumCols && PHPExcel_Cell::columnIndexFromString($beforeColumn0{
  168.             for ($i $beforeRow$i <= $highestRow 1++$i{
  169.  
  170.                 // Style
  171.                 $pSheet->duplicateStyle(
  172.                     $pSheet->getStyle(
  173.                         (PHPExcel_Cell::stringFromColumnIndexPHPExcel_Cell::columnIndexFromString($beforeColumn$i)
  174.                     ),
  175.                     ($beforeColumn $i':' (PHPExcel_Cell::stringFromColumnIndexPHPExcel_Cell::columnIndexFromString($beforeColumn$pNumCols $i)
  176.                 );
  177.  
  178.             }
  179.         }
  180.  
  181.         if ($pNumRows && $beforeRow 0{
  182.             for ($i PHPExcel_Cell::columnIndexFromString($beforeColumn1$i <= PHPExcel_Cell::columnIndexFromString($highestColumn1++$i{
  183.  
  184.                 // Style
  185.                 $pSheet->duplicateStyle(
  186.                     $pSheet->getStyle(
  187.                         (PHPExcel_Cell::stringFromColumnIndex($i($beforeRow 1))
  188.                     ),
  189.                     (PHPExcel_Cell::stringFromColumnIndex($i$beforeRow':' (PHPExcel_Cell::stringFromColumnIndex($i($beforeRow $pNumRows))
  190.                 );
  191.  
  192.             }
  193.         }
  194.  
  195.  
  196.         // Update worksheet: column dimensions
  197.         $aColumnDimensions array_reverse($pSheet->getColumnDimensions()true);
  198.         foreach ($aColumnDimensions as $objColumnDimension{
  199.             $newReference $this->updateCellReference($objColumnDimension->getColumnIndex('1'$pBefore$pNumCols$pNumRows);
  200.             list($newReferencePHPExcel_Cell::coordinateFromString($newReference);
  201.             if ($objColumnDimension->getColumnIndex(!= $newReference{
  202.                 $objColumnDimension->setColumnIndex($newReference);
  203.             }
  204.         }
  205.         $pSheet->refreshColumnDimensions();
  206.  
  207.  
  208.         // Update worksheet: row dimensions
  209.         $aRowDimensions array_reverse($pSheet->getRowDimensions()true);
  210.         foreach ($aRowDimensions as $objRowDimension{
  211.             $newReference $this->updateCellReference('A' $objRowDimension->getRowIndex()$pBefore$pNumCols$pNumRows);
  212.             list($newReferencePHPExcel_Cell::coordinateFromString($newReference);
  213.             if ($objRowDimension->getRowIndex(!= $newReference{
  214.                 $objRowDimension->setRowIndex($newReference);
  215.             }
  216.         }
  217.         $pSheet->refreshRowDimensions();
  218.  
  219.         $copyDimension $pSheet->getRowDimension($beforeRow 1);
  220.         for ($i $beforeRow$i <= $beforeRow $pNumRows++$i{
  221.             $newDimension $pSheet->getRowDimension($i);
  222.             $newDimension->setRowHeight($copyDimension->getRowHeight());
  223.             $newDimension->setVisible($copyDimension->getVisible());
  224.             $newDimension->setOutlineLevel($copyDimension->getOutlineLevel());
  225.             $newDimension->setCollapsed($copyDimension->getCollapsed());
  226.         }
  227.  
  228.  
  229.         // Update worksheet: breaks
  230.         $aBreaks array_reverse($pSheet->getBreaks()true);
  231.         foreach ($aBreaks as $key => $value{
  232.             $newReference $this->updateCellReference($key$pBefore$pNumCols$pNumRows);
  233.             if ($key != $newReference{
  234.                 $pSheet->setBreak$newReference$value );
  235.                 $pSheet->setBreak$keyPHPExcel_Worksheet::BREAK_NONE );
  236.             }
  237.         }
  238.  
  239.  
  240.         // Update worksheet: merge cells
  241.         $aMergeCells array_reverse($pSheet->getMergeCells()true);
  242.         foreach ($aMergeCells as $key => $value{
  243.             $newReference $this->updateCellReference($key$pBefore$pNumCols$pNumRows);
  244.             if ($key != $newReference{
  245.                 $pSheet->mergeCells$newReference );
  246.                 $pSheet->unmergeCells$key );
  247.             }
  248.         }
  249.  
  250.  
  251.         // Update worksheet: protected cells
  252.         $aProtectedCells array_reverse($pSheet->getProtectedCells()true);
  253.         foreach ($aProtectedCells as $key => $value{
  254.             $newReference $this->updateCellReference($key$pBefore$pNumCols$pNumRows);
  255.             if ($key != $newReference{
  256.                 $pSheet->protectCells$newReference$valuetrue );
  257.                 $pSheet->unprotectCells$key );
  258.             }
  259.         }
  260.  
  261.  
  262.         // Update worksheet: autofilter
  263.         if ($pSheet->getAutoFilter(!= ''{
  264.             $pSheet->setAutoFilter$this->updateCellReference($pSheet->getAutoFilter()$pBefore$pNumCols$pNumRows) );
  265.         }
  266.  
  267.  
  268.         // Update worksheet: freeze pane
  269.         if ($pSheet->getFreezePane(!= ''{
  270.             $pSheet->setFreezePane$this->updateCellReference($pSheet->getFreezePane()$pBefore$pNumCols$pNumRows) );
  271.         }
  272.  
  273.  
  274.         // Page setup
  275.         if ($pSheet->getPageSetup()->isPrintAreaSet()) {
  276.             $pSheet->getPageSetup()->setPrintArea$this->updateCellReference($pSheet->getPageSetup()->getPrintArea()$pBefore$pNumCols$pNumRows) );
  277.         }
  278.  
  279.  
  280.         // Update worksheet: drawings
  281.         $aDrawings $pSheet->getDrawingCollection();
  282.         foreach ($aDrawings as $objDrawing{
  283.             $newReference $this->updateCellReference($objDrawing->getCoordinates()$pBefore$pNumCols$pNumRows);
  284.             if ($objDrawing->getCoordinates(!= $newReference{
  285.                 $objDrawing->setCoordinates($newReference);
  286.             }
  287.         }
  288.  
  289.  
  290.         // Update workbook: named ranges
  291.         if (count($pSheet->getParent()->getNamedRanges()) 0{
  292.             foreach ($pSheet->getParent()->getNamedRanges(as $namedRange{
  293.                 if ($namedRange->getWorksheet()->getHashCode(== $pSheet->getHashCode()) {
  294.                     $namedRange->setRange(
  295.                         $this->updateCellReference($namedRange->getRange()$pBefore$pNumCols$pNumRows)
  296.                     );
  297.                 }
  298.             }
  299.         }
  300.  
  301.  
  302.         // Garbage collect
  303.         $pSheet->garbageCollect();
  304.     }
  305.  
  306.     /**
  307.      * Update references within formulas
  308.      *
  309.      * @param     string    $pFormula    Formula to update
  310.      * @param     int        $pBefore    Insert before this one
  311.      * @param     int        $pNumCols    Number of columns to insert
  312.      * @param     int        $pNumRows    Number of rows to insert
  313.      * @return     string    Updated formula
  314.      * @throws     Exception
  315.      */
  316.     public function updateFormulaReferences($pFormula ''$pBefore 'A1'$pNumCols 0$pNumRows 0{
  317.         // Formula stack
  318.         $executableFormulaArray array();
  319.  
  320.         // Parse formula into a tree of tokens
  321.         $objParser new PHPExcel_Calculation_FormulaParser($pFormula);
  322.  
  323.         // Loop trough parsed tokens and create an executable formula
  324.         $inFunction false;
  325.         $token         null;
  326.         $tokenCount $objParser->getTokenCount();
  327.         for ($i 0$i $tokenCount++$i{
  328.             $token $objParser->getToken($i);
  329.  
  330.             // Is it a cell reference? Not a cell range?
  331.             if ( ($token->getTokenType(== PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND&&
  332.                  ($token->getTokenSubType(== PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_RANGE) ) {
  333.                      // New cell reference
  334.                      $newCellReference $this->updateCellReference($token->getValue()$pBefore$pNumCols$pNumRows);
  335.  
  336.                      // Add adjusted cell coordinate to executable formula array
  337.                      array_push($executableFormulaArray$newCellReference);
  338.  
  339.                      continue;
  340.             }
  341.  
  342.             // Is it a subexpression?
  343.             if ($token->getTokenType(== PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION{
  344.                 // Temporary variable
  345.                 $tmp '';
  346.                 switch($token->getTokenSubType()) {
  347.                     case PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START:
  348.                         $tmp '(';
  349.                         break;
  350.                     case PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP:
  351.                         $tmp ')';
  352.                         break;
  353.                 }
  354.  
  355.                 // Add to executable formula array
  356.                 array_push($executableFormulaArray$tmp);
  357.  
  358.                 continue;
  359.             }
  360.  
  361.             // Is it a function?
  362.             if ($token->getTokenType(== PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION{
  363.                 // Temporary variable
  364.                 $tmp '';
  365.  
  366.                 // Check the function type
  367.                 if ($token->getValue(== 'ARRAY' || $token->getValue(== 'ARRAYROW'{
  368.                     // An array or an array row...
  369.                     $tmp '(';
  370.                 else {
  371.                     // A regular function call...
  372.                     switch($token->getTokenSubType()) {
  373.                         case PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START:
  374.                             $tmp strtoupper($token->getValue()) '(';
  375.                             $inFunction true;
  376.                             break;
  377.                         case PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP:
  378.                             $tmp ')';
  379.                             break;
  380.                     }
  381.                 }
  382.  
  383.                 // Add to executable formula array
  384.                 array_push($executableFormulaArray$tmp);
  385.  
  386.                 continue;
  387.             }
  388.  
  389.             // Is it text?
  390.             if ( ($token->getTokenType(== PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND&&
  391.                  ($token->getTokenSubType(== PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_TEXT) ) {
  392.                      // Add to executable formula array
  393.                      array_push($executableFormulaArray'"' $token->getValue('"');
  394.  
  395.                      continue;
  396.             }
  397.  
  398.             // Is it something else?
  399.             array_push($executableFormulaArray$token->getValue());
  400.         }
  401.  
  402.         // Return result
  403.         return '=' implode(' '$executableFormulaArray);
  404.     }
  405.  
  406.     /**
  407.      * Update cell reference
  408.      *
  409.      * @param     string    $pCellRange            Cell range
  410.      * @param     int        $pBefore            Insert before this one
  411.      * @param     int        $pNumCols            Number of columns to increment
  412.      * @param     int        $pNumRows            Number of rows to increment
  413.      * @return     string    Updated cell range
  414.      * @throws     Exception
  415.      */
  416.     public function updateCellReference($pCellRange 'A1'$pBefore 'A1'$pNumCols 0$pNumRows 0{
  417.         // Is it a range or a single cell?
  418.         if (strpos($pCellRange':'=== false{
  419.             // Single cell
  420.             return $this->_updateSingleCellReference($pCellRange$pBefore$pNumCols$pNumRows);
  421.         else {
  422.             // Range
  423.             return $this->_updateCellRange($pCellRange$pBefore$pNumCols$pNumRows);
  424.         }
  425.     }
  426.  
  427.     /**
  428.      * Update cell range
  429.      *
  430.      * @param     string    $pCellRange            Cell range
  431.      * @param     int        $pBefore            Insert before this one
  432.      * @param     int        $pNumCols            Number of columns to increment
  433.      * @param     int        $pNumRows            Number of rows to increment
  434.      * @return     string    Updated cell range
  435.      * @throws     Exception
  436.      */
  437.     private function _updateCellRange($pCellRange 'A1:A1'$pBefore 'A1'$pNumCols 0$pNumRows 0{
  438.         if (strpos($pCellRange,':'!== false{
  439.             // Range
  440.             $referenceA '';
  441.             $referenceB '';
  442.             list($referenceA$referenceBPHPExcel_Cell::splitRange($pCellRange);
  443.  
  444.             return $this->_updateSingleCellReference($referenceA$pBefore$pNumCols$pNumRows':' $this->_updateSingleCellReference($referenceB$pBefore$pNumCols$pNumRows);
  445.         else {
  446.             throw new Exception("Only cell ranges may be passed to this method.");
  447.         }
  448.     }
  449.  
  450.     /**
  451.      * Update single cell reference
  452.      *
  453.      * @param     string    $pCellReference        Single cell reference
  454.      * @param     int        $pBefore            Insert before this one
  455.      * @param     int        $pNumCols            Number of columns to increment
  456.      * @param     int        $pNumRows            Number of rows to increment
  457.      * @return     string    Updated cell reference
  458.      * @throws     Exception
  459.      */
  460.     private function _updateSingleCellReference($pCellReference 'A1'$pBefore 'A1'$pNumCols 0$pNumRows 0{
  461.         if (strpos($pCellReference':'=== false{
  462.             // Get coordinates of $pBefore
  463.             $beforeColumn     'A';
  464.             $beforeRow        1;
  465.             list($beforeColumn$beforeRowPHPExcel_Cell::coordinateFromString$pBefore );
  466.  
  467.             // Get coordinates
  468.             $newColumn     'A';
  469.             $newRow     1;
  470.             list($newColumn$newRowPHPExcel_Cell::coordinateFromString$pCellReference );
  471.  
  472.             // Verify which parts should be updated
  473.             $updateColumn (PHPExcel_Cell::columnIndexFromString($newColumn>= PHPExcel_Cell::columnIndexFromString($beforeColumn))
  474.                             && (strpos($newColumn'$'=== false)
  475.                             && (strpos($beforeColumn'$'=== false);
  476.  
  477.             $updateRow ($newRow >= $beforeRow)
  478.                             && (strpos($newRow'$'=== false)
  479.                             && (strpos($beforeRow'$'=== false);
  480.  
  481.             // Create new column reference
  482.             if ($updateColumn{
  483.                 $newColumn     PHPExcel_Cell::stringFromColumnIndexPHPExcel_Cell::columnIndexFromString($newColumn$pNumCols );
  484.             }
  485.  
  486.             // Create new row reference
  487.             if ($updateRow{
  488.                 $newRow     $newRow $pNumRows;
  489.             }
  490.  
  491.             // Return new reference
  492.             return $newColumn $newRow;
  493.         else {
  494.             throw new Exception("Only single cell references may be passed to this method.");
  495.         }
  496.     }
  497.  
  498.     /**
  499.      * __clone implementation. Cloning should not be allowed in a Singleton!
  500.      *
  501.      * @throws    Exception
  502.      */
  503.     public final function __clone({
  504.         throw new Exception("Cloning a Singleton is not allowed!");
  505.     }
  506. }

Documentation generated on Mon, 27 Oct 2008 08:41:07 +0100 by phpDocumentor 1.4.1