I would like to copy all the data and the style of a certain range to other cells. for example I want to copy from A4: I15 and then paste exactly want I copied the contents and
Update: @pavelDD pointed out that since version 1.x.x some of the imports has been renamed. Instead of accepting his edits to the original code I will share new version. Besides the renaming I've also fixed the annoying index bug and added a helper that copies styles from the original sheet. Unfortunately I'm too lazy to convert it from a class to a simple function like I did last time. But based on the previous version you should be able to do that by yourself if needed.
getCellByColumnAndRow($col, $row);
$style = $sheet->getStyleByColumnAndRow($col, $row);
$dstCell = Coordinate::stringFromColumnIndex($destColumnStart + $colCount) . (string)($destRowStart + $rowCount);
$destSheet->setCellValue($dstCell, $cell->getValue());
$destSheet->duplicateStyle($style, $dstCell);
// Set width of column, but only once per column
if ($rowCount === 0) {
$w = $sheet->getColumnDimensionByColumn($col)->getWidth();
$destSheet->getColumnDimensionByColumn ($destColumnStart + $colCount)->setAutoSize(false);
$destSheet->getColumnDimensionByColumn ($destColumnStart + $colCount)->setWidth($w);
}
$colCount++;
}
$h = $sheet->getRowDimension($row)->getRowHeight();
$destSheet->getRowDimension($destRowStart + $rowCount)->setRowHeight($h);
$rowCount++;
}
foreach ($sheet->getMergeCells() as $mergeCell) {
$mc = explode(":", $mergeCell);
$mergeColSrcStart = Coordinate::columnIndexFromString(preg_replace("/[0-9]*/", "", $mc[0]));
$mergeColSrcEnd = Coordinate::columnIndexFromString(preg_replace("/[0-9]*/", "", $mc[1]));
$mergeRowSrcStart = ((int)preg_replace("/[A-Z]*/", "", $mc[0]));
$mergeRowSrcEnd = ((int)preg_replace("/[A-Z]*/", "", $mc[1]));
$relativeColStart = $mergeColSrcStart - $srcColumnStart;
$relativeColEnd = $mergeColSrcEnd - $srcColumnStart;
$relativeRowStart = $mergeRowSrcStart - $srcRowStart;
$relativeRowEnd = $mergeRowSrcEnd - $srcRowStart;
if (0 <= $mergeRowSrcStart && $mergeRowSrcStart >= $srcRowStart && $mergeRowSrcEnd <= $srcRowEnd) {
$targetColStart = Coordinate::stringFromColumnIndex($destColumnStart + $relativeColStart);
$targetColEnd = Coordinate::stringFromColumnIndex($destColumnStart + $relativeColEnd);
$targetRowStart = $destRowStart + $relativeRowStart;
$targetRowEnd = $destRowStart + $relativeRowEnd;
$merge = (string)$targetColStart . (string)($targetRowStart) . ":" . (string)$targetColEnd . (string)($targetRowEnd);
//Merge target cells
$destSheet->mergeCells($merge);
}
}
}
public static function copyStyleXFCollection(Spreadsheet $sourceSheet, Spreadsheet $destSheet) {
$collection = $sourceSheet->getCellXfCollection();
foreach ($collection as $key => $item) {
$destSheet->addCellXf($item);
}
}
}
?>
I've taken Prashant's answer and extended it for easier use and added some additional functionality. It was a great source to begin with. But it was missing some key features for me: Taking a range (e.g. A10:B15) instead of just indexes Taking a destination cell rather then just a row. Setting width of the destination columns
Please note that I'm using PHPSpreadsheet, the successor of PHPExcel. If you are using the older version just need to update the path for the Cell class.
getCellByColumnAndRow($col, $row);
$style = $sheet->getStyleByColumnAndRow($col, $row);
$dstCell = Cell::stringFromColumnIndex($destColumnStart + $colCount) . (string)($destRowStart + $rowCount);
$sheet->setCellValue($dstCell, $cell->getValue());
$sheet->duplicateStyle($style, $dstCell);
// Set width of column, but only once per row
if ($rowCount === 0) {
$w = $sheet->getColumnDimensionByColumn($col)->getWidth();
$sheet->getColumnDimensionByColumn ($destColumnStart + $colCount)->setAutoSize(false);
$sheet->getColumnDimensionByColumn ($destColumnStart + $colCount)->setWidth($w);
}
$colCount++;
}
$h = $sheet->getRowDimension($row)->getRowHeight();
$sheet->getRowDimension($destRowStart + $rowCount)->setRowHeight($h);
$rowCount++;
}
foreach ($sheet->getMergeCells() as $mergeCell) {
$mc = explode(":", $mergeCell);
$mergeColSrcStart = Cell::columnIndexFromString(preg_replace("/[0-9]*/", "", $mc[0])) - 1;
$mergeColSrcEnd = Cell::columnIndexFromString(preg_replace("/[0-9]*/", "", $mc[1])) - 1;
$mergeRowSrcStart = ((int)preg_replace("/[A-Z]*/", "", $mc[0]));
$mergeRowSrcEnd = ((int)preg_replace("/[A-Z]*/", "", $mc[1]));
$relativeColStart = $mergeColSrcStart - $srcColumnStart;
$relativeColEnd = $mergeColSrcEnd - $srcColumnStart;
$relativeRowStart = $mergeRowSrcStart - $srcRowStart;
$relativeRowEnd = $mergeRowSrcEnd - $srcRowStart;
if (0 <= $mergeRowSrcStart && $mergeRowSrcStart >= $srcRowStart && $mergeRowSrcEnd <= $srcRowEnd) {
$targetColStart = Cell::stringFromColumnIndex($destColumnStart + $relativeColStart);
$targetColEnd = Cell::stringFromColumnIndex($destColumnStart + $relativeColEnd);
$targetRowStart = $destRowStart + $relativeRowStart;
$targetRowEnd = $destRowStart + $relativeRowEnd;
$merge = (string)$targetColStart . (string)($targetRowStart) . ":" . (string)$targetColEnd . (string)($targetRowEnd);
//Merge target cells
$sheet->mergeCells($merge);
}
}
}
?>
Example usage:
copyRange($sheet, 'A4:B8', 'E1');
copyRange($sheet, 'A4:B8', 'A10');
copyRange($sheet, 'A4:B8', 'C17');
Note: I haven't tried it with a single cell. But in theory it should work with A1:A1
Please let me if I have made any mistake, or feel free to edit the answer.