Цитата |
---|
Александр Солошенко написал: Я кажись понял, /home/bitrix/www/bitrix/modules/documentgenerator/lib/body/d |
02.09.2020 18:18:53
|
|||
|
|
02.09.2020 18:27:30
Антон Горбылев,
у меня стоит следующая задача: необходимо подменять изображение подписи на КП в зависимости от ответственного за сделку. Думаю, сценарий будет следующим: 1. в карточке сотрудника загрузим файлы с росписями. 2. на событии: onBeforeProcessDocument достаю файл соответствующего изображения. 3. подменяю роспись на КП изображением полученным на шаге №2. ACHTUNG!!! вопрос: как сделать 3-й шаг: подменяю роспись на КП изображением полученным на шаге №2. |
|
|
|
03.09.2020 09:55:07
Ахат Баязи,передайте в качестве значения путь к файлу или ид из b_file.
|
|
|
|
03.09.2020 17:56:31
1. $rootActivity = $this->GetRootActivity(); 2. Открываю как zip-архив сгенерированный файл docx, который сформировался на основе ранее подгруженного шаблона и данных передаваемых из бп. 3. Открываю документ xml и делаю замены так, как Вы указали в пункте 1. 4. Вставляю то, что нужно в rels 5. Сохраняю архив и выдаю пользователю новый файл. Верно? В пункте 3 что нужно использовать? Если можно, то более детально расписать блоки кода (логику). Я не очень силен в php, но хорошо знаю английский и есть большое желание подтянуть php. |
|||
|
|
04.09.2020 10:03:21
Александр Солошенко, в общих чертах верно. По поводу работы с БП не подскажу, посмотрите существующие действия (папка activities).
|
|
|
|
05.09.2020 18:29:32
Антон, добрый день, я взял файл docxxml.php
И сделал свои правки, основываясь на коде, который используется для вставок картинок. Получилось что-то такое: /** * Get all hyperlink nodes marked with placeholders. * If $generateNewhyperlinkIds is true - will replace relation ids to new values. * * @param bool $generateNewHyperlinkIds * @param \DOMNode|null $contextNode * @return array */ public function findHyperlinks(bool $generateNewHyperlinkIds = false, \DOMNode $contextNode = null): array { $this->initDomDocument(); if($contextNode) $HyperlinkDescriptions = $this->xpath->query('//w:hyperlink w:history', $contextNode); } else { $HyperlinkDescriptions = $this->xpath->query('//w:hyperlink w:history'); } $placeholders = []; foreach($HyperlinkDescriptions as $description) { /** @var \DOMElement $description */ if($description->hasAttributes()) { $name = $description->attributes->getNamedItem('name'); $descr = $description->attributes->getNamedItem('descr'); $placeholder = null; if($descr) { $placeholder = static::getCodeFromPlaceholder($descr->nodeValue); } if(!$placeholder && $name) { $placeholder = static::getCodeFromPlaceholder($name->nodeValue); } if($placeholder) { if(!isset($placeholders[$placeholder])) { $placeholders[$placeholder] = [ 'hyperlinkNode' => [], 'innerIDs' => [], ]; } $placeholders[$placeholder]['hyperlinkNode'][] = $description->parentNode->parentNode; $embeds = $description->parentNode->getElementsByTagNameNS(static::getNamespaces()['a'], 'blip'); if($embeds->length > 0) { /** @var \DOMAttr $innerHyperlinkId */ $hyperlinkId = $innerhyperlinkId->value; if($generateNewHyperlinkIds && !isset($this->arrayHyperlinkValues['originalId'][$hyperlinkId])) { $newHyperlinkId = static::getRandomId('rId', true); $placeholders[$placeholder]['originalId'][$newHyperlinkId] = $HyperlinkId; $HyperlinkId = $innerHyperlinkId->value = $newHyperlinkId; } if(!in_array($HyperlinkId, $placeholders[$placeholder]['innerIDs'])) { $placeholders[$placeholder]['innerIDs'][] = $hyperlinkId; if(isset($this->arrayHyperlinkValues['values'][$hyperlinkId])) { $placeholders[$placeholder]['values'][$hyperlinkId] = $this->arrayHyperlinkValues['values'][$hyperlinkId]; $placeholders[$placeholder]['originalId'][$hyperlinkId] = $this->arrayHyperlinkValues['originalId'][$hyperlinkId]; } } } } } }
if(!empty($placeholders) && $generateNewHyperlinkIds) { $this->saveContent(); }
return $placeholders; }
/** * @param mixed $value * @param string $placeholder * @param string $modifier * @param array $params * @return string */ protected function printValue($value, $placeholder, $modifier = '', array $params = []): string { $value = parent::printValue($value, $placeholder, $modifier); if(empty($value)) { return (string) $value; } if (ToUpper(SITE_CHARSET) !== 'UTF-8') { if(is_array($value) || is_object($value)) { $value = ''; } elseif(!Encoding::detectUtf8($value)) { $value = Encoding::convertEncoding($value, SITE_CHARSET, 'UTF-8'); } } if(is_string($value)) { if($this->isHyperlinkValue($placeholder, $this->values)) { return ''; }
if($this->isHtml($value)) { $context = []; if(isset($params['currentNode']) && $params['currentNode'] instanceof \DOMElement) { $context['rowProperties'] = $this->getRowPropertyNodeValue($params['currentNode']); } $value = $this->htmlToXml($value, $context); } else { $value = $this->prepareTextValue($value); } }
return $value; }
/** * @param string $placeholder * @param array $values * @param array|null $fields * @return bool */ protected function isHyperlinkValue(string $placeholder, array $values, array $fields = null): bool { if(!$fields) { $fields = $this->fields; }
return ( array_key_exists($placeholder, $values) && isset($fields[$placeholder]['TYPE']) && ( $fields[$placeholder]['TYPE'] === DataProvider::FIELD_TYPE_HYPERLINK || $fields[$placeholder]['TYPE'] === DataProvider::FIELD_TYPE_STAMP ) ); }
/** * @return string */ protected function getBreakLineTag(): string { return '</w:t><w:br/><w:t>'; }
/** * @param $string * @return bool */ protected function isHtml($string): bool { return (preg_match('/<\s?[^\>]*\/?\s?>/i', $string) != false); }
/** * Converts html to xml with the same rendering. * * @param string $html * @param array $context * @return string */ protected function htmlToXml(string $html, array $context = []): string { $htmlDocument = new DOM\Document(); $htmlDocument->loadHTML($html); $result = $this->htmlNodeToXml($htmlDocument, $context); if(!empty($result)) { $result = '</w:t></w:r>'.$result.'<w:r><w:t>'; } return $result; }
/** * @param DOM\Node $node * @param array $properties * @return DOM\DisplayProperties */ protected function getDisplayProperties(DOM\Node $node, array $properties = []): DOM\DisplayProperties { return new DOM\DisplayProperties($node, $properties); }
/** * Recursively converts html node to xml. * * @param DOM\Node $node * @param array $context * @return string */ protected function htmlNodeToXml(DOM\Node $node, array &$context = []): string { $result = '';
$this->deleteLastBreakLineInBlockTag($node); $displayProperties = $this->getDisplayProperties($node);
if($displayProperties->isHidden()) { return $result; } $nodes = $node->getChildNodes(); $nodeName = mb_strtolower($node->getNodeName()); if($nodeName === 'ul') { $context['currentList'] = [ 'type' => static::NUMBERING_TYPE_UNORDERED, 'id' => $this->getRandomId('numberingValue', false), ]; } elseif($nodeName === 'ol') { $context['currentList'] = [ 'type' => static::NUMBERING_TYPE_ORDERED, 'id' => $this->getRandomId('numberingValue', false), ]; } elseif($nodeName === 'li') { $context['showNumber'] = true; }
if($displayProperties->isDisplayBlock()) { $context['display'] = DOM\DisplayProperties::DISPLAY_BLOCK; } if(!isset($context['font']) || !is_array($context['font'])) { $context['font'] = []; } $context['font'] = array_merge($context['font'], $displayProperties->getProperties()['font']); // The trick is in order we get tags. We have to carry $context all along. // First we have 'b' tag and then we have #text tag. But they are on the same level of hierarchy. // So we have to put 'bold font' into context and we need to know about it in the next tag. /** @var DOM\Node $childNode */ foreach($nodes as $childNode) { $nodeValue = str_replace("\n", '', $childNode->getNodeValue()); if($context['display'] === DOM\DisplayProperties::DISPLAY_BLOCK || $displayProperties->isDisplayBlock()) { $nodeValue = trim($nodeValue); } $childNodeName = mb_strtolower($childNode->getNodeName()); if($childNodeName === 'br') { $result .= '<w:r>'; $result .= '<w:br/>'; $result .= '</w:r>'; } elseif($childNode instanceof DOM\Text && !empty($nodeValue)) { if(isset($context['showNumber']) && isset($context['currentList'])) { $result .= '</w:p>'; $result .= '<w:p>'; $this->numberingIds[$context['currentList']['id']] = $context['currentList']; $result .= '<w:pPr>'; $result .= '<w:numPr>'; $result .= '<w:ilvl w:val="0" />'; $result .= '<w:numId w:val="'.$context['currentList']['id'].'" />'; $result .= '</w:numPr>'; $result .= '</w:pPr>'; unset($context['showNumber']); $context['display'] = $displayProperties->getProperties()[DOM\DisplayProperties::DISPLAY]; $result .= '<w:r>'; } elseif($context['display'] === DOM\DisplayProperties::DISPLAY_BLOCK) { $result .= '<w:r>'; $result .= '<w:br/>'; $context['display'] = $displayProperties->getProperties()[DOM\DisplayProperties::DISPLAY]; } else { $result .= '<w:r>'; } $result .= $this->addRowPropertiesTag($context); $result .= '<w:t xml:space="preserve">'; $result .= $this->prepareTextValue($nodeValue); $result .= '</w:t>'; $result .= '</w:r>'; } else { $result .= $this->htmlNodeToXml($childNode, $context); } }
if($nodeName === 'ul' || $nodeName === 'ol') { unset($context['currentList']); $result .= '</w:p>'; $result .= '<w:p>'; } elseif($nodeName === 'li') { unset($context['showNumber']); } $context['font'] = array_diff_assoc($context['font'], $displayProperties->getProperties()['font']);
return $result; } Все ли изменения я сделал и что еще нужно поменять в самом docxxml.php?И какой файл должен отвечать за передачу гиперссылок? БП мне генерирует ссылки вида: [url= |
|
|
|
15.09.2020 18:05:57
Александр Чувилёв, список поддерживаемых шрифтов небольшой. Какой-то дефолтный список, что входит в CentOS, подробнее не скажу.
Попробуйте поставить галочку "сохранить шрифт в файле" в шаблоне документа - возможно, поможет (а может и нет). |
|
|
|
11.10.2020 23:36:57
1. создаем пользовательское поле у сотрудника (тип файл): UF_CRM_SIGN 2. загрузить в него файл росписи сотрудника 3. в шаблоне использовать штатную картинку росписи директора 3. В событии onBeforeProcessDocument делаем подмену росписи директора росписью сотрудника.
|
|||||
|
|
12.12.2020 21:43:39
Антон Горбылев,
Пощупал своими руками, что такое создать документ docx без генератора документов. Действовал по следующему алгоритму: 1. Установил композер 2. Установил библиотеку phpword 3. Подключил файл autoload.php, который расположен в папке vendor, в файле init.php 4. Собственно по подготовленному раннее шаблону разобрал документ на текст и переменные и данные зависимые от переменных 5. В генераторе бизнес-процессов запустил действие "Произвольный PHP-код". Получил текущий бизнес-процесс. 6. Преобразовал данные и записал их в документ docx, после чего сохранил на сервере. Итого вышло 220 строк кода на 1-1,5 страницы документа в зависимости от количества данных(гиперссылок и строк, генерируемых в генераторе бп) и примерно 15 часов работы. Я не профессиональный разработчик php, поэтому код скорее всего можно оптимизировать, но сэкономить получится не более 30-40 строк кода. Вывод: генератор документов мощнейший инструмент, который позволяет создавать документы со скоростью в 10-15 раз быстрее, чем писать ручками, притом еще нужно понимать, что писать. Поэтому автору большой респект. И все-таки функционал гиперссылок очень нужен, хочется верить, что в ближайших релизах появится, а пока пользуемся PHPWord кому нужны, как и мне, гиперссылки из генератора бизнес-процессов. |
||||
|
|
|||