PHPOffice / PHPWord

A pure PHP library for reading and writing word processing documents
https://phpoffice.github.io/PHPWord/
Other
7.25k stars 2.69k forks source link

addText() function and text formatting (new line "\n") #553

Open simogeo opened 9 years ago

simogeo commented 9 years ago

Hi,

I have a problem regarding formatting text. Actually, it seems, all \n are not interpreted when opening file with Word 2007. Here are some screenshots :

This is how it appears in LibreOffice : lo

And how it (sadly) appears in Word 2007 :

w2007

ANy help would be welcome ! I use last stable version - 0.12.0. Thanks !

--- Want to back this issue? **[Post a bounty on it!](https://www.bountysource.com/issues/21688412-addtext-function-and-text-formatting-new-line-n?utm_campaign=plugin&utm_content=tracker%2F323108&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F323108&utm_medium=issues&utm_source=github).
RKaczmarek commented 9 years ago

Hi,

you maybe misunderstood how phpword works.

addText is for adding a paragraph with text. The text is not seperated by line breaks. If you would like to add line breaks then use addTextRun.

With a textrun you can add text and textbreaks within one paragraph.

$text = "foo\nbar\nfoobar";
$textlines = explode("\n", $text);

$textrun = $section->addTextRun();
$textrun->addText(array_shift($textlines));
foreach($textlines as $line) {
    $textrun->addTextBreak();
    // maybe twice if you want to seperate the text
    // $textrun->addTextBreak(2);
    $textrun->addText($line);
}
simogeo commented 9 years ago

Thanks for your interest on that. But why not an optional parameter for commodity ? here is my proposed idea (not sure it works since it is not tested)

morrido commented 9 years ago

How to apply this in the template? e.g.: $templateProcessor->setValue....

cbloss commented 9 years ago

I second morrido. How do you do it in a template?

Motchouk commented 8 years ago

$text = "foo\nbar\nfoobar"; $textlines = explode("\n", $text);

$textrun = $section->addTextRun(); $textrun->addText(array_shift($textlines)); foreach($textlines as $line) { $textrun->addTextBreak(); // maybe twice if you want to seperate the text // $textrun->addTextBreak(2); $textrun->addText($line); }

This also works (I just used it) :

$text = "foo\nbar\nfoobar";
$textlines = explode("\n", $text);

for ($i = 0; $i < sizeof($textlines); $i++) {
    $section->addText($textlines[$i]);
}
feakuru commented 7 years ago

I, just like @morrido and @cbloss here, would like to know if this is usable in a template. Please answer. Thx in advance

Dvlv commented 7 years ago

@feakuru @morrido @cbloss Looks for me like <w:br /> is interpreted as a newline in proper Word. In libreoffice it just looks like a space (was frustrating me).

so e.g.

$templateProcessor->setValue(name_address, 'John <w:br /> 123 fake street');

BafS commented 7 years ago

I used "\n" and then the regex $text = preg_replace('~\R~u', '</w:t><w:br/><w:t>', $text);.

geigel commented 7 years ago

Awesome @RKaczmarek, exactly what I needed. Thank you. The solution works for addListItemRuns as well as that is what I was using.

guenter47 commented 6 years ago

@RKaczmarek & @BafS in my case: $text='aaa\nbbb' $text = preg_replace('~\R~u', '</w:t>', $text); $templateProcessor->setValue('sp'.$i.'z1#'.$j,$text);

write in word: 'aaa\nbbb'

simogeo commented 6 years ago

replace simple quotes by double quotes :

$text="aaa\nbbb"

nacesprin commented 5 years ago

@feakuru @morrido @cbloss Looks for me like <w:br /> is interpreted as a newline in proper Word. In libreoffice it just looks like a space (was frustrating me).

so e.g.

$templateProcessor->setValue(name_address, 'John <w:br /> 123 fake street');

https://github.com/PHPOffice/PHPWord/issues/838

joaodos3v commented 5 years ago

@feakuru @morrido @cbloss Looks for me like <w:br /> is interpreted as a newline in proper Word. In libreoffice it just looks like a space (was frustrating me).

so e.g.

$templateProcessor->setValue(name_address, 'John <w:br /> 123 fake street');

As @BafS answered, add \n to the text you want to format, like this: $templateProcessor->setValue("value_to_change", "value\nthat _will_replace");

After that, go to your TemplateProcessor.php file and find the setValueForPart($ search, $ replace, $ documentPartXML, $ limit). In the first line of this function, add: $replace = preg_replace('~\R~u', '</w:t><w:br/><w:t>', $replace);

This worked perfectly for me in LibreOffice and Word. I hope this helps someone.

Francesco-Manicardi commented 3 years ago

Here's the true answer to "How to add newline while template processing"

You can't just replace \n with </w:t><w:br/><w:t> because that will BREAK PARAGRAPHS. This means that tab stops that have been set on the placeholder will not carry over to the next line!

The real solution is to always use a complex type instead of using strings.

So in my function instead of returning a string I do this:

            $res = "some text\n with\n newlines\tand\ttabs
            $textlines = explode("\n", $res);
            $textrun = new PhpOffice\PhpWord\Element\TextRun();
            $textrun->addText(array_shift($textlines));
            foreach ($textlines as $line) {
                $textrun->addTextBreak();
                $textrun->addText($line);
            }
            return $textrun;

and in the template processor driver I use:

$templateProcessor->setComplexValue($key, $textrun);

this will result in newlines and tab stops and other paragraph related things are preserved in the next lines!

This allows you to create basic tables with tab stops and not worry about them breaking after the new lines.

jjdejong commented 3 years ago

setComplexValue($key, $textrun) throws an error when there are multiple lines. Apparently setComplexBlock($key, $textrun) should be used instead, but that deletes all the other text present in the same line.

Francesco-Manicardi commented 3 years ago

setComplexValue($key, $textrun) throws an error when there are multiple lines.

What is the error thrown? I'm using it in production right now and I'm not having any problems. Also, it looks like setComplexValue also deletes all other text in the same line.

jjdejong commented 3 years ago

I get "Trying to access array offset on value of type bool" in line 277 of TemplateProcessor.php.

So if the "Value" flavor also deletes all other text, what's the difference between the "Value" and "Block" flavors ?

jjdejong commented 3 years ago

I'll take that back, the "Value" flavor does work in most cases, but there is just one situation in my application where it throws the error. I need to find out still.

Francesco-Manicardi commented 3 years ago

That's the same error I have, but in PhpSpreadsheet instead. Let me know if you get to the root of it, i still haven't understood what causes it. My solutino was just putting everything in a try catch block and call it a day

jjdejong commented 3 years ago

Also, it looks like setComplexValue also deletes all other text in the same line.

Are you sure ? Not in my case. That would be the difference between the Block and Value flavors.

Francesco-Manicardi commented 3 years ago

Yes, i have a .docx template like this: image

As you can see there's content to the right of the placeholder. when i call setComplexValue with a textRun, that text gets deleted this is the result of the setComplexValue image

jjdejong commented 3 years ago

As you can see there's content to the right of the placeholder. when i call setComplexValue with a textRun, that text gets deleted this is the result of the setComplexValue

Ah, in my case it's text on the left that is preserved.

jjdejong commented 3 years ago

That's the same error I have, but in PhpSpreadsheet instead. Let me know if you get to the root of it, i still haven't understood what causes it. My solution was just putting everything in a try catch block and call it a day

This happens when the ${macro} is not present in the template. Maybe a bug, because this should not generate an error.

geigel commented 3 years ago

@jjdejong @Pocciox what versions of PHP are you using?

Francesco-Manicardi commented 3 years ago

I am using version 7.4 :)

Il mer 13 gen 2021, 13:22 Art Geigel notifications@github.com ha scritto:

@jjdejong https://github.com/jjdejong @Pocciox https://github.com/Pocciox what versions of PHP are you using?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/PHPOffice/PHPWord/issues/553#issuecomment-759413944, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHXWIFVLYIQIUYW6PVF3AWDSZWGBTANCNFSM4BIEI6LA .

jjdejong commented 3 years ago

7.4 too

damienfa commented 3 years ago

I'm on 7.4 too. I agree with @jjdejong , in my case the text on the left is well preserved when I use setComplexValue instead of setComplexBlock (this last one deletes all the content which already exists in the paragraph where the macro is applied).