{"id":23366848,"url":"https://github.com/voilab/tctable","last_synced_at":"2025-06-23T00:05:03.463Z","repository":{"id":29192777,"uuid":"32723882","full_name":"voilab/tctable","owner":"voilab","description":"Create quickly and efficiently TCPDF tables with advanced page break options and memory optimization","archived":false,"fork":false,"pushed_at":"2023-01-13T12:06:56.000Z","size":93,"stargazers_count":5,"open_issues_count":3,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-10T14:16:22.345Z","etag":null,"topics":["php","table","tcpdf"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/voilab.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-03-23T09:57:45.000Z","updated_at":"2020-04-23T09:25:13.000Z","dependencies_parsed_at":"2023-01-14T14:20:09.374Z","dependency_job_id":null,"html_url":"https://github.com/voilab/tctable","commit_stats":null,"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/voilab/tctable","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voilab%2Ftctable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voilab%2Ftctable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voilab%2Ftctable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voilab%2Ftctable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/voilab","download_url":"https://codeload.github.com/voilab/tctable/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voilab%2Ftctable/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261386724,"owners_count":23150869,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["php","table","tcpdf"],"created_at":"2024-12-21T14:18:52.963Z","updated_at":"2025-06-23T00:04:58.426Z","avatar_url":"https://github.com/voilab.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Voilab TcTable for TCPDF\n\n## Install\n\nVia Composer\n\nCreate a composer.json file in your project root:\n``` json\n{\n    \"require\": {\n        \"voilab/tctable\": \"1.*\"\n    }\n}\n```\n\n``` bash\n$ composer require voilab/tctable\n```\n\n## Usage\nThe goal of this library is not to replace a complex HTML table with row and\ncell spans. It's mainly useful if you want to display loads of lines (for an\ninvoice, etc.) and be sure page breaks are in the right place. You can adapt\nthe number of widow lines (minimum of lines that must appear on the last page),\nand use plugins to customize the flow (see below).\n\n###  Basic usage\n```php\n$pdf = new \\TCPDF();\n$minRowHeight = 6; //mm\n\n$tctable = new \\voilab\\tctable\\TcTable($pdf, $minRowHeight);\n$tctable-\u003esetColumns([\n    'description' =\u003e [\n        'isMultiLine' =\u003e true,\n        'header' =\u003e 'Description',\n        'width' =\u003e 100\n        // check inline documentation to see what options are available.\n        // Basically, it's everything TCPDF Cell and MultiCell can eat.\n    ],\n    'quantity' =\u003e [\n        'header' =\u003e 'Quantity',\n        'width' =\u003e 20,\n        'align' =\u003e 'R'\n    ],\n    'price' =\u003e [\n        'header' =\u003e 'Price',\n        'width' =\u003e 20,\n        'align' =\u003e 'R'\n    ]\n]);\n\n// get rows data\n$rows = getMyDatasAsMyObjs();\n\n// add a page so the content can be printed on something\n$pdf-\u003eAddPage();\n// draw body\n$tctable-\u003eaddBody($rows, function (\\voilab\\tctable\\TcTable $table, \\MyObj $row) {\n    $change_rate = 0.8;\n    // map row data to TcTable column definitions\n    return [\n        'description' =\u003e $row-\u003egetDescription(),\n        'quantity' =\u003e $row-\u003egetQuantity(),\n        'price' =\u003e $row-\u003egetPrice() * $change_rate\n    ];\n});\n\n$pdf-\u003eOutput('tctable.pdf', 'I');\n```\n\n### Plugins\n#### Have a column that fit the remaining page width\n```php\n$tctable\n    -\u003eaddPlugin(new \\voilab\\tctable\\plugin\\FitColumn('text'))\n    -\u003eaddColumn('text', [\n        'isMultiLine' =\u003e true,\n        'header' =\u003e 'Text'\n        // no need to set width here, the plugin will calculate it for us,\n        // depending on the other columns width\n    ]);\n```\n\n#### Stripe rows\n```php\n$tctable\n    // set true to have the first line with colored background\n    -\u003eaddPlugin(new \\voilab\\tctable\\plugin\\StripeRows(true));\n```\n\n#### Widows management\n```php\n// set the minimum elements you want to see on the last page (if any)\n$nb = 4;\n// set a footer margin. Useful when you have lot of lines, and a total as the\n// last one. If you want the total to appears at least with 4 lines, you have\n// to add to the pageBreakTrigger margin this line height: the footer\n$mFooter = 10; // i.e: mm\n\n$tctable-\u003eaddPlugin(new \\voilab\\tctable\\plugin\\Widows($nb, $mFooter));\n```\n\n#### Debug\nThe TcTable comes with a debug plugin tool that display datas passed in each\nevent.\n```php\n// create the plugin. You can define which events to listen (default to rowadd,\n// rowadded, rowskipped, headeradd, headeradded, pageadd and pageadded) and the\n// printer object (default to an HTML output with \u003cpre\u003e)\n$debug = new \\voilab\\tctable\\plugin\\Debug();\n$debug\n    -\u003esetBounds($fromIndex = 0, $numberOfRows = 2, $dieWhenOutOfBounds = true);\n\n// $dieWhenOutOfBounds will stop the script with die(). Usefull for quick\n// debug\n\n$tctable-\u003eaddPlugin($debug);\n```\n\nYou can extend the printer object by creating your own:\n```php\nclass MyDebugPrinter implements \\voilab\\tctable\\plugin\\debug\\PrinterInterface {\n\n    public function output(TcTable $table, array $data) {\n        // do something, log, etc.\n    }\n}\n\n// ... create an instance of debug plugin\n\n// you can set printer the way below, or via the 2nd argument in plugin\n// constructor.\n$debug-\u003esetPrinter(new MyDebugPrinter());\n```\n\n#### Advanced plugin: draw a subtotal for a column at end of each page\nWe can go further by calculating a sum for a column, and display the current\nsum at the end of the page, and finally report it on the next page.\n```php\n\u003c?php\n\nnamespace your\\namespace;\n\nuse voilab\\tctable\\TcTable;\nuse voilab\\tctable\\Plugin;\n\nclass Report implements Plugin {\n\n    // column on which we sum its value\n    private $column;\n    // the current calculated sum\n    private $currentSum = 0;\n\n    public function __construct($column) {\n        $this-\u003ecolumn = $column;\n    }\n\n    public function configure(TcTable $table) {\n        $table\n            // when launching the main process, reset sum at 0\n            -\u003eon(TcTable::EV_BODY_ADD, [$this, 'resetSum'])\n            // after each added row, add the value to the sum\n            -\u003eon(TcTable::EV_ROW_ADDED, [$this, 'makeSum'])\n            // when a page is added, draw the \"subtotal\" string\n            -\u003eon(TcTable::EV_PAGE_ADD, [$this, 'addSubTotal'])\n            // after a page is added, draw the \"sum from previous page\" string\n            -\u003eon(TcTable::EV_PAGE_ADDED, [$this, 'addReport']);\n    }\n\n    public function resetSum() {\n        $this-\u003ecurrentSum = 0;\n    }\n\n    public function makeSum(TcTable $table, $data) {\n        $this-\u003ecurrentSum += $data[$this-\u003ecolumn] * 1;\n    }\n\n    public function getSum() {\n        return $this-\u003ecurrentSum;\n    }\n\n    public function addSubTotal(TcTable $table) {\n        $pdf = $table-\u003egetPdf();\n        $pdf-\u003eSetFont('', 'I');\n        $pdf-\u003eSetTextColor(150, 150, 150);\n        $pdf-\u003eCell($table-\u003egetColumnWidthUntil($this-\u003ecolumn), $table-\u003egetColumnHeight(), \"Sub-total:\", false, false, 'R');\n        $pdf-\u003eCell($table-\u003egetColumnWidth($this-\u003ecolumn), $table-\u003egetColumnHeight(), $this-\u003ecurrentSum, false, false, 'R');\n        $pdf-\u003eSetTextColor(0, 0, 0);\n        $pdf-\u003eSetFont('', '');\n    }\n\n    public function addReport(TcTable $table) {\n        $pdf = $table-\u003egetPdf();\n        $pdf-\u003eSetFont('', 'I');\n        $pdf-\u003eSetTextColor(150, 150, 150);\n        $table-\u003egetPdf()-\u003eCell($table-\u003egetColumnWidthUntil($this-\u003ecolumn), $table-\u003egetColumnHeight(), \"Sum from previous page\", 'B', false, 'R');\n        $table-\u003egetPdf()-\u003eCell($table-\u003egetColumnWidth($this-\u003ecolumn), $table-\u003egetColumnHeight(), $this-\u003ecurrentSum, 'B', true, 'R');\n        $pdf-\u003eSetTextColor(0, 0, 0);\n        $pdf-\u003eSetFont('', '');\n    }\n\n}\n```\nAnd the TcTable\n```php\n$tctable-\u003eaddPlugin(new \\your\\namespace\\Report('total'));\n```\n\n### Custom events\nTcTable triggers some events we can listen to. Plugins use them a lot. But you\ncan simply define events without the need of plugins. It allows us to add some\nusefull methods.\n\n#### Add headers on each new page\n```php\nuse \\voilab\\tctable\\TcTable;\n// ... create tctable\n\n$tctable\n    // when a page is added, draw headers\n    -\u003eon(TcTable::EV_PAGE_ADDED, function(TcTable $t) {\n        $t-\u003eaddHeader();\n    })\n    // just before headers are drawn, set font style to bold\n    -\u003eon(TcTable::EV_HEADER_ADD, function(TcTable $t) {\n        $t-\u003egetPdf()-\u003eSetFont('', 'B');\n    })\n    // after headers are drawn, reset the font style\n    -\u003eon(TcTable::EV_HEADER_ADDED, function(TcTable $t) {\n        $t-\u003egetPdf()-\u003eSetFont('', '');\n    });\n```\n\n### Renderer and body functions\n\nWhen parsing data, you can define either a renderer function for each or some\ncolumns, or an anonymous function when calling $tctable-\u003eaddBody(). These\nfunctions are called twice, because it is needed in the process for height\ncalculation. You need to take that into account in certain cases.\n\n```php\n$total = 0;\n$tctable-\u003eaddBody($rows, function (TcTable $t, $row, $index, $isHeightCalculation) use (\u0026$total) {\n    // if $height is true, it means this method is called when height\n    // calculation is running. If we want to do a sum, we check first if\n    // $isHeightCalculation is false, so it means the func is called during row\n    // draw.\n    if (!$isHeightCalculation) {\n        $total += $row-\u003egetSomeValue();\n    }\n    // you still need to return the data regardless of $isHeightCalculation\n    return [\n        'description' =\u003e $row-\u003egetDescription(),\n        'value' =\u003e $row-\u003egetSomeValue()\n    ];\n});\n\necho sprintf('Total: %d', $total);\n```\n\nThe same idea applies to column renderers.\n\n\u003e *Note*\n\u003e In cases like the one above (creating a sum), you better should use plugins\n\u003e or events. With the event _TcTable::EV_ROW_ADDED_, you can do exactely the\n\u003e same thing without bothering with height calculation (see below).\n\n```php\n$total = 0;\n$tctable\n    -\u003eon(TcTable::EV_ROW_ADDED, function (TcTable $t, $row) use (\u0026$total) {\n        $total += $row-\u003egetSomeValue();\n    })\n    -\u003eaddBody($rows, function (TcTable $t, $row) {\n        return [\n            'description' =\u003e $row-\u003egetDescription(),\n            'value' =\u003e $row-\u003egetSomeValue()\n        ];\n    });\n\necho sprintf('Total: %d', $total);\n```\n\n### Optimizations\nYou can optimize the workflow if you know exactly the height of each row. You\ncan bypass the height calculation this way:\n```php\n$tctable-\u003eon(TcTable::EV_ROW_HEIGHT_GET, function (TcTable $t, $row, $index) {\n    return 6.4; // or null for default calculation\n});\n```\n\nIf you want to change the way cell's height is calculated, you can override the\ndefault behaviour this way:\n```php\n$tctable-\u003eon(TcTable::EV_CELL_HEIGHT_GET, function (TcTable $t, $column, $data, $row) {\n    if ($column == 'specialColumn') {\n        return 12.8;\n    }\n    // use default calculation\n    return null;\n});\n```\n\u003e Remember that only multiline cells are checked for their height. The others\n\u003e aren't taken in the process.\n\n### Custom drawing function\nIf you need to insert images or need to do very specific things with cell's\ndrawing, you can bypass the normal drawing function this way:\n```php\n$tctable-\u003eaddColumn('specialColumn', [\n    'header' =\u003e \"Special column\",\n    'width' =\u003e 15,\n    'drawFn' =\u003e function (TcTable $t, $data, array $definition, $column, $row) {\n        $t-\u003egetPdf()-\u003eImage(); //configure TCPDF Image method your way\n        // return false to draw the cell normally, if there's no image to\n        // display, for example\n    },\n    'drawHeaderFn' =\u003e function (TcTable $t, $data, array $definition, $column, $row) {\n        // same comments as above\n    }\n]);\n```\n\n## Testing\nNo test currently written...\n``` bash\n$ phpunit\n```\n\n## Security\n\nIf you discover any security related issues, please use the issue tracker.\n\n## Credits\n\n- [tafel](https://github.com/tafel)\n- [voilab](https://github.com/voilab)\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoilab%2Ftctable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvoilab%2Ftctable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoilab%2Ftctable/lists"}