diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index a393043d..8a8886c2 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -26,7 +26,7 @@ $config 'combine_consecutive_issets' => true, 'combine_consecutive_unsets' => true, 'combine_nested_dirname' => true, - 'comment_to_phpdoc' => true, + 'comment_to_phpdoc' => false, // interferes with annotations 'compact_nullable_typehint' => true, 'concat_space' => ['spacing' => 'one'], 'constant_case' => true, @@ -171,7 +171,7 @@ $config 'phpdoc_separation' => true, 'phpdoc_single_line_var_spacing' => true, 'phpdoc_summary' => true, - 'phpdoc_to_comment' => true, + 'phpdoc_to_comment' => false, // interferes with annotations 'phpdoc_to_param_type' => false, // Because experimental, but interesting for one shot use 'phpdoc_to_return_type' => false, // idem 'phpdoc_trim' => true, diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index eb20b3cf..ab910eee 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -4220,26 +4220,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Style/NumberFormat/PercentageFormatter.php - - - message: "#^Cannot call method getCell\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/BaseDrawing.php - - - - message: "#^Cannot call method getDrawingCollection\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/BaseDrawing.php - - - - message: "#^Cannot call method getHashCode\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/BaseDrawing.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\BaseDrawing\\:\\:\\$shadow \\(PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Drawing\\\\Shadow\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Drawing\\\\Shadow\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/BaseDrawing.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\CellIterator\\:\\:adjustForExistingOnlyRange\\(\\) has no return type specified\\.$#" count: 1 @@ -5250,36 +5230,6 @@ parameters: count: 2 path: src/PhpSpreadsheet/Writer/Xlsx/DocProps.php - - - message: "#^Parameter \\#1 \\$coordinates of static method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:indexesFromString\\(\\) expects string, string\\|null given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx/Drawing.php - - - - message: "#^Parameter \\#1 \\$index of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:getChartByIndex\\(\\) expects string, int\\<0, max\\> given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx/Drawing.php - - - - message: "#^Parameter \\#2 \\$chart of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Drawing\\:\\:writeChart\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart, PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\|false given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx/Drawing.php - - - - message: "#^Parameter \\#2 \\$content of method XMLWriter\\:\\:writeElement\\(\\) expects string\\|null, int given\\.$#" - count: 20 - path: src/PhpSpreadsheet/Writer/Xlsx/Drawing.php - - - - message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int given\\.$#" - count: 10 - path: src/PhpSpreadsheet/Writer/Xlsx/Drawing.php - - - - message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int\\<0, max\\> given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx/Drawing.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Rels\\:\\:writeUnparsedRelationship\\(\\) has parameter \\$relationship with no type specified\\.$#" count: 1 diff --git a/samples/Basic/48_Image_move_size_with_cells.php b/samples/Basic/48_Image_move_size_with_cells.php new file mode 100644 index 00000000..abf7ee34 --- /dev/null +++ b/samples/Basic/48_Image_move_size_with_cells.php @@ -0,0 +1,78 @@ +log('Create new Spreadsheet object'); +$spreadsheet = new Spreadsheet(); +$sheet = $spreadsheet->getActiveSheet(); +$sheet->getCell('A1')->setValue('twocell'); +$sheet->getCell('A2')->setValue('twocell'); +$sheet->getCell('A3')->setValue('onecell'); +$sheet->getCell('A6')->setValue('absolute'); + +// Add a drawing to the worksheet +$helper->log('Add a drawing to the worksheet two-cell anchor not resized'); +$drawing = new Drawing(); +$drawing->setName('PhpSpreadsheet'); +$drawing->setDescription('PhpSpreadsheet'); +$drawing->setPath(__DIR__ . '/../images/PhpSpreadsheet_logo.png'); +// anchor type will be two-cell because Coordinates2 is set +//$drawing->setAnchorType(Drawing::ANCHORTYPE_TWOCELL); +$drawing->setCoordinates('B1'); +$drawing->setCoordinates2('B1'); +$drawing->setOffsetX2($drawing->getImageWidth()); +$drawing->setOffsetY2($drawing->getImageHeight()); +$drawing->setWorksheet($spreadsheet->getActiveSheet()); + +// Add a drawing to the worksheet +$helper->log('Add a drawing to the worksheet two-cell anchor resized'); +$drawing2 = new Drawing(); +$drawing2->setName('PhpSpreadsheet'); +$drawing2->setDescription('PhpSpreadsheet'); +$drawing2->setPath(__DIR__ . '/../images/PhpSpreadsheet_logo.png'); +// anchor type will be two-cell because Coordinates2 is set +//$drawing->setAnchorType(Drawing::ANCHORTYPE_TWOCELL); +$drawing2->setCoordinates('C2'); +$drawing2->setCoordinates2('C2'); +$drawing2->setOffsetX2($drawing->getImageWidth()); +$drawing2->setOffsetY2($drawing->getImageHeight()); +$drawing2->setWorksheet($spreadsheet->getActiveSheet()); + +$spreadsheet->getActiveSheet()->getColumnDimension('C')->setWidth($drawing->getImageWidth(), Dimension::UOM_PIXELS); +$spreadsheet->getActiveSheet()->getRowDimension(2)->setRowHeight($drawing->getImageHeight(), Dimension::UOM_PIXELS); + +// Add a drawing to the worksheet one cell anchor +$helper->log('Add a drawing to the worksheet one-cell anchor'); +$drawing3 = new Drawing(); +$drawing3->setName('PhpSpreadsheet'); +$drawing3->setDescription('PhpSpreadsheet'); +$drawing3->setPath(__DIR__ . '/../images/PhpSpreadsheet_logo.png'); +// anchor type will be one-cell because Coordinates2 is not set +//$drawing->setAnchorType(Drawing::ANCHORTYPE_ONECELL); +$drawing3->setCoordinates('D3'); +$drawing3->setWorksheet($spreadsheet->getActiveSheet()); + +// Add a drawing to the worksheet +$helper->log('Add a drawing to the worksheet two-cell anchor resized absolute'); +$drawing4 = new Drawing(); +$drawing4->setName('PhpSpreadsheet'); +$drawing4->setDescription('PhpSpreadsheet'); +$drawing4->setPath(__DIR__ . '/../images/PhpSpreadsheet_logo.png'); +// anchor type will be two-cell because Coordinates2 is set +//$drawing->setAnchorType(Drawing::ANCHORTYPE_TWOCELL); +$drawing4->setCoordinates('C6'); +$drawing4->setCoordinates2('C6'); +$drawing4->setOffsetX2($drawing->getImageWidth()); +$drawing4->setOffsetY2($drawing->getImageHeight()); +$drawing4->setWorksheet($spreadsheet->getActiveSheet()); +$drawing4->setEditAs(Drawing::EDIT_AS_ABSOLUTE); + +//$spreadsheet->getActiveSheet()->getColumnDimension('C')->setWidth($drawing->getImageWidth(), Dimension::UOM_PIXELS); +$spreadsheet->getActiveSheet()->getRowDimension(6)->setRowHeight($drawing->getImageHeight(), Dimension::UOM_PIXELS); + +$helper->write($spreadsheet, __FILE__, ['Xlsx']); diff --git a/samples/Chart/33_Chart_create_area.php b/samples/Chart/33_Chart_create_area.php index 57db90fc..95d9149c 100644 --- a/samples/Chart/33_Chart_create_area.php +++ b/samples/Chart/33_Chart_create_area.php @@ -3,7 +3,7 @@ use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; -use PhpOffice\PhpSpreadsheet\Chart\Legend; +use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend; use PhpOffice\PhpSpreadsheet\Chart\PlotArea; use PhpOffice\PhpSpreadsheet\Chart\Title; use PhpOffice\PhpSpreadsheet\IOFactory; @@ -71,7 +71,7 @@ $series = new DataSeries( // Set the series in the plot area $plotArea = new PlotArea(null, [$series]); // Set the chart legend -$legend = new Legend(Legend::POSITION_TOPRIGHT, null, false); +$legend = new ChartLegend(ChartLegend::POSITION_TOPRIGHT, null, false); $title = new Title('Test %age-Stacked Area Chart'); $yAxisLabel = new Title('Value ($k)'); diff --git a/samples/Chart/33_Chart_create_bar_stacked.php b/samples/Chart/33_Chart_create_bar_stacked.php index 0c87224e..bb2d8f6d 100644 --- a/samples/Chart/33_Chart_create_bar_stacked.php +++ b/samples/Chart/33_Chart_create_bar_stacked.php @@ -3,7 +3,7 @@ use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; -use PhpOffice\PhpSpreadsheet\Chart\Legend; +use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend; use PhpOffice\PhpSpreadsheet\Chart\PlotArea; use PhpOffice\PhpSpreadsheet\Chart\Title; use PhpOffice\PhpSpreadsheet\IOFactory; @@ -74,7 +74,7 @@ $series->setPlotDirection(DataSeries::DIRECTION_BAR); // Set the series in the plot area $plotArea = new PlotArea(null, [$series]); // Set the chart legend -$legend = new Legend(Legend::POSITION_RIGHT, null, false); +$legend = new ChartLegend(ChartLegend::POSITION_RIGHT, null, false); $title = new Title('Test Chart'); $yAxisLabel = new Title('Value ($k)'); diff --git a/samples/Chart/33_Chart_create_column.php b/samples/Chart/33_Chart_create_column.php index 5af0908c..68aa983d 100644 --- a/samples/Chart/33_Chart_create_column.php +++ b/samples/Chart/33_Chart_create_column.php @@ -3,7 +3,7 @@ use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; -use PhpOffice\PhpSpreadsheet\Chart\Legend; +use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend; use PhpOffice\PhpSpreadsheet\Chart\PlotArea; use PhpOffice\PhpSpreadsheet\Chart\Title; use PhpOffice\PhpSpreadsheet\IOFactory; @@ -74,7 +74,7 @@ $series->setPlotDirection(DataSeries::DIRECTION_COL); // Set the series in the plot area $plotArea = new PlotArea(null, [$series]); // Set the chart legend -$legend = new Legend(Legend::POSITION_RIGHT, null, false); +$legend = new ChartLegend(ChartLegend::POSITION_RIGHT, null, false); $title = new Title('Test Column Chart'); $yAxisLabel = new Title('Value ($k)'); diff --git a/samples/Chart/33_Chart_create_column_2.php b/samples/Chart/33_Chart_create_column_2.php index a62b4906..96f5e316 100644 --- a/samples/Chart/33_Chart_create_column_2.php +++ b/samples/Chart/33_Chart_create_column_2.php @@ -3,7 +3,7 @@ use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; -use PhpOffice\PhpSpreadsheet\Chart\Legend; +use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend; use PhpOffice\PhpSpreadsheet\Chart\PlotArea; use PhpOffice\PhpSpreadsheet\Chart\Title; use PhpOffice\PhpSpreadsheet\IOFactory; @@ -82,7 +82,7 @@ $series->setPlotDirection(DataSeries::DIRECTION_COL); // Set the series in the plot area $plotArea = new PlotArea(null, [$series]); // Set the chart legend -$legend = new Legend(Legend::POSITION_BOTTOM, null, false); +$legend = new ChartLegend(ChartLegend::POSITION_BOTTOM, null, false); $title = new Title('Test Grouped Column Chart'); $xAxisLabel = new Title('Financial Period'); diff --git a/samples/Chart/33_Chart_create_composite.php b/samples/Chart/33_Chart_create_composite.php index ce42d2fc..b2952420 100644 --- a/samples/Chart/33_Chart_create_composite.php +++ b/samples/Chart/33_Chart_create_composite.php @@ -3,7 +3,7 @@ use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; -use PhpOffice\PhpSpreadsheet\Chart\Legend; +use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend; use PhpOffice\PhpSpreadsheet\Chart\PlotArea; use PhpOffice\PhpSpreadsheet\Chart\Title; use PhpOffice\PhpSpreadsheet\IOFactory; @@ -128,7 +128,7 @@ $series3 = new DataSeries( // Set the series in the plot area $plotArea = new PlotArea(null, [$series1, $series2, $series3]); // Set the chart legend -$legend = new Legend(Legend::POSITION_RIGHT, null, false); +$legend = new ChartLegend(ChartLegend::POSITION_RIGHT, null, false); $title = new Title('Average Weather Chart for Crete'); diff --git a/samples/Chart/33_Chart_create_line.php b/samples/Chart/33_Chart_create_line.php index feae2f27..fee2a284 100644 --- a/samples/Chart/33_Chart_create_line.php +++ b/samples/Chart/33_Chart_create_line.php @@ -3,7 +3,7 @@ use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; -use PhpOffice\PhpSpreadsheet\Chart\Legend; +use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend; use PhpOffice\PhpSpreadsheet\Chart\PlotArea; use PhpOffice\PhpSpreadsheet\Chart\Title; use PhpOffice\PhpSpreadsheet\IOFactory; @@ -72,7 +72,7 @@ $series = new DataSeries( // Set the series in the plot area $plotArea = new PlotArea(null, [$series]); // Set the chart legend -$legend = new Legend(Legend::POSITION_TOPRIGHT, null, false); +$legend = new ChartLegend(ChartLegend::POSITION_TOPRIGHT, null, false); $title = new Title('Test Stacked Line Chart'); $yAxisLabel = new Title('Value ($k)'); diff --git a/samples/Chart/33_Chart_create_multiple_charts.php b/samples/Chart/33_Chart_create_multiple_charts.php index 608ffc53..3032bc28 100644 --- a/samples/Chart/33_Chart_create_multiple_charts.php +++ b/samples/Chart/33_Chart_create_multiple_charts.php @@ -3,7 +3,7 @@ use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; -use PhpOffice\PhpSpreadsheet\Chart\Legend; +use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend; use PhpOffice\PhpSpreadsheet\Chart\PlotArea; use PhpOffice\PhpSpreadsheet\Chart\Title; use PhpOffice\PhpSpreadsheet\IOFactory; @@ -71,7 +71,7 @@ $series1 = new DataSeries( // Set the series in the plot area $plotArea1 = new PlotArea(null, [$series1]); // Set the chart legend -$legend1 = new Legend(Legend::POSITION_TOPRIGHT, null, false); +$legend1 = new ChartLegend(ChartLegend::POSITION_TOPRIGHT, null, false); $title1 = new Title('Test %age-Stacked Area Chart'); $yAxisLabel1 = new Title('Value ($k)'); @@ -146,7 +146,7 @@ $series2->setPlotDirection(DataSeries::DIRECTION_COL); // Set the series in the plot area $plotArea2 = new PlotArea(null, [$series2]); // Set the chart legend -$legend2 = new Legend(Legend::POSITION_RIGHT, null, false); +$legend2 = new ChartLegend(ChartLegend::POSITION_RIGHT, null, false); $title2 = new Title('Test Column Chart'); $yAxisLabel2 = new Title('Value ($k)'); diff --git a/samples/Chart/33_Chart_create_pie.php b/samples/Chart/33_Chart_create_pie.php index 5480a18a..4b35b24e 100644 --- a/samples/Chart/33_Chart_create_pie.php +++ b/samples/Chart/33_Chart_create_pie.php @@ -4,7 +4,7 @@ use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; use PhpOffice\PhpSpreadsheet\Chart\Layout; -use PhpOffice\PhpSpreadsheet\Chart\Legend; +use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend; use PhpOffice\PhpSpreadsheet\Chart\PlotArea; use PhpOffice\PhpSpreadsheet\Chart\Title; use PhpOffice\PhpSpreadsheet\IOFactory; @@ -73,7 +73,7 @@ $layout1->setShowPercent(true); // Set the series in the plot area $plotArea1 = new PlotArea($layout1, [$series1]); // Set the chart legend -$legend1 = new Legend(Legend::POSITION_RIGHT, null, false); +$legend1 = new ChartLegend(ChartLegend::POSITION_RIGHT, null, false); $title1 = new Title('Test Pie Chart'); diff --git a/samples/Chart/33_Chart_create_pie_custom_colors.php b/samples/Chart/33_Chart_create_pie_custom_colors.php index ca5397a1..91f7e51b 100644 --- a/samples/Chart/33_Chart_create_pie_custom_colors.php +++ b/samples/Chart/33_Chart_create_pie_custom_colors.php @@ -4,7 +4,7 @@ use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; use PhpOffice\PhpSpreadsheet\Chart\Layout; -use PhpOffice\PhpSpreadsheet\Chart\Legend; +use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend; use PhpOffice\PhpSpreadsheet\Chart\PlotArea; use PhpOffice\PhpSpreadsheet\Chart\Title; use PhpOffice\PhpSpreadsheet\IOFactory; @@ -79,7 +79,7 @@ $layout1->setShowPercent(true); // Set the series in the plot area $plotArea1 = new PlotArea($layout1, [$series1]); // Set the chart legend -$legend1 = new Legend(Legend::POSITION_RIGHT, null, false); +$legend1 = new ChartLegend(ChartLegend::POSITION_RIGHT, null, false); $title1 = new Title('Test Pie Chart'); diff --git a/samples/Chart/33_Chart_create_radar.php b/samples/Chart/33_Chart_create_radar.php index eba4dc39..59a8a5d9 100644 --- a/samples/Chart/33_Chart_create_radar.php +++ b/samples/Chart/33_Chart_create_radar.php @@ -4,7 +4,7 @@ use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; use PhpOffice\PhpSpreadsheet\Chart\Layout; -use PhpOffice\PhpSpreadsheet\Chart\Legend; +use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend; use PhpOffice\PhpSpreadsheet\Chart\PlotArea; use PhpOffice\PhpSpreadsheet\Chart\Title; use PhpOffice\PhpSpreadsheet\IOFactory; @@ -85,7 +85,7 @@ $layout = new Layout(); // Set the series in the plot area $plotArea = new PlotArea($layout, [$series]); // Set the chart legend -$legend = new Legend(Legend::POSITION_RIGHT, null, false); +$legend = new ChartLegend(ChartLegend::POSITION_RIGHT, null, false); $title = new Title('Test Radar Chart'); diff --git a/samples/Chart/33_Chart_create_scatter.php b/samples/Chart/33_Chart_create_scatter.php index c67e4e95..9a54c18b 100644 --- a/samples/Chart/33_Chart_create_scatter.php +++ b/samples/Chart/33_Chart_create_scatter.php @@ -3,7 +3,7 @@ use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; -use PhpOffice\PhpSpreadsheet\Chart\Legend; +use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend; use PhpOffice\PhpSpreadsheet\Chart\PlotArea; use PhpOffice\PhpSpreadsheet\Chart\Title; use PhpOffice\PhpSpreadsheet\IOFactory; @@ -68,7 +68,7 @@ $series = new DataSeries( // Set the series in the plot area $plotArea = new PlotArea(null, [$series]); // Set the chart legend -$legend = new Legend(Legend::POSITION_TOPRIGHT, null, false); +$legend = new ChartLegend(ChartLegend::POSITION_TOPRIGHT, null, false); $title = new Title('Test Scatter Chart'); $yAxisLabel = new Title('Value ($k)'); diff --git a/samples/Chart/33_Chart_create_stock.php b/samples/Chart/33_Chart_create_stock.php index 58686784..34fa3a6c 100644 --- a/samples/Chart/33_Chart_create_stock.php +++ b/samples/Chart/33_Chart_create_stock.php @@ -3,7 +3,7 @@ use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; -use PhpOffice\PhpSpreadsheet\Chart\Legend; +use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend; use PhpOffice\PhpSpreadsheet\Chart\PlotArea; use PhpOffice\PhpSpreadsheet\Chart\Title; use PhpOffice\PhpSpreadsheet\IOFactory; @@ -79,7 +79,7 @@ $series = new DataSeries( // Set the series in the plot area $plotArea = new PlotArea(null, [$series]); // Set the chart legend -$legend = new Legend(Legend::POSITION_RIGHT, null, false); +$legend = new ChartLegend(ChartLegend::POSITION_RIGHT, null, false); $title = new Title('Test Stock Chart'); $xAxisLabel = new Title('Counts'); diff --git a/samples/templates/chartSpreadsheet.php b/samples/templates/chartSpreadsheet.php index 2ad61d32..a5b1b882 100644 --- a/samples/templates/chartSpreadsheet.php +++ b/samples/templates/chartSpreadsheet.php @@ -3,7 +3,7 @@ use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; -use PhpOffice\PhpSpreadsheet\Chart\Legend; +use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend; use PhpOffice\PhpSpreadsheet\Chart\PlotArea; use PhpOffice\PhpSpreadsheet\Chart\Title; use PhpOffice\PhpSpreadsheet\Spreadsheet; @@ -71,7 +71,7 @@ $series->setPlotDirection(DataSeries::DIRECTION_BAR); // Set the series in the plot area $plotArea = new PlotArea(null, [$series]); // Set the chart legend -$legend = new Legend(Legend::POSITION_RIGHT, null, false); +$legend = new ChartLegend(ChartLegend::POSITION_RIGHT, null, false); $title = new Title('Test Bar Chart'); $yAxisLabel = new Title('Value ($k)'); diff --git a/src/PhpSpreadsheet/Helper/Html.php b/src/PhpSpreadsheet/Helper/Html.php index 26526605..4737379a 100644 --- a/src/PhpSpreadsheet/Helper/Html.php +++ b/src/PhpSpreadsheet/Helper/Html.php @@ -619,6 +619,7 @@ class Html // Load the HTML file into the DOM object // Note the use of error suppression, because typically this will be an html fragment, so not fully valid markup $prefix = ''; + /** @scrutinizer ignore-unhandled */ @$dom->loadHTML($prefix . $html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); // Discard excess white space $dom->preserveWhiteSpace = false; @@ -808,7 +809,7 @@ class Html if (isset($callbacks[$callbackTag])) { $elementHandler = $callbacks[$callbackTag]; if (method_exists($this, $elementHandler)) { - // @phpstan-ignore-next-line + /** @phpstan-ignore-next-line */ call_user_func([$this, $elementHandler], $element); } } diff --git a/src/PhpSpreadsheet/Reader/Xls/MD5.php b/src/PhpSpreadsheet/Reader/Xls/MD5.php index a1108f92..14b6bc54 100644 --- a/src/PhpSpreadsheet/Reader/Xls/MD5.php +++ b/src/PhpSpreadsheet/Reader/Xls/MD5.php @@ -71,7 +71,7 @@ class MD5 */ public function add(string $data): void { - /** @phpstan-ignore-next-line */ + // @phpstan-ignore-next-line $words = array_values(unpack('V16', $data)); $A = $this->a; diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index c0b0c5ee..992002bb 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -1315,6 +1315,11 @@ class Xlsx extends BaseReader $outerShdw = $twoCellAnchor->pic->spPr->children(Namespaces::DRAWINGML)->effectLst->outerShdw; $hlinkClick = $twoCellAnchor->pic->nvPicPr->cNvPr->children(Namespaces::DRAWINGML)->hlinkClick; $objDrawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing(); + /** @scrutinizer ignore-call */ + $editAs = $twoCellAnchor->attributes(); + if (isset($editAs, $editAs['editAs'])) { + $objDrawing->setEditAs($editAs['editAs']); + } $objDrawing->setName((string) self::getArrayItem(self::getAttributes($twoCellAnchor->pic->nvPicPr->cNvPr), 'name')); $objDrawing->setDescription((string) self::getArrayItem(self::getAttributes($twoCellAnchor->pic->nvPicPr->cNvPr), 'descr')); $embedImageKey = (string) self::getArrayItem( diff --git a/src/PhpSpreadsheet/Shared/XMLWriter.php b/src/PhpSpreadsheet/Shared/XMLWriter.php index 84ad8a83..3dc0aad9 100644 --- a/src/PhpSpreadsheet/Shared/XMLWriter.php +++ b/src/PhpSpreadsheet/Shared/XMLWriter.php @@ -54,7 +54,9 @@ class XMLWriter extends \XMLWriter public function __destruct() { // Unlink temporary files + // There is nothing reasonable to do if unlink fails. if ($this->tempFileName != '') { + /** @scrutinizer ignore-unhandled */ @unlink($this->tempFileName); } } diff --git a/src/PhpSpreadsheet/Worksheet/BaseDrawing.php b/src/PhpSpreadsheet/Worksheet/BaseDrawing.php index bd90b2bc..815536b5 100644 --- a/src/PhpSpreadsheet/Worksheet/BaseDrawing.php +++ b/src/PhpSpreadsheet/Worksheet/BaseDrawing.php @@ -8,6 +8,22 @@ use PhpOffice\PhpSpreadsheet\IComparable; class BaseDrawing implements IComparable { + const EDIT_AS_ABSOLUTE = 'absolute'; + const EDIT_AS_ONECELL = 'onecell'; + const EDIT_AS_TWOCELL = 'twocell'; + private const VALID_EDIT_AS = [ + self::EDIT_AS_ABSOLUTE, + self::EDIT_AS_ONECELL, + self::EDIT_AS_TWOCELL, + ]; + + /** + * The editAs attribute, used only with two cell anchor. + * + * @var string + */ + protected $editAs = ''; + /** * Image counter. * @@ -27,14 +43,14 @@ class BaseDrawing implements IComparable * * @var string */ - protected $name; + protected $name = ''; /** * Description. * * @var string */ - protected $description; + protected $description = ''; /** * Worksheet. @@ -48,70 +64,84 @@ class BaseDrawing implements IComparable * * @var string */ - protected $coordinates; + protected $coordinates = 'A1'; /** * Offset X. * * @var int */ - protected $offsetX; + protected $offsetX = 0; /** * Offset Y. * * @var int */ - protected $offsetY; + protected $offsetY = 0; /** * Coordinates2. * - * @var null|string + * @var string */ - protected $coordinates2; + protected $coordinates2 = ''; /** * Offset X2. * * @var int */ - protected $offsetX2; + protected $offsetX2 = 0; /** * Offset Y2. * * @var int */ - protected $offsetY2; + protected $offsetY2 = 0; /** * Width. * * @var int */ - protected $width; + protected $width = 0; /** * Height. * * @var int */ - protected $height; + protected $height = 0; + + /** + * Pixel width of image. See $width for the size the Drawing will be in the sheet. + * + * @var int + */ + protected $imageWidth = 0; + + /** + * Pixel width of image. See $height for the size the Drawing will be in the sheet. + * + * @var int + */ + protected $imageHeight = 0; /** * Proportional resize. * * @var bool */ - protected $resizeProportional; + protected $resizeProportional = true; /** * Rotation. * * @var int */ - protected $rotation; + protected $rotation = 0; /** * Shadow. @@ -132,7 +162,7 @@ class BaseDrawing implements IComparable * * @var int */ - protected $type; + protected $type = IMAGETYPE_UNKNOWN; /** * Create a new BaseDrawing. @@ -140,91 +170,43 @@ class BaseDrawing implements IComparable public function __construct() { // Initialise values - $this->name = ''; - $this->description = ''; - $this->worksheet = null; - $this->coordinates = 'A1'; - $this->offsetX = 0; - $this->offsetY = 0; - $this->coordinates2 = null; - $this->offsetX2 = 0; - $this->offsetY2 = 0; - $this->width = 0; - $this->height = 0; - $this->resizeProportional = true; - $this->rotation = 0; - $this->shadow = new Drawing\Shadow(); - $this->type = IMAGETYPE_UNKNOWN; + $this->setShadow(); // Set image index ++self::$imageCounter; $this->imageIndex = self::$imageCounter; } - /** - * Get image index. - * - * @return int - */ - public function getImageIndex() + public function getImageIndex(): int { return $this->imageIndex; } - /** - * Get Name. - * - * @return string - */ - public function getName() + public function getName(): string { return $this->name; } - /** - * Set Name. - * - * @param string $name - * - * @return $this - */ - public function setName($name) + public function setName(string $name): self { $this->name = $name; return $this; } - /** - * Get Description. - * - * @return string - */ - public function getDescription() + public function getDescription(): string { return $this->description; } - /** - * Set Description. - * - * @param string $description - * - * @return $this - */ - public function setDescription($description) + public function setDescription(string $description): self { $this->description = $description; return $this; } - /** - * Get Worksheet. - * - * @return null|Worksheet - */ - public function getWorksheet() + public function getWorksheet(): ?Worksheet { return $this->worksheet; } @@ -233,16 +215,16 @@ class BaseDrawing implements IComparable * Set Worksheet. * * @param bool $overrideOld If a Worksheet has already been assigned, overwrite it and remove image from old Worksheet? - * - * @return $this */ - public function setWorksheet(?Worksheet $worksheet = null, $overrideOld = false) + public function setWorksheet(?Worksheet $worksheet = null, bool $overrideOld = false): self { if ($this->worksheet === null) { // Add drawing to \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet - $this->worksheet = $worksheet; - $this->worksheet->getCell($this->coordinates); - $this->worksheet->getDrawingCollection()->append($this); + if ($worksheet !== null) { + $this->worksheet = $worksheet; + $this->worksheet->getCell($this->coordinates); + $this->worksheet->getDrawingCollection()->append($this); + } } else { if ($overrideOld) { // Remove drawing from old \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet @@ -267,168 +249,84 @@ class BaseDrawing implements IComparable return $this; } - /** - * Get Coordinates. - * - * @return string - */ - public function getCoordinates() + public function getCoordinates(): string { return $this->coordinates; } - /** - * Set Coordinates. - * - * @param string $coordinates eg: 'A1' - * - * @return $this - */ - public function setCoordinates($coordinates) + public function setCoordinates(string $coordinates): self { $this->coordinates = $coordinates; return $this; } - /** - * Get OffsetX. - * - * @return int - */ - public function getOffsetX() + public function getOffsetX(): int { return $this->offsetX; } - /** - * Set OffsetX. - * - * @param int $offsetX - * - * @return $this - */ - public function setOffsetX($offsetX) + public function setOffsetX(int $offsetX): self { $this->offsetX = $offsetX; return $this; } - /** - * Get OffsetY. - * - * @return int - */ - public function getOffsetY() + public function getOffsetY(): int { return $this->offsetY; } - /** - * Get Coordinates2. - * - * @return null|string - */ - public function getCoordinates2() - { - return $this->coordinates2; - } - - /** - * Set Coordinates2. - * - * @param null|string $coordinates2 eg: 'A1' - * - * @return $this - */ - public function setCoordinates2($coordinates2) - { - $this->coordinates2 = $coordinates2; - - return $this; - } - - /** - * Get OffsetX2. - * - * @return int - */ - public function getOffsetX2() - { - return $this->offsetX2; - } - - /** - * Set OffsetX2. - * - * @param int $offsetX2 - * - * @return $this - */ - public function setOffsetX2($offsetX2) - { - $this->offsetX2 = $offsetX2; - - return $this; - } - - /** - * Get OffsetY2. - * - * @return int - */ - public function getOffsetY2() - { - return $this->offsetY2; - } - - /** - * Set OffsetY2. - * - * @param int $offsetY2 - * - * @return $this - */ - public function setOffsetY2($offsetY2) - { - $this->offsetY2 = $offsetY2; - - return $this; - } - - /** - * Set OffsetY. - * - * @param int $offsetY - * - * @return $this - */ - public function setOffsetY($offsetY) + public function setOffsetY(int $offsetY): self { $this->offsetY = $offsetY; return $this; } - /** - * Get Width. - * - * @return int - */ - public function getWidth() + public function getCoordinates2(): string + { + return $this->coordinates2; + } + + public function setCoordinates2(string $coordinates2): self + { + $this->coordinates2 = $coordinates2; + + return $this; + } + + public function getOffsetX2(): int + { + return $this->offsetX2; + } + + public function setOffsetX2(int $offsetX2): self + { + $this->offsetX2 = $offsetX2; + + return $this; + } + + public function getOffsetY2(): int + { + return $this->offsetY2; + } + + public function setOffsetY2(int $offsetY2): self + { + $this->offsetY2 = $offsetY2; + + return $this; + } + + public function getWidth(): int { return $this->width; } - /** - * Set Width. - * - * @param int $width - * - * @return $this - */ - public function setWidth($width) + public function setWidth(int $width): self { // Resize proportional? if ($this->resizeProportional && $width != 0) { @@ -442,24 +340,12 @@ class BaseDrawing implements IComparable return $this; } - /** - * Get Height. - * - * @return int - */ - public function getHeight() + public function getHeight(): int { return $this->height; } - /** - * Set Height. - * - * @param int $height - * - * @return $this - */ - public function setHeight($height) + public function setHeight(int $height): self { // Resize proportional? if ($this->resizeProportional && $height != 0) { @@ -482,14 +368,9 @@ class BaseDrawing implements IComparable * $objDrawing->setWidthAndHeight(160,120); * * - * @param int $width - * @param int $height - * - * @return $this - * * @author Vincent@luo MSN:kele_100@hotmail.com */ - public function setWidthAndHeight($width, $height) + public function setWidthAndHeight(int $width, int $height): self { $xratio = $width / ($this->width != 0 ? $this->width : 1); $yratio = $height / ($this->height != 0 ? $this->height : 1); @@ -509,72 +390,38 @@ class BaseDrawing implements IComparable return $this; } - /** - * Get ResizeProportional. - * - * @return bool - */ - public function getResizeProportional() + public function getResizeProportional(): bool { return $this->resizeProportional; } - /** - * Set ResizeProportional. - * - * @param bool $resizeProportional - * - * @return $this - */ - public function setResizeProportional($resizeProportional) + public function setResizeProportional(bool $resizeProportional): self { $this->resizeProportional = $resizeProportional; return $this; } - /** - * Get Rotation. - * - * @return int - */ - public function getRotation() + public function getRotation(): int { return $this->rotation; } - /** - * Set Rotation. - * - * @param int $rotation - * - * @return $this - */ - public function setRotation($rotation) + public function setRotation(int $rotation): self { $this->rotation = $rotation; return $this; } - /** - * Get Shadow. - * - * @return Drawing\Shadow - */ - public function getShadow() + public function getShadow(): Drawing\Shadow { return $this->shadow; } - /** - * Set Shadow. - * - * @return $this - */ - public function setShadow(?Drawing\Shadow $shadow = null) + public function setShadow(?Drawing\Shadow $shadow = null): self { - $this->shadow = $shadow; + $this->shadow = $shadow ?? new Drawing\Shadow(); return $this; } @@ -589,7 +436,7 @@ class BaseDrawing implements IComparable return md5( $this->name . $this->description . - $this->worksheet->getHashCode() . + (($this->worksheet === null) ? '' : $this->worksheet->getHashCode()) . $this->coordinates . $this->offsetX . $this->offsetY . @@ -626,10 +473,7 @@ class BaseDrawing implements IComparable $this->hyperlink = $hyperlink; } - /** - * @return null|Hyperlink - */ - public function getHyperlink() + public function getHyperlink(): ?Hyperlink { return $this->hyperlink; } @@ -639,15 +483,19 @@ class BaseDrawing implements IComparable */ protected function setSizesAndType(string $path): void { - if ($this->width == 0 && $this->height == 0 && $this->type == IMAGETYPE_UNKNOWN) { + if ($this->imageWidth === 0 && $this->imageHeight === 0 && $this->type === IMAGETYPE_UNKNOWN) { $imageData = getimagesize($path); if (is_array($imageData)) { - $this->width = $imageData[0]; - $this->height = $imageData[1]; + $this->imageWidth = $imageData[0]; + $this->imageHeight = $imageData[1]; $this->type = $imageData[2]; } } + if ($this->width === 0 && $this->height === 0) { + $this->width = $this->imageWidth; + $this->height = $this->imageHeight; + } } /** @@ -657,4 +505,31 @@ class BaseDrawing implements IComparable { return $this->type; } + + public function getImageWidth(): int + { + return $this->imageWidth; + } + + public function getImageHeight(): int + { + return $this->imageHeight; + } + + public function getEditAs(): string + { + return $this->editAs; + } + + public function setEditAs(string $editAs): self + { + $this->editAs = $editAs; + + return $this; + } + + public function validEditAs(): bool + { + return in_array($this->editAs, self::VALID_EDIT_AS); + } } diff --git a/src/PhpSpreadsheet/Worksheet/MemoryDrawing.php b/src/PhpSpreadsheet/Worksheet/MemoryDrawing.php index 91acbb7b..e65541dc 100644 --- a/src/PhpSpreadsheet/Worksheet/MemoryDrawing.php +++ b/src/PhpSpreadsheet/Worksheet/MemoryDrawing.php @@ -47,6 +47,9 @@ class MemoryDrawing extends BaseDrawing */ private $uniqueName; + /** @var null|resource */ + private $alwaysNull; + /** * Create a new MemoryDrawing. */ @@ -56,6 +59,7 @@ class MemoryDrawing extends BaseDrawing $this->renderingFunction = self::RENDERING_DEFAULT; $this->mimeType = self::MIMETYPE_DEFAULT; $this->uniqueName = md5(mt_rand(0, 9999) . time() . mt_rand(0, 9999)); + $this->alwaysNull = null; // Initialize parent parent::__construct(); @@ -64,8 +68,9 @@ class MemoryDrawing extends BaseDrawing public function __destruct() { if ($this->imageResource) { - imagedestroy($this->imageResource); - $this->imageResource = null; + $rslt = @imagedestroy($this->imageResource); + // "Fix" for Scrutinizer + $this->imageResource = $rslt ? null : $this->alwaysNull; } } diff --git a/src/PhpSpreadsheet/Worksheet/Row.php b/src/PhpSpreadsheet/Worksheet/Row.php index b5933356..a5f8f326 100644 --- a/src/PhpSpreadsheet/Worksheet/Row.php +++ b/src/PhpSpreadsheet/Worksheet/Row.php @@ -35,8 +35,7 @@ class Row */ public function __destruct() { - // @phpstan-ignore-next-line - $this->worksheet = null; + $this->worksheet = null; // @phpstan-ignore-line } /** diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Drawing.php b/src/PhpSpreadsheet/Writer/Xlsx/Drawing.php index 6868212a..816bb9d4 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Drawing.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Drawing.php @@ -3,6 +3,7 @@ namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; +use PhpOffice\PhpSpreadsheet\Shared\Drawing as SharedDrawing; use PhpOffice\PhpSpreadsheet\Shared\XMLWriter; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Worksheet\BaseDrawing; @@ -56,7 +57,10 @@ class Drawing extends WriterPart // Loop through charts and write the chart position if ($chartCount > 0) { for ($c = 0; $c < $chartCount; ++$c) { - $this->writeChart($objWriter, $worksheet->getChartByIndex($c), $c + $i); + $chart = $worksheet->getChartByIndex((string) $c); + if ($chart !== false) { + $this->writeChart($objWriter, $chart, $c + $i); + } } } } @@ -90,16 +94,16 @@ class Drawing extends WriterPart $objWriter->startElement('xdr:twoCellAnchor'); $objWriter->startElement('xdr:from'); - $objWriter->writeElement('xdr:col', $tlColRow[0] - 1); - $objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($tl['xOffset'])); - $objWriter->writeElement('xdr:row', $tlColRow[1] - 1); - $objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($tl['yOffset'])); + $objWriter->writeElement('xdr:col', (string) ($tlColRow[0] - 1)); + $objWriter->writeElement('xdr:colOff', self::stringEmu($tl['xOffset'])); + $objWriter->writeElement('xdr:row', (string) ($tlColRow[1] - 1)); + $objWriter->writeElement('xdr:rowOff', self::stringEmu($tl['yOffset'])); $objWriter->endElement(); $objWriter->startElement('xdr:to'); - $objWriter->writeElement('xdr:col', $brColRow[0] - 1); - $objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($br['xOffset'])); - $objWriter->writeElement('xdr:row', $brColRow[1] - 1); - $objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($br['yOffset'])); + $objWriter->writeElement('xdr:col', (string) ($brColRow[0] - 1)); + $objWriter->writeElement('xdr:colOff', self::stringEmu($br['xOffset'])); + $objWriter->writeElement('xdr:row', (string) ($brColRow[1] - 1)); + $objWriter->writeElement('xdr:rowOff', self::stringEmu($br['yOffset'])); $objWriter->endElement(); $objWriter->startElement('xdr:graphicFrame'); @@ -107,7 +111,7 @@ class Drawing extends WriterPart $objWriter->startElement('xdr:nvGraphicFramePr'); $objWriter->startElement('xdr:cNvPr'); $objWriter->writeAttribute('name', 'Chart ' . $relationId); - $objWriter->writeAttribute('id', 1025 * $relationId); + $objWriter->writeAttribute('id', (string) (1025 * $relationId)); $objWriter->endElement(); $objWriter->startElement('xdr:cNvGraphicFramePr'); $objWriter->startElement('a:graphicFrameLocks'); @@ -153,28 +157,31 @@ class Drawing extends WriterPart public function writeDrawing(XMLWriter $objWriter, BaseDrawing $drawing, $relationId = -1, $hlinkClickId = null): void { if ($relationId >= 0) { - $isTwoCellAnchor = $drawing->getCoordinates2() !== null; + $isTwoCellAnchor = $drawing->getCoordinates2() !== ''; if ($isTwoCellAnchor) { // xdr:twoCellAnchor $objWriter->startElement('xdr:twoCellAnchor'); + if ($drawing->validEditAs()) { + $objWriter->writeAttribute('editAs', $drawing->getEditAs()); + } // Image location $aCoordinates = Coordinate::indexesFromString($drawing->getCoordinates()); $aCoordinates2 = Coordinate::indexesFromString($drawing->getCoordinates2()); // xdr:from $objWriter->startElement('xdr:from'); - $objWriter->writeElement('xdr:col', $aCoordinates[0] - 1); - $objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getOffsetX())); - $objWriter->writeElement('xdr:row', $aCoordinates[1] - 1); - $objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getOffsetY())); + $objWriter->writeElement('xdr:col', (string) ($aCoordinates[0] - 1)); + $objWriter->writeElement('xdr:colOff', self::stringEmu($drawing->getOffsetX())); + $objWriter->writeElement('xdr:row', (string) ($aCoordinates[1] - 1)); + $objWriter->writeElement('xdr:rowOff', self::stringEmu($drawing->getOffsetY())); $objWriter->endElement(); // xdr:to $objWriter->startElement('xdr:to'); - $objWriter->writeElement('xdr:col', $aCoordinates2[0] - 1); - $objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getOffsetX2())); - $objWriter->writeElement('xdr:row', $aCoordinates2[1] - 1); - $objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getOffsetY2())); + $objWriter->writeElement('xdr:col', (string) ($aCoordinates2[0] - 1)); + $objWriter->writeElement('xdr:colOff', self::stringEmu($drawing->getOffsetX2())); + $objWriter->writeElement('xdr:row', (string) ($aCoordinates2[1] - 1)); + $objWriter->writeElement('xdr:rowOff', self::stringEmu($drawing->getOffsetY2())); $objWriter->endElement(); } else { // xdr:oneCellAnchor @@ -184,16 +191,16 @@ class Drawing extends WriterPart // xdr:from $objWriter->startElement('xdr:from'); - $objWriter->writeElement('xdr:col', $aCoordinates[0] - 1); - $objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getOffsetX())); - $objWriter->writeElement('xdr:row', $aCoordinates[1] - 1); - $objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getOffsetY())); + $objWriter->writeElement('xdr:col', (string) ($aCoordinates[0] - 1)); + $objWriter->writeElement('xdr:colOff', self::stringEmu($drawing->getOffsetX())); + $objWriter->writeElement('xdr:row', (string) ($aCoordinates[1] - 1)); + $objWriter->writeElement('xdr:rowOff', self::stringEmu($drawing->getOffsetY())); $objWriter->endElement(); // xdr:ext $objWriter->startElement('xdr:ext'); - $objWriter->writeAttribute('cx', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getWidth())); - $objWriter->writeAttribute('cy', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getHeight())); + $objWriter->writeAttribute('cx', self::stringEmu($drawing->getWidth())); + $objWriter->writeAttribute('cy', self::stringEmu($drawing->getHeight())); $objWriter->endElement(); } @@ -205,7 +212,7 @@ class Drawing extends WriterPart // xdr:cNvPr $objWriter->startElement('xdr:cNvPr'); - $objWriter->writeAttribute('id', $relationId); + $objWriter->writeAttribute('id', (string) $relationId); $objWriter->writeAttribute('name', $drawing->getName()); $objWriter->writeAttribute('descr', $drawing->getDescription()); @@ -247,11 +254,11 @@ class Drawing extends WriterPart // a:xfrm $objWriter->startElement('a:xfrm'); - $objWriter->writeAttribute('rot', \PhpOffice\PhpSpreadsheet\Shared\Drawing::degreesToAngle($drawing->getRotation())); + $objWriter->writeAttribute('rot', (string) SharedDrawing::degreesToAngle($drawing->getRotation())); if ($isTwoCellAnchor) { $objWriter->startElement('a:ext'); - $objWriter->writeAttribute('cx', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getWidth())); - $objWriter->writeAttribute('cy', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getHeight())); + $objWriter->writeAttribute('cx', self::stringEmu($drawing->getWidth())); + $objWriter->writeAttribute('cy', self::stringEmu($drawing->getHeight())); $objWriter->endElement(); } $objWriter->endElement(); @@ -271,9 +278,9 @@ class Drawing extends WriterPart // a:outerShdw $objWriter->startElement('a:outerShdw'); - $objWriter->writeAttribute('blurRad', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getShadow()->getBlurRadius())); - $objWriter->writeAttribute('dist', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($drawing->getShadow()->getDistance())); - $objWriter->writeAttribute('dir', \PhpOffice\PhpSpreadsheet\Shared\Drawing::degreesToAngle($drawing->getShadow()->getDirection())); + $objWriter->writeAttribute('blurRad', self::stringEmu($drawing->getShadow()->getBlurRadius())); + $objWriter->writeAttribute('dist', self::stringEmu($drawing->getShadow()->getDistance())); + $objWriter->writeAttribute('dir', (string) SharedDrawing::degreesToAngle($drawing->getShadow()->getDirection())); $objWriter->writeAttribute('algn', $drawing->getShadow()->getAlignment()); $objWriter->writeAttribute('rotWithShape', '0'); @@ -283,7 +290,7 @@ class Drawing extends WriterPart // a:alpha $objWriter->startElement('a:alpha'); - $objWriter->writeAttribute('val', $drawing->getShadow()->getAlpha() * 1000); + $objWriter->writeAttribute('val', (string) ($drawing->getShadow()->getAlpha() * 1000)); $objWriter->endElement(); $objWriter->endElement(); @@ -528,4 +535,9 @@ class Drawing extends WriterPart $objWriter->writeAttribute('r:id', 'rId' . $hlinkClickId); $objWriter->endElement(); } + + private static function stringEmu(int $pixelValue): string + { + return (string) SharedDrawing::pixelsToEMU($pixelValue); + } } diff --git a/tests/PhpSpreadsheetTests/Worksheet/DrawingTest.php b/tests/PhpSpreadsheetTests/Worksheet/DrawingTest.php index d18ff002..17e17e19 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/DrawingTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/DrawingTest.php @@ -2,7 +2,10 @@ namespace PhpOffice\PhpSpreadsheetTests\Worksheet; +use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException; use PhpOffice\PhpSpreadsheet\Spreadsheet; +use PhpOffice\PhpSpreadsheet\Worksheet\Drawing; +use PhpOffice\PhpSpreadsheet\Worksheet\HeaderFooterDrawing; use PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing; use PHPUnit\Framework\TestCase; @@ -41,4 +44,76 @@ class DrawingTest extends TestCase $spreadsheet->disconnectWorksheets(); } } + + public function testChangeWorksheet(): void + { + $spreadsheet = new Spreadsheet(); + $sheet1 = $spreadsheet->getActiveSheet(); + $sheet2 = $spreadsheet->createSheet(); + + $drawing = new Drawing(); + $drawing->setName('Green Square'); + $drawing->setPath('tests/data/Writer/XLSX/green_square.gif'); + self::assertEquals($drawing->getWidth(), 150); + self::assertEquals($drawing->getHeight(), 150); + $drawing->setCoordinates('A1'); + $drawing->setOffsetX(30); + $drawing->setOffsetY(10); + $drawing->setWorksheet($sheet1); + + try { + $drawing->setWorksheet($sheet2); + self::fail('Should throw exception when attempting set worksheet without specifying override'); + } catch (PhpSpreadsheetException $e) { + self::assertStringContainsString('A Worksheet has already been assigned.', $e->getMessage()); + } + self::assertSame($sheet1, $drawing->getWorksheet()); + self::assertCount(1, $sheet1->getDrawingCollection()); + self::assertCount(0, $sheet2->getDrawingCollection()); + $drawing->setWorksheet($sheet2, true); + self::assertSame($sheet2, $drawing->getWorksheet()); + self::assertCount(0, $sheet1->getDrawingCollection()); + self::assertCount(1, $sheet2->getDrawingCollection()); + } + + public function testHeaderFooter(): void + { + $drawing1 = new HeaderFooterDrawing(); + $drawing1->setName('Blue Square'); + $drawing1->setPath('tests/data/Writer/XLSX/blue_square.png'); + self::assertEquals($drawing1->getWidth(), 100); + self::assertEquals($drawing1->getHeight(), 100); + $drawing2 = new HeaderFooterDrawing(); + $drawing2->setName('Blue Square'); + $drawing2->setPath('tests/data/Writer/XLSX/blue_square.png'); + self::assertSame($drawing1->getHashCode(), $drawing2->getHashCode()); + $drawing2->setOffsetX(100); + self::assertNotEquals($drawing1->getHashCode(), $drawing2->getHashCode()); + } + + public function testSetWidthAndHeight(): void + { + $drawing = new Drawing(); + $drawing->setName('Blue Square'); + $drawing->setPath('tests/data/Writer/XLSX/blue_square.png'); + self::assertSame(100, $drawing->getWidth()); + self::assertSame(100, $drawing->getHeight()); + self::assertTrue($drawing->getResizeProportional()); + $drawing->setResizeProportional(false); + $drawing->setWidthAndHeight(150, 200); + self::assertSame(150, $drawing->getWidth()); + self::assertSame(200, $drawing->getHeight()); + $drawing->setResizeProportional(true); + $drawing->setWidthAndHeight(300, 250); + // width increase% more than height, so scale width + self::assertSame(188, $drawing->getWidth()); + self::assertSame(250, $drawing->getHeight()); + $drawing->setResizeProportional(false); + $drawing->setWidthAndHeight(150, 200); + $drawing->setResizeProportional(true); + // height increase% more than width, so scale height + $drawing->setWidthAndHeight(175, 350); + self::assertSame(175, $drawing->getWidth()); + self::assertSame(234, $drawing->getHeight()); + } } diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php index f9df2b1c..ccbced32 100644 --- a/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php @@ -8,7 +8,9 @@ use PhpOffice\PhpSpreadsheet\IOFactory; use PhpOffice\PhpSpreadsheet\Reader\Xlsx; use PhpOffice\PhpSpreadsheet\Shared\File; use PhpOffice\PhpSpreadsheet\Spreadsheet; +use PhpOffice\PhpSpreadsheet\Worksheet\BaseDrawing; use PhpOffice\PhpSpreadsheet\Worksheet\Drawing; +use PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing; use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional; class DrawingsTest extends AbstractFunctional @@ -28,6 +30,8 @@ class DrawingsTest extends AbstractFunctional // Fake assert. The only thing we need is to ensure the file is loaded without exception self::assertNotNull($reloadedSpreadsheet); + $spreadsheet->disconnectWorksheets(); + $reloadedSpreadsheet->disconnectWorksheets(); } /** @@ -59,6 +63,8 @@ class DrawingsTest extends AbstractFunctional // Fake assert. The only thing we need is to ensure the file is loaded without exception self::assertNotNull($reloadedSpreadsheet); + $spreadsheet->disconnectWorksheets(); + $reloadedSpreadsheet->disconnectWorksheets(); } /** @@ -96,6 +102,8 @@ class DrawingsTest extends AbstractFunctional unlink($tempFileName); self::assertNotNull($reloadedSpreadsheet); + $spreadsheet->disconnectWorksheets(); + $reloadedSpreadsheet->disconnectWorksheets(); } /** @@ -173,7 +181,8 @@ class DrawingsTest extends AbstractFunctional self::assertEquals($comment->getBackgroundImage()->getType(), IMAGETYPE_PNG); unlink($tempFileName); - self::assertNotNull($reloadedSpreadsheet); + $spreadsheet->disconnectWorksheets(); + $reloadedSpreadsheet->disconnectWorksheets(); } /** @@ -287,6 +296,7 @@ class DrawingsTest extends AbstractFunctional $drawing->setPath('tests/data/Writer/XLSX/orange_square_24_bit.bmp'); self::assertEquals($drawing->getWidth(), 70); self::assertEquals($drawing->getHeight(), 70); + self::assertSame(IMAGETYPE_PNG, $drawing->getImageTypeForSave()); $comment = $sheet->getComment('A6'); $comment->setBackgroundImage($drawing); $comment->setSizeAsBackgroundImage(); @@ -304,6 +314,8 @@ class DrawingsTest extends AbstractFunctional $drawing = new Drawing(); $drawing->setName('Purple Square'); $drawing->setPath('tests/data/Writer/XLSX/purple_square.tiff'); + self::assertStringContainsString('purple_square.tiff', $drawing->getFilename()); + self::assertFalse($drawing->getIsUrl()); $comment = $sheet->getComment('A7'); self::assertTrue($comment instanceof Comment); self::assertFalse($comment->hasBackgroundImage()); @@ -326,6 +338,14 @@ class DrawingsTest extends AbstractFunctional self::assertEquals($e->getMessage(), 'Unsupported image type in comment background. Supported types: PNG, JPEG, BMP, GIF.'); } + try { + $drawing->getMediaFilename(); + self::fail('Should throw exception when attempting to get media file name for tiff'); + } catch (PhpSpreadsheetException $e) { + self::assertTrue($e instanceof PhpSpreadsheetException); + self::assertEquals($e->getMessage(), 'Unsupported image type in comment background. Supported types: PNG, JPEG, BMP, GIF.'); + } + try { $drawing->getImageFileExtensionForSave(); self::fail('Should throw exception when attempting to get image file extention for tiff'); @@ -428,7 +448,8 @@ class DrawingsTest extends AbstractFunctional unlink($tempFileName); - self::assertNotNull($reloadedSpreadsheet); + $spreadsheet->disconnectWorksheets(); + $reloadedSpreadsheet->disconnectWorksheets(); } /** @@ -436,7 +457,6 @@ class DrawingsTest extends AbstractFunctional */ public function testTwoCellAnchorDrawing(): void { - $reader = new Xlsx(); $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); @@ -455,31 +475,133 @@ class DrawingsTest extends AbstractFunctional $drawing->setWorksheet($sheet); // Write file - $writer = IOFactory::createWriter($spreadsheet, 'Xlsx'); - $tempFileName = File::sysGetTempDir() . '/drawings_image_that_two_cell_anchor.xlsx'; - $writer->save($tempFileName); - - // Read new file - $reloadedSpreadsheet = $reader->load($tempFileName); - $sheet = $reloadedSpreadsheet->getActiveSheet(); + $reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx'); + $spreadsheet->disconnectWorksheets(); + $rsheet = $reloadedSpreadsheet->getActiveSheet(); // Check image coordinates. - $drawingCollection = $sheet->getDrawingCollection(); + $drawingCollection = $rsheet->getDrawingCollection(); + self::assertCount(1, $drawingCollection); $drawing = $drawingCollection[0]; self::assertNotNull($drawing); + self::assertSame(150, $drawing->getWidth()); + self::assertSame(150, $drawing->getHeight()); + self::assertSame('A1', $drawing->getCoordinates()); + self::assertSame(30, $drawing->getOffsetX()); + self::assertSame(10, $drawing->getOffsetY()); + self::assertSame('E8', $drawing->getCoordinates2()); + self::assertSame(-50, $drawing->getOffsetX2()); + self::assertSame(-20, $drawing->getOffsetY2()); + self::assertSame($rsheet, $drawing->getWorksheet()); + $reloadedSpreadsheet->disconnectWorksheets(); + } + + /** + * Test editAs attribute for two-cell anchors. + * + * @dataProvider providerEditAs + */ + public function testTwoCellEditAs(string $editAs, ?string $expectedResult = null): void + { + if ($expectedResult === null) { + $expectedResult = $editAs; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + + // Add gif image that coordinates is two cell anchor. + $drawing = new Drawing(); + $drawing->setName('Green Square'); + $drawing->setPath('tests/data/Writer/XLSX/green_square.gif'); self::assertEquals($drawing->getWidth(), 150); self::assertEquals($drawing->getHeight(), 150); - self::assertEquals($drawing->getCoordinates(), 'A1'); - self::assertEquals($drawing->getOffsetX(), 30); - self::assertEquals($drawing->getOffsetY(), 10); - self::assertEquals($drawing->getCoordinates2(), 'E8'); - self::assertEquals($drawing->getOffsetX2(), -50); - self::assertEquals($drawing->getOffsetY2(), -20); - self::assertEquals($drawing->getWorksheet(), $sheet); + $drawing->setCoordinates('A1'); + $drawing->setOffsetX(30); + $drawing->setOffsetY(10); + $drawing->setCoordinates2('E8'); + $drawing->setOffsetX2(-50); + $drawing->setOffsetY2(-20); + if ($editAs !== '') { + $drawing->setEditAs($editAs); + } + $drawing->setWorksheet($sheet); - unlink($tempFileName); + // Write file + $reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx'); + $spreadsheet->disconnectWorksheets(); + $rsheet = $reloadedSpreadsheet->getActiveSheet(); - self::assertNotNull($reloadedSpreadsheet); + // Check image coordinates. + $drawingCollection = $rsheet->getDrawingCollection(); + $drawing = $drawingCollection[0]; + self::assertNotNull($drawing); + + self::assertSame(150, $drawing->getWidth()); + self::assertSame(150, $drawing->getHeight()); + self::assertSame('A1', $drawing->getCoordinates()); + self::assertSame(30, $drawing->getOffsetX()); + self::assertSame(10, $drawing->getOffsetY()); + self::assertSame('E8', $drawing->getCoordinates2()); + self::assertSame(-50, $drawing->getOffsetX2()); + self::assertSame(-20, $drawing->getOffsetY2()); + self::assertSame($rsheet, $drawing->getWorksheet()); + self::assertSame($expectedResult, $drawing->getEditAs()); + $reloadedSpreadsheet->disconnectWorksheets(); + } + + public function providerEditAs(): array + { + return [ + 'absolute' => ['absolute'], + 'onecell' => ['onecell'], + 'twocell' => ['twocell'], + 'unset (will be treated as twocell)' => [''], + 'unknown (will be treated as twocell)' => ['unknown', ''], + ]; + } + + public function testMemoryDrawingDuplicateResource(): void + { + $gdImage = imagecreatetruecolor(120, 20); + $textColor = ($gdImage === false) ? false : imagecolorallocate($gdImage, 255, 255, 255); + if ($gdImage === false || $textColor === false) { + self::fail('imagecreatetruecolor or imagecolorallocate failed'); + } else { + $spreadsheet = new Spreadsheet(); + $aSheet = $spreadsheet->getActiveSheet(); + imagestring($gdImage, 1, 5, 5, 'Created with PhpSpreadsheet', $textColor); + $listOfModes = [ + BaseDrawing::EDIT_AS_TWOCELL, + BaseDrawing::EDIT_AS_ABSOLUTE, + BaseDrawing::EDIT_AS_ONECELL, + ]; + + foreach ($listOfModes as $i => $mode) { + $drawing = new MemoryDrawing(); + $drawing->setName('In-Memory image ' . $i); + $drawing->setDescription('In-Memory image ' . $i); + + $drawing->setCoordinates('A' . ((4 * $i) + 1)); + $drawing->setCoordinates2('D' . ((4 * $i) + 4)); + $drawing->setEditAs($mode); + + $drawing->setImageResource($gdImage); + $drawing->setRenderingFunction( + MemoryDrawing::RENDERING_JPEG + ); + + $drawing->setMimeType(MemoryDrawing::MIMETYPE_DEFAULT); + + $drawing->setWorksheet($aSheet); + } + $reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx'); + $spreadsheet->disconnectWorksheets(); + + foreach ($reloadedSpreadsheet->getActiveSheet()->getDrawingCollection() as $index => $pDrawing) { + self::assertEquals($listOfModes[$index], $pDrawing->getEditAs(), 'functional test drawing twoCellAnchor'); + } + $reloadedSpreadsheet->disconnectWorksheets(); + } } }