Skip to content

Add support for charts in template processor #2012

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions docs/templates-processing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -249,17 +249,28 @@ See ``Sample_40_TemplateSetComplexValue.php`` for examples.
$table->addCell(150)->addText('Cell B2');
$table->addCell(150)->addText('Cell B3');
$templateProcessor->setComplexBlock('table', $table);


setChartValue
"""""""""""""
Replace a variable by a chart.

.. code-block:: php

$categories = array('A', 'B', 'C', 'D', 'E');
$series1 = array(1, 3, 2, 5, 4);
$chart = new Chart('doughnut', $categories, $series1);
$templateProcessor->setChartValue('myChart', $chart);

save
"""""""""
""""
Saves the loaded template within the current directory. Returns the file path.

.. code-block:: php

$filepath = $templateProcessor->save();

saveAs
"""""""""
""""""
Saves a copy of the loaded template in the indicated path.

.. code-block:: php
Expand Down
45 changes: 45 additions & 0 deletions samples/Sample_41_TemplateSetChart.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php
use PhpOffice\PhpWord\Element\Chart;
use PhpOffice\PhpWord\Shared\Converter;

include_once 'Sample_Header.php';

// Template processor instance creation
echo date('H:i:s'), ' Creating new TemplateProcessor instance...', EOL;
$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('resources/Sample_41_TemplateSetChart.docx');

$chartTypes = array('pie', 'doughnut', 'bar', 'column', 'line', 'area', 'scatter', 'radar', 'stacked_bar', 'percent_stacked_bar', 'stacked_column', 'percent_stacked_column');
$twoSeries = array('bar', 'column', 'line', 'area', 'scatter', 'radar', 'stacked_bar', 'percent_stacked_bar', 'stacked_column', 'percent_stacked_column');
$threeSeries = array('bar', 'line');

$categories = array('A', 'B', 'C', 'D', 'E');
$series1 = array(1, 3, 2, 5, 4);
$series2 = array(3, 1, 7, 2, 6);
$series3 = array(8, 3, 2, 5, 4);

$i = 0;
foreach ($chartTypes as $chartType) {
$chart = new Chart($chartType, $categories, $series1);

if (in_array($chartType, $twoSeries)) {
$chart->addSeries($categories, $series2);
}
if (in_array($chartType, $threeSeries)) {
$chart->addSeries($categories, $series3);
}

$chart->getStyle()
->setWidth(Converter::inchToEmu(3))
->setHeight(Converter::inchToEmu(3));

$templateProcessor->setChart("chart{$i}", $chart);
$i++;
}

echo date('H:i:s'), ' Saving the result document...', EOL;
$templateProcessor->saveAs('results/Sample_41_TemplateSetChart.docx');

echo getEndingNotes(array('Word2007' => 'docx'), 'results/Sample_41_TemplateSetChart.docx');
if (!CLI) {
include_once 'Sample_Footer.php';
}
Binary file added samples/resources/Sample_41_TemplateSetChart.docx
Binary file not shown.
40 changes: 40 additions & 0 deletions src/PhpWord/TemplateProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,46 @@ public function setValues(array $values)
}
}

/**
* @param string $search
* @param \PhpOffice\PhpWord\Element\AbstractElement $complexType
*/
public function setChart($search, \PhpOffice\PhpWord\Element\AbstractElement $chart)
{
$elementName = substr(get_class($chart), strrpos(get_class($chart), '\\') + 1);
$objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $elementName;

// Get the next relation id
$rId = $this->getNextRelationsIndex($this->getMainPartName());
$chart->setRelationId($rId);

// Define the chart filename
$filename = "charts/chart{$rId}.xml";

// Get the part writer
$writerPart = new \PhpOffice\PhpWord\Writer\Word2007\Part\Chart();
$writerPart->setElement($chart);

// ContentTypes.xml
$this->zipClass->addFromString("word/{$filename}", $writerPart->write());

// add chart to content type
$xmlRelationsType = "<Override PartName=\"/word/{$filename}\" ContentType=\"application/vnd.openxmlformats-officedocument.drawingml.chart+xml\"/>";
$this->tempDocumentContentTypes = str_replace('</Types>', $xmlRelationsType, $this->tempDocumentContentTypes) . '</Types>';

// Add the chart to relations
$xmlChartRelation = "<Relationship Id=\"rId{$rId}\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart\" Target=\"charts/chart{$rId}.xml\"/>";
$this->tempDocumentRelations[$this->getMainPartName()] = str_replace('</Relationships>', $xmlChartRelation, $this->tempDocumentRelations[$this->getMainPartName()]) . '</Relationships>';

// Write the chart
$xmlWriter = new XMLWriter();
$elementWriter = new $objectClass($xmlWriter, $chart, true);
$elementWriter->write();

// Place it in the template
$this->replaceXmlBlock($search, '<w:p>' . $xmlWriter->getData() . '</w:p>', 'w:p');
}

private function getImageArgs($varNameWithArgs)
{
$varElements = explode(':', $varNameWithArgs);
Expand Down
21 changes: 10 additions & 11 deletions src/PhpWord/Writer/Word2007/Part/Chart.php
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ private function writeSeries(XMLWriter $xmlWriter, $scatter = false)
$colors = $style->getColors();

$index = 0;
$colorIndex = 0;
foreach ($series as $seriesItem) {
$categories = $seriesItem['categories'];
$values = $seriesItem['values'];
Expand Down Expand Up @@ -265,23 +266,21 @@ private function writeSeries(XMLWriter $xmlWriter, $scatter = false)
$this->writeSeriesItem($xmlWriter, 'cat', $categories);
$this->writeSeriesItem($xmlWriter, 'val', $values);

// setting the chart colors was taken from https://github.com/PHPOffice/PHPWord/issues/494
if (is_array($colors) && count($colors)) {
// This is a workaround to make each series in a stack chart use a different color
if ($this->options['type'] == 'bar' && stristr($this->options['grouping'], 'stacked')) {
array_shift($colors);
}
$colorIndex = 0;
foreach ($colors as $color) {
// check that there are colors
if (is_array($colors) && count($colors) > 0) {
// assign a color to each value
$valueIndex = 0;
for ($i = 0; $i < count($values); $i++) {
// check that there are still enought colors
$xmlWriter->startElement('c:dPt');
$xmlWriter->writeElementBlock('c:idx', 'val', $colorIndex);
$xmlWriter->writeElementBlock('c:idx', 'val', $valueIndex);
$xmlWriter->startElement('c:spPr');
$xmlWriter->startElement('a:solidFill');
$xmlWriter->writeElementBlock('a:srgbClr', 'val', $color);
$xmlWriter->writeElementBlock('a:srgbClr', 'val', $colors[$colorIndex++ % count($colors)]);
$xmlWriter->endElement(); // a:solidFill
$xmlWriter->endElement(); // c:spPr
$xmlWriter->endElement(); // c:dPt
$colorIndex++;
$valueIndex++;
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/PhpWord/TemplateProcessorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ public function testSetImageValue()
return $imagePath;
},
'documentContent' => array('path' => $imagePath, 'width' => 500, 'height' => 500),
'footerValue' => array('path' => $imagePath, 'width' => 100, 'height' => 50, 'ratio' => false),
'footerValue' => array('path' => $imagePath, 'width' => 100, 'height' => 50, 'ratio' => false),
);
$templateProcessor->setImageValue(array_keys($variablesReplace), $variablesReplace);

Expand Down
2 changes: 1 addition & 1 deletion tests/PhpWord/Writer/Word2007/Element/ChartTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public function testChartElements()
for ($idxp1 = 1; $idxp1 < $numColor; ++$idxp1) {
$idx = $idxp1; // stacked bar chart is shifted
$element = $path . "/c:ser/c:dPt[$idxp1]/c:spPr/a:solidFill/a:srgbClr";
self::assertEquals($colorArray[$idx], $doc->getElementAttribute($element, 'val'), "bar chart idx=$idx");
self::assertEquals($colorArray[$idx - 1], $doc->getElementAttribute($element, 'val'), "bar chart idx=$idx");
}
}

Expand Down