Unable to convert an excel to pdf using php - php

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.

Related

Attempted to load class "Mpdf" from namespace "Mpdf"

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);

How can I create a Gantt diagram with phpSpreadSheet?

I am using phpSpreadSheet to create a Gantt diagram from a template, but when I complete the template using this library the diagram appears empty. But if I complete the template manually, the diagram appears completed. I have downloaded the template from here
This is my code:
//For documentation creation
require_once '../../vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
//Excel
$inputFileType = 'Xlsx';
$inputFileName = 'files/Cronograma.xlsx';
/** Create a new Reader of the type defined in $inputFileType * */
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
/** Load $inputFileName to a Spreadsheet Object * */
$spreadsheet = $reader->load($inputFileName);
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValue('C5', 1);
$sheet->setCellValue('D5', 5);
$sheet->setCellValue('E5', 1);
$sheet->setCellValue('F5', 5);
$writer = new Xlsx($spreadsheet);
$excelName = 'test.xlsx';
$writer->save($excelName);
Data manually introduced:
Data introduced by code:
Some parts of the excel features aren't implemented (e.g. format as table, pivot tables).
It would not be so pretty, but you can color single cells/ cellranges in a specific color like
$spreadsheet->getActiveSheet()->getStyle('B3:B7')->getFill()
->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)
->getStartColor()->setARGB('FFFF0000');
for more information take a look to enter link description here

PhpSpreadSheet : Writing to a specific WorkSheet

I'm new to PhpSpreadSheet, and I'd like to know if there is a way to load a CSV into a specific WorkSheet ?
I tried the code bellow but it seems to keep loadind the CSVs into the first WorkSheet :/.
<?php
require 'vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Reader\Csv;
$spreadsheet = new Spreadsheet();
$spreadsheet->setActiveSheetIndex(0);
$pathToCsv1 = 'files/csv_files/1.csv';
$pathToCsv2 = 'files/csv_files/2.csv';
$pathToCsv3 = 'files/csv_files/3.csv';
$pathToCsv4 = 'files/csv_files/4.csv';
$aCsvFiles = array($pathToCsv1, $pathToCsv2, $pathToCsv3, $pathToCsv4);
foreach ($aCsvFiles as $index => $csvFile) {
$reader = new Csv();
$reader->setDelimiter(';');
$reader->loadIntoExisting($csvFile, $spreadsheet);
$workSheet = $spreadsheet->createSheet();
$spreadsheet->setActiveSheetIndex($index + 1);
}
$writer = new Xlsx($spreadsheet);
$writer->save('files/xls_files/all.xlsx');
I only get 4.csv in all.xlsx but i have the created WorkSheets
Combining Multiple Files into a Single Spreadsheet Object
While you can limit the number of worksheets that are read from a
workbook file using the setLoadSheetsOnly() method, certain readers also
allow you to combine several individual "sheets" from different files
into a single Spreadsheet object, where each individual file is a
single worksheet within that workbook. For each file that you read, you
need to indicate which worksheet index it should be loaded into using
the setSheetIndex() method of the $reader, then use the
loadIntoExisting() method rather than the load() method to actually read
the file into that worksheet.
Example:
$inputFileType = 'Csv';
$inputFileNames = [
'./sampleData/example1.csv',
'./sampleData/example2.csv'
'./sampleData/example3.csv'
];
/** Create a new Reader of the type defined in $inputFileType **/
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
/** Extract the first named file from the array list **/
$inputFileName = array_shift($inputFileNames);
/** Load the initial file to the first worksheet in a `Spreadsheet` Object **/
$spreadsheet = $reader->load($inputFileName);
/** Set the worksheet title (to the filename that we've loaded) **/
$spreadsheet->getActiveSheet()
->setTitle(pathinfo($inputFileName,PATHINFO_BASENAME));
/** Loop through all the remaining files in the list **/
foreach($inputFileNames as $sheet => $inputFileName) {
/** Increment the worksheet index pointer for the Reader **/
$reader->setSheetIndex($sheet+1);
/** Load the current file into a new worksheet in Spreadsheet **/
$reader->loadIntoExisting($inputFileName,$spreadsheet);
/** Set the worksheet title (to the filename that we've loaded) **/
$spreadsheet->getActiveSheet()
->setTitle(pathinfo($inputFileName,PATHINFO_BASENAME));
}
Note that using the same sheet index for multiple sheets won't append files into the same sheet, but overwrite the results of the previous load. You cannot load multiple CSV files into the same worksheet.
https://phpspreadsheet.readthedocs.io/en/develop/topics/reading-files/#combining-multiple-files-into-a-single-spreadsheet-object

