at the moment I pass one of my functions an array like so
$inputs = array("FOOD" => "Pancake");
And then in my function I do something like the following
foreach ($inputs as $label => $data)
{
echo ($label . $data);
}
The above is only an example I have just written so I hope it is correct. Anyways, the function which has that foreach loop also has the following within it
$this->SetFillColor(190,205,44);
Now for each loop, I also want to set the fill colour of the output. So I was thinking about doing something like the following instead
$inputs = array("FOOD" => array("Pancake", '190,205,44'));
If I var_dump the array I am passing my function, I see
array:1 [▼
"FOOD" => array:2 [▼
0 => "PANCAKE"
1 => "190,205,44"
]
]
So this all seems correct. Now in my function I do
foreach($inputs as $label => $data){
foreach($data as $content => $colour) {
$this->SetFillColor($colour);
$this->Cell(65, 7, $label, 0, 0, 'L', 1, 0);
$this->Cell(100, 7, $content, 0, 0, 'L', 1, 0);
}
}
Now I have a couple of problems. Firstly, it seems to output two rows. The first cell prints out FOOD like it should do but the second cell prints out 0 (should be PANCAKE). The second row once again prints out FOOD, but the second cell prints out 1.
So how can I get it printing out just the first row? The other problem is $colour, because this is a string when it needs to be an int I think.
Any advice appreciated.
Thanks
Try this:
<?php
foreach($inputs as $label => $data){
$this->Cell(65, 7, $label, 0, 0, 'L', 1, 0);
// content is on index 0
$this->Cell(100, 7, $data[0], 0, 0, 'L', 1, 0);
// color on index 1
$this->SetFillColor($data[1]);
}
Or maybe even better create an object of \stdClass like this:
<?php
$foo[0]['food'] = new \stdClass;
$foo[0]['food']->content= 'Pancake';
$foo[0]['food']->color = '190,205,44';
$foo[1]['food'] = new \stdClass;
$foo[1]['food']->content= 'Apple';
$foo[1]['food']->color = '255,0,0';
for($i=0,$cnt=count($foo);$i<$cnt;$i++) {
foreach($foo[$i] as $label => $data) {
$this->Cell(65, 7, $label, 0, 0, 'L', 1, 0);
$this->Cell(100, 7, $data->content, 0, 0, 'L', 1, 0);
$this->SetFillColor($data->color);
}
}
Edit:
You can do this too:
<?php
$foo[0]['food']->color = new \stdClass;
$foo[0]['food']->content= 'Pancake';
$foo[0]['food']->color->r = 190;
$foo[0]['food']->color->g = 205;
$foo[0]['food']->color->b = 44;
... [snip]
$c = $data->color;
$this->SetFillColor($c->r,$c->g,$c->b);
Or even do it more OOP style
<?php
class color {
private $r;
private $g;
private $b;
public function get_r() {
return (float) $this->r;
}
public function get_g() {
return (float) $this->g;
}
public function get_b() {
return (float) $this->b;
}
public function set_r($r) {
$this->r = $r;
return $this;
}
public function set_g($g) {
$this->g = $g;
return $this;
}
public function set_b($b) {
$this->b = $b;
return $this;
}
static public function factory() {
return new color;
}
public function __construct() {
}
}
class food {
private $content;
private $color;
public function get_content() {
return $this->content;
}
public function get_color() {
return $this->color;
}
public function set_content($content) {
$this->content = $content;
return $this;
}
public function set_color(color $color) {
$this->color = $color;
return $this;
}
static public function factory() {
return new food;
}
public function __construct() {
}
}
$color = color::factory()->set_r(255)->set_g(0)->set_b(0);
$dataarray[] = food::factory()->set_content('Apple')->set_color($color);
foreach($dataarray as $food) {
echo $food->get_content();
echo $food->get_color()->get_r();
echo $food->get_color()->get_g();
echo $food->get_color()->get_b();
}
I think you wanted to write
$inputs = array("FOOD" => array("Pancake" => '190,205,44'));
so that 'Pancake' is a key that has a color string as its value.
Otherwise you should adjust your code to read like this:
foreach($inputs as $label => $data){
$content = $data[0];
$color = $data[1];
$this->SetFillColor($colour);
$this->Cell(65, 7, $label, 0, 0, 'L', 1, 0);
$this->Cell(100, 7, $content, 0, 0, 'L', 1, 0);
}
Either way should do the trick.
Currently $inputs = array("FOOD" => array("Pancake", '190,205,44')); just sets the 'FOOD' entry of $inputs to contain an array that has keys of 0,1 and so your $content variable will iterate 0,1 while $color iterates the values 'PANCAKE','190,205,44'.
Related
I found this code in an older post. It works absolutely fine for my project except one problem. If the string from the mysql db is too long it will overflow the cells. I want it to automatically break and start a new line in the particular cell.
Original post I got the code from: Basic table creation fpdf
<?php
require('fpdf.php');
class People {
public function all() {
try {
$db = new PDO('mysql:host=localhost;dbname=test;charset=UTF-8', 'user', 'password');
$query = $db->prepare("SELECT first_name, middle_name, last_name, age, email FROM people ");
$query->execute();
$people = $query->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
//echo "Exeption: " .$e->getMessage();
$result = false;
}
$query = null;
$db = null;
return $people;
}
}
class PeoplePDF extends FPDF {
// Create basic table
public function CreateTable($header, $data)
{
// Header
$this->SetFillColor(0);
$this->SetTextColor(255);
$this->SetFont('','B');
foreach ($header as $col) {
//Cell(float w [, float h [, string txt [, mixed border [, int ln [, string align [, boolean fill [, mixed link]]]]]]])
$this->Cell($col[1], 10, $col[0], 1, 0, 'L', true);
}
$this->Ln();
// Data
$this->SetFillColor(255);
$this->SetTextColor(0);
$this->SetFont('');
foreach ($data as $row)
{
$i = 0;
foreach ($row as $field) {
$this->Cell($header[$i][1], 6, $field, 1, 0, 'L', true);
$i++;
}
$this->Ln();
}
}
}
// Column headings
$header = array(
array('First Name', 30),
array('Middle Name', 30),
array('Last Name', 30),
array('Age', 12),
array('Email', 47)
);
// Get data
$people = new People();
$data = $people->all();
$pdf = new PeoplePDF();
$pdf->SetFont('Arial', '', 12);
$pdf->AddPage();
$pdf->CreateTable($header,$data);
$pdf->Output();
I have a code that get categories from database but I don't know how to get all subcategories(parents).
This my php code :
function get_the_category($allCats,$filter_id = null) {
$re_struct_cat = array();
$filter_id = 10;
$ids = array();
$xx = array();
foreach($allCats as $cat_key=>$cat_val) {
$re_struct_cat[$cat_val["id"]] = array(
"title" => $cat_val["cat_title"],
"parent" => $cat_val["cat_parent"],
);
$ids = array_merge($ids,array($cat_val["id"]));
}
foreach($ids as $k=>$v) {
if($re_struct_cat[$v]["parent"]) {
$xx[] = $re_struct_cat[$re_struct_cat[$v]["parent"]];
}
}
return $xx;
//return $re_struct_cat;
//print_r($re_struct_cat);
}
What I want exactly
I have table with 3 columns [id,title,parent]
ID TITLE PARENT
1 Science 0
2 Math 1
3 Algebra 2
4 Analyse 2
5 Functions 4
So if variable filter_id = 10 I got cat_parent = 4
So I want to take that value and looking for it in array and if find another cat_parent do the same thing until find 0 or null value
It is not the most optimal solution, but you can use iterators.
Firstly, create the custom iterator, that can handle categories:
class AdjacencyListIterator extends RecursiveArrayIterator
{
private $adjacencyList;
public function __construct(
array $adjacencyList,
array $array = null,
$flags = 0
) {
$this->adjacencyList = $adjacencyList;
$array = !is_null($array)
? $array
: array_filter($adjacencyList, function ($node) {
return is_null($node['parent']);
});
parent::__construct($array, $flags);
}
private $children;
public function hasChildren()
{
$children = array_filter($this->adjacencyList, function ($node) {
return $node['parent'] === $this->current()['id'];
});
if (!empty($children)) {
$this->children = $children;
return true;
}
return false;
}
public function getChildren()
{
return new static($this->adjacencyList, $this->children);
}
}
It is taken from my another answer.
Then you can simply loop over this iterator until you find the needed id:
$id = 5;
$categories = [];
$result = null;
foreach ($iterator as $node) {
$depth = $iterator->getDepth();
$categories[$depth] = $node['categoryname'];
if ($node['id'] === $id) {
$result = array_slice($categories, 0, $depth + 1);
break;
}
}
Here is the demo.
I have FPDF to generate a member list from a Mysql database to a list in PDF. But after my website-host has update the php version, has mine member list not worked !
Now it show :
Warning: Invalid argument supplied for foreach() in
/customers/8/f/b/xxx.com/httpd.www/test/printmedlemsliste.php on line
46 FPDF error: Some data has already been output, can't send PDF file
(output started at
/customers/8/f/b/xxx.com/httpd.www/test/printmedlemsliste.php:46)
My code :
<?php
require('fpdf.php');
class People {
public function all() {
try {
$db = new PDO('mysql:host=localhost;dbname=xxx_com;charset=UTF-8', 'xxx_com', 'xxx');
$query = $db->prepare("SELECT o.user_post, o.user_name1, o.user_name2, o.user_address1, o.user_address2, o.user_phone1, o.user_phone2, c.user_email, o.user_type FROM e107_user c, e107_user_extended o WHERE c.user_id = o.user_extended_id Order By user_name1");
$query->execute();
$people = $query->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
//echo "Exeption: " .$e->getMessage();
$result = false;
}
$query = null;
$db = null;
return $people;
}
}
class PeoplePDF extends FPDF{
// Create basic table
public function BasicTable($header, $data)
{
// Header
$this->SetFont('','B', 12);
$this->Cell(0,6,'Medlemsliste'.'',1,1,'C');
$this->SetFont('','B', 9);
$dateinvoice = substr( $invoice[ 'dateinvoice' ], 6 ).substr( $invoice[ 'dateinvoice' ], 3, 2 ).substr( $invoice[ 'dateinvoice' ], 0, 2 );
$dateinvoice = date_create( $dateinvoice );
$dateinvoice = false === $dateinvoice ? '' : $dateinvoice->format( 'd-M-Y' );
$this->Cell( 10 ); $this->Cell( 17, 5, 'Print Dato:' ); $this->Cell( 17, 5, $dateinvoice, 0, 1 );
$this->SetFillColor(255);
$this->SetTextColor(0);
$this->SetFont('','B');
foreach ($header as $col) {
//Cell(float w [, float h [, string txt [, mixed border [, int ln [, string align [, boolean fill [, mixed link]]]]]]])
$this->Cell($col[1], 5, $col[0], 1, 0, 'L', true); }
$this->Ln();
// Data
$this->SetFillColor(255);
$this->SetTextColor(0);
$this->SetFont('');
foreach ($data as $row)
{
$i = 0;
foreach ($row as $field) {
$this->Cell($header[$i][1], 6, $field, 1, 0, 'L', true);
$i++;
}
$this->Ln();
}
}
}
// Column headings
$header = array(
array('Post', 20),
array('Fornavn', 18),
array('Efternavn', 46),
array('Adresse', 40),
array('Postnummer & By', 40),
array('Telefon', 22),
array('Mobil', 22),
array('E-Mail', 57),
array('Type', 12)
);
// Get data
$people = new People();
$data = $people->all();
$pdf = new PeoplePDF();
$pdf->SetFont('Arial', '', 9);
$pdf->AddPage('L');
$pdf->Ln(0);
$pdf->SetTitle("Medlemsliste", boolean);
$pdf->SetAuthor("-");
$pdf->BasicTable($header,$data);
$pdf->Output('yourfilename.pdf','D');
?>
Line 46 is foreach ($data as $row).
If I set // front of foreach ($data as $row), it a new error on line 49. Line 49 is foreach ($row as $field) {
Also if I set // front of Line 49, it generate the PDF file, but with no data in !
Can anyone help ?
That's because $data contains nothing , so the loop fails.
Confirm that you've got the correct data in $data when you've performed the query with $data = $people->all();
Try var_dump($data); to see that your return in the all() function actually returns a result.
I would also change your try / catch to this.
try {
$db = new PDO('mysql:host=localhost;dbname=xxx_com;charset=UTF-8', 'xxx_com', 'xxx');
$query = $db->prepare("SELECT o.user_post, o.user_name1, o.user_name2, o.user_address1, o.user_address2, o.user_phone1, o.user_phone2, c.user_email, o.user_type FROM e107_user c, e107_user_extended o WHERE c.user_id = o.user_extended_id Order By user_name1");
$query->execute();
$people = $query->fetchAll(PDO::FETCH_ASSOC);
return $people;
} catch (PDOException $e) {
//echo "Exeption: " .$e->getMessage();
return false;
}
Because this seems like what I have to do to get this effect:
$arr = ['a'=>'first', 'b'=>'second', ...];
$iter = new ArrayIterator( $arr );
// Do a bunch of iterations...
$iter->next();
// ...
$new_iter = new ArrayIterator( $arr );
while( $new_iter->key() != $iter->key() ) {
$new_iter->next();
}
Edit: Also, just to be clear, should I NOT be modifying the base array with unset()? I figure the array iterator stores its own copy of the base array, so using offsetUnset() doesn't seem right.
ArrayIterator does not implement a tell() function, but you can emulate this, and then use seek() to go to the position you want. Here's an extended class that does just that:
<?php
class ArrayIteratorTellable extends ArrayIterator {
private $position = 0;
public function next() {
$this->position++;
parent::next();
}
public function rewind() {
$this->position = 0;
parent::rewind();
}
public function seek($position) {
$this->position = $position;
parent::seek($position);
}
public function tell() {
return $this->position;
}
public function copy() {
$clone = clone $this;
$clone->seek($this->tell());
return $clone;
}
}
?>
Use:
<?php
$arr = array('a' => 'first', 'b' => 'second', 'c' => 'third', 'd' => 'fourth');
$iter = new ArrayIteratorTellable( $arr );
$iter->next();
$new_iter = new ArrayIteratorTellable( $arr );
var_dump($iter->current()); //string(6) "second"
var_dump($new_iter->current()); //string(6) "first"
$new_iter->seek($iter->tell()); //Set the pointer to the same as $iter
var_dump($new_iter->current()); //string(6) "second"
?>
DEMO
Alternately, you can use the custom copy() function to clone the object:
<?php
$arr = array('a' => 'first', 'b' => 'second', 'c' => 'third', 'd' => 'fourth');
$iter = new ArrayIteratorTellable( $arr );
$iter->next();
$new_iter = $iter->copy();
var_dump($iter->current()); //string(6) "second"
var_dump($new_iter->current()); //string(6) "second"
?>
DEMO
The only solution I thought of is using a copy of current array
$arr = ['a'=>'first', 'b'=>'second'];
$iter = new ArrayIterator( $arr );
// Do a bunch of iterations...
$iter->next();
var_dump($iter->current());
// ...
$arr2 = $iter->getArrayCopy();
$new_iter = new ArrayIterator( $arr2 );
while( $new_iter->key() != $iter->key() ) {
var_dump($new_iter->current());
$new_iter->next();
}
I need to be able to echo a value from a private property in one of my classes if a method is called within the class. It's a little tricky to explain so let me demostrate and hopefully someone can fill in the blank for me :)
<?php
class test {
private $array['teachers']['classes'][23] = "John";
public function __construct($required_array) {
$this->array['teachers']['classes'][23] = "John";
$this->array['students'][444] = "Mary";
$this->echo_array($required_array);
}
public function echo_array($array) {
// Echo the value from the private $this->array;
// remembering that the array I pass can have either
// 1 - 1000 possible array values which needs to be
// appended to the search.
}
}
// Getting the teacher:
$test = new test(array('teachers','classes',23));
// Getting the student:
$test = new test(array('students',444));
?>
Is this possible?
$tmp = $this->array;
foreach ($array as $key) {
$tmp = $tmp[$key];
}
// $tmp === 'John'
return $tmp; // never echo values but only return them
An other approach to get value;
class Foo {
private $error = false,
$stack = array(
'teachers' => array(
'classes' => array(
23 => 'John',
24 => 'Jack',
)
)
);
public function getValue() {
$query = func_get_args();
$stack = $this->stack;
$result = null;
foreach ($query as $i) {
if (!isset($stack[$i])) {
$result = null;
break;
}
$stack = $stack[$i];
$result = $stack;
}
if (null !== $result) {
return $result;
}
// Optional
// trigger_error("$teacher -> $class -> $number not found `test` class", E_USER_NOTICE);
// or
$this->error = true;
}
public function isError() {
return $this->error;
}
}
$foo = new Foo();
$val = $foo->getValue('teachers', 'classes', 24); // Jack
// $val = $foo->getValue('teachers', 'classes'); // array: John, Jack
// $val = $foo->getValue('teachers', 'classes', 25); // error
if (!$foo->isError()) {
print_r($val);
} else {
print 'Value not found!';
}