Can PHPword show Pie Chart in percenage with two decimals? - php

I use PHPword class to create Word file in PHP.
Can you create Pie chart to show value in percentage with two decimals?
$c3 = array('Expensive kW', 'Cheap kW');
$s3 = array($expensive, $cheap);
$tablePie2Charts = $section->addTable('Chart');
$tablePie2Charts->addRow();
$stylePie2Chart = array(
'width' => Converter::inchToEmu(5),
'height' => Converter::inchToEmu(3),
'valueAxisTitle' => 'Last month consumed in kW',
'showLegend' => true,
'dataLabelOptions' => array(
'showCatName' => false,
'showVal' => false,
'showPercent' => true
)
);
$c1 = $tablePie2Charts->addCell()->addChart('pie', $c3, $s3, $stylePie2Chart);

I also encountered the same problem.But i can't find an api to support it.
And here my solution:
edit the file /PhpOffice/Phpword/Writer/Word2007/Part/Chart.php
near the line 250. Insert the code
$xmlWriter->writeElementBlock("c:numFmt",['formatCode'=>'0.00%','sourceLinked'=>'0']);
between
$xmlWriter->startElement('c:dLbls');
and
foreach ($style->getDataLabelOptions() as $option => $val) {
It finally look like that:
$xmlWriter->startElement('c:dLbls');
$xmlWriter->writeElementBlock("c:numFmt",['formatCode'=>'0.00%','sourceLinked'=>'0']);
foreach ($style->getDataLabelOptions() as $option => $val)
if you just want it in pie chart and you should:
if ('pie' === $this->element->getType()){
$xmlWriter->writeElementBlock("c:numFmt",['formatCode'=>'0.00%','sourceLinked'=>'0']);
}
You can change the formatCode like 0.0% 0.00% 0.000% whatever you want.
If someone find the better way,plz tell me,thanks.

Related

XML Parsing error; PHPWord

I am using PHPOffice/PHPWord in my Laravel Application. It is used to generate a .docx document with results in tables. This works great for a document of 3 tables with 6 rows, but when there are more rows the document is generated but when opening it the following error occurs:
We're sorry, We can't open (documentname) because we found a problem with its contents.
Details: XML parsing error Location: Part:/word/document.xml, Line: 2, Column 14349.
Now, I have started working on another result page where I would also want to generate a .docx document. This will contain 5 tables, but with 3 rows I get the same XML parsing error but in a different location (Location: Part: /word/document.xml, Line:4, Column:2888). Could someone explain to me whether this is a error in my code, or phpword/words?
I have done some troubleshooting by deleting everything, and slowly adding new rows. I have found the error but how could i fix it. The first two tables are generated good..
$phpWord = new \PhpOffice\PhpWord\PhpWord();
$section = $phpWord->addSection();
$section->addImage('../public/img/2.jpg', array('width' => 230, 'height' => 65, 'alignment' => 'left'));
$section->addText('Project IDs:' . $parameter);
$header =$section->addHeader();
$header->addText('Results Summary');
$section->addLine(
array(
'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(16),
'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(0),
'positioning' => 'absolute',
)
);
$tableName = 'rStyle';
$phpWord->addFontStyle($tableName, array('italic' => true, 'size' => 12));
$thName = 'tStyle';
$phpWord->addFontStyle($thName, array('bold' => true, 'size' => 9));
$section->addText('General Information Table', $tableName);
$fancyTableStyle = array('borderSize' => 6, 'borderColor' => '999999');
$spanTableStyleName = 'Overview tables';
$phpWord->addTableStyle($spanTableStyleName, $fancyTableStyle);
$table = $section->addTable($spanTableStyleName);
$table->addRow(null, array('tblHeader' => true, 'cantSplit' => true));
$table->addCell(1750)->addText('Project ID',$thName);
$table->addCell(1750)->addText('Description',$thName);
$table->addCell(1750)->addText('Notes',$thName);
foreach ($id_array_explode as $char) {
$table->addRow();
$singlenumber = (int)$char;
$cursor = $collection->find(array("id" => $singlenumber));
foreach ($cursor as $document) {
$table->addCell(1750)->addText($document["project_id"]);
$table->addCell(1750)->addText($document["description"]);
$table->addCell(1750)->addText($document["notes"]);
}
}
$section->addText('
');
$section->addLine(
array(
'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(16),
'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(0),
'positioning' => 'absolute',
)
);
$section->addText('Input Table', $tableName);
$table1 = $section->addTable($spanTableStyleName);
$table1->addRow(null, array('tblHeader' => true, 'cantSplit' => true));
$table1->addCell(1750)->addText('Project ID',$thName);
$table1->addCell(1750)->addText('#',$thName);
foreach ($id_array_explode as $char) {
$table1->addRow();
$singlenumber = (int)$char;
$cursor = $collection->find(array("id" => $singlenumber));
foreach ($cursor as $document) {
if (is_array($document['input'])) {
foreach ($document['input'] as $samples) {
$table1->addCell(1750)->addText($document["project_id"]);
$table1->addCell(1750)->addText($samples['nr']);
}
}
}
}
$section->addText('
');
$section->addLine(
array(
'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(16),
'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(0),
'positioning' => 'absolute',
)
);
$section->addText('Output Table', $tableName);
$table2 = $section->addTable($spanTableStyleName);
//// THIS IS WHERE THE ERROR OCCURS!!
$table2->addRow(null, array('tblHeader' => true, 'cantSplit' => true));
$table2->addCell(1750)->addText('ID',$thName);
Thank you!
SOLUTION
Oke, so I have deleted the whole document and added every single sentence separately to see where the error occurred. This led to seeing that the error came from the data which I was getting. It couldn't handle ">" and "&" signs!
So, if you every have this error, check the data which you're printing!
A better solution is to add the following line of code before you do anything with the word document:
PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true);
This will automatically escape any problematic characters.
Indeed, It comes from your data : you have a XML special character in it and when Word, parses your doc, it doesn't understand.
I solved this problem by using htmlspecialchars(). I'm not sure it is the best way but it works.
Not very familiar with PHPWord, but make sure the encoding of your document and the data you are inserting into it are the same. Used to have the same problem with an old library for creating excel files.

Nested tables with phpdocx

Im trying to create a nested table with the library phpdocx. In their documentation they write that it is possible to have a nested table in a table cell. But its not clearly written how to make it work..
I tried the following code:
$valuesTable = array(
array(
array(array(1,2,34),12,13,14),
array(21,22,23,24),
array(31,32,33,34),
);
$params = array(
'border' => 'single',
'tableAlign' => 'center',
'borderWidth' => 10,
'borderColor' => 'B70000',
'textProperties' => array('bold' => true, 'font' => 'Algerian', 'fontSize' => 18),
);
$docx->addTable($valuesTable, $params);
But the cell is just empty. Is there an easy way to get this nested table displayed?
I finally found the solution. It is possible with WordFragments.
$innerData = array(1,2,3,4);
$innerTable = new \WordFragment($docx);
$innerTable->addTable($innerData, array('rawWordML' => true));
$tableParams = array(); // Add here the table params
$outerData = array("A", "B", $innerTable);
$outerTable->addTable($outerData, $tableParams);

Parsing Text File into Variables with PHP

Need some help with parsing a text file into PHP. The file is generated by a PHP script, so I don't have control over the content formatting. The text file looks like this:
7/4/2013-7/4/2013 Best Legs in a Kilt To start the summer
off with a bang, the Playhouse has teamed up with the folks at The
Festival. kilt.jpg 1,1,0,
-
7/8/2013-7/23/2013 Hot Legs Yes, folks, it's all platform
shoes, leisure suits, and crazy hair-do's. hotstuff.jpg
1,1,0,
-
The code that I have thus far is:
$content = file_get_contents('DC_PictureCalendar/admin/database/cal2data.txt');
list($date, $showname, $summary, $image, $notneeded, $notneeded2) = explode("\n", $content);
echo 'Show Name' . $showname . '<br/>';
This only gets me the first show title, I need to grab all of them. I'm sure a For loop would do it, but not sure how to do it based on the contents of the file. All I need is the 2nd line (show title) and the 4th line (image). Any help? Thanks in advance.
If you are reading the entire file into an array anyway, then just use file() which will read each line into an array.
$content = file('DC_PictureCalendar/admin/database/cal2data.txt', FILE_IGNORE_NEW_LINES);
You can then filter all the lines you don't want like this
$content = array_diff($content, array('1,1,0', '-'));
You can then break into chunks of 4 lines each (i.e. one item per entry)
$content_chunked = array_chunk($content, 4);
This would give you an array like
Array(
0 => Array(
0 => '7/4/2013-7/4/2013',
1 => 'Best Legs in a Kilt',
2 => 'To start the summer off with a bang, the Playhouse has teamed up with the folks at The Festival.',
3 => 'kilt.jpg'
),
1 => Array(
0 => '7/8/2013-7/23/2013',
1 => 'Hot Legs',
2 => 'Yes, folks, it's all platform shoes, leisure suits, and crazy hair-do's.',
3 => 'hotstuff.jpg'
) ... etc.
)
I would then map this array into a useful array of objects with property names that are meaningful to you:
$items = array_map(function($array)) {
$item = new StdClass;
$item->date = $array[0];
$item->showname = $array[1];
$item->summary = $array[2];
$item->image = $array[3];
return $item;
}, $content_chunked);
That would leave you with an array of objects like:
Array(
0 => stdClass(
'date' => '7/4/2013-7/4/2013',
'showname' => 'Best Legs in a Kilt',
'summary' => 'To start the summer off with a bang, the Playhouse has teamed up with the folks at The Festival.',
'image' => 'kilt.jpg'
),
1 => stdClass(
'date' => '7/8/2013-7/23/2013',
'showname' => 'Hot Legs',
'summary' => 'Yes, folks, it's all platform shoes, leisure suits, and crazy hair-do's.',
'image' => 'hotstuff.jpg'
) ... etc.
)

php logic loop step by 5

I am reading an excell file with php. No problem with that but I am stuck on a little logical part. I want to make an array that containts multiple other arrays with data.
The data is provided in my excell file I know from what column should start reading but not when to stop because this is dynamic.
My question is how can a make a loop that reads my columns and makes on every 5th column a new array.
so what I want is something like this:
(My data for the excell file is proved in $line[] each column has its number.)
array(
'length' => $line[15],
'width' => $line[16]
'price_per' => $line[17],
'price' => $line[18],
'stock' => $line[19]
),
array(
'length' => $line[20],
'width' => $line[21]
'price_per' => $line[22],
'price' => $line[23],
'stock' => $line[24]
),
array(
'length' => $line[25],
'width' => $line[26]
'price_per' => $line[27],
'price' => $line[28],
'stock' => $line[29]
), ....
So how can I make this dynamic (for loop ?) so that I have 1 big indexed Array , with multiple asscociated arrays? Note: my for loop should always star from line[15]!
To begin with, if $line has any elements that you don't want to process (e.g. the first 15 as your example indicates), slice them off with array_slice:
$line = array_slice($line, 15);
Then use array_chunk to split your original array into as many pieces as there are:
$chunks = array_chunk($line, 5);
Then, turn each chunk into its own array by associating each value with the correct key using array_combine:
$results = array();
$keys = array('length', 'width', 'price_per', 'price', 'stock');
foreach ($chunks as $chunk) {
$results[] = array_combine($keys, $chunk);
}
for($i = 15; $i < ????; $i += 5)
{
$your_array[] = array(
'length' => $line[$i],
'width' => $line[$i+1]
'price_per' => $line[$i+2],
'price' => $line[$i+3],
'stock' => $line[$i+4]
);
}
Replace ???? by the number of lines

Using supplier with largest margin using PHP logic

I have the following values from a database call that I want to apply some logic to. I thought I could originally use PHP's max however this doesn't appear to be the case.
I have three suppliers of a product. They might not all stock the item I am displaying, and they all offer a different margin, on a product by product basis though, so that is why I can't just say generally supplier 1 is better than supplier 2 etc.
$supplier1Live = 1
$supplier2Live = 1
$supplier3Live = 0
$marginSupplier1 = 20
$marginSupplier2 = 40
$martinSupplier3 = 50
In this example I would want to use Supplier 2 as they stock the product supplier2Live = 1 and also have the better margin than the other supplier who stocks the product (supplier1)
My mind however is drawing a complete blank in how to code this?
I thought I could add it to an array giving:
$array = array(
"supplier1" => array(
"live" => 1,
"margin" => 20
),
"supplier2" => array(
"live" => 1,
"margin" => 40
),
"supplier3" => array(
"live" => 0,
"margin" => 50
)
);
And run something on that, but not sure what to.
Filter the array using array_filter (filter by live==1), and then find the maximum out of the resultant array (maximum on the "margin" value)
Like this, if I understand correctly
$array = array(
"supplier1" => array(
"live" => 1,
"margin" => 20
),
"supplier2" => array(
"live" => 1,
"margin" => 40
),
"supplier3" => array(
"live" => 0,
"margin" => 50
)
);
$res = array_filter($array,function($v){return $v["live"];});
$supplier = array_reduce($res, function($a, $b){
return $a["margin"]>$b["margin"]?$a:$b;
});
print_r($supplier);
Try something like this:
$best_supplier = null;
$best_supplier_margin = null;
foreach($array as $name => $supplier) {
if($supplier['live']) {
if($supplier['margin'] > $best_supplier_margin || is_null($best_supplier_margin)) {
$best_supplier = $name;
$best_supplier_margin = $supplier['margin'];
}
}
}
if(is_null($best_supplier)) throw new Exception('No suppliers are live!');
echo $best_supplier;
So you basically want to find the max of supplierXLive * marginSupplierX?
You can also implement a custom compare function and provide it to PHPs usort() function

Categories