Using the mikehaertl\php-pdftk library for manipulating PDFs, chaining commands fails when getDataFields is called first

I'm attempting to create a wrapper class around the mikehaertl\php-pdftk\pdf object for the purposes of populating PDF form fields. When trying to chain commands via the documentation the pdf fails to correctly execute the second command (or any after the first). It looks as though this is an issue with the underlying temp file handling and the tmep file not being written out as I watch my temp folder. As I debug, the temp file is there, but of 0 size.
Sample code demonstrating the issue
use mikehaertl\pdftk\Pdf;
class PDFTKTest extends TestCase
{
public function testPdfTkOperations()
{
$cmdPath = 'D:\PDFtk\bin\pdftk.exe';
$formPath = 'D:\test\sample_files\test.pdf';
$options = ['command' => $cmdPath];
$pdf = new Pdf($formPath, $options);
$this->assertNotNull($pdf);
//Get fields from PDF
$fields = $pdf->getDataFields();
$this->assertNotNull($fields);
//Set some field Values
$values = ['full_name' => 'John Q. Programmer'];
$pdf2 = new Pdf($pdf, $options); //chaining broken
//$pdf2 = new Pdf($formPath, $options); //works fine creating a new Pdf object
$this->assertNotNull($pdf2);
$res = $pdf2->fillForm($values)->execute();
//Next assertion fails using chaining
$this->assertTrue($res, "Execute failed: \n". $pdf2->getError());
//Get fields with the updates
$fields = $pdf2->getDataFields();
$this->assertNotNull($fields);
//Next assertion fails, getDataFields fails on a chained command
$this->assertGreaterThan(0, count($fields));
}
}
I've got a work around where I use separate \Pdf objects for each action and manage my own temp file, I was just hoping to take advantage of the classes functionality a bit more and not have to do so much of the mundane. Is this functionality broken, or am I using it incorrectly?
After looking deeper in to the PDFTK library which mikehaertl\php-pdftk\pdf wraps and reading the documentation on the dump_data_fields option I came up with the folowing observations:
PDFTK doesn't produce an output file for the dump_data_fields command
The php-pdftk class does create the underlying temp file when calling getDataFields, but it is empty and remains that way.
When chaining another Pdf object, it references the empty temp file from the previous command. Here lies the rub.
Solution
When I call getFieldData I create a new Pdf object and chain it to the previous, however I don't save a reference to that. I only save the newly chained object if it is form a command that creates actual output.
Here's an exmaple to demonstate:
<?php
use mikehaertl\pdftk\Pdf;
class PDFTKFormService
{
protected $pdf = null;
/**
* #return array|bool|\mikehaertl\pdftk\DataFields
*/
public function getDataFields()
{
//get data fields doesn't output a new file
//so we need to use the existing instance or create a new one and
$pdf = $this->getNextPdf();
$fields = $pdf->getDataFields();
if ($fields === false)
return [];
return $fields;
}
/**
* #param array $data
*
* #return resource The stream resource
*/
public function setDataFieldValues($data = [])
{
$this->pdf = $this->getNextPdf();
$this->pdf->fillForm($data)->execute();
}
protected function getNextPdf()
{
$options = ['command' => 'Path\To\PDFTK\binary'];
if ($this->pdf === null) {
return new Pdf($this->getTemplatePath(), $options);
} else {
return new Pdf($this->pdf, $options);
}
}
}
Hopefully this can help someone else.

Phpword $objWriter attributes

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.)

Categories