Phpword is a php library that provides the ability to read from and write to different document file formats. In this case I will be creating a formatted word document.
This is an image of what we are trying to create:
Create a base project:
laravel new phpword_democd phpword_demophp artisan serve
Create the controller:
php artisan make:Controller ExportController
Add the route to web.php
:
Route::get('/export', [ExportController::class, 'export']);
*I am using a Laravel 8 project. Older versions may have a different syntax.
Have a look at the requirements https://phpword.readthedocs.io/en/latest/installing.html#requirements and follow the installation.
I installed the package this way:
composer require phpoffice/phpword
Then I set up some fake data:
$businessName = 'Hardware store';
$subtitleLine1 = 'Jill Simpson';
$subtitleLine2 = '57 Central Park, New York';
$subtitleLine3 = 'Tel 04316034877';$customerName = 'Fred Allington';
$address = '1028 Long Lane, New York';$items = [
[
'name' => 'hammer',
'price' => '5.37',
],
[
'name' => 'nails',
'price' => '3.65',
],
[
'name' => 'drill',
'price' => '55.46',
],
];
I’ll export the file to storage/app
:
//beginning of method
$pathToFile = storage_path('app/exportedfile.docx');//end - when we're finished writing to the file:
$writer = IOFactory::createWriter($phpWord, 'Word2007');
$writer->save($pathToFile);
Now we can concentrate on writing the data to the file and formatting.
I set up some document properties:
$phpWord = new \\PhpOffice\\PhpWord\\PhpWord();$properties = $phpWord->getDocInfo();
$properties->setCreator('Paul');
$properties->setCompany('Orange Juice Factory');
$properties->setTitle('Purchase invoice');$phpWord->setDefaultFontName('Arial');
And then added some styles to use throughout the document:
$title = array('size' => 24, 'bold' => false);
$subtitle = array('size' => 14, 'bold' => false, 'color' => '85837f');
$subtitleSecondary = array('size' => 11, 'bold' => false, 'color' => '85837f');
$heading = array('size' => 14, 'bold' => false, 'color' => '65676B');
$fullLineHorizontalRule = array('weight' => 0, 'width' => 450, 'height' => 0);
$customerTableStyle = array('cellMargin' => 80, 'alignment' => JcTable::START);
$itemsTableStyle =array('borderSize' => 4, 'borderColor' => '85837f', 'cellMargin' => 80, 'alignment' => JcTable::START);
For the first part of the document — title and store data:
$section = $phpWord->addSection();
$phpWord->addParagraphStyle('pStyleCenter', array('align' => Jc::CENTER));$section->addText($businessName, $title, 'pStyleCenter');
$section->addText($subtitleLine1, $subtitle, 'pStyleCenter');
$section->addText($subtitleLine2, $subtitle, 'pStyleCenter');
$section->addText($subtitleLine3, $subtitleSecondary, 'pStyleCenter');$section->addTextBreak(1);
$section->addLine($fullLineHorizontalRule);
$section->addTextBreak(1);
The document will only have 1 section, we want to center the text and apply different fonts and styles to the headings.
For the ‘Customer Details’:
$customerTableHeading = 'Customer';$phpWord->addTableStyle($customerTableHeading, $customerTableStyle);$section->addText('Customer Details', $heading);
$table = $section->addTable($customerTableHeading);$table->addRow(500);
$table->addCell(1750)->addText("Name:");
$table->addCell(2200)->addText($customerName);
$table->addRow();
$table->addCell(1750)->addText("Address:");
$table->addCell(4000)->addText($address);$section->addTextBreak(1);
$section->addTextBreak(1);
$section->addLine($fullLineHorizontalRule);
$section->addTextBreak(1);
We add a table with no border and we read this table horizontally to display the customer details.
For the ‘Items’:
$itemsTableHeading = 'Items';$phpWord->addTableStyle($itemsTableHeading, $itemsTableStyle);$section->addText('Items', $heading);
$table = $section->addTable($itemsTableHeading);
$table->addRow(500);
$table->addCell(1750)->addText('Item', array('bold' => true));
$table->addCell(1750)->addText('Price', array('bold' => true));foreach ($items as $item)
{
$table->addRow(500);
$table->addCell(1750)->addText($item['name']);
$table->addCell(1750)->addText('$' . $item['price']);
}
We introduce a border for this table and read vertically — iterating through the items to display the name and price.
The complete method:
public function export()
{
$businessName = 'Hardware store';
$subtitleLine1 = 'Jill Simpson';
$subtitleLine2 = '57 Central Park, New York';
$subtitleLine3 = 'Tel 04316034877'; $customerName = 'Fred Allington';
$address = '1028 Long Lane, New York'; $items = [
[
'name' => 'hammer',
'price' => '5.37',
],
[
'name' => 'nails',
'price' => '3.65',
],
[
'name' => 'drill',
'price' => '55.46',
],
]; $pathToFile = storage_path('app/exportedfile.docx'); $phpWord = new \\PhpOffice\\PhpWord\\PhpWord(); $properties = $phpWord->getDocInfo();
$properties->setCreator('Paul');
$properties->setCompany('Orange Juice Factory');
$properties->setTitle('Purchase invoice'); $phpWord->setDefaultFontName('Arial'); $title = array('size' => 24, 'bold' => false);
$subtitle = array('size' => 14, 'bold' => false, 'color' => '85837f');
$subtitleSecondary = array('size' => 11, 'bold' => false, 'color' => '85837f');
$heading = array('size' => 14, 'bold' => false, 'color' => '65676B');
$fullLineHorizontalRule = array('weight' => 0, 'width' => 450, 'height' => 0);
$customerTableStyle = array('cellMargin' => 80, 'alignment' => JcTable::START);
$itemsTableStyle =array('borderSize' => 4, 'borderColor' => '85837f', 'cellMargin' => 80, 'alignment' => JcTable::START); //start building document
$section = $phpWord->addSection();
$phpWord->addParagraphStyle('pStyleCenter', array('align' => Jc::CENTER)); $section->addText($businessName, $title, 'pStyleCenter');
$section->addText($subtitleLine1, $subtitle, 'pStyleCenter');
$section->addText($subtitleLine2, $subtitle, 'pStyleCenter');
$section->addText($subtitleLine3, $subtitleSecondary, 'pStyleCenter'); $section->addTextBreak(1);
$section->addLine($fullLineHorizontalRule);
$section->addTextBreak(1); //add customer table
$customerTableHeading = 'Customer'; $phpWord->addTableStyle($customerTableHeading, $customerTableStyle); $section->addText('Customer Details', $heading);
$table = $section->addTable($customerTableHeading); $table->addRow(500);
$table->addCell(1750)->addText("Name:");
$table->addCell(2200)->addText($customerName);
$table->addRow();
$table->addCell(1750)->addText("Address:");
$table->addCell(4000)->addText($address); $section->addTextBreak(1);
$section->addTextBreak(1);
$section->addLine($fullLineHorizontalRule);
$section->addTextBreak(1); //items table
$itemsTableHeading = 'Items'; $phpWord->addTableStyle($itemsTableHeading, $itemsTableStyle); $section->addText('Items', $heading);
$table = $section->addTable($itemsTableHeading);
$table->addRow(500);
$table->addCell(1750)->addText('Item', array('bold' => true));
$table->addCell(1750)->addText('Price', array('bold' => true)); foreach ($items as $item)
{
$table->addRow(500);
$table->addCell(1750)->addText($item['name']);
$table->addCell(1750)->addText('$' . $item['price']);
} $footer = $section->addFooter();
$footer->addPreserveText('Page {PAGE} of {NUMPAGES}.', null, array('alignment' => \\PhpOffice\\PhpWord\\SimpleType\\Jc::CENTER));
$footer->addLink('<https://paulreaney.medium.com/>', 'PHPWord demo'); $writer = IOFactory::createWriter($phpWord, 'Word2007');
$writer->save($pathToFile); return 'Exported the file.';
}
Hopefully this helps somebody!