{"id":36573492,"url":"https://github.com/42coders/document-templates","last_synced_at":"2026-01-12T07:21:02.545Z","repository":{"id":35850944,"uuid":"219696896","full_name":"42coders/document-templates","owner":"42coders","description":"Laravel package for creating and managing user editable document templates with placeholders and various data sources.","archived":false,"fork":false,"pushed_at":"2024-08-09T08:21:50.000Z","size":3299,"stargazers_count":201,"open_issues_count":8,"forks_count":24,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-11-19T17:29:29.342Z","etag":null,"topics":["document-generation","editable-documents","editable-emails","hacktoberfest","laravel","laravel-package"],"latest_commit_sha":null,"homepage":"https://42coders.com/bwf/","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/42coders.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-11-05T08:41:09.000Z","updated_at":"2025-10-24T03:16:43.000Z","dependencies_parsed_at":"2024-06-21T13:14:49.384Z","dependency_job_id":"e60a8678-737b-4a74-af7d-68818d83522c","html_url":"https://github.com/42coders/document-templates","commit_stats":{"total_commits":79,"total_committers":5,"mean_commits":15.8,"dds":0.3417721518987342,"last_synced_commit":"4655af4083f84d57b9fa3e643b4f3ce570db4eba"},"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/42coders/document-templates","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/42coders%2Fdocument-templates","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/42coders%2Fdocument-templates/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/42coders%2Fdocument-templates/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/42coders%2Fdocument-templates/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/42coders","download_url":"https://codeload.github.com/42coders/document-templates/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/42coders%2Fdocument-templates/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28336500,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T06:09:07.588Z","status":"ssl_error","status_checked_at":"2026-01-12T06:05:18.301Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["document-generation","editable-documents","editable-emails","hacktoberfest","laravel","laravel-package"],"created_at":"2026-01-12T07:21:01.826Z","updated_at":"2026-01-12T07:21:02.535Z","avatar_url":"https://github.com/42coders.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Document Templates\n\n[![Build Status](https://github.com/42coders/document-templates/actions/workflows/test.yml/badge.svg)](https://github.com/42coders/document-templates/actions/workflows/test.yml)\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/42coders/document-templates?style=flat-square)](https://packagist.org/packages/42coders/document-templates)\n[![Total Downloads](https://img.shields.io/packagist/dt/42coders/document-templates.svg?style=flat-square)](https://packagist.org/packages/42coders/document-templates)\n![GitHub](https://img.shields.io/github/license/42coders/document-templates)\n## Introduction\nDocument templates Laravel package is intended for creating/managing user editable document templates, with ability to add placeholders, and fill them from various data sources (models, collections, arrays, objects).\nThe package uses [Twig](https://twig.symfony.com/) as a main template engine, but it is possible to extend it with other template engines. Document templates can be used as a base for creating editable pdf documents such as invoices, reports etc., for email templates or any other editable, server generated documents. The user editable parts of the document template are secured using [Twig Sandbox Extension](https://twig.symfony.com/doc/2.x/api.html#sandbox-extension). The sandbox behaviour can be configured in the config file.\nThis package is part of the Business Workflow Framework. For a quick introduction on how to use the package please see this [blog post](https://42coders.com/how-to-create-invoices-easily-with-document-templates-package/).\n\n![Template editor](https://42coders.com/wp-content/uploads/2019/08/Document_Template_wysiwyg.png \"Logo Title Text 1\")\n![Rendered template](https://42coders.com/wp-content/uploads/2019/08/Document_Template_Menu.png \"Logo Title Text 1\")\n![Edit and render](https://42coders.com/wp-content/uploads/2019/06/1-gif-3.gif \"Logo Title Text 1\")\n\n## Getting started\n### Requirements\n#### Document templates version 6\n- Laravel 9 or newer\n- php 8+\n#### Document templates version 5 \n - Laravel 9 or 10\n - php 8+\n#### Document templates version 4\n- Laravel 5.7 or newer\n- php 7.4+\n#### Document templates version 3\n- Laravel 5.7 or newer\n- php 7.3+\n\n\n### Installation\n\nInstall with composer\n\n```sh\ncomposer require 42coders/document-templates \n```\n\nPublish the migrations, views, vue components and config:\n\n```sh\nphp artisan vendor:publish --provider=\"BWF\\DocumentTemplates\\DocumentTemplatesServiceProvider\"\n```\n\nThere are separate publish groups if you don't need all the vendor files in your application.\nTo publish only one group use the following command\n```sh\nphp artisan vendor:publish --provider=\"BWF\\DocumentTemplates\\DocumentTemplatesServiceProvider --tag=group_name\".\n```\n\nThe following file groups are available for publishing:\n\n - **migrations** publishes the migration files to the database directory \n - **views** publishes the views for the basic administration of the document templates to the `resources/views/vendor/document-templates`\n - **components** publishes the views for the basic administration of the document templates to the `resources/js/vendor/document-templates/components`\n - **config** publishes the configuration file to the config directory\n - **ckeditor** publishes the ckeditor and the placeholders plugin for the ckeditor into the `public/vendor/document-templates/js/lib/ckeditor` and `resources/js/vendor/document-templates/js/ckeditor` respectively \n - **js** publishes the javascript for easier initialization of the administration gui\n\n**DANGER ZONE**\nIf you already published the files and want to overwrite them use the: `--force` argument. \nThis command overwrites your changes in the published files, use it carefully. \n\nRun the migration\n\n```sh\nphp artisan migrate\n```\n\nAdd the routes from the package to your routes file:\n\n```sh\n\\BWF\\DocumentTemplates\\DocumentTemplates::routes(YourExtendedDocumentTemplatesController::class);\n```\n\nThe routes function accepts 1 argument:\n\n1. Controller class name to use with the routes\n\n## Basics\n\n### DocumentTemplate\nThis trait is responsible for reading the layout files, handling the datasources and rendering the document with data. Can be applied to any class with the convention that the class has only optional parameters in the constructor. These classes represent the document types, create separate classes for Invoices, Letters, Registration Emails etc.\n\n### DocumentTemplateModel\nThe model responsible to store the document templates, the default table is: `document_templates`.\n\n### EditableTemplate\nEditable template is the dynamic part in the layout that the user can modify.\n\n### Layout\nThe layouts are twig template files created by the developer, they can be used by document templates.\n\n### DocumentTemplatesController\nThe default controller for administration of the document templates.\n\n### Placeholders\nPlaceholders are twig template variables or expressions used in the editable templates to be replaced during the rendering, e.g. `{{user.name}}` or `{% for user in users %}`\n\n### Data Sources\nData sources are the objects that provide data to the document template, and replace the placeholders with actual data in the rendering process. Data sources can be created from Models, Objects, arrays, or from any scalar types (strings, integers).\n\n## Basic usage\n\n### Configuration\nThe configuration can be found in `config/document_templates`. \n\n`layout_path` - path to the layout files, defaults to: `resources/templates`.\n\nThe twig sandbox can be configured with the settings below, read more about sandbox configuration [here](https://twig.symfony.com/doc/2.x/api.html#sandbox-extension). The extended sandbox policy class adds support for allowing all object properties by setting wildcard `*` in the first position in the allowed properties array.  \n```php\n    'template_sandbox' =\u003e [\n        'allowedTags' =\u003e ['for'],\n        'allowedFilters' =\u003e ['escape'],\n        'allowedMethods' =\u003e [],\n        'allowedProperties' =\u003e ['*'],\n        'allowedFunctions' =\u003e []\n    ]\n```\n\nTwig environment options can be configured with the settings below, read more about the options [here](https://twig.symfony.com/doc/2.x/api.html#environment-options).\n\n```php\n    'twig' =\u003e [\n        'environment' =\u003e [\n            'debug' =\u003e false,\n            'charset' =\u003e 'utf-8',\n            'base_template_class' =\u003e '\\Twig\\Template',\n            'cache' =\u003e false,\n            'auto_reload' =\u003e false,\n            'strict_variables' =\u003e false,\n            'autoescape' =\u003e false,\n            'optimizations' =\u003e -1\n        ]\n    ]\n```\n\nTwig extensions can be loaded over `twig.extensions` by adding the extension's class to the array (which extends `\\Twig\\Extension\\AbstractExtension` or implements `\\Twig\\Extension\\ExtensionInterface`).\n\n```php\n    'twig' =\u003e [\n        'extensions' =\u003e []\n    ]\n```\n\nThe model class to be used with route model binding, and in the `DocumentTemplatesController`\n\n```php\n    'model_class' =\u003e \\BWF\\DocumentTemplates\\DocumentTemplates\\DocumentTemplateModel::class,\n```\n\nBase url to use for generating the routes with `DocumentTemplate::routes()` (e.g /document-templates/, /document-templates/1/edit).\nThese routes are also named by this base url, and they look like this: `route('document-template.index')`\n\n```php\n    'base_url' =\u003e 'document-templates'\n```\n\nConfigure if the package should load it's default routes\n\n```php\n    'load_default_routes' =\u003e false\n```\n\n### Creating the layout\nCreate a layout file in the configured layout path, the layout files should have `.twig` extension. The editable parts in the layout should be defined as blocks in the layout:\n```twig\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n\u003chead\u003e\n    \u003cmeta charset=\"UTF-8\"\u003e\n    \u003ctitle\u003e\n        {% block title %}\n        {% endblock %}\n    \u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    {% block content %}\n    {% endblock %}\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\nThe name of the block is used as the name of the editable template.\n\n### Creating the document template class\nDocument Template class can be any class which is uses the `DocumentTemplate` trait and implements the `DocumentTemplateInterface`. When using the trait the `dataSources` method should be implemented, it defines the data used by the document.\n\nThe following example show the datasources method:\n```php\nclass DemoDocumentTemplate implements DocumentTemplateInterface\n{\n    use DocumentTemplate;\n\n    protected function dataSources()\n    {\n        return [\n            $this-\u003edataSource($userModelInstance, 'user', true, 'users'),\n            $this-\u003edataSource($orderAssociativeArray, 'order', true, 'orders'),\n            $this-\u003edataSource($anyObject, 'test'),\n            $this-\u003edataSource('', 'text'),\n            $this-\u003edataSource(0, 'number'),\n        ];\n    }\n}\n```\n\nThe dataSource method accepts 4 arguments:\n\n- `$data` - instance of the data to use, it can be an empty instance, it is used to be able to show the possible placeholders when editing the document template in the admin area.\n- `$name` - defines the namespace for the data object e.g. $name = 'user'. The placeholders will be prefixed with the name: `{{user.name}}`. When using scalar data sources, the namespace is mandatory, for arrays and objects it can be omitted.\n- `$isIterable` - defines if the datasource can be used in a for loop in the template\n- `$iterableName` - defines the name of the iterable variable, which should be used in the template e.g. $iterableName = 'users' the placeholder for iteration would be `{% for user in users %}`\n\nThe signature if the dataSource method can be found below:\n`protected function dataSource($data, $name = '', $isIterable = false, $iterableName = '')`\n\n### Laravel models as data source\nLaravel models can act as a data source for the document templates by using the `ModelProvidesTemplateData` trait and implementing the `TemplateDataSourceInterface`. The developer can define which fields can be used as a template placeholder by overriding the `getTemplateFields` method. Example model used as a data source, allowing the fillable attributes as placeholders:\n\n```php\nclass User implements TemplateDataSourceInterface\n{\n    use ModelProvidesTemplateData;\n\n    /**\n     * The attributes that are mass assignable.\n     *\n     * @var array\n     */\n    protected $fillable = [\n        'name', 'email'\n    ];\n\n    protected function getTemplateFields()\n    {\n        return $this-\u003efillable;\n    }\n}\n```\n\n### Rendering template with data\nThe document template class can be instantiated with the `DocumentTemplateFactory`. The `build` method accepts one argument: the DocumentTemplateModel.\n\n```php\n        $documentTemplateModel = DemoDocumentTemplateModel::findOrFail($id);\n        $documentTemplate = DocumentTemplateFactory::build($documentTemplateModel);\n```\n\nOr the document template can be instantiated manually, in this case the `init()` method should be used to initialize the document template (it creates the document template by retrieving the first row from the database with the given document template class).\nUse the `addTemplateData` method to add the data which should replace the placeholders in the document. The arguments for the method are:\n\n- `$data` - the data object or collection of data sources e.g. `User::all()`, assuming the `User` model is implementing the `TemplateDataSourceInterface`\n- `$name` - The namespace used in the template, it should be the same as defined in `dataSources` method of the `DocumentTemplate` class.\n\nThe render method is used to render the document with the given data, returns the rendered document as string.\n\n\n```php\n        $documentTemplate = new DemoDocumentTemplate();\n        $documentTemplate-\u003einit();\n\n        $documentTemplate-\u003eaddTemplateData(User::all(), 'users');\n        $documentTemplate-\u003eaddTemplateData($ordersCollection, 'orders');\n        $documentTemplate-\u003eaddTemplateData($testObject, 'test');\n        $documentTemplate-\u003eaddTemplateData(42, 'number');\n        $documentTemplate-\u003eaddTemplateData('coders', 'text');\n\n        echo $documentTemplate-\u003erender();\n```\n\n#### Generating PDF\nThe need for pdf generation is a quite common thing in web development. The package support pdf generation \nwith [dompdf](https://github.com/dompdf/dompdf), (using [laravel-dompdf](https://github.com/barryvdh/laravel-dompdf) package) \nand [pupeteeer](https://github.com/GoogleChrome/puppeteer) (using [spatie/browsershot](https://github.com/spatie/browsershot) package). \nThe document template data should be set up the same way like for the simple rendering (see the previous section: Rendering template with data), but instead of the `render` method you should use the `renderPdf` method:\n\n```php\n$pdf = $documentTemplate-\u003erenderPdf(storage_path( 'app/my_example.pdf'));\n```\n\nThe only argument of the method is the desired path and file name, and it returns the path of the generated file.\n\nThe package supports multiple pdf renderers, the desired pdf renderer can be set up in the `config/document-templates.php`:\n\n**DomPdf:**\n```php\n    'pdf_renderer' =\u003e \\BWF\\DocumentTemplates\\Renderers\\DomPdfRenderer::class\n```\n\nIf you would like to configure the dompdf package, publish the dompdf configuration with:\n```php\nphp artisan vendor:publish --provider=\"Barryvdh\\DomPDF\\ServiceProvider\"\n```\n\nWhen published, the config file can be found in `config/dompdf.php`.\nFor more details about the dompdf configuration please check the [laravel-dompdf documentation](https://github.com/barryvdh/laravel-dompdf#configuration).\n\n\n**Browsershot:**\n```php\n    'pdf_renderer' =\u003e \\BWF\\DocumentTemplates\\Renderers\\BrowsershotPdfRenderer::class\n```\n\nThe browsershot package requires node 7.6.0 or higher and the Puppeteer Node library.\n\nOn MacOS you can install Puppeteer in your project via NPM:\n\n```\nnpm install puppeteer\n```\n\nOr you could opt to just install it globally\n\n```\nnpm install puppeteer --global\n```\n\nOn a Forge provisioned Ubuntu 16.04 server you can install the latest stable version of Chrome like this:\n\n```\ncurl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -\nsudo apt-get install -y nodejs gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget\nsudo npm install --global --unsafe-perm puppeteer\nsudo chmod -R o+rx /usr/lib/node_modules/puppeteer/.local-chromium\n```\n\nFor more details please check the [browsershot documentation](https://github.com/spatie/browsershot#requirements).\n\n## Administration\nThis package includes Vue component and a resource controller as a starting point for the document template admin implementation. In order to use the components you have to use the [Vue](https://vuejs.org/) JavaScript framework. The component is published to `resources/js/components/document-templates`. Register the component in your application (`app.js`):\n```javascript\nVue.component('document-template-form', require('./vendor/document-templates/components/DocumentTemplateFormComponent.vue').default);\n```\n\nPlease note that the pats may vary depending on your application's directory structure.\n\n### Editing the templates\nThe admin form component uses CKEditor for the user editable templates. The package ships with a custom built placeholders plugin for CKEditor. The placeholders plugin displays the placeholders as select boxes, every dataSource has it's own select box. The selected placeholders are automatically inserted into the editor's content as CKEditor inline widgets. The placeholder widgets can be moved across the text, and can be removed, but theirs content is read only to prevent rendering problems caused by incorrect/modified placeholders.\n\nThe CKEditor initialization using the placeholders plugin can be found below:\n\n```javascript\n    CKEDITOR.replace(editorId, {\n        customConfig: '',\n        extraPlugins: 'richcombo,placeholder_select',\n        toolbarGroups:[\n            { name: 'basicstyles' },\n            '/',\n            { name: 'placeholder_select'}\n        ],\n        placeholder_select: {\n            placeholders: _this.placeholders,\n        }\n    });\n``` \n\n### Inlcude all the necessary javascript at once\nIf you'd like to require/initialize all the necessary javascript automatically, you can use the `document-template.js` to do so.\nAdd the following to the `app.js`:\n```javascript\nrequire('./vendor/document-templates/js/document-templates');\n```\n\nIt includes the ckeditor, the placeholder plugin for ckeditor, sets the ckeditor base path, and registers the Vue component. \n\n### Document Templates Controller\nThe package ships with a default controller for your convenience, to be able to quickly scaffold an administration interface for the package.\nYou could extend the `DocumentTemplatesController`, and define the available document template classes, like below:\n\n```php\nclass DemoDocumentTemplatesController extends DocumentTemplatesController\n{\n    protected $documentClasses = [\n        DemoDocumentTemplate::class,\n        DemoDocumentTemplate2::class\n    ];\n}\n```\n\nThese classes appear on the create/edit form for the document, every class should correspond to a document type (e.g. create separate classes for Invoices, Letters, Registration Emails etc.).\nIf you need to change the default behaviour of the controller feel free to skip the extension and implement the necessary methods yourself.\nIn this case you can still use the `ManagesDocumentTemplates` trait which contains the methods to get the data for the api endpoints used by the vue components, \nthose endpoints are: `/placeholders` and `/templates`. If you use the trait you should implement the actions for these endpoints.\n\n\n## Demo application\nDemo application can be found here: https://github.com/42coders/bwf-demo. You can use a symlinked version of the document templates package in the `composer.json`:\n```json\n    \"repositories\": [\n        {\n            \"type\": \"path\",\n            \"url\": \"../document-templates\",\n            \"options\": {\n                \"symlink\": true\n            }\n        }\n    ],\n```\n\nAs you can see from the repository configuration, the package should be cloned in the same directory as the demo app. Also the demo app requires app.js directly from the package 'require('./../../vendor/42coders/document-templates/resources/js/app');', this allows you to develop the package and check the changes in the demo app immediately, without the need for composer install, and vendor:publish.\n\n## Contribution\nEvery contribution is welcome. We should use the usual [GitFlow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow) like workflow: create branches for features and bug fixes, when the development has been finished create a pull request to the `develop` and it will be reviewed by other developer, and merged/commented/declined accordingly.\nIt is important to create unit tests for all new features developed, and also for all bug fixes to keep the package stable and easy to use.\nFor the new features it is recommended to add a demo of the feature to the demo application and extend the documentation as well.\n\n### Test\nThe php tests are using [PHPUnit](https://phpunit.de/), to run the test you can use either `vendor/bin/phpunit` or `composer test` command.\nTest code coverage can be generated with `composer test-coverage` command. In order to generate coverage it is necessary to have [Xdebug](https://xdebug.org/) extension installed and enabled for php cli. The code coverage html report can be found in the `tests/coverage` directory. \nJavascript tests are using [Jasmine](https://jasmine.github.io/) test framework. Run the javascript test with the following command `npm run test`\n\n### Documentation\nApi documentation can be generated with [phpDox](http://phpdox.de/). To download and install `phpDox` please follow the instructions [here](http://phpdox.de/getting-started.html). Once the `phpDox` is installed generate the api documentation by running `composer build-docs`. When the process is finished the documentation can be found in `docs/html` directory.\n\n## License\nThe Document Templates is free software licensed under the MIT license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F42coders%2Fdocument-templates","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F42coders%2Fdocument-templates","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F42coders%2Fdocument-templates/lists"}