I'm using PhpWord library for generating docx files.
In most cases I need to generate this file from HTML, so if I want to generate numeric list I need to use
$section->addListItemRun();
So if I generate two lists in the document I'm expecting result
1.Item 1
2.Item 2
3.Item 3
Some text here
1.Item 1
2.Item 2
3.Item 3
But I'm getting
1.Item 1
2.Item 2
3.Item 3
Some text here
4.Item 1
5.Item 2
6.Item 3
Does anybody know how I can reset numbering?
Another question, this library can add footnotes with this method
$section->addFootnote();
Can I change the label of the footnote?
Thanks
this is the behavior in word. Not the document.
but you can hack with create unique list name
$n = 1;
foreach ($lists as $list) {
// Hack to reset lists
$listFormat = $phpWord->addNumberingStyle(
'multilevel-'.$n,
array('type' => 'multilevel', 'levels' => array(
array('format' => 'decimal', 'text' => '%1.', 'left' => 720, 'hanging' => 360, 'tabPos' => 720)
)
)
);
$section->addText(htmlspecialchars('Multilevel list.'));
$section->addListItem(htmlspecialchars('List Item I'), 0, null, 'multilevel-'.$n);
$section->addListItem(htmlspecialchars('List Item I.a'), 1, null, 'multilevel-'.$n);
$section->addListItem(htmlspecialchars('List Item I.b'), 1, null, 'multilevel-'.$n);
$section->addListItem(htmlspecialchars('List Item II'), 0, null, 'multilevel-'.$n);
$section->addListItem(htmlspecialchars('List Item II.a'), 1, null, 'multilevel-'.$n);
$section->addListItem(htmlspecialchars('List Item III'), 0, null, 'multilevel-'.$n);
$section->addTextBreak(2);
$n++;
}
Related
I am working on an application that has a web based backend and a Android app based front end.
The backend is used to input data into MySQl (using PHP) and then generate a JSON which is then supplied to the Android App (front end) and displayed.
So here is what I have:
This is my Database
CREATE TABLE IF NOT EXISTS `tddept` (
`deptId` int(11) NOT NULL AUTO_INCREMENT,
`deptName` varchar(50) NOT NULL,
`deptIsRoot` tinyint(1) NOT NULL,
`deptHasChild` tinyint(1) NOT NULL,
`deptParentId` int(11) NOT NULL,
PRIMARY KEY (`deptId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=16 ;
--
-- Dumping data for table `tddept`
--
INSERT INTO `tddept` (`deptId`, `deptName`, `deptIsRoot`, `deptHasChild`, `deptParentId`) VALUES
(2, 'One', 1, 1, 0),
(3, 'Two', 1, 1, 0),
(4, 'Three', 1, 1, 0),
(5, 'One1', 0, 0, 2),
(6, 'One2', 0, 0, 2),
(7, 'One3', 0, 0, 2),
(12, 'Two1', 0, 0, 3),
(13, 'Three1', 0, 0, 4),
(14, 'Dept1', 1, 1, 0),
(15, 'dept1.1', 0, 0, 14);
My intention is simple to create a tree structure. only that there are multiple root nodes. and hence multiple leafs.
If put in simple words, I am trying to create a directory tree structure. I would want to display the data in the above table in to a dropdown menu (i.e. using <select> and <option>) as:
One
One1
One2
One3
Two
Two1
Three
Three1
Dept1
dept1.1
Where One, Two, Three, Dept1 are root departments while the rest are sub-departments.
There can definitely be situations in the future where in I might have to have something like:
- One
- - One1
- - - One1a
- - - One1b
so on and so forth.
How can I traversal through them using Core PHP and how can I display them in the very structure as above in to a <select>/<option> (dropdown) menu.
PS: any heads up on JSON would also be a great help.
Here's the solution for image2
echo '<select>';
structureTree(0,0);
echo '</select>';
function structureTree($deptParentId, $level){
$result = getDataFromDb($deptParentId); // change this into SQL
foreach($result as $result){
echo '<option value="'.$deptParentId.'">'.str_repeat('-',$level).$result['deptName'].'</option>';
structureTree($result['deptId'], $level+2);
}
}
// mocking database record
function getDataFromDb($deptParentId)
{
$data = array(
array(
'deptId' => 1,
'deptName' => 'IT',
'deptParentId' => 0,
),
array(
'deptId' => 2,
'deptName' => 'Human Resources',
'deptParentId' => 1,
),
array(
'deptId' => 3,
'deptName' => 'Opreational',
'deptParentId' => 1,
),
array(
'deptId' => 4,
'deptName' => 'Networking Department',
'deptParentId' => 1,
),
array(
'deptId' => 5,
'deptName' => 'Software Development',
'deptParentId' => 1,
),
array(
'deptId' => 6,
'deptName' => 'Mobile Software Development',
'deptParentId' => 5,
),
array(
'deptId' => 7,
'deptName' => 'ERP',
'deptParentId' => 5,
),
array(
'deptId' => 8,
'deptName' => 'Product Development',
'deptParentId' => 5,
),
);
$result = array();
foreach ($data as $record) {
if ($record['deptParentId'] === $deptParentId) {
$result[] = $record;
}
}
return $result;
}
regarding 1.png Here's the SQL based on your sample db table
SELEC dep.deptId As DepId
,dep.deptName As DepartmenName
,parent.deptId As ParentId
,parent.deptName As ParentDepartmentName
FROM tddept As dep
JOIN tddept As parent ON parent.deptParentId = dep.deptId;
recursion is the solution for this problem. While the parent still has a child then it keeps querying until there's no child left.
e.g
One
.One1
.One2
.One3
Here's the php application
function structureTree($depParentId = 0){
$result = queryFunction("SELECT *FROM
tddept WHERE deptParentId = '$depParentId'");
foreach($results as $result){
echo $result['deptName'].'<br/>';
structureTree($resultp['deptParentId']);
}
}
structureTree();
I have a table cell where I would like to place a few list items. Below is my code.
Basically, I have a whole bunch of styles defined and then I add rows and cells. Inside one of the cells, I am adding an unordered list.
Note: If you are wondering why I have the "exact" parameter here, $table->addRow(250, "exact"); it is because I've used this fix for controlling table row height.
// Table
$styleTable = array( 'borderSize' => 7,
'cellMarginTop' => 0,
'cellMarginLeft' => 100,
'valign' => 'center',
'spaceAfter' => 0
);
$styleCell = array( 'spaceAfter' => 0
);
$cellTextStyle = array( 'bold' => false,
'size' => 10,
'name' => 'Calibri'
);
$cellTextStyleBold = array( 'bold' => true,
'size' => 10,
'name' => 'Calibri'
);
$listStyleText = array( 'spaceAfter' => 0,
'spaceBefore' => 0,
'spacing' => 0,
'size' => 10
);
$listStyle = array( 'spaceAfter' => 0,
'spaceBefore' => 0,
'spacing' => 0
);
$listStyleParagraph = array( 'spaceAfter' => 0,
'spaceBefore' => 0,
'spacing' => 0
);
$PHPWord->addTableStyle('myTable', $styleTable);
$table = $section->addTable('myTable');
$table->addRow(250, "exact");
$table->addCell(5760, $styleCell)->addText('Type:', $cellTextStyleBold);
$table->addCell(5760, $styleCell)->addText('Kazvin', $cellTextStyle);
$table->addRow(250, "null");
$table->addCell(5760, $styleCell)->addText('Description:', $cellTextStyleBold);
$cell = $table->addCell(5760, $styleCell);
// Add listitem elements inside table cell
$PHPWord->addParagraphStyle('listStyle', array('spaceAfter'=>0));
$cell->addListItem('100% wool pile on a cotton foundation', 0, null, null, 'listStyle');
$cell->addListItem('Semi-open ivory field', 0, null, null, 'listStyle');
$cell->addListItem('Coral and powder blue floral medallion', 0, null, null, 'listStyle');
$cell->addListItem('Formal coral, powder blue and ivory border', 0, null, null, 'listStyle');
The problem is that the the List Item Paragraph Style does not get used when doing something like $cell->addListItem....
If I were to use $section-> instead of $cell->
// Add listitem elements inside table cell
$PHPWord->addParagraphStyle('listStyle', array('spaceAfter'=>0));
$section->addListItem('100% wool pile on a cotton foundation', 0, null, null, 'listStyle');
$section->addListItem('Semi-open ivory field', 0, null, null, 'listStyle');
$section->addListItem('Coral and powder blue floral medallion', 0, null, null, 'listStyle');
$section->addListItem('Formal coral, powder blue and ivory border', 0, null, null, 'listStyle');
Then the 'spaceAfter' => 0 works fine. However, the unordered list appears outside of the table cell.
I've tried for days trying to find a way to apply a 'spaceAfter' => 0 Paragraph Style to my list items inside the table cell but with no luck.
Does anyone know how something like this could be accomplished?
Make a change in Cell.php.
Replace :
public function addListItem($text, $depth = 0, $styleText = null, $styleList = null) {
$text = utf8_encode($text);
$listItem = new PHPWord_Section_ListItem($text, $depth, $styleText, $styleList, $styleParagraph);
$this->_elementCollection[] = $listItem;
return $listItem;
}
By :
public function addListItem($text, $depth = 0, $styleText = null, $styleList = null, $styleParagraph = null) {
$text = utf8_encode($text);
$listItem = new PHPWord_Section_ListItem($text, $depth, $styleText, $styleList, $styleParagraph);
$this->_elementCollection[] = $listItem;
return $listItem;
}
Work like a charm for me !
I'm editing my invoices file in
/Mage/Sales/Model/Order/Pdf/Items/Invoice/Default.php
And I'm running into a problem with columns running into and overlapping other columns if they have long content. eg Product description running over the next column. I'm trying to figure out how to limit the width / word wrap / create a new line for content.
Code is:
// draw Product name
$lines[0] = array(array(
'text' => Mage::helper('core/string')->str_split($item->getName(), 60, true, true),
'feed' => 35,
));
// draw SKU
// $lines[0][] = array(
// 'text' => Mage::helper('core/string')->str_split($this->getSku($item), 25),
// 'feed' => 255
// );
// draw Brand (Added by James)
$product = Mage::getModel('catalog/product')->loadByAttribute('sku', $this->getSku($item), array('manufacturer'));
if ($product) {
$lines[0][] = array(
'text' => Mage::helper('core/string')->str_split($product->getAttributeText('manufacturer'), 15),
'feed' => 220
);
}
// draw Colour (Added by James)
$product = Mage::getModel('catalog/product')->loadByAttribute('sku', $this->getSku($item), array('pos_short_colour'));
if ($product) {
$lines[0][] = array(
'text' => Mage::helper('core/string')->str_split($product->getAttributeText('pos_short_colour'), 15),
'feed' => 320
);
}
I know that 'feed' is what sets how far in from the left the array starts (pretty much = to a margin-left if all items were 'absolute' in css terms).
But I'm not sure how I can limit their width and word-wrap so that if I have a long manufacturer it won't run into the colour. There isn't enough space on the invoice to just simply give each attribute more room.
The answer was right there:
$lines[0] = array(array(
'text' => Mage::helper('core/string')->str_split($item->getName(), 60, true, true),
'feed' => 35,
));
The 60 here is how many characters will be displayed per line ->getName(), 60, true,
I had the same issue. When I added a new column, Product description column disappeared. I solved this by reducing a number (length) in str_split function of $productDescr.
I am trying to make a PDF document with TCPDF using HTML code.
At the moment I use this code:
// set font
$pdf->SetFont('dejavusans', '', 36);
// add a page
$pdf->AddPage();
$html = '
<style>
.h1 {
color: #2B6999;
font-weight: normal;
}
</style>
<h1 class="h1">Test</h1>
';
// output the HTML content
$pdf->writeHTML($html, true, false, true, false, 'C');
How can I position this text? I cannot use between the tags margin-top etc..
Can anyone help me with this problem?
You can add something like this:
$tagvs = array('h1' => array(0 => array('h' => 1, 'n' => 3), 1 => array('h' => 1, 'n' => 2)),
'h2' => array(0 => array('h' => 1, 'n' => 2), 1 => array('h' => 1, 'n' => 1)));
$pdf->setHtmlVSpace($tagvs);
And here is the format description from the docs / examples:
File: tcppdf.php :
/**
* Set the vertical spaces for HTML tags.
* The array must have the following structure (example):
* $tagvs = array('h1' => array(0 => array('h' => '', 'n' => 2), 1 => array('h' => 1.3, 'n' => 1)));
* The first array level contains the tag names,
* the second level contains 0 for opening tags or 1 for closing tags,
* the third level contains the vertical space unit (h) and the number spaces to add (n).
* If the h parameter is not specified, default values are used.
* #param $tagvs (array) array of tags and relative vertical spaces.
* #public
* #since 4.2.001 (2008-10-30)
*/
File http://www.tcpdf.org/examples/example_061.phps :
// REMOVE TAG TOP AND BOTTOM MARGINS
//
// $tagvs = array('p' => array(0 => array('h' => 0, 'n' => 0), 1 => array('h' => 0, 'n' => 0)));
// $pdf->setHtmlVSpace($tagvs);
//
// Since the CSS margin command is not yet implemented on TCPDF, you
// need to set the spacing of block tags using the above method.
You are using writeHTML which outupts the HTML exactly, you need to use the "$pdf->Cell" function. There are lots of example on this here http://www.tcpdf.org/examples.php
I want a table of comments like so
id | comment | parent_id
--------------------------
1 text1 0
2 text2 1
3 text3 2
4 text4 3
5 text5 3
6 text6 5
I want to construct an array displaying the hierarchy of the parents and children. The tree should go back a undetermined number of generations. I don't want to use nesting foreach loops as I'm not sure how deep it goes. That is why I'm here, I'm not sure of the best practice for a problem like this. I also want to display the depth in the array. Below is an example. It doesn't really relate to table above, but hopefully gives you an idea of what I need.
array(
"depth"=> 4
"parent" => array(
"id"=> 1,
"comment" => "sometext1"
"child_count" => 2,
"children" => array(
0 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 0,
"children" => null
),
1 => array(
"id" => 3
"comment" => "sometext3"
"child_count" => 1,
"children" => array(
0 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 2,
"children" => array(
0 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 0,
"children" => null
),
1 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 1,
"children" => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 0,
"children" => null
)
)
)
)
)
)
)
)
I was going to use foreach and do a SQL statement to retrive that parent/childs children. ie
$sql = "SELECT * FROM comments WHERE parent = $parent_id";
Im not really looking for the code for all this, just a pseudo code solution.
This can be easily done in PHP... For this you need two arrays and a two while loops.
This code will make a tree the way you wanted and for an undetermined depth and number of children.
Pastebin to the working code.
Using references, lets imagine everything is saved in an array $data with this structure: (id, comment, parent_id) where parent_id points to an id.
Code to build the tree.
$tree = array();
reset($data);
while (list($k, $v) = each($data))
if (0 == ($pid = $v['parent_id']))
$tree[$k] =& $data[$k]; else
$data[$pid]['children'][$k] =& $data[$k];
And to generate the depth and child count.
reset($data);
while (list($k, $v) = each($data))
if (0 != $v['parent_id'])
{
$ref =& $data[$k];
$depth = 0;
do
{
if ($depth) $ref =& $data[$ref['parent_id']];
$dre =& $ref['depth'];
if (!isset($dre) || $dre <= $depth) $dre = $depth++;
if (isset($ref['children']))
$ref['child_count'] = count($ref['children']);
else
{
$ref['child_count'] = 0;
$ref['children'] = null;
}
}
while ($ref['parent_id']);
}
All my code has been written on the fly and not even tested, so if there are any errors please forgive meeeeeeeee!!!!!!!!!!! ← Forget that, I tried it, fixed a couple of issues and now works perfectly.
Note
For this code to work, the index of every item has to be equal to its ID.
The array I used to try the code.
$data = array(
'1' => array('id' => '1', 'comment' => 'a', 'parent_id' => 0),
'2' => array('id' => '2', 'comment' => 'b', 'parent_id' => 0),
'3' => array('id' => '3', 'comment' => 'c', 'parent_id' => 1),
'4' => array('id' => '4', 'comment' => 'd', 'parent_id' => 1),
'5' => array('id' => '5', 'comment' => 'e', 'parent_id' => 2),
'6' => array('id' => '6', 'comment' => 'f', 'parent_id' => 2),
'7' => array('id' => '7', 'comment' => 'g', 'parent_id' => 5),
'8' => array('id' => '8', 'comment' => 'h', 'parent_id' => 7)
);
This is the problem when you use Adjacency list for trying to retrieve all child nodes in the hierarchy. It just doesn'y handle recursion very well if you are using mysql. (Oracle is another matter).
Creating the structure is simple, you should not really concern yourself with how to create the array structure just yet, first you want to try and create an efficient query and effiecient models that play perfectly to the type of queries that you will be making.
For example, you say that you want to retrieve all child nodes. Well then you should probably be using nested set models instead or in addition to adjacency list.
Take a look at some of these resources...
Is there a simple way to query the children of a node?
The idea of a nested set, is that you store the lft and right edge values of a node, meaning that retrieving any child nodes, is incredibly simple, beause you just select nodes which have a lft value greater than the target nodes lft value, and smaller than the rgt value.
Once you retrieve your result set, creating your array structure will be effortless.
See here : http://en.wikipedia.org/wiki/Nested_set_model
Once you have your results, then take a look at this question, which I asked a year or so ago, which is exactly what you want. PHP > Form a multi-dimensional array from a nested set model flat array
Example
id | comment | parent_id | lft | rgt |
-------------------------------------------------
1 World null 1 12
2 Europe 1 2 11
3 England 2 3 10
4 Kent 3 4 5
5 Devon 3 6 9
6 Plymouth 5 7 8