Laravel create invoice document using PHPWord
By: Paul Reaney
Tags: PHP, Php Development, Microsoft Word, Laravel

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_demo cd phpword_demo php 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!