Выгрузка в формате docx по заранее подготовленному шаблону.

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
surrealistic_pillow
Сообщения: 39
Зарегистрирован: 2016.11.22, 18:14

Выгрузка в формате docx по заранее подготовленному шаблону.

Сообщение surrealistic_pillow » 2017.04.03, 17:10

Есть модель заявок на обучение, в которых содержатся пользовательские данные - ФИО, реквизиты организации и тд.
Нужно чтобы из вьюхи (view.php например) можно было нажатием кнопки выгружать Договор в формате .docx, подготовленный по шаблону, в который бы вставлялись данные каждого конкретного пользователя.

Посоветуйте наиболее рациональное решение такой ззадачи


Аватара пользователя
futbolim
Сообщения: 2050
Зарегистрирован: 2012.07.08, 19:28

Re: Выгрузка в формате docx по заранее подготовленному шаблону.

Сообщение futbolim » 2017.04.03, 19:09

Вот обёртка https://github.com/strong2much/yii2-word
Warning. Последний коммит в ноябре 2015-го


surrealistic_pillow
Сообщения: 39
Зарегистрирован: 2016.11.22, 18:14

Re: Выгрузка в формате docx по заранее подготовленному шаблону.

Сообщение surrealistic_pillow » 2017.04.14, 15:15

