Недавно в проекте на Laravel+Eloquent понадобилось сделать печатные формы документов счетов, договоров в формате Word. Так как в системе много разных документов, то решил сделать универсально, чтобы можно было потом использовать и в других проектах.
В итоге получилась реализация, которая требует минимум затрат на интеграцию в проект.
Как я раньше делал печатные формы. Использовал разные подходы
- В шаблон документа размещал теги и заменял их при генерации.
- Генерировал текст документа с нуля.
- Генерировал html и конвертировал его в word.
- Делал свою систему для генерации документов по аналогии с той, что описана в этой статье, но на других технологиях.
Каждый вариант хорош для своей задачи. Но если у вас Eloquent, то весьма рекомендую вариант, описанный в этой статье.
Итак, подключаем пакет
composer require mnvx/eloquent-print-form
И описываем модели Eloquent, если они еще не описаны. Допустим, есть следующие модели.
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; }}
Для наглядности, диаграмма связей
То есть описана таблица с договорами (Contract
), у
договора может быть заполнен контрагент (Customer
), у
контрагента может быть заполнена категория. У договора может быть
несколько приложений (ContractAppendix
).
Все что нужно для генерации печатной формы описать поля в шаблоне печатной формы. Создаем docx файл с таким содержимым
В переменных указываем названия полей сущностей Eloquent. Если
нужно добраться по связям до соседних таблиц, используем точку, как
в примере выше, в ${customer.category.name}
.
Если необходимо обработать данные из базы, используем оператор
конвейер |
, как в примере
${number|placeholder}
. Если нужно выполнить несколько
обработок, строим цепочку конвейеров, например
${start_at|date|placeholder}
.
Примеры готовых операций
placeholder
заменяет пустое значение на "____",date
приводит дату к формату 24.12.2020,dateTime
приводит дату-время к формату 24.12.2020 23:11,int
приводит целое число к формату 2`145,decimal
приводит дробное число к формату 2`145.07.
Для заполнения табличных данных вставляем переменные в таблицу
как в примере документа выше. Для нумерации строк таблицы можно
использовать отдельную конструкцию
${entities.#row_number}
.
Теперь, когда документ описан, остается просто запустить генерацию печатной формы
use Mnvx\EloquentPrintForm\PrintFormProcessor;$entity = Contract::find($id);$printFormProcessor = new PrintFormProcessor();$templateFile = resource_path('path_to_print_forms/your_print_form.docx');$tempFileName = $printFormProcessor->process($templateFile, $entity);
В сгенерированном файле $tempFileName
будет лежать
подготовленная печатная форма.
В проекте на Laravel метод контроллера, отвечающий за генерацию печатной формы, может выглядеть так
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();}
Резюмируя, скажу, что я прилично разгрузил себя, сделав эту небольшую библиотеку в проекте, где довольно много печатных форм. Мне не надо для каждой из них писать свой уникальный код. Я просто описываю переменные как сказано выше и весьма быстро получаю результат. Буду рад, если и вам пакет поможет сэкономить время.
Ссылка на проект на гитхабе: https://github.com/mnvx/eloquent-print-form