Excel-аналог mail-merge: как заполнить готовый XLSX-шаблон данными

aVadim • 27.08.2026 00:00 •

В Word есть слияние (mail-merge): дизайнер верстает бланк, расставляет поля, а программа подставляет в них данные из источника. Удобно, потому что вёрстка отделена от данных. Когда та же задача приходит для Excel — «вот бланк договора в xlsx, подставьте туда реквизиты» — разработчик почему-то лезет собирать документ в коде с нуля.

А ведь нужна ровно та же идея, что в Word: шаблон с плейсхолдерами плюс подстановка. Для XLSX её даёт FastExcelTemplator. Всё ниже проверено на версии 3.2.0.

Наивный путь и почему он плохой

Соблазн — открыть готовый файл в PhpSpreadsheet, найти нужные ячейки по адресам и переписать их значения:

php
$sheet->setCellValue('B3', $company);   // а если бланк поправят и B3 переедет?
$sheet->setCellValue('B4', $address);   // адреса ячеек захардкожены

Минусов два. Во-первых, вы привязываетесь к конкретным адресам: стоит бухгалтеру вставить строку — и B3 уже не та ячейка. Во-вторых, PhpSpreadsheet ради этого загружает всю книгу в память.

Плейсхолдеры снимают обе проблемы: вы подставляете значение не по адресу, а по метке {{COMPANY}}, где бы она ни оказалась.

Два вида подстановки: fill и replace

В шаблоне размечаем поля любым удобным маркером — например, {{COMPANY}}. Дальше открываем шаблон и задаём замены:

php
use avadim\FastExcelTemplator\Excel;

$excel = Excel::template('contract-tpl.xlsx', 'contract-out.xlsx');
$sheet = $excel->sheet();

// fill() — заменяет значение ЦЕЛОЙ ячейки
$sheet->fill([
    '{{COMPANY}}' => 'ООО «Ромашка»',
    '{{INN}}'     => '7701234567',
]);

// replace() — заменяет ПОДСТРОКУ внутри значения ячейки
$sheet->replace([
    '{{DATE}}' => date('d.m.Y'),
]);

$sheet->transferRows();  // перенести строки шаблона в вывод
$excel->save();

Разница между двумя методами — главные грабли новичка, поэтому разберём подробно.

  • fill() срабатывает, только если значение ячейки целиком равно ключу. Ячейка со значением {{COMPANY}} — заменится. А вот ячейка Компания: {{COMPANY}} через fill() не изменится, потому что её значение не равно ключу целиком.
  • replace() ищет подстроку в любом месте текста. Ячейка Дата: {{DATE}} превратится в Дата: 25.07.2026 — заменяется только вхождение метки, остальной текст остаётся.

Отсюда простое правило: если поле занимает ячейку целиком — берите fill(); если метка сидит внутри фразы — replace(). Когда «плейсхолдер не подставился», в девяти случаях из десяти причина именно эта: fill() применили к ячейке, где метка была частью текста.

Где действуют замены

Замены, заданные через fill() и replace(), применяются ко всем ячейкам, которые библиотека пишет в вывод, — не нужно указывать адреса или листы. Вы один раз объявили словарь замен, а дальше он срабатывает везде, где встретит метку. Это и есть то самое отделение вёрстки от данных: бланк можно перекроить как угодно, лишь бы метки остались на месте.

Значение замены — обычный скаляр: строка, число, дата (заранее отформатированная в строку). Формат самой ячейки (денежный, датовый) берётся из шаблона, так что число подставится и отобразится так, как задумал автор бланка.

Чего плейсхолдеры не делают

Важно не спутать этот механизм с полноценным шаблонизатором вроде Blade или Twig. Плейсхолдеры Templator — это подстановка значений, и только:

  • Нет логики в шаблоне. Никаких {{ if }}, циклов или выражений внутри ячейки — метка либо заменяется на значение, либо нет.
  • Повторяющиеся строки — это отдельная механика. Если в документе таблица, где строк заранее не известно сколько (позиции счёта, список сотрудников), одними заменами не обойтись: там нужна строка-образец и её размножение (getRowTemplate() + insertRow()) — это тема отдельного разбора.
  • Только XLSX. Шаблон в старом .xls не подойдёт — сначала пересохраните его в .xlsx.
  • Формулы библиотека не вычисляет. Если в бланке есть формула, её результат посчитает Excel при открытии файла.

Кому это подходит

Плейсхолдерная подстановка — идеальное решение, когда документ по структуре фиксирован, а меняются только значения: договоры, справки, гарантийные письма, титульные листы, анкеты. Вы отдаёте вёрстку тому, кто умеет в Excel, а в коде оставляете короткий словарь замен. Если же в документе есть таблица переменной длины — к fill()/replace() добавляется размножение строк, о котором стоит почитать отдельно.

Комментарии (0)