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

Setting Specific Table Column Width #2571

Open
BrendonKoz opened this issue Feb 15, 2024 · 0 comments
Open

Setting Specific Table Column Width #2571

BrendonKoz opened this issue Feb 15, 2024 · 0 comments

Comments

@BrendonKoz
Copy link

BrendonKoz commented Feb 15, 2024

Describe the Bug

The last version I had used (v0.18) prior to the current release, seemed to handle the creation of columns (for/in Microsoft Word) that, based on the twip, seemed to correlate to the appropriate inches (via internal Microsoft Word ruler) when rendered. I only needed to assign a width to a single cell within the row for the column (as shown below, this is the TIME column), and the other columns would auto-fit the content.

For version 1.2.0, this functionality has seemingly regressed for rendering in Microsoft Word (2016). LibreOffice appears to render better, but still incorrectly. I believe this is because PhpWord is now explicitly assigning column sizes in the document.xml file.

image
Microsoft Word 2016 on PhpWord v0.18

image
Libre Office v24.2.0.3 on PhpWord v0.18

image
Microsoft Word 2016 on PhpWord v1.2.0

image
Libre Office v24.2.0.3 on PhpWord 1.2.0

In trying to track down the rendering differences between versions, I examined the uncompressed XML files to try to identify differences. The most glaring was in word/document.xml in the w:tblGrid definition. In version 0.18 the widths were only defined for the columns explicitly provided via PhpWord code/style, the other columns had no width attribute. This, however, had a detrimental impact on LibreOffice Writer. The updates may have caused a different result in rendering, and an unexpected one, but at least the rendering is the same in both editors. That said, attempting to modify the column width attributes and recompressing to a DOCX file did not provide any level of correction, so there must be a few other places where widths are defined.

For reference, in v0.18, the column's Preferred Width in Microsoft Word was defined as 1.39". For v1.2.0, it is still reporting a Preferred Width of 1.39"...but is very obviously being prevented from rendering that way, from something else.

Steps to Reproduce

Please provide a code sample that reproduces the issue.

<?php

require __DIR__.'/vendor/autoload.php';

// ... the FUN stuff !!!
$doc = new \PhpOffice\PhpWord\PhpWord();
\PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true);
$paper = new \PhpOffice\PhpWord\Style\Paper();
$paper->setSize('Letter');

// Set Styles
$sectionStyle = array(
    'marginTop'    => \PhpOffice\PhpWord\Shared\Converter::inchToTwip(.25),
    'marginRight'  => \PhpOffice\PhpWord\Shared\Converter::inchToTwip(.5),
    'marginBottom' => \PhpOffice\PhpWord\Shared\Converter::inchToTwip(.25),
    'marginLeft'   => \PhpOffice\PhpWord\Shared\Converter::inchToTwip(.5),
    'pageSizeW'    => $paper->getWidth(),
    'pageSizeH'    => $paper->getHeight()
);
$section = $doc->addSection($sectionStyle);
$header  = $section->addHeader();
$footer  = $section->addFooter();
$footer->addPreserveText('{PAGE} of {NUMPAGES}', null, array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER));
$tableStyle = array(
    'width'       => 100 * 50, // Word 2007 table width, in percentages, is measured in 50ths of a percent
    'unit'        => 'pct',
    'alignment'   => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER,
    'borderSize'  => 5,
    'borderColor' => '333333',
    'cellMargin'  => 60,
);
$doc->addTableStyle('reportTable', $tableStyle);
$dayCellStyle = array(
    'bgColor'     => '333333',
    'valign'      => 'center',
    'gridSpan'    => 5
);
$columnHeaderStyle = array(
    'bgColor'     => 'E1E1E1',
    'valign'      => 'center'
);
$columnTimeHeaderStyle = array(
    'bgColor'     => 'E1E1E1',
    'valign'      => 'center',
    'width'       => 2000
);
$dayCellTextStyle = 'dayCellTextStyle';
$doc->addFontStyle(
    $dayCellTextStyle, array(
        'size'       => 15,
        'bold'       => true,
        'align'      => 'center',
        'spaceAfter' => 0
    )
);
$stdCellStyle = array('valign' => 'center');
$stdCellTextStyle = 'stdCellTextStyle';
$doc->addFontStyle(
    $stdCellTextStyle, array(
        'size'       => 12,
        'align'      => 'center',
        'spaceAfter' => 0
    )
);
$boldCellTextStyle = 'boldCellTextStyle';
$doc->addFontStyle(
    $boldCellTextStyle, array(
        'size'       => 12,
        'align'      => 'center',
        'spaceAfter' => 0,
        'bold'       => true
    )
);
$columnHeaderTextStyle = 'columnHeaderTextStyle';
$doc->addFontStyle(
    $columnHeaderTextStyle, array(
        'size'       => 12,
        'bold'       => true,
        'allCaps'    => true,
        'align'      => 'center',
        'spaceAfter' => 0
    )
);
$paragraphStyle = array(
    'align' => 'center',
    'spaceAfter' => 0
);

