Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Insert bold text into tamplates #750

Closed
n-osennij opened this issue Mar 1, 2016 · 23 comments
Closed

Insert bold text into tamplates #750

n-osennij opened this issue Mar 1, 2016 · 23 comments

Comments

@n-osennij
Copy link

n-osennij commented Mar 1, 2016

So, I need to do the following:
I have a docx tamplate with table. I "cloneRow" her. And insert in cells data from mysql database (DB). And I need insert this data with some bold pieces. In the DB I keep the text without formatting, but I can insert some marks like ${bold}. BUT I need to do bold not all text.
For example, I have in my DB the following:

Some text in my database

And I need insert in template the following:

Some text in my database

In DB I can store text with marks, but how to do bold marked text? And what kind marks to use?

Help me please. It is very important for me!

@pv451
Copy link

pv451 commented Mar 5, 2016

If you need only bold text in the middle of plain text you can dirty hack this in TemplateProcessor.
Add to method setValueForPart this code
$replace = str_replace('&lt;B&gt;', '</w:t></w:r><w:r><w:rPr><w:b/></w:rPr><w:t xml:space="preserve"> ', $replace); $replace = str_replace('&lt;/B&gt;', '</w:t></w:r><w:r><w:t>', $replace);

And add to your text tag <B>. In your example it will be Some <B>text in my</B> database.

Even better put this code into setValue method.

@pv451
Copy link

pv451 commented Mar 6, 2016

Same trick but a little wider
while (strstr($replace,'&lt;FORMAT=')){ preg_match('/(&lt;FORMAT=([BIU]+)&gt;)/', $replace,$matches); $lrep = str_replace('<w:u/>','<w:u w:val="single"/>', preg_replace('/&gt;$/i', '</w:rPr><w:t xml:space="preserve">', preg_replace('/&lt;format=/i', '</w:t></w:r><w:r><w:rPr>', preg_replace('/(([BIU]))/i', '<w:\1/>', strtolower($matches[0])) ) ) ); $replace = str_replace($matches[0],$lrep, $replace); } $replace = str_replace('&lt;/FORMAT&gt;', '</w:t></w:r><w:r><w:t xml:space="preserve">', $replace);

And mark your code as Some <FORMAT=B>text in my</FORMAT> database.

Additionally you can use I and U markers.

Bt of course some kind of system solutin would be better.

@n-osennij
Copy link
Author

@pv451
in your first answer did you are talking about "protected function setValueForPart"

protected function setValueForPart($documentPartXML, $search, $replace, $limit)
    {
        if (substr($search, 0, 2) !== '${' && substr($search, -1) !== '}') {
            $search = '${' . $search . '}';
        }

        if (!SharedString::isUTF8($replace)) {
            $replace = utf8_encode($replace);
        }

        // Note: we can't use the same function for both cases here, because of performance considerations.
        if (self::MAXIMUM_REPLACEMENTS_DEFAULT === $limit) {
            return str_replace($search, $replace, $documentPartXML);
        } else {
            $regExpDelim = '/';
            $escapedSearch = preg_quote($search, $regExpDelim);
            return preg_replace("{$regExpDelim}{$escapedSearch}{$regExpDelim}u", $replace, $documentPartXML, $limit);
        }

    }

In which plase i need to insert your fix-code?

@pv451
Copy link

pv451 commented Mar 27, 2016

Actually i corrected myself, and said that setValue would be better place

public function setValue($macro, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT)
{

    if (substr($macro, 0, 2) !== '${' && substr($macro, -1) !== '}') {
        $macro = '${' . $macro . '}';
    }       

    if (!String::isUTF8($replace)) {
        $replace = utf8_encode($replace);
    }

    $replace = preg_replace('~(*BSR_ANYCRLF)\R~', '<w:br/>', $replace); // 05.03.2016 making multiline insertion

    $replace = str_replace('&lt;B&gt;', '</w:t></w:r><w:r><w:rPr><w:b/></w:rPr><w:t xml:space="preserve">', $replace);
    $replace = str_replace('&lt;/B&gt;', '</w:t></w:r><w:r><w:t xml:space="preserve">', $replace);
    foreach ($this->tempDocumentHeaders as $index => $headerXML) {
        $this->tempDocumentHeaders[$index] = $this->setValueForPart($this->tempDocumentHeaders[$index], $macro, $replace, $limit);
    }

    $this->tempDocumentMainPart = $this->setValueForPart($this->tempDocumentMainPart, $macro, $replace, $limit);

    foreach ($this->tempDocumentFooters as $index => $headerXML) {
        $this->tempDocumentFooters[$index] = $this->setValueForPart($this->tempDocumentFooters[$index], $macro, $replace, $limit);
    }
}

