How to create invoices easily with document-templates package
Tags: articles, laravel, php, documenttemplates
Published: 2019-11-14 07:58:03

---
title: How to create invoices easily with document-templates package
published: true
date: 2019-11-13 09:13:27 UTC
tags: Articles,Laravel,PHP,documenttemplates
canonical_url: https://42coders.com/how-to-create-invoices-easily-with-document-templates-package
---

## Introduction

There are some common features almost every web application has: registration, login, email sending, pdf generation, admin interface etc. We created our document-templates Laravel package to allow the admins to easily edit their email (and any other) templates using a wysiwyg editor. This package is a generic templating system, which can be used to create any output format like: html, markdown, txt, etc, but the most common usage is to use html template. The package comes with build in pdf rendering engine and it can be used seamlessly with Laravel mailables. The package uses [Twig](https://twig.symfony.com/) as a template engine.

## Why Twig instead of Blade?

This is a logical question, why would we use different template engines? We already have a good build in template engine in Laravel. The basic idea was to allow the users/admins to put some logic into the templates like: ifs, for loops etc. It could be easily solved also with Blade as well, but for security reasons I wanted to allow the developers have control on what functions/logic can be used in the editable part of the template. Twig has a built in configurable sandboxing feature. The sandbox is applied on every part of the templates which can be edited by the users/admins.

## How it works?

We create a basic layout of the document, and define which parts of it can be editable by the user. To achieve this we use the block feature of Twig. In the next step we create a document class which uses a trait from the package, and defines the datasources for the document. Every document class represents a document type in your application. For example you should create different classes for invoice, confirmation email, registration email, etc. Render the document on the proper place in your application (for example generate the invoice when the payment finished).

## How can I use it?

The architecture of the package consists of 3 main parts:

1. The core features include the twig engine, datasources and the layout
2. The rendering module allows the document rendering as html, pdf etc
3. Admin part comes with routes, controller, vue component, and Ckeditor to quickly build the administration for the documents

You can decide if you want to simply use the core features and use the advantages of twig, and build the other parts yourself. You can also utilize the pdf rendering capabilities, or use the whole package with all the belts and whistles.

The conceptual diagram of the package can be found below:

![](https://42coders.com/wp-content/uploads/2019/11/document_tempaltes-1024x848.png)

## Let’s build something!

In the next paragraphs we will build an invoice generation system from scratch using this package.

#### Installation

Install the package with composer:

```
composer require 42coders/document-templates
```

Publish the migrations, views, vue components and config:

```
php artisan vendor:publish --provider="BWF\DocumentTemplates\DocumentTemplatesServiceProvider"
```

Run the migration

```
php artisan migrate
```

 

#### Create the base layout

Create the template file:  **resources/templates/InvoiceTemplate.html.twig** with the following content:

```
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Invoice - #123</title>
 
    <style type="text/css">
        @page {
            margin: 0px;
        }
 
        body {
            margin: 0px;
        }
 
        * {
            font-family: Verdana, Arial, sans-serif;
        }
 
        a {
            color: #fff;
            text-decoration: none;
        }
 
        table {
            font-size: x-small;
        }
 
        tfoot tr td {
            font-weight: bold;
            font-size: x-small;
        }
 
        .invoice table {
            margin: 15px;
        }
 
        .invoice h3 {
            margin-left: 15px;
        }
 
        .information {
            background-color: rgb(85, 47, 218);
            color: #FFF;
        }
 
        .information .logo {
            margin: 5px;
        }
 
        .information table {
            padding: 10px;
        }
    </style>
 
</head>
<body>
 
<div class="information">
    <table width="100%">
        <tr>
            <td align="left" style="width: 40%;">
                {% block customer_details %}
                {% endblock %}
<br/><br/>
<pre>
Date: 2018-01-01
Identifier: #uniquehash
Status: Paid
</pre>
 
 
            </td>
            <td align="center">
                <img src="https://42coders.com/wp-content/uploads/elementor/thumbs/logo-o9jp5a9c6jnn02f7yrqrfuzv6pr1lrqw5amfzuffv4.png" alt="Logo" width="64" class="logo"/>
            </td>
            <td align="right" style="width: 40%;">
 
                <h3>42coders</h3>
                <pre>
                    https://42coders.com
 
                    Schopenhauerstr. 71
                    80807 München
                </pre>
            </td>
        </tr>
 
    </table>
</div>
 
 
<br/>
 
<div class="invoice">
    <h3>Invoice specification #123</h3>
        {% block order_items %}
        {% endblock %}
</div>
 
<div class="information" style="position: absolute; bottom: 0;">
    <table width="100%">
        <tr>
            <td align="left" style="width: 50%;">
            </td>
            <td align="right" style="width: 50%;">
                42coders
            </td>
        </tr>
 
    </table>
</div>
</body>
</html>
```

In the above template we’ve defined 2 blocks: **customer_details** and  **order_items**. These blocks will be editable in the admin area with Ckeditor.

#### Create the document class

Let’s create our document class in **app/DocumentTemplates/InvoiceTemplate.php** :

```
<?php
 
 
namespace App\DocumentTemplates;
 
use App\User;
use BWF\DocumentTemplates\DocumentTemplates\DocumentTemplate;
use BWF\DocumentTemplates\DocumentTemplates\DocumentTemplateInterface;
 
class InvoiceTemplate implements DocumentTemplateInterface
{
    use DocumentTemplate;
 
    protected $testOrders = [
        [
            'id' => '1',
            'description' => 'Package Basic',
            'price' => 10
        ],
        [
            'id' => '2',
            'description' => 'Package Pro',
            'price' => 20
        ],
        [
            'id' => '3',
            'description' => 'Package Advanced',
            'price' => 30
        ],
    ];
 
    protected function dataSources()
    {
        return [
            $this->dataSource($this->testOrders[0], 'order', true, 'orders'),
            $this->dataSource(new User(), 'user'),
        ];
    }
 
```

In this step we create the document class, and define the datasources for the document. For the sake of simplicity we use an array as the order data, and the User model for the customer data. To be able to use the `User` as a datasource for the invoice, it needs to implement  the **TemplateDataSourceInterface** , so we will use the **ModelProvidesTemplateData** trait to achieve this:

```
<?php
 
namespace App;
 
use BWF\DocumentTemplates\TemplateDataSources\ModelProvidesTemplateData;
use BWF\DocumentTemplates\TemplateDataSources\TemplateDataSourceInterface;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
 
class User extends Authenticatable implements TemplateDataSourceInterface
{
    use Notifiable, ModelProvidesTemplateData;
```

#### Create controller

We create a controller for administration and to test the document editing/rendering:

```
<?php
 
namespace App\Http\Controllers;
 
use App\DocumentTemplates\InvoiceTemplate;
use BWF\DocumentTemplates\DocumentTemplates\DocumentTemplateFactory;
use BWF\DocumentTemplates\DocumentTemplates\DocumentTemplateModelInterface;
use BWF\DocumentTemplates\Http\Controllers\DocumentTemplatesController;
use BWF\DocumentTemplates\TemplateDataSources\TemplateDataSource;
use BWF\DocumentTemplates\TemplateDataSources\TemplateDataSourceFactory;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
 
class InvoiceTemplatesController extends DocumentTemplatesController
{
    protected $testOrders = [
        [
            'id' => '1',
            'description' => 'Package Basic',
            'price' => 10
        ],
        [
            'id' => '2',
            'description' => 'Package Pro',
            'price' => 20
        ],
        [
            'id' => '3',
            'description' => 'Package Advanced',
            'price' => 30
        ],
    ];
 
    /**
     * @return TemplateDataSource[]
     */
    protected function getTestOrders()
    {
        $dataSources = [];
 
        foreach ($this->testOrders as $item) {
            $dataSources[] = TemplateDataSourceFactory::build($item, 'order');
        }
 
        return collect($dataSources);
    }
 
    protected $documentClasses = [
        InvoiceTemplate::class,
    ];
 
    protected function getTemplateData()
    {
        return [
            'user' => Auth::user(),
            'orders' => $this->getTestOrders(),
        ];
    }
 
    public function show(DocumentTemplateModelInterface $documentTemplateModel)
    {
 
        $documentTemplate = DocumentTemplateFactory::build($documentTemplateModel);
 
        $templateData = $this->getTemplateData();
 
        foreach ($templateData as $name => $data) {
            $documentTemplate->addTemplateData($data, $name);
        }
 
        return $documentTemplate->render();
 
    }
}
```

Add the package routes to the routes file:

```
\BWF\DocumentTemplates\DocumentTemplates::routes(InvoiceTemplatesController::class);
```

#### Create seeders

Now it is time to fill the database with some test data. Create seeder for editable templates **database/seeds/EditableTemplatesTableSeeder.php:**

```
<?php
 
use Illuminate\Database\Seeder;
 
class EditableTemplatesTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $documentTemplate = \BWF\DocumentTemplates\DocumentTemplates\DocumentTemplateModel::create([
            'name' => 'Invoice',
            'document_class' => \App\DocumentTemplates\InvoiceTemplate::class,
            'layout' => 'InvoiceTemplate.html.twig'
        ]);
 
        $documentTemplate->save();
 
 
        \BWF\DocumentTemplates\EditableTemplates\EditableTemplate::create([
            'document_template_id' => $documentTemplate->id,
            'name' => 'order_items',
            'content' => '
    <table width="100%">
        <thead>
        <tr>
            <th>Description</th>
            <th>Quantity</th>
            <th>Total</th>
        </tr>
        </thead>
        <tbody>
                {% for order in orders %}
                    <tr>
                        <td>
                            {{order.description}}
                        </td>
                        <td>1</td>
                        <td>
                            €{{order.price}}
                        </td>
                    </tr>
                {% endfor %}
                            </tbody>
 
        <tfoot>
        <tr>
            <td colspan="1"></td>
            <td align="left">Total</td>
            <td align="left" class="gray">€60,-</td>
        </tr>
        </tfoot>
    </table>
                '
        ])->save();
 
        \BWF\DocumentTemplates\EditableTemplates\EditableTemplate::create([
            'document_template_id' => $documentTemplate->id,
            'name' => 'customer_details',
            'content' => '
                <h3>{{user.name}}</h3>
                <pre>
Street 15
123456 City
United Kingdom
</pre>
                '
        ])->save();
    }
}
```

**database/seeds/UsersTableSeeder.php:**

```
<?php
 
use Illuminate\Database\Seeder;
 
class UsersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        factory(App\User::class, 1)->create(
            [
                'name' => 'Administrator',
                'email' => 'admin@bwf',
                'password' => bcrypt('secret')
            ]
        );
    }
}
```

Add these seeders to the **DatabaseSeeder:**

```
public function run()
    {
        $this->call(UsersTableSeeder::class);
        $this->call(EditableTemplatesTableSeeder::class);
    }
```

Run the seeders:

```
php artisan db:seed
```

If you use Laravel 6 you might need to create frontend scaffolding, please check the Laravel documentation [here](https://laravel.com/docs/6.x/frontend):

```
composer require laravel/ui --dev 
php artisan ui bootstrap 
php artisan ui vue
```

Compile the assets:

```
npm run dev
```

#### Create the app layout – optional

If your application don’t have already, create the app layout: **resources/views/layouts/app.blade.php:**

```
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
 
    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">
 
    <title>{{ config('app.name', 'Laravel') }}</title>
 
    <!-- Scripts -->
    <script src="{{ asset('js/app.js') }}" defer></script>
 
    <!-- Fonts -->
    <link rel="dns-prefetch" href="//fonts.gstatic.com">
    <link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet" type="text/css">
 
    <!-- Styles -->
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
    <div id="app">
        <nav class="navbar navbar-expand-md navbar-light navbar-laravel">
            <div class="container">
                <a class="navbar-brand" href="{{ url('/') }}">
                    {{ config('app.name', 'Laravel') }}
                </a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
                    <span class="navbar-toggler-icon"></span>
                </button>
 
                <div class="collapse navbar-collapse" id="navbarSupportedContent">
                    <!-- Left Side Of Navbar -->
                    <ul class="navbar-nav mr-auto">
                        <li class="nav-item">
                            <a class="nav-link" href="{{ route(config('document_templates.base_url') . '.index') }}">{{ __('Document templates') }}</a>
                        </li>
                    </ul>
 
                    <!-- Right Side Of Navbar -->
                    <ul class="navbar-nav ml-auto">
                    </ul>
                </div>
            </div>
        </nav>
 
        <main class="py-4">
            @yield('content')
        </main>
    </div>
</body>
</html>
```

#### Let’s try it

If everything went well when we navigate to the **/document-templates/** url, we should see something like this:

![](https://42coders.com/wp-content/uploads/2019/11/Screen-Shot-2019-11-12-at-3.45.17-PM-1024x182.png)

The edit form should look like this:

![](https://42coders.com/wp-content/uploads/2019/11/Screen-Shot-2019-11-12-at-3.45.28-PM-1024x751.png)

and the generated invoice with with the placeholders filled should look like this:

![](https://42coders.com/wp-content/uploads/2019/11/Screen-Shot-2019-11-13-at-9.09.02-AM-1024x232.png)

## Closing thoughts

The package has been tested with Laravel version \>=5.7. For more information on how to use the package and for more code examples, please check the source code of the demo application [here](https://github.com/42coders/bwf-demo) and the package [documentation](https://github.com/42coders/document-templates).

The post [How to create invoices easily with document-templates package](https://42coders.com/how-to-create-invoices-easily-with-document-templates-package/) appeared first on [42 Coders](https://42coders.com).