Я установил PhpWord.
Возникла проблема - при попытке выгрузить файл он открывается браузером вместо того чтобы скачаться.
Вот такие кракозябры в браузере выводятся
PKy�J�j�c![Content_Types].xml���N�0E�|E�-Jܲ@5��*Q>��'��_�8}�=��DAC�v)��s�G�G��5� "j�J6,,'��nQ���s~�2L�)a���m�d|5�m`F�K�L)�s�r V`�8�T>Z��5.x�C,���\z���<56=B%j��� }n�D0Ȳ���q�L�`���|��K�74����xM ��jh*�s����dSӋ��ŕ����1"�1r6�y Ĥ�Kz�H�ㅾ��bԖF hV�@�5&oOַ���>*ލ��nh䕀H�5EW�B������)Zn���v�FΟ�C��R��KlaO莁�9<9�ӫ\���b�� R�w&���C��~� PKy�J�iM��_rels/.rels���J1��>E�{7�*"�l/"�&�>��Lw7��L�}{CQt���=��?߄�7?�7Jy�``Yՠ(XvC�����;PY089��#e�4W�gQ�NU��l���Zgۓ�\q�P&;N�����+v�Wu}��O4��:i떠�c����'A���r�ELe;�PNQ-��Āc�T���� �y��߅x�,=��{ r΋B���W�献/id�Y���D�̜��%���o�wNN������|��PKy�J�����BdocProps/app.xml��;k1�{��C�����N�؄4�+����w�v��1�?kW�3;ju Cu��=a#�ZT���Ǿ����ST� :3B#F�b�'�M!��\�F���R�lOL��K�Q ��M�����d �E]H�0�7����g~������1�V�o
вот код из контроллера:

Код: Выделить всё

    public function actionGetdoc($id,$org_id){   
		$phpWord = new \PhpOffice\PhpWord\PhpWord();
		$phpWord->setDefaultFontName('Times New Roman');
		$phpWord->setDefaultFontSize(14);
		$properties = $phpWord->getDocInfo(); 
		$properties->setCreator('Name');
		$properties->setCompany('Company');
		$properties->setTitle('Title');
		$properties->setDescription('Description');
		$properties->setCategory('My category');
		$properties->setLastModifiedBy('My name');
		$properties->setCreated(mktime(0, 0, 0, 3, 12, 2015));
		$properties->setModified(mktime(0, 0, 0, 3, 14, 2015));
		$properties->setSubject('My subject');
		$properties->setKeywords('my, key, word');   
		$sectionStyle = array(
					
					'orientation' => 'landscape',
					'marginTop' => \PhpOffice\PhpWord\Shared\Converter::pixelToTwip(10),
					'marginLeft' => 600,
				    'marginRight' => 600,
				    'colsNum' => 1,
				    'pageNumberingStart' => 1,
				    'borderBottomSize'=>100,
				    'borderBottomColor'=>'C0C0C0'
				
					);
		$section = $phpWord->addSection($sectionStyle); 
		\PhpOffice\PhpWord\Shared\Converter::pixelToTwip(10);
		$text = "PHPWord is a library written in pure PHP that provides a set of classes to write to and read from different document file formats.";
		$fontStyle = array('name'=>'Arial', 'size'=>36, 'color'=>'075776', 'bold'=>TRUE, 'italic'=>TRUE);
		$parStyle = array('align'=>'right','spaceBefore'=>10);

		$section->addText(htmlspecialchars($text), $fontStyle,$parStyle);
		$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord,'Word2007');
		//$objWriter->save('/var/www/web/mysite.ru/public_html/contracts/'.$id.'-'.$org_id.'.docx');
		$objWriter->save("php://output");
		
		
        return $this->redirect(['contract','id' => $id]);
    }	
не срабатывает вот эта строка как я понимаю
$objWriter->save("php://output");


вот кнопка во вьюхе:

Код: Выделить всё

Html::a('Договор', ['getdoc', 'org_id' => $org_id, 'id' => $this->id], [
					'class' => 'btn btn-default',
					'data' => [
						'method' => 'post',
					]
Когда не отдаю файл на скачивание а просто создаю на сервере то проблем не возникает, файл создается с заданным содержимым.
Вот таким образом:
$objWriter->save('/var/www/web/mysite.ru/public_html/contracts/'.$id.'-'.$org_id.'.docx');

В чем может быть проблема?

Аватара пользователя
Alexum
Сообщения: 674
Зарегистрирован: 2016.09.26, 10:00

Re: Выгрузка в формате docx по заранее подготовленному шаблону.

Сообщение Alexum » 2017.04.14, 15:43

Установите правильный заголовок перед выводом, браузер должен понимать что ему отдают.

Н-р:

Код: Выделить всё

...
header("Content-Type:application/vnd.ms-office");
header('Content-Disposition: attachment; filename="'.iconv('UTF-8','WINDOWS-1251', 'Название на русском языке.docx').'"');
$objWriter->save("php://output");

surrealistic_pillow
Сообщения: 39
Зарегистрирован: 2016.11.22, 18:14

Re: Выгрузка в формате docx по заранее подготовленному шаблону.

Сообщение surrealistic_pillow » 2017.04.14, 23:34

Alexum, спасибо! Файл стал скачиваться, с содержимым, все как надо.
Теперь возникла другая проблема. Пытаюсь использовать готовый шаблон, и подставлять в него переменные. Файл скачивается пустой.
в файле-шаблоне прописываю ${variable}
в контроллере

Код: Выделить всё

    public function actionGetdoc($id,$org_id){   
		$PhpWord = new \PhpOffice\PhpWord\PhpWord();
		$document = $PhpWord->loadTemplate('/var/www/web/mysite.ru/public_html/contracts/template.docx'); //шаблон
		$document->setValue('variable', 'test'); 
		header("Content-Type:application/vnd.ms-office");
		header('Content-Disposition: attachment; filename="'.iconv('UTF-8','WINDOWS-1251', 'test.docx').'"');
	
		$document->save("php://output");  
}
если перед или после ${variable} вставляю текст, файл все равно скачивается пустой

surrealistic_pillow
Сообщения: 39
Зарегистрирован: 2016.11.22, 18:14

Re: Выгрузка в формате docx по заранее подготовленному шаблону.

Сообщение surrealistic_pillow » 2017.04.21, 12:10

Никто не подскажет, в чем может быть тут проблема? Все еще не смог найти решения.
Неужели такой баг только у меня наблюдается

Аватара пользователя
Lexx
Сообщения: 6
Зарегистрирован: 2015.08.17, 18:32

Re: Выгрузка в формате docx по заранее подготовленному шаблону.

Сообщение Lexx » 2018.10.03, 11:16

видос на испанском,но думаю без слов понятно че делать,все работает, проверено.. кому надо ссылка на видос
https://www.youtube.com/watch?v=3fmsZ6fZz1w
Шокирующее интервью веб-разработчика http://www.youtube.com/watch?v=sVby7a2dpr8

kolibri.sib
Сообщения: 3
Зарегистрирован: 2016.01.04, 11:49

Re: Выгрузка в формате docx по заранее подготовленному шаблону.

Сообщение kolibri.sib » 2019.11.11, 18:24

Если требуется генерировать таблицу (много строк), можно использовать это расширение: https://github.com/natmars/yii2-word

unknownby
Сообщения: 34
Зарегистрирован: 2019.11.05, 16:34

Re: Выгрузка в формате docx по заранее подготовленному шаблону.

Сообщение unknownby » 2019.11.12, 08:45

В конце, когда ты хочешь его скачать.
Я бы предложил такой вариант.

Код: Выделить всё

//вверху подключил бы
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\PhpWord;

//код в экшене
$PHPWord = new PhpWord();
$fileinputname = 'myname.docx';
//путь к файлу шаблона
$fileinputpath = \Yii::getAlias('@app') . "/templates/" . $fileinputname;
// генерируем конкретный файл
$document = $PHPWord->loadTemplate($fileinputpath);
//установку setValue попробуй так
$document->setValue('variable', $text);
//указываешь имя файла выходного, какое тебе хочется
//переменная $tmpdir это путь до файла
$fileoutputname = 'myname_'.$model->id.'.docx';
$fileoutputpath = $tmpdir . $fileoutputname;
//сохраняешь файл
$document->saveAs($fileoutputpath);
//а дальше интересно, отправляешь файл на скачку и после отправки удаляешь его с сервера.
return \Yii::$app->response->sendFile($fileoutputpath)
            ->on(\yii\web\Response::EVENT_AFTER_SEND, function($event) {
                unlink($event->data);
            }, $fileoutputpath)
            ;

Аватара пользователя
svil
Сообщения: 560
Зарегистрирован: 2018.02.12, 22:41

Re: Выгрузка в формате docx по заранее подготовленному шаблону.

Сообщение svil » 2019.11.12, 13:34

Аналогичная задача была https://github.com/svil1502/rbac/tree/test
http://ilin.itcrk.ru/rbac/web/

Мне так много помогали на этом сайте, что я рада тоже кому-то помочь

Аватара пользователя
svil
Сообщения: 560
Зарегистрирован: 2018.02.12, 22:41

Re: Выгрузка в формате docx по заранее подготовленному шаблону.

Сообщение svil » 2019.11.12, 13:45

Если несколько строк в цикле вывести:

Код: Выделить всё

<?php

use PhpOffice\PhpWord\PhpWord;


$general_edu_company="АFFFF \"FFFFFFF\"";
$general_edu_company_full="FFFFFFF \"FFFFFFF\"";
$general_edu_company_ceo="Иванов В.И.";



$PHPWord = new \PhpOffice\PhpWord\PhpWord();
$PHPWord->setDefaultFontName('Times New Roman');
$PHPWord->setDefaultFontSize(12);


$sectionStyle = array(
'marginTop' => '634' // по-умолчанию равен 1418* и соответствует 2,5 см отступа сверху
,'marginLeft' => '718' // по-умолчанию равен 1418* и соответствует 2,5 см отступа слева
,'marginRight' => '718' // по-умолчанию равен 1418* и соответствует 2,5 см отступа справа
,'marginBottom' => '634' // по-умолчанию равен 1134* и соответствует 2 см отступа снизу
   
);


$section = $PHPWord->createSection($sectionStyle);


$PHPWord->addFontStyle('rStyle14', array('bold'=>true, 'size'=>14));
$PHPWord->addParagraphStyle('pStyle', array('align'=>'center', 'spaceAfter'=>400, 'spaceAfter'=>400));
$section->addText($general_edu_company_full, 'rStyle14', 'pStyle');

$section->addText('Название документа', 'rStyle14', 'pStyle');

$PHPWord->addFontStyle('rStyle12', array('size'=>12, 'bold'=>true));
$section->addText('№                                          от '.Yii::$app->formatter->asDate($model->start,'php:d.m.Y').' г.', 'rStyle12');
$section->addText('«Какой то текст»');

$section->addText('Какой-то текст:', 'rStyle14', 'pStyle');

$PHPWord->addFontStyle('rStyle12n', array('size'=>12));
$PHPWord->addParagraphStyle('pStyle12n', array('spaceAfter'=>100));
$section->addText('1.Текстc '.Yii::$app->formatter->asDate($model->start,'php:d.m.Y').' по '.Yii::$app->formatter->asDate($model->end,'php:d.m.Y').' в текст какой-то «'.$model->courses->ord1.'».', 'rStyle12n', 'pStyle12n');
$section->addTextBreak(1);

$section->addText('2. Текст № '.$model['num'].' текст:', 'rStyle12n', 'pStyle12n');

// Add table
$styleTable = array('borderSize'=>1, 'borderColor' => '000000');
$PHPWord->addTableStyle('myOwnTableStyle', $styleTable);
$table = $section->addTable('myOwnTableStyle');

// Add row
$table->addRow();

// Add cells
$styleCell = array('valign' => 'center');
$PHPWord->addFontStyle('myOwnCellStyle', array('bold'=>true, 'italic'=>true, 'size'=>12));
$table->addCell(2000, $styleCell)->addText('№ п/п', 'myOwnCellStyle');
$table->addCell(2000, $styleCell)->addText('Фамилия, имя, отчество', 'myOwnCellStyle');
$table->addCell(2000, $styleCell)->addText('Должность', 'myOwnCellStyle');
$table->addCell(2000, $styleCell)->addText('Организация', 'myOwnCellStyle');

$r = 1;

foreach ($model->listeners as $list)
{
    $table->addRow();

   
    $uname = $list->listeners->surname." ".$list->listeners->name." ".$list->listeners->thirdname;
    $ucompany =  $list->jobs->companies->name;
    $ujob = $list->jobs->name;

    $table->addCell(null)->addText("$r");
    $table->addCell(null)->addText("$uname");
    $table->addCell(null)->addText("$ujob");
    $table->addCell(null)->addText("$ucompany");

    $r++;

}

$section->addTextBreak(1);

$section->addText('3. '.$model->courses->ord2, 'rStyle12n', 'pStyle12n');
$section->addTextBreak(1);

// Add table
$table = $section->addTable();

// Add row
$table->addRow();

// Add cells


$table->addCell(6000)->addText('Текст');
$table->addCell(4000)->addText($general_edu_company_ceo);



$file = 'Order'.$model->num."-".Yii::$app->formatter->asDate($model->start,'php:d.m.Y').".docx";


$xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($PHPWord, 'Word2007');
$xmlWriter->save($file);
$dir = Yii::getAlias('@app/web/'.$file);
Yii::$app->response->sendFile($dir);
?>




kolibri.sib
Сообщения: 3
Зарегистрирован: 2016.01.04, 11:49

Re: Выгрузка в формате docx по заранее подготовленному шаблону.

Сообщение kolibri.sib » 2019.11.12, 19:09

unknownby писал(а):
2019.11.12, 08:45
В конце, когда ты хочешь его скачать.
Я бы предложил такой вариант.

Код: Выделить всё

//вверху подключил бы
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\PhpWord;

//код в экшене
$PHPWord = new PhpWord();
$fileinputname = 'myname.docx';
//путь к файлу шаблона
$fileinputpath = \Yii::getAlias('@app') . "/templates/" . $fileinputname;
// генерируем конкретный файл
$document = $PHPWord->loadTemplate($fileinputpath);
//установку setValue попробуй так
$document->setValue('variable', $text);
//указываешь имя файла выходного, какое тебе хочется
//переменная $tmpdir это путь до файла
$fileoutputname = 'myname_'.$model->id.'.docx';
$fileoutputpath = $tmpdir . $fileoutputname;
//сохраняешь файл
$document->saveAs($fileoutputpath);
//а дальше интересно, отправляешь файл на скачку и после отправки удаляешь его с сервера.
return \Yii::$app->response->sendFile($fileoutputpath)
            ->on(\yii\web\Response::EVENT_AFTER_SEND, function($event) {
                unlink($event->data);
            }, $fileoutputpath)
            ;
Спасибо за подсказку, скачивание и удаление временного файла выделено в функцию. saveFromMultiLineTemplate нужна для того, чтобы упростить и не вызывать каждый раз setValue. generate() - просто пример.

unknownby
Сообщения: 34
Зарегистрирован: 2019.11.05, 16:34

Re: Выгрузка в формате docx по заранее подготовленному шаблону.

Сообщение unknownby » 2019.11.13, 09:18

kolibri.sib писал(а):
2019.11.12, 19:09
Спасибо за подсказку, скачивание и удаление временного файла выделено в функцию. saveFromMultiLineTemplate нужна для того, чтобы упростить и не вызывать каждый раз setValue. generate() - просто пример.
Для этого и нужен форум, чтобы подсказывать и помогать друг другу :D
Генерирование новой таблицы с нужными заголовками и содержимым можно делать по разному.
setValue устанавливает значение переменной, а переменную внутри шаблона можно использовать сколько угодно :D

У нас в проекте, если нужно сгенерировать таблицу например 5х5, где первый заголовок, а остальные 4-ре это тело. Вызывается один раз setValue, в который устанавливается значение переменной, которая внутри себя имеет созданную таблицу при помощи TableSingleHelper, который сделан нами в проекте.
Пример рисования таблицы:

Код: Выделить всё

	$header = ['Код', 'Наименование'];
        foreach ($model->test as $v) {
            $body [] = [
                $v->test_code,
                $v->test_name,
            ];
        }
        $settings = [
            ['font-size' => '12pt',],
            ['font-size' => '12pt',],
        ];
        $test= TableSingleHelper::create($header, $body, $settings);
        
        $document->setValue('test', $test);

Ответить