@n-osennij
Copy link
Author

@pv451
in my TemplateProcessor public function setValue and protected function setValueForPart it is a different sunctions. In your code both functions are integrated into one.

My fuctions:

public function setValue($macro, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT)
    {

        foreach ($this->tempDocumentHeaders as $index => $headerXML) {
            $this->tempDocumentHeaders[$index] = $this->setValueForPart($this->tempDocumentHeaders[$index], $macro, $replace, $limit);
        }

        $this->tempDocumentMainPart = $this->setValueForPart($this->tempDocumentMainPart, $macro, $replace, $limit);

        foreach ($this->tempDocumentFooters as $index => $headerXML) {
            $this->tempDocumentFooters[$index] = $this->setValueForPart($this->tempDocumentFooters[$index], $macro, $replace, $limit);
        }
    }
 protected function setValueForPart($documentPartXML, $search, $replace, $limit)
    {
        if (substr($search, 0, 2) !== '${' && substr($search, -1) !== '}') {
            $search = '${' . $search . '}';
        }

        if (!SharedString::isUTF8($replace)) {
            $replace = utf8_encode($replace);
        }

        // Note: we can't use the same function for both cases here, because of performance considerations.
        if (self::MAXIMUM_REPLACEMENTS_DEFAULT === $limit) {
            return str_replace($search, $replace, $documentPartXML);
        } else {
            $regExpDelim = '/';
            $escapedSearch = preg_quote($search, $regExpDelim);
            return preg_replace("{$regExpDelim}{$escapedSearch}{$regExpDelim}u", $replace, $documentPartXML, $limit);
        }
        $replace = str_replace('&lt;B&gt;', '</w:t></w:r><w:r><w:rPr><w:b/></w:rPr><w:t xml:space="preserve"> ', $replace); 
        $replace = str_replace('&lt;/B&gt;', '</w:t></w:r><w:r><w:t>', $replace);

    }

I try to change my "setValue" function by yours. But I have an err in my word document - the document is damaged.

I try to insert 2 rows (see below) into setValueForPart and setValue

$replace = str_replace('&lt;B&gt;', '</w:t></w:r><w:r><w:rPr><w:b/></w:rPr><w:t xml:space="preserve"> ', $replace); 
$replace = str_replace('&lt;/B&gt;', '</w:t></w:r><w:r><w:t>', $replace);

But my document damaged.

So, wat can I do? Perhaps you can send me yours TemplateProcessor.php file?

@n-osennij
Copy link
Author

I accidentally closed the discussion.

@n-osennij n-osennij reopened this Mar 28, 2016
@pv451
Copy link

pv451 commented Mar 28, 2016

Yep. it's diffrent functions in my class too.
First of all what version of PHPWord do you use? I'm patching current master version. This is my TemplateProcessor, but i`m using second variant now.

TemplateProcessor.zip

@n-osennij
Copy link
Author

I use special version fore php7 (there was a problem with String, because 'String' is a special class name)

