How can I force PhpWord to write at the begin of the next multi-colum ?
I don't think there is a breaker function (such as addTextBreak() or addPageBreak()) for doing this.
$phpWord = new \PhpOffice\PhpWord\PhpWord();
$section = $phpWord->addSection(array(
'colsNum' => 2,
'colsSpace' => 100,
'breakType' => 'continuous',
));
$table1 = $section->addTable();
//...add rows and cells to table 1
$table2 = $section->addTable();
//...add rows and cells to table 2
As expected, the result of this code snippet is two table stacked on the first multi-colum.
Adding in the code
$section->addPageBreak()
doesn't obviously work.
Any advice on how to solve this problem?
Is it a good option to add some TextBreakers to the bottom of the page for filling the space that remain after the first table?
Thanks!
I am using TCPDF library to generate a PDF file dynamically in my Laravel Project.
I have a requirement to create the Table Of Content section dynamic and set the header of each page using Summary titles. And to give link to each items below which will lead user to the start of that section/content.
Example:
My Table Of Content
Summary ............................... 1
Organization & Management Structure.... 5
Credit History......................... 7
Public Records......................... 8
So,
My page 1 should have header as Summary
Page 2 to 4 should have header as Summary(Cont.)
Page 5 => Organization & Management Structure
Page 6 => Organization & Management Structure(Cont.)
Page 7 => History
Page 8 => Public Records
If you can help me by sending some tricks I can use to complete this, it will be a great help. Thanks!
Honestly, what you're describing sounds like the content of example 45 included TCPDF examples where you could get by just using the built-in TOC generator.
Something I didn't like about the example however is it's lack of body text. So I created a simple example with very basic document structure and randomly generated text below. The idea would be that you set a Bookmark right before you begin writing your content for each section and then have the TOC generator do the rest.
Setting the bookmark right before rendering your content makes it so you don't have to calculate the position of the bookmark. By default it'll take it's current position. I use a pre-built array here and very basic output for simplicity's sake.
Notes:
here may be edge cases where the content immediately overflows to the next page without outputting on the current page. I decided that was out of scope for now since you may not encounter it, but figured I'd note the possibility of it happening.
It may seem obvious, but it's worth mentioning anyway: If adding a page before starting your new section, call the Bookmark method after addPage.
You can view the output of my script: here
As mentioned, I based this off example 045 which you can view on the TCPDF example page. You can also use HTML to format the TOC entries made this way, see example 059.
<?php
// Include the main TCPDF library (search for installation path).
// Change this for your installation.
require_once('TCPDF-6.2.17/tcpdf.php');
// create new PDF document
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT,
PDF_PAGE_FORMAT, true, 'UTF-8', false);
// set default monospaced font
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
// set auto page breaks
$pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
// set image scale factor
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
//These will become the different colors for our TOC labels.
//Main section is a dark blue, sub-section is a lighter blue. This is
//strictly optional, but I kind of like it myself.
$level_colors = array(
0 => array(0, 0, 66),
1 => array(0, 0, 100),
2 => array(0, 0, 130),
);
/**
* Just produces some filler text.
*/
function gen_random_section_text($min = 70, $max = 300) {
$words = array('Iris', 'Daffodil', 'Dandelion', 'Daisy', 'Orchid', 'Lily',
'Rhododendron', 'Sakura', 'Blossom', 'Larkspur', 'Anemone', 'Hydrangea');
$word_max_index = count($words)-1;
$word_count = rand($min, $max);
$output = array();
for($i = 0; $i < $word_count; $i++) {
$output[] = $words[rand(0, $word_max_index)];
}
return implode(' ', $output);
}
// ---------------------------------------------------------
// set font
$pdf->SetFont('times', '', 14);
/**
* I'll build our list of sections outright for this example.
*/
$sections[] = array(
'title' => 'Summary',
'content' => '<p>'.gen_random_section_text(20,30).'</p>',
'level' => 0,
);
$sections[] = array(
'title' => 'Organization & Management',
'content' => '<p>'.gen_random_section_text(100,200).'</p>'.
'<p>'.gen_random_section_text(120,230).'</p>',
'level' => 0,
);
$sections[] = array(
'title' => 'Hiring Procedures',
'content' => '<p>'.gen_random_section_text(100,200).'</p>',
'level' => 1,
);
$sections[] = array(
'title' => 'In Absence of HR',
'content' => '<p>'.gen_random_section_text(30,100).'</p>',
'level' => 2,
);
$sections[] = array(
'title' => 'History',
'content' => '<p>'.gen_random_section_text().'</p>',
'level' => 0,
);
$sections[] = array(
'title' => 'History (1990-2000)',
'content' => '<p>'.gen_random_section_text().'</p>',
'level' => 1,
);
$sections[] = array(
'title' => 'History (2001-Present)',
'content' => '<p>'.gen_random_section_text().'</p>',
'level' => 1,
);
//Now we'll take our fake sections and add pages/content as needed.
foreach($sections as $section) {
$headertag = 'h1';
if(empty($section['level'])) {
//Both not set and value of 0 will evaluate true here.
//I'm adding new pages for any top-level section here, but you don't need to.
$pdf->addPage();
$level = 0;
} else {
//Any non-zero level header I'll give an h2.
$headertag = 'h2';
$level = $section['level'];
}
//We add a bookmark right before we start our output for the section copy.
$bookmark_style = $level > 0 ? 'I' : 'B'; //Make subheading italic.
$pdf->Bookmark($section['title'], $level, -1, '', $bookmark_style, $level_colors[$level], -1, '');
//See below for some notes on the Bookmark method.
//Then we output our content.
$pdf->WriteHTML("<{$headertag}>".htmlspecialchars($section['title'], ENT_COMPAT, 'UTF-8').
"</{$headertag}> {$section['content']}");
}
// add a new page for TOC
$pdf->addTOCPage();
// write the TOC title
$pdf->SetFont('times', 'B', 16);
//Writes my little "TOC Note"
$pdf->MultiCell(0, 0, 'My Table Of Content', 0, 'C', 0, 1, '', '', true, 0);
$pdf->Ln();
$pdf->SetFont('dejavusans', '', 12);
// add a simple Table Of Content at first page
// (check the example n. 59 for the HTML version)
$pdf->addTOC(1, 'courier', '.', 'INDEX', 'B', array(128,0,0));
// end of TOC page
$pdf->endTOCPage();
//Close and output PDF document
$pdf->Output('example_045.pdf', 'I');
For reference, the parameters for Bookmark are, at time of writing, here:
#param $txt (string) Bookmark description.
#param $level (int) Bookmark level (minimum value is 0).
#param $y (float) Y position in user units of the bookmark on the selected page (default = -1 = current position; 0 = page start;).
#param $page (int|string) Target page number (leave empty for current page). If you prefix a page number with the * character, then this page will not be changed when adding/deleting/moving pages.
#param $style (string) Font style: B = Bold, I = Italic, BI = Bold + Italic.
#param $color (array) RGB color array (values from 0 to 255).
#param $x (float) X position in user units of the bookmark on the selected page (default = -1 = current position;).
#param $link (mixed) URL, or numerical link ID, or named destination (# character followed by the destination name), or embedded file (* character followed by the file name).
I am working with phpWord and bringing changes to the header/footer content gives me a real hard time. What I am trying is to have header content arranged in a table. The table is created through the code I write. But the styles I try to apply to the table placed in a header does not take effect.
Following is a part of my code in which I may be making a mistake.
$phpWordObj = new PhpWord();
$section = $phpWordObj->addSection();
$styleTable = array('borderSize' => 18, 'borderColor' => '006699');
$phpWordObj->addTableStyle('My Custom Style', $styleTable);
//ADD HEADER TO DOCUMENT
$header = $section->addHeader();
$header->firstPage();
$table = $header->addTable();
$table->addRow();
//logo
$table->addCell(2000)->addImage(
'../vendor/phpoffice/phpword/samples/resources/PhpWord.png',
array('width' => 80, 'height' => 80, 'align' => 'left')
); //logo
$cell = $table->addCell(7000);
$textrun = $cell->addTextRun();
$textrun->addText(htmlspecialchars('Custom Name goes here...'));
$headerGen = $section->addHeader();
$tableGenHeader = $headerGen->addTable();
$tableGenHeader->addRow();
//logo
$tableGenHeader->addCell(2000)->addImage(
'../vendor/phpoffice/phpword/samples/resources/PhpWord.png',
array('width' => 80, 'height' => 80, 'align' => 'left')
);
$cellGenHeader = $tableGenHeader->addCell(7000);
$textrunGenHeader = $cellGenHeader->addTextRun();
$textrunGenHeader->addText(htmlspecialchars('Custom Name goes here...'));
All I want is borders to appear so that the header contents can be differentiated from each other.
Thanks!
The $phpWordObj->addTableStyle(...) adds a new table style that you need to reference in the table addition (i.e. it is not a global definition). Adding the style name as a parameter to your addTable calls should do the trick:
$table = $header->addTable('My Custom Style');
I would like to use the highchart plugin in cakephp. I installed it and I can run all the demos that come with the plugin.
I would like to use it in my own controller and took one of the examples as an implementation guide.
If I have the following code in my controller it does NOT work, i.e. highchart does not display any of the input values.
$resultStatistics = $this->Statistic->find("all", $params = array( 'fields' => 'new_students_total','recursive' => -1) );
$chartData1 = array();
$chartData1 = Hash::extract($resultStatistics, '{n}.Statistic.new_students_total');
// $chartData1 = array(0=>5, 1=>5, 2=>4, 3=>4);
$this->print_r2($chartData1);
$chartName = 'Evolution of Actual Number of Students';
$mychart = $this->Highcharts->create($chartName, 'line');
$this->Highcharts->setChartParams($chartName, array(
'renderTo' => 'linewrapper', // div to display chart inside
'chartWidth' => 600,
'chartHeight' => 500,
'chartMarginTop' => 60,
'chartMarginLeft' => 90,
'xAxisCategories' => array('Jan', 'Feb', 'Mar', 'Apr'),
// autostep options
// 'enableAutoStep' => TRUE
)
);
$series1 = $this->Highcharts->addChartSeries();
$series1->addName('ABC')
->addData($chartData1);
$mychart->addSeries($series1);
$this->set(compact('chartName'));
The result from the database query is a simple array with 4 integer values.
But if I uncomment the line 4, “$chartData1 = array(0=>5, 1=>5, 2=>4, 3=>4);”, basically defining the values of the array manually it DOES WORK and a linechart is drawn. I use Cakephp 2.4.3 and PHP 5.6
I can't seem to figure out the difference between the "mysql" version of the array $chartData1 and the "manual defined" version of $chartData1. What am I missing?
After lots of checking I eventually found the problem. The Cake plug in helper expects integer (or reals) in the chartData1 array. So simple adding the following lines:
foreach ($resultStatistics as $result) {
$chartData[] = (int) $result['Statistic']['new_students_total'];
}
at last solved my problem.
Thank anyway for your help
I've got this input form: (Using the blade template engine with Laravel, but the html should be easy to understand from this and ultimately trivial)
{{ Form::text('amount[]', Input::old('amount')) }}
<?php echo Form::select('unit[]',
array(
'whole' => _('whole'),
'ml' => _('milliliter'),
'l' => _('liter'),
'dl' => _('deciliter'),
'mg' => _('milligram'),
'g' => _('gram'),
'kg' => _('kilogram'),
'tsp' => _('teaspoon'),
'tbs' => _('tablespoon'),
)) ?>
{{ Form::text('ingredient[]', Input::old('ingredient')) }}
I'm trying to format this to my database to return it in a string like this :
<li><span>1</span> liter red wine</li>
I'm considering making it a simpler form and eliminating the unit measurement forcing my users to type it in instead for flexibility, but I'll still have to cramp it all into one table for my database. The span tag is used in a jQuery to dynamically increase the number so is needed. I've been at this for quite a few days on and off but I can't crack how to do this.
Here is my formatting logic:
$amount = Input::get('amount[]');
$unit = Input::get('unit[]');
$ingredient = Input::get('ingredient[]');
for ( $i = 0, $c = count(Input::get('ingredient[]')); $i < $c; $i++ )
{
$ingredients .= '<li><span>'.$amount[$i].'</span>'.$unit[$i].' '.$ingredient[$i].'</li>';
}
and I send it using
$new = Recipe::create(array(
'title' => Input::get('title'),
'curiousity' => Input::get('curiousity'),
'ingredients' => $ingredients,
'steps' => Input::get('recipe')
));
I've tried numerous ways and I get errors like the $ingredients array not being defined or not being able to use [] in the variable. I tried defining the variable as an '$ingredients = '';' variable but that just produced an empty string. My problem must be in the logic.
Build your select list outside the form for brevity as well as (what I do anyway to keep controllers very slim) send the input to the model all at once.
$input = Input::all();
$new = Recipe::create($input);
Build the array for the ingredients elsewhere. In the model (perhaps?):
$ingredients = array(
'dbname1' => 'displayname1',
'dbname2' => 'displayname2'
);
And display it accordingly, then the form inputs should be sent over with the $input in an array that you can parse and then save to your db.
Other notes about Blade syntax. I'm not aware of a need to define the array brackets [].
{{Form::open()}}
{{Form::label('label1','Display Label 1')}}
{{Form::text('fieldname1',Input::old('fieldname1'))}}
With your ingredients array already built (your current syntax will produce a dropdown and I assume you want checkboxes)
{{Form::select('ingredientsFIELDNAME',$ingredients)}}
{{Form::close()}}
In your Input::all() array your ingredientsFIELDNAME field name will have an array if you've built it as checkbox instead of select. Hope this all makes sense.