I am using PHPWord in a project.
I am trying to find out some information about the attributes that go with the $objWriter:
$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007');
Specifically, what is the 'Word2007' used for at the end? I have tried searching $objWriter but can't locate any info. I have tried replacing it with 'Word2013' or 'Word2016' but I get:
"Word2016" is not a valid writer. in wamp...\vendor\phpoffice\phpword\src\PhpWord\IOFactory.php on line 29
The 2nd parameter is for the type of document you're creating a writer for. There are 5 allowed types:
'ODText'
'RTF'
'Word2007'
'HTML'
'PDF'
You can see this in the code for the IOFactory class:
public static function createWriter(PhpWord $phpWord, $name = 'Word2007')
{
/**
* Notice the allowed names in the array here.
*/
if ($name !== 'WriterInterface' && !in_array($name, array('ODText', 'RTF', 'Word2007', 'HTML', 'PDF'), true)) {
throw new Exception("\"{$name}\" is not a valid writer.");
}
$fqName = "PhpOffice\\PhpWord\\Writer\\{$name}";
return new $fqName($phpWord);
}
https://github.com/PHPOffice/PHPWord/blob/develop/src/PhpWord/IOFactory.php
If you want to support a later MS Word document format, you will need to implement your own writer that extends AbstractWriter implements WriterInterface. However, at this time, there are no later formats yet created. (Note that Word 2007 the format is different from the application version.)
Related
I'm using PHPSpreadsheet to create Excel.
I want t generate the Excel file, then convert the Excel file in a PDF one.
So I've done the following :
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf;
use PhpOffice\PhpSpreadsheet\Reader\Exception;
class DevisGenerator
{
public function runDevis()
{
$spreadsheet = $this->loadexcelTemplate();
$uuid = $this->uniqidReal();
$filename = $this->writeName($spreadsheet, $uuid);
$this->convertPdf($spreadsheet, $filename);
}
public function writeName($spreadsheet, $uuid)
{
$worksheet = $spreadsheet->getActiveSheet();
$worksheet->getCell('B2')->setValue('Toto');
try {
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
$filename = $uuid;
$writer->save($filename.'.xlsx');
}catch (Exception $e)
{
//TODO gestion erreur
}
return $filename;
}
public function convertPdf($spreadsheet, $filename)
{
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf($spreadsheet);
$writer->save($filename.'.pdf');
}
But whan I run the code the following error appear :
Attempted to load class "Mpdf" from namespace "Mpdf".
Did you forget a "use" statement for "PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf"?
I did not understand this error, I have correctly insert the use statement in my code.
Any idea ?
I've already got a similar issue with Mpdf.
PHPSpreadsheet supports multiple Librairies to generate PDF.
I'm nut using Mpdf but Tcpdf.
I'm also not sure but you need to install them manually.
composer require tecnickcom/tcpdf
Then in your code :
$writer = new Tcpdf($spreadsheet);
And don't forget the use statement ;)
Hope this help !
After use statement before class, you should use only:
public function convertPdf($spreadsheet, $filename)
{
$writer = new Mpdf($spreadsheet);
$writer->save($filename.'.pdf');
}
Since you use the fully qualified namespace when creating the instance, the use statement is not taken into account (thus the error message).
It seems like you have added a supplementary slash at the beginning of the namespace when creating your Mpdf instance, removing it will solve your issue.
$writer = new PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf($spreadsheet);
But since you have added a use statement, you do not need to use the fully qualified namespace again, you can do
$writer = new Mpdf($spreadsheet);
I am using Symfony 3.4.8 and I try to create a form for uploading a file. I followed exact the Symfony document steps but got the error:
Controller "AppBundle\Report::uploadReport()" requires that you provide a value for the "$fileUploader" argument. Either the argument is nullable and no null value has been provided, no default value has been provided or because there is a non optional argument after this one.
Here is part of my code, the rest are the same from the document except I changed the class name. Clearly when the function get called, there is no FileUploader argument passed into the function. If I remove the argument FileUploader $fileUploader, the page can load without throwing exception but it won't get the file. I am new to Symfony, how can I solve this problem?
/**
* #Route("/report/create-report/upload/", name="report_create")
*/
public function uploadReport(Request $request, FileUploader $fileUploader)
{
$report = new Report();
$form = $this->createForm(ReportType::class, $report);
$form->add('submit', SubmitType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// $file stores the uploaded PDF file
/** #var Symfony\Component\HttpFoundation\File\UploadedFile $file */
$file = $report->getReport();
$fileName = $fileUploader->upload($file);
$report->setBrochure($fileName);
//$fileName = $this->generateUniqueFileName().'.'.$file->guessExtension();
// moves the file to the directory where brochures are stored
//$file->move(
// $this->getParameter('reports_directory'),
// $fileName
//);
// updates the 'brochure' property to store the PDF file name
// instead of its contents
//$report->setReport($fileName);
// ... persist the $product variable or any other work
}
return $this->render('report/createReport.html.twig', array(
'form' => $form->createView(),
));
}
I have seen the post but I cannot get that answer to work on my end as there is no such variable $container.
Last update: I gave up trying implement upload from scratch. I used the recommended bundle to make it work with minimum amount of coding.
the argument brochures_directory of your FileUploader.php service seems to be emtpy.
Did you specify it in service.yml?
Did you also add it in your config.yml ?
And then did you clear symfony cache after change ?
I have installed PhpSpreadsheet and dompdf successfully using composer.
My requirement is that I need to convert an excel sheet into pdf, I got it working using the default settings, this is the code I have used.
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Writer\Csv;
use PhpOffice\PhpSpreadsheet\Exception;
use PhpOffice\PhpSpreadsheet\IOFactory;
use \PhpOffice\PhpSpreadsheet\Writer\Pdf\Dompdf;
$spreadsheet = new Spreadsheet();
try {
$sheet = $spreadsheet->getActiveSheet();
// code to fill in the data
$spreadsheet->getActiveSheet()->fromArray(
$data, // The data to set
NULL, // Array values with this value will not be set
'A2' // Top left coordinate of the worksheet range where
);
} catch (Exception $e) {
}
$writer = new Xlsx($spreadsheet);
try {
IOFactory::registerWriter("PDF", Dompdf::class);
$pdfwriter = IOFactory::createWriter($spreadsheet, 'PDF');
$pdfwriter->save($filepath . 'pdf_test.pdf');
} catch (\PhpOffice\PhpSpreadsheet\Writer\Exception $e) {
}
I have skipped out code for brevity, this code works fine and generates a pdf file, I require the pdf to be printed in landscape mode, for that the docs mention a Custom implementation or configuration of the pdf library, so I created a file called PDFBase_DOMPDF that looks like this
use Dompdf\Dompdf;
class PDFBase_DOMPDF extends Dompdf
{
}
And I have created a file called PDFBase_Writer that looks like this.
use PhpOffice\PhpSpreadsheet\Writer\Pdf\Dompdf;
class PDFBase_Writer extends Dompdf
{
protected function createExternalWriterInstance()
{
$instance = new PDFBase_DOMPDF();
$instance->setPaper('A4', 'landscape');
return $instance;
}
}
I modified the original code to use the new pdf class so the line changed to this.
IOFactory::registerWriter("PDF", PDFBase_Writer::class);
The problem is I get an exception with the following error
Registered writers must implement PhpOffice\PhpSpreadsheet\Writer\IWriter
How exactly do I fix this?
Reading and writing to a persisted storage is not possible using the base PhpSpreadsheet classes. For this purpose, PhpSpreadsheet provides readers and writers, which are implementations of \PhpOffice\PhpSpreadsheet\Reader\IReader and \PhpOffice\PhpSpreadsheet\Writer\IWriter.
You must load the Excel file like this:
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
$reader->setReadDataOnly(true);
$spreadsheet = $reader->load("TestRead.xlsx");
Registered writers must implement PhpOffice\PhpSpreadsheet\Writer\IWriter
PHPSpreadsheet Writer classes must implement all the methods defined in the IWriter interface. You're creating a new Writer, so it needs to provide an implementation of all those methods:
interface IWriter
{
/**
* IWriter constructor.
*
* #param Spreadsheet $spreadsheet
*/
public function __construct(Spreadsheet $spreadsheet);
/**
* Save PhpSpreadsheet to file.
*
* #param string $pFilename Name of the file to save
*
* #throws \PhpOffice\PhpSpreadsheet\Writer\Exception
*/
public function save($pFilename);
}
So your Writer needs to implement a constructor that accepts a Spreadsheet object as an argument, and a save() method that accepts a filename (as a string) argument.
I am contributing to sonata/exporter, a library used for export data in many formats (CSV, JSON, XML, XLS, ...).
I work on a Writer that converts boolean values into strings (e.g. yes/no) by encapsulating another Writer (like CsvWriter or XlsWriter).
It's my first experience with phpunit.
All unit tests made on the existing Writers use this logic :
- Create a file.
- Write data in file using the corresponding format.
- Make an assertEquals on file_get_contents(filename).
So, I've written this test :
public function setUp()
{
$this->filename = 'formatedbool.xls';
$this->sampleWriter = new XlsWriter($this->filename, false);
$this->trueLabel = 'oui';
$this->falseLabel = 'non';
if (is_file($this->filename)) {
unlink($this->filename);
}
}
public function testValidDataFormat()
{
$writer = new FormatedBoolWriter($this->sampleWriter, $this->trueLabel, $this->falseLabel);
$writer->open();
$writer->write(array('john', 'doe', false, true));
$writer->close();
$expected = '<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><meta name=ProgId content=Excel.Sheet><meta name=Generator content="https://github.com/sonata-project/exporter"></head><body><table><tr><td>john</td><td>doe</td><td>non</td><td>oui</td></tr></table></body></html>';
$this->assertEquals($expected, trim(file_get_contents($this->filename)));
}
When submitting my PR, the owner says me :
just use a mock with expected method call and check calling argument, this will avoid creating the file. see https://phpunit.de/manual/current/en/test-doubles.html#test-doubles.mock-objects.examples.with-consecutive.php
I have begin to rewrite tests using a Mock but I have an error on file_get_contents because file is not created.
The "write" method just write in a file and return nothing.
I think he want I test the data after converting bools, but before writing in file.
How can I check the result of the file content without really create it ?
Or simply access to my $data during the method call ?
EDIT Thanks to #Cerad, the code I've submitted :
public function testValidDataFormat()
{
$data = array('john', 'doe', false, true);
$expected = array('john', 'doe', 'no', 'yes');
$mock = $this->getMockBuilder('Exporter\Writer\XlsWriter')
->setConstructorArgs(array('formattedbool.xls', false))
->getMock();
$mock->expects($this->any())
->method('write')
->with($this->equalTo($expected));
$writer = new FormattedBoolWriter($mock, $this->trueLabel, $this->falseLabel);
$writer->open();
$writer->write($data);
$writer->close();
}
I'm waiting for answer of the project owner.
EDIT PR merged at https://github.com/sonata-project/exporter/pull/56
This question has been answered by #Cerad by commenting on the question.
The PR has been accepted and merged, see https://github.com/sonata-project/exporter/pull/56
I am using the latest master of PHPExcel (most recent commit March 28th 2015) to parse an xlsx file for a client, the following code reads the file without complaining but finds no data (the only output I currently get is NULL):
<?php
include 'PHPExcel/IOFactory.php';
$inputFileName = 'foo.xlsx';
try {
$objReader = PHPExcel_IOFactory::createReaderForFile($inputFileName);
$objPHPExcel = $objReader->load($inputFileName);
} catch (Exception $e) {
print_r('Error loading file "' . pathinfo($inputFileName,
PATHINFO_BASENAME) . '": ' . $e->getMessage());
}
$sheet = $objPHPExcel->getSheetByName("Orders");
var_dump($sheet);
?>
The workbook definition inside the xlsx file looks like this:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<x:workbook xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<x:fileVersion appName="xl" lastEdited="4" lowestEdited="4" rupBuild="4506" />
<x:workbookPr defaultThemeVersion="124226" />
<x:bookViews>
<x:workbookView xWindow="480" yWindow="345" windowWidth="24495" windowHeight="11955" />
</x:bookViews>
<x:sheets>
<x:sheet name="Orders" sheetId="4" r:id="relId4" />
</x:sheets>
<x:calcPr calcId="125725" />
</x:workbook>
I think it's not working out that there's an "Orders" sheet because it's looking for "sheets" in the default namespace rather than the "x" namespace. Sorry if terminology is a bit gibberish there but hopefully you can see what I mean.
There is definitely data there, in that worksheet, because I can open the file in LibreOffice and see it.
Is there a way to get PHPExcel to use the x namespace as the default or in some other way get it to load worksheets defined in this way?
In my quest to find out I found a bug report from 20101 regarding a similar issue which doesn't seem to have been addressed.
This issue is tracked at https://github.com/PHPOffice/PHPExcel/issues/571
What follows is a workaround, it is ugly but may help until this issue has been fixed...
Create a new class PHPExcel_Reader_Excel2007_XNamespace.php:
<?php
class PHPExcel_Reader_Excel2007_XNamespace extends PHPExcel_Reader_Excel2007
{
public function securityScan($xml)
{
$xml = parent::securityScan($xml);
return str_replace(['<x:', '</x:'], ['<', '</'], $xml);
}
}
Then load your excel file using this reader:
$excelReader = new PHPExcel_Reader_Excel2007_XNamespace();
$objPHPExcel = $excelReader->load($inputFileName);
UPDATE: A more general issue for handling of non-standard namespaces has been filed and an updated workaround (covering the "d" namespace as well) is found at https://github.com/PHPOffice/PHPExcel/issues/1187#issuecomment-295032648