// Create the table
$table = $section->addTable($tableStyle);
$table->addRow(null, array('tblHeader' => true));
$table->addCell(null, $dayCellStyle)->addText(date('l, n/j/Y', time()), $dayCellTextStyle, $paragraphStyle);

$table->addRow(null, array('tblHeader' => true));
// TABLE COLUMN HEADERS: | Location | Time | Event | Owner | Setup |
$table->addCell(null, $columnHeaderStyle)->addText('Location',     $columnHeaderTextStyle, $paragraphStyle);
$table->addCell(2000, $columnTimeHeaderStyle)->addText('Time',     $columnHeaderTextStyle, $paragraphStyle);
$table->addCell(null, $columnHeaderStyle)->addText('Event',        $columnHeaderTextStyle, $paragraphStyle);
$table->addCell(null, $columnHeaderStyle)->addText('Contact',      $columnHeaderTextStyle, $paragraphStyle);
$table->addCell(null, $columnHeaderStyle)->addText('Setup / Info', $columnHeaderTextStyle, $paragraphStyle);

$rooms = [
    'Community Room' => [
        1696366800 => [
            'booking_id' => 'cs_o7xaaBsJ',
            'owner' => 'User #1',
            'event' => 'Paint with Patrice Workshop',
            'open' => 1696366800,
            'close' => 1696379400,
            'event_id' => 10902028,
            'start' => 1696370400,
            'end' => 1696377600,
            'equipment' => 'Square Folding Table #4, Square Folding Table #3, Square Folding Table #2, Square Folding Table #1, Microphone (Cordless) #1',
            'setup' => '',
            'notes' => ''
        ],
        '1696352400' => [
            'booking_id' => 'cs_a55vjKS2',
            'owner' => 'User #2',
            'event' => 'Tech Run Through for Caffe Lena Presents 60 Years of Banned Books',
            'open' => 1696352400,
            'close' => 1696356000,
            'event_id' => 11086161,
            'start' => 1696352400,
            'end' => 1696356000,
            'equipment' => '',
            'setup' => '',
            'notes' => ''
        ],
        '1696341600' => [
            'booking_id' => 'cs_K2VPwAtp',
            'owner' => 'User #2',
            'event' => 'Mah Jongg Class',
            'open' => 1696341600,
            'close' => 1696347000,
            'event_id' => 10608804,
            'start' => 1696341600,
            'end' => 1696347000,
            'equipment' => '',
            'setup' => 'Set up 5 square tables with 4 chairs each.',
            'notes' => ''
        ]
    ]
];

foreach ($rooms as $room => $booking) {
    ksort($booking);

    $firstRow = true;
    foreach ($booking as $open => $data) {
        $table->addRow(null, array('cantSplit' => true));

        // Add the first cell (room name)
        if (count($booking) > 1) {
            if ($firstRow) {
                $vMergeCellStyle = array_merge($stdCellStyle, array('vMerge' => 'restart'));
                $table->addCell(null, $vMergeCellStyle)->addText($room, $stdCellTextStyle, $paragraphStyle);
                $firstRow = false;
            } else {
                $table->addCell(null, array('vMerge' => 'continue'));
            }
        } else {
            $table->addCell(null, $stdCellStyle)->addText($room, $stdCellTextStyle, $paragraphStyle);
        }

        // Add the remaining cells
        // TIME
        if ($data['start']) {
            $timeCell = $table->addCell(null, $stdCellStyle);
            $timeCellText = $timeCell->addTextRun($paragraphStyle);
            $timeCellText->addText('RESERVED:', $boldCellTextStyle);
            $timeCellText->addTextBreak();
            $timeCellText->addText(date('g:ia', $data['open']) . '-' . date('g:ia', $data['close']), $stdCellTextStyle);
            $timeCellText->addTextBreak();
            $timeCellText->addText('EVENT:', $boldCellTextStyle);
            $timeCellText->addTextBreak();
            $timeCellText->addText(date('g:ia', $data['start']) . '-' . date('g:ia', $data['end']), $stdCellTextStyle);
        } else {
            $table->addCell(null, $stdCellStyle)->addText(date('g:ia', $data['open']) . '-' . date('g:ia', $data['close']), $stdCellTextStyle, $paragraphStyle);
        }
        // EVENT
        $table->addCell(null, $stdCellStyle)->addText($data['event'], $stdCellTextStyle, $paragraphStyle);
        // OWNER
        $table->addCell(null, $stdCellStyle)->addText($data['owner'], $stdCellTextStyle, $paragraphStyle);
        // SETUP (Equipment, Setup, and/or Notes)
        $setupCell = $table->addCell(null, $stdCellStyle);
        $setupCellText = $setupCell->addTextRun($paragraphStyle);
        if ($data['equipment']) {
            $setupCellText->addText('EQUIPMENT: ', $boldCellTextStyle);
            $setupCellText->addText($data['equipment'], $stdCellTextStyle);
            if ($data['setup']) {
                $setupCellText->addTextBreak();
            }
        }
        if ($data['setup']) {
            $setup = explode("\n", $data['setup']);
            $setupCellText->addText('SETUP: ', $boldCellTextStyle);
            foreach ($setup as $index => $line) {
                if ($index !== 0) {
                    $setupCellText->addTextBreak();
                }
                $setupCellText->addText($line, $stdCellTextStyle);
            }
        }
        if ($data['notes']) {
            $setup = explode("\n", $data['notes']);
            $text = $data['equipment'] ? ' NOTES: ' : 'NOTES: ';
            $setupCellText->addText($text, $boldCellTextStyle);
            foreach ($setup as $index => $line) {
                if ($index !== 0) {
                    $setupCellText->addTextBreak();
                }
                $setupCellText->addText($line, $stdCellTextStyle);
            }
        }

    }
}

// Set the header information based on data accumulated above
$room_text = 'Header Text';
$week_text = 'Week Text';
$header->addText($room_text . "\n", array('size' => 11), $paragraphStyle);
$header->addText($week_text, array('size' => 11, 'bold' => true), array('align' => 'center'));

// Configure metadata
$metadata = $doc->getDocInfo();
$metadata->setCreator('BrendonKoz');
$metadata->setTitle('PHPWord Test');
$metadata->setDescription('Rendered test document');
$metadata->setCreated(time());
$metadata->setModified(time());

// Create the Word Doc
header("Content-Description: File Transfer");
header('Content-Disposition: attachment; filename="Untitled.docx"');
header('Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document');
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Expires: 0');
$xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($doc, 'Word2007');
$xmlWriter->save("php://output");

Expected Behavior

The expectation was that the 2000 twip units on the TIME column would've been set to the converted 1.39" column width, and the other columns would've auto-fit.

Current Behavior

The preferred width is set, but it seems that the other columns are overriding widths in some sort of calculated width...

Context

Please fill in your environment information:

  • PHP Version: 8.2
  • PHPWord Version: 1.2.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

1 participant