DEV Community

Cover image for Zero code print forms for Eloquent
Nick Mathias
Nick Mathias

Posted on

Zero code print forms for Eloquent

Recently, in a project on Laravel+Eloquent needed to make print forms of documents — invoices, contracts in Word format. Since there are a lot of different documents in the system, I decided to make it universal so that it can be used in other projects later.

The result is an implementation that requires minimal integration costs into the project.

How I used to make print forms. I used different approaches

  • I was placing tags in the document template and replacing them during generation.
  • Was generating the document text from scratch.
  • Was generating html and converting it to word.
  • I was creating my own system for generating documents similar to the one described in this article, but using other technologies.

Each option is good for its task. But if you have Eloquent, I highly recommend the way described in this article.

So, we connect the package

composer require mnvx/eloquent-print-form
Enter fullscreen mode Exit fullscreen mode

And we describe Eloquent models, if they are not already described. Let’s say there are the following models.

use Illuminate\Database\Eloquent\Model;

/**
 * @property string $number
 * @property string $start_at
 * @property Customer $customer
 * @property ContractAppendix[] $appendixes
 */
class Contract extends Model
{
    public function customer()
    {
        return $this->belongsTo(Customer::class);
    }

    public function appendixes()
    {
        return $this->hasMany(ContractAppendix::class);
    }
}

/**
 * @property string $name
 * @property CustomerCategory $category
 */
class Customer extends Model
{
    public function category()
    {
        return $this->belongsTo(CustomerCategory::class);
    }
}

/**
 * @property string $number
 * @property string $date
 * @property float $tax
 */
class ContractAppendix extends Model
{
    public function getTaxAttribute()
    {
        $tax = 0;
        foreach ($this->items as $item) {
            $tax += $item->total_amount * (1 - 100 / 
                (100+($item->taxStatus->vat_rate ?? 0)));
        }
        return $tax;
    }
}
Enter fullscreen mode Exit fullscreen mode

For clarity, the diagram of the relationships

Class diagram

In other words, we described the table with contracts (Contract), the contract can have a client (Customer) filled in, and the client can have a category filled in. A contract can have several appendices (ContractAppendix).

All you need to generate a print form is to describe the fields in the print form template. Creating a docx file with the following content

Document example

In variables, specify the names of Eloquent entity fields. If you need to get to neighboring tables via links, use a dot, as in the example above, in ${customer.category.name}.

If you need to process data from the database, use the pipeline operator |, as in the example ${number|placeholder}. If you need to perform multiple processes, build a chain of pipelines, for example ${start_at|date|placeholder}.

Examples of ready-made operations

  • placeholder — replaces an empty value with “____”,
  • date — sets the date to the format 24.12.2020,
  • dateTime — sets the date-time to the format 24.12.2020 23:11,
  • int — converts an integer to the format 2'145,
  • decimal — converts a fractional number to the format 2'145.07.

To fill in table data, insert variables into the table as in the document example above. You can use a separate construction to number table rows ${entities.#row_number}.

Now that the document is described, you just need to start generating the printed form

use Mnvx\EloquentPrintForm\PrintFormProcessor;
$entity = Contract::find($id);
$printFormProcessor = new PrintFormProcessor();
$templateFile = resource_path('path/your_print_form.docx');
$tempFileName = $printFormProcessor
    ->process($templateFile, $entity);
Enter fullscreen mode Exit fullscreen mode

The generated $tempFileName file will contain the prepared print form.

In a Laravel project, the controller method responsible for generating the printed form may look like this

public function downloadPrintForm(FormRequest $request)
{
    $id = $request->get('id');
    $entity = Contract::find($id);
    $printFormProcessor = new PrintFormProcessor();
    $templateFile = resource_path(
        'path_to_print_forms/your_print_form.docx');
    $tempFileName = $printFormProcessor
        ->process($templateFile, $entity);
    $filename = 'contract_' . $id;
    return response()
        ->download($tempFileName, $filename . '.docx')
        ->deleteFileAfterSend();
}
Enter fullscreen mode Exit fullscreen mode

In summary, I will say that I decently unloaded myself by making this small library for a project where there are quite a lot of print forms. I don’t need to write my own unique code for each of them. I just describe the variables in the documents as mentioned above and get the result very quickly. I will be glad if the package will help you save time.

Link to the project on github.

Top comments (0)