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

CloneRow to include multiple rows #283

Open
cyrillkalita opened this issue Jun 18, 2014 · 7 comments
Open

CloneRow to include multiple rows #283

cyrillkalita opened this issue Jun 18, 2014 · 7 comments

Comments

@cyrillkalita
Copy link

cyrillkalita commented Jun 18, 2014

Would it be to much to suggest an update for Tempalte/cloneRow function to include the third parameter, $search_end, null by default, that would serve as the value to look up to close the row?

if null, it is then made equal to the $search and update the functions that look up closing w:tr tag by the $search_end - thus allowing cloning multiple rows at a time?


Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

@ivanlanin ivanlanin added this to the 0.12.0 milestone Jun 18, 2014
@ivanlanin
Copy link
Contributor

Hi @cyrillkalita. Feel free to fork PHPWord and make any changes to the code as required by your project. You can also request a pull request if you think your enhancement will be useful for other users. To be integrated into the develop branch of PHPWord, we will review your changes because we need to make sure that the changes fit well with the rest of the code. cc: @RomanSyroeshko.

@ghost
Copy link

ghost commented Jun 19, 2014

As for me, I clone rows with XSLT. :)

@flohmueller
Copy link

phpword_clonetable
A little late, but maybe this will help (or would have helped).. it's a cloneTable function to clone a complete table. Nested tables should be supported as well, though i'm not 100% sure if my algorithm to look for the corresponding end tag of the table is correct...
Sorry that I'm too lazy to make a real contribution, but maybe someone working on the Template.php can add and verify that stuff !?

//Template.php
    public function cloneTable($search, $numberOfClones) {
        if (substr($search, 0, 2) !== '${' && substr($search, -1) !== '}') {
            $search = '${' . $search . '}';
        }

        $tagPos = strpos($this->documentXML, $search);
        if (!$tagPos) {
            throw new Exception("Can not clone table, template variable not found or variable contains markup.");
        }

        $tableStart = $this->findTableStart($tagPos);
        $tableEnd = $this->findTableEnd($tagPos);

        // nested table logic: find correct end tag position 
        $openings = 0;
        $tableStartNext = $this->findTableStart($tableStart + 1, true);
        while($tableStartNext !== false && $tableStartNext < $tableEnd) {
            $openings++;
            $tableStartNext = $this->findTableStart($tableStartNext + 1, true);
            while($openings > 0 &&  ($tableStartNext === false || $tableEnd < $tableStartNext)) {
                $openings--;
                $tableEnd = $this->findTableEnd($tableEnd + 1);
            }
        } // /nested table logic end

        $xmlRow = $this->getSlice($tableStart, $tableEnd);

        $result = $this->getSlice(0, $tableStart);
        for ($i = 1; $i <= $numberOfClones; $i++) {
            $result .= preg_replace('/\$\{(.*?)\}/', '\${\\1#' . $i . '}', $xmlRow);
        }
        $result .= $this->getSlice($tableEnd);

        $this->documentXML = $result;
    }

    private function findTableStart($offset, $forward = false)
    {
        // beware: strpos != strrpos
        if($forward) {
            $tableStart = strpos($this->documentXML, "<w:tbl ", $offset);
            if (!$tableStart) {
                $tableStart = strpos($this->documentXML, "<w:tbl>", $offset);
            }
        } else {
            $tableStart = strrpos($this->documentXML, "<w:tbl ", ((strlen($this->documentXML) - $offset) * -1));
            if (!$tableStart) {
                $tableStart = strrpos($this->documentXML, "<w:tbl>", ((strlen($this->documentXML) - $offset) * -1));
            }
            if (!$tableStart) {
                throw new Exception("Can not find the start position of the row to clone.");
            }
        }
        return $tableStart;
    }

    private function findTableEnd($offset)
    {   
        $tableEnd = strpos($this->documentXML, "</w:tbl>", $offset) + 8;
        return $tableEnd;
    }

And there's also a little proof of concept (done with PHPWord-0.11.1).. see the screenshot for a comparison of the template (left) and the resulting docx (right). The "${h1_bug_table}"-Tag cannot be seen, it has a font-size of 1, sits in the upper left table cell, will be replaced by an empty string and was only added to the template to find the table.

$t_bug_count = 3;
$document->cloneTable('h1_bug_table', $t_bug_count);
for ($i = 1; $i <= $t_bug_count; $i++) {
    $document->setValue('h1_bug_table#' . $i, '');
    $document->setValue('h1_bug#' . $i, 'Bug header 2 #' . $i);
    $document->setValue('h1_bug_id#' . $i, 'Bug ID #' . $i);
    $document->setValue('h1_bug_type#' . $i, 'Bug Type #' . $i);
    $document->setValue('h1_bug_summary#' . $i, 'Bug Summary #' . $i);

    $document->cloneTable('h1_inner3#' . $i, 2);
    for ($j = 1; $j <= 2; $j++) {
        $document->setValue('h1_inner3#' . $i . '#' . $j, 'inner3 #' . $i . '#' . $j);

        $document->cloneRow('h1_inner31#' .$i.'#'.$j, 2);
        for ($k = 1; $k <= 2; $k++) {
            $document->setValue('h1_inner31#' .$i.'#'.$j.'#'.$k, 'inner31 #' .$i.'#'.$j.'#'.$k);
        }
    }
}

@ghost ghost modified the milestones: 0.13.0, 0.12.0 Jan 3, 2015
@ghost ghost removed this from the v0.13.0 milestone Jul 30, 2016
@FBnil
Copy link

FBnil commented Sep 26, 2017

@flohmueller That is a nice table function, however, a table (or any other object) can be cloned with cloneBlock(), so there is no need for a specialized function

@jeffsrepoaccount
Copy link

jeffsrepoaccount commented Nov 16, 2017

@FBnil Cloning a block only allows a single replacement, so if you have a table that has multiple replacements in it then a way to iterate over the cloned tables and replace all of the different placeholders is necessary. See #1071

FYI, the additions by @flohmueller still seem to work, after replacing $this->documentXML with $this->tempDocumentMainPart

@FBnil
Copy link

FBnil commented Nov 16, 2017

@jeffsrepoaccount Ah, yes, next version (0.15.0) will have enumeration, thus all macro's in your cloned block will have #1 or #2 (if it's the second cloned block) ... etc appended to them. This way you can setValue() without problems.

@github-actions
Copy link

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
If this is still an issue for you, please try to help by debugging it further and sharing your results.
Thank you for your contributions.

@github-actions github-actions bot added the Stale label Nov 18, 2022
@Progi1984 Progi1984 removed the Stale label Nov 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

6 participants