So your file is not fore my(

@pv451
Copy link

pv451 commented Mar 28, 2016

Actually if you diff them there not so many changes.
Just replace use PhpOffice\PhpWord\Shared\String; to use PhpOffice\PhpWord\Shared\SharedString; and all should work.

I mean replace it in my file.

@n-osennij
Copy link
Author

@pv451
i do it. But I replace too:

        if (!String::isUTF8($replace)) {
            $replace = utf8_encode($replace);
        }

to

        if (!SharedString::isUTF8($replace)) {
            $replace = utf8_encode($replace);
        }

php work. But I have bad docx file - the document is damaged.

@n-osennij
Copy link
Author

@pv451
i try to do:

require_once 'PhpWord/Autoloader.php';
\PhpOffice\PhpWord\Autoloader::register();
$phpWord = new \PhpOffice\PhpWord\PhpWord();

$template_path="templates/protocol/test.docx";
$document_name="protocol_"; 
$save_path="";
$template = $phpWord->loadTemplate(realpath($template_path));

$st="djkfjkdjfsdkf <B>FFFFFdsf</B> dfgdgdgdgdf.";
$template->setValue('st', $st);

$sample_number="df";
$file_name = str_replace(" ", "", $document_name.$sample_number) . '.docx';
$file =$save_path.$file_name;
$template->saveAS($file);

in word document test.docx I insert ${st}

@pv451
Copy link

pv451 commented Mar 28, 2016

Attach your modified templateprocessor

@n-osennij
Copy link
Author

@pv451
I modified only rows 23 and 152-154
TemplateProcessor.zip

@pv451
Copy link

pv451 commented Mar 28, 2016

You are using second version of my "patch" use <FORMAT=B>some text</FORMAT> in your code to get bold text.

@n-osennij
Copy link
Author

@pv451
without changes - the document is damaged.
Maybe my phpword is outdated. Where can I download the current version of phpword for php7?
And I will try all over again.

@pv451
Copy link

pv451 commented Mar 28, 2016

Try develop branch. As I see there is no issue with String or SharedString. It replaced with
use Zend\Stdlib\StringUtils;

@n-osennij
Copy link
Author

@pv451
There are no Autoloader.php in develop branch...

I copy it from my old phpword

there is a zip file with develop branch phpword, my php file and docx tamplate (in PhpWord folder). And i insert into TemplateProcessor.php your code.

The document is still damaged...

test.zip

@pv451
Copy link

pv451 commented Mar 28, 2016

Yep, it seems that develop branch can only be installed over composer.
Here is your test case gathered in my env. it works, but it seems that you have some problems with template itself. try disable spellchecker in your word instance before you start preparing template.
test.zip

@n-osennij
Copy link
Author

@pv451
your code gave me the idea
in my test.php file I have
$template->setValue('st', $st);
In your code:
$template->setValue('st', htmlspecialchars($st));

So, i replace my code to yours and it is work!)
Thus, it works on the old code (not the develop branch) with 1 change - this line. I'm not try disable spellchecker.

Thank you very much!!!

@n-osennij
Copy link
Author

n-osennij commented Jun 27, 2016

@pv451
Hi again!) Your code wors grate! But I have only one problem - it cuts spaces.
Fore example:

$st="Some text. <FORMAT=B>Some text</FORMAT>. Some text.";
$template->setValue('st', htmlspecialchars($st));

I expect:
Some text. Some text. Some text.

But I have next text without spaces:
Some text.Some text.Some text.

How can I fix it?

@n-osennij n-osennij reopened this Jun 27, 2016
@rafabarbosa
Copy link

static public function b($str, $hex=null, $style=''){
$cor = $hex ? "<w:color w:val='".$hex."'/>" : "";
$before="/w:t/w:r<w:r><w:rPr>".$cor."<w:".$style."/>/w:rPr<w:t xml:space='preserve'>";
$after='/w:t/w:r<w:r><w:t>';
return $before.$str.$after;
}

Maybe this helps you.
I solved my problem about on this situation with this code.

@troosan troosan closed this as completed Sep 11, 2017
@theenescresta
Copy link

Can we change fonts like this?

@HugoCaulfield
Copy link

HugoCaulfield commented Apr 26, 2021

How I solved it:

PhpWord/TemplateProcessor.php
In the function public function setValue
$replace = str_replace('&lt;B&gt;', '</w:t></w:r><w:r><w:rPr><w:b/></w:rPr><w:t xml:space="preserve"> ', $replace); $replace = str_replace('&lt;/B&gt;', '</w:t></w:r><w:r><w:t xml:space="preserve">', $replace);

And finally

$templateProcessor->setValue('artist', htmlspecialchars("Some <B>text in my</B> database."));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

6 participants