I'm currently learning php, and I'm testing out oop and classes.
My code is:
<?php
require('user.php');
$user = new User($username);
$projects = $user->getProjects();
for ($n = 0; $n<count($projects); $n++) {
echo "<li>";
echo "<a id=\"menu_pages\" href=\"\"><img src=\"../images/types/project.png\"/>" . $projects[$n]->name . "</a>";
echo "<ul>";
$items = $user->getItems($n);
for ($i = 0; $i<count($items); $i++) {
echo "<li><img src=\"../images/types/" . $items[$i]->type . ".png\"/>" . $items[$i]->name . "</li>";
}
echo "</ul>";
echo "</li>";
}
?>
and I'm getting the error:
Fatal error: Cannot redeclare class Item in /home/ios/public_html/classes/item.php on line 2
I found that its because I'm using
$items = $user->getItems($n);
in a loop. Because if I change it to
$items = $user->getItems(1);
it works. I cannot really figure out anyway of getting around the error.
Help please :)
Thanks in advance.
The methods:
function getItems($parent,$type = NULL) {
$items = array();
$username = $this->uname;
$userid = $this->getId($username);
include('classes/config.php');
if ($type != NULL) {
}
require_once('classes/item.php');
foreach ($pdo->query($sql) as $row) {
$instance = new Item();
$instance->name = $row['name'];
$instance->id = $row['id'];
$instance->type = $row['type'];
$instance->parent_id = $row['parent_id'];
$items[] = $instance;
unset($instance);
}
function getProjects() {
$projects = array();
$username = $this->uname;
$userid = $this->getId($username);
include('classes/config.php');
require_once('classes/project.php');
foreach ($pdo->query($sql) as $row) {
$proj = new Project();
$proj->name = $row['name'];
$proj->id = $row['id'];
$projects[] = $proj;
unset($proj);
}
return $projects;
}
edit:
its still not working with changing it. The code goes through with no errors, but now what should be under the first is under the second and the first is blank. See any issues in my logic?
Use require_once while including files with classes definition (I guess this will be somewhere in getItems()) or organize your files and define magic function __autoload() that will load it for you when used.
After looking into provided source, I doubt that this works for more than one row...
Here you create instance of Item before even checking if there are any items, and after first loop $instance is destroyed:
require('classes/item.php');
$instance = new Item();
foreach ($pdo->query($sql) as $row) {
$instance->name = $row['name'];
$instance->id = $row['id'];
$instance->type = $row['type'];
$instance->parent_id = $row['parent_id'];
$items[] = $instance;
unset($instance);
}
This should look like:
require_once('classes/item.php');
foreach ($pdo->query($sql) as $row) {
$instance = new Item();
$instance->name = $row['name'];
$instance->id = $row['id'];
$instance->type = $row['type'];
$instance->parent_id = $row['parent_id'];
$items[] = $instance;
unset($instance);
}
So for every item new instance is created.
change it to require_once('user.php'); and it won't try to execute user.php on each pass.
It's hard to say withut seeing what's in getItems() function, but it is possible that it includes a file where Item class is defined in a loop, which triggers this error. Try using require_once() instead.
The error message points to a duplicate class definition (The blueprint that starts with Class classname).
If you are pointing at the correct line of code - I'm not competely convinced you are - I'm pretty sure that $user->getItems() includes a PHP file, in which the class is redefined.
The immediate problem can be fixed using require_once() or include_once() but you should probably change your getItems function so that the class definition is loaded elsewhere in the first place.
I'll guess that the getItems() function on the User class probably has a line something like:
require('item.php');
if you change that to:
require_once('item.php');
you should be good to go.
(if I'm wrong about that, then please post the code for the getItems() function, so we can diagnose further).
Related
I have a class names Product.php in my model directory. in my view directory, I have an index.php currently I fetching data out of my table using this function
the code works fine but I want to field $row['name'] to be called as an object. because I am not sure the way I'm doing is a semantically correct for oop programming.
public function display(){
$pizza = $this->connect()->query("SELECT * FROM pizza");
while ($row = $pizza->fetch(PDO::FETCH_ASSOC)) {
$data[]= $row;
} return $data;
}//end of method
and in my index page i write :
$blog = new Product();
$name = $blog->display();
foreach ($name as $row ) {
echo $row['name']. '<br>';
}
All you need to do is change PDO::FETCH_ASSOC to PDO::FETCH_OBJ.
Then for your index.php:
$blog = new Product();
$name = $blog->display();
foreach ($name as $row ) {
echo $row->name . '<br>';
}
Here is a really good article to read for PDO.
PDO Tutotrial
I am looking for a way to make this foreach loop run on the UserData objects.
<?php
echo '<pre>';
class UserData{
public $FName;
public $LName;
public $IP;
}
$user001 = new UserData();
$user002 = new UserData();
$user003 = new UserData();
$user001->FName = 'Erez';
$user001->LName = 'T';
$user001->IP = '192.168.0.1';
$user002->FName = 'Netali';
$user002->LName = 'Goz';
$user002->IP = '192.168.0.2';
$user003->FName = 'Charley';
$user003->LName = 'Abu Ben David';
$user003->IP = '192.168.0.3';
So up to here the class has the attributes picked up by the new objects above.
Now from this part below I'm using the get_object_vars to retrieve the UserData but I have no idea how to run it dynamically.
Can you help me with this in the shortest code possible with the most basic code?
(a for loop would be great!)
$vars = get_object_vars('UserData');
print_r($vars);
echo '<hr>';
foreach ($vars as $OP =>$OPVal){
echo $OP .' is '.$OPVal.'<br>';
}
You can disregard the print_r and echo's.
Thanks!
you can loop with this methode
for($x=1;$x<4;$x++){
$vars = get_object_vars(${'user00'.$x});
print_r($vars);
echo '<hr>';
foreach ($vars as $OP =>$OPVal){
echo $OP .' is '.$OPVal.'<br>';
}
echo '<hr>';
}
but, you better learn OOP concept first.
Instead of making individual instances of the object, create an array of objects, and add as many as you need.
You can also add a constructor for the class, to instantiate easier.
Example:
class UserData{
public $FName;
public $LName;
public $IP;
public function __construct($fname,$lname,$ip){
$this->FName = $fname;
$this->LName = $lname;
$this->IP = $ip;
}
}
//store your data in some arrays
$firstNames = array('Erez','Netali','Charley');
$lastNames = array('T','Goz','Abu Ben David');
$ips = array('192.168.0.1','192.168.0.2','192.168.0.3');
$users = array();
for ($i=0;$i<3;$i++){
// instantiate each new object using data from the above arrays
$users[] = new UserData($firstNames[$i],$lastNames[$i],$ips[$i]);
// or use your method
/*
$users[] = new UserData('Netali','Goz','192.168.0.2')
*/
}
// now iterate over your array of UserData objects and print their properties
foreach ($users as $user){
print $user->FName . ", " . $user->LName . ", " . $user->IP . PHP_EOL;
}
// outputs
Erez, T, 192.168.0.1
Netali, Goz, 192.168.0.2
Charley, Abu Ben David, 192.168.0.3
public function getCats($model){
$levels = array();
$tree = array();
$cur = array();
foreach($model as $rows){
$cur = &$levels[$rows['id']];
$cur['parent_id'] = $rows['parent_id'];
$cur['title'] = $rows['title'];
if($rows['parent_id'] == 0){
$tree[$rows['id']] = &$cur;
}
else{
$levels[$rows['parent_id']]['children'][$rows['id']] = &$cur;
}
}
return $tree;
}
public function getTree($arr){
echo '<ul>';
foreach($arr as $k=>$v){
echo '<li>';
echo ''.$v['title'].'';
if(!empty($v['children'])){
echo getTree($v['children']);
}
echo '</li>';
}
echo '</ul>';
}
public function allCats($pos) {
$model = Category::model()->findallBySql('SELECT id, parent_id, title FROM {{category}} WHERE position="'.$pos.'"');
$cats = getCats($model);
echo getTree($cats);
}
I wonder, why these functions don`t work in model file(inside class)?
If i use them inside controllers, they work fine, and if i paste them inside model(class) file, they stop working(as if they are becoming invisible). The last function causing the above two functions.
You are calling getCats($model) which would be a global function. But it's defined as a class function/method. Call it $this->getCats($model) and $this->getTree($cats) and it should work.
I want to get the value from a loop function but am stuck in this problem, maybe you guys can give me help, thanks.
I define the parameters here
$my_value1 = "Order";
$my_value2 = "Transaction";
$my_value3 = "Name";
$doc2 = new DOMDocument();
$doc2->load( 'GetOrders.xml' );
$info2 = $doc2->getElementsByTagName( $my_value1 );
foreach( $info2 as $Type2 )
{
$ebayOrder = $Type2->getElementsByTagName($my_value2);
foreach($ebayOrder as $Type3)
{
echo getMyValue("OrderLineItemID",$Type3); echo '</br>';
}
The problem is that I want to call something like set the my_value2 in the loop and call something like
getMyValue($my_value3,$Type3)
Is possible to rewrite the function, so I can always call using the new parameter?
thanks in advance,
Mike
You can use variables as a parts of the names of other variables. Try with:
for ($i = 1; $i <= 3; $i++) {
$my_value = ${'my_value' . $i};
$info2 = $doc2->getElementsByTagName( $my_value );
}
I'm creating a tree-structure of categories with parentid's which can be called from children in such a way:
ID | Name | ParentID
1 1 0
2 2 1
3 3 2
4 4 1
Resulting in this:
1 = 1
2 = 1 -> 2
3 = 1 -> 2 -> 3
4 = 1 -> 4
which means 3 is a child of 2, which is a child of 1.
when trying to get this idea (with the -> to show what relations are set) I only get to the second grade (1 -> 2) but not to the third (1->2->3) because of the looping function I use for it.
//put all ID's in an array
while ($row2 = $connector->fetchArray($result2)){
$id = $row2['ID'];
$parents[$id] = $row2['name'];
}
// show the tree-structure
while ($row = $connector->fetchArray($result)){
if($row['parentid']!=0)echo $parents[$row['parentid']].' -> ';
echo $row['name'].' - ';
echo '<br>';
}
I'd like two things to change:
have the code automatically generate a tree sized as necessary.
in the while-loops i have to select the $result twice (once as $result, once as $result2) to make it work. these $result's have exactly the same database-query:SELECT ID,name,parentid FROM categories
to fetch results from. I'd like to only declare this once.
Thanks for all the good answers. I've gone with the easiest, less-code-to-implement approach:
$result = $connector->query('SELECT ID,name,parentid FROM categories');
// Get an array containing the results.
$parents = array();
while ($row = $connector->fetchArray($result)){
$id = $row['ID'];
$parents[$id] = array('ID' => $row['ID'],'name' => $row['name'],'parentid' => $row['parentid']);
}
foreach ($parents as $id => $row){
$pid=$id;
$arrTmp= array();
do { // iterate through all parents until top is reached
$arrTmp[]=$pid;
$pid = $parents[$pid]['parentid'];
}while ($pid != 0);
$arrTmp = array_reverse($arrTmp);
foreach($arrTmp as $id){
echo $parents[$id]['name'].' -> ';
}
echo '<br>';
}
Rather than have PHP organize the items into a tree, why not ask the database to do it for you? I found this article on hierarchical data to be very good and the examples are almost identical to yours.
EDIT
The SQL for getting the full tree using the Adjacency Model is not ideal. As the article explains it requires rather a lot of joins for even a small hierarchy. Is it not possible for you to use the Nested Set approach? The SQL stays the same regardless of the size of the hierarchy and INSERT and DELETE shouldn't be very difficult either.
If you really want to do hierachies with parent ids(suitable only for small number of items/hierachies)
I modified your code a little bit(I did not test it so there may be some syntax errors):
//put all recordsets in an array to save second query
while ($row2 = $connector->fetchArray($result2)){
$id = $row2['ID'];
$parents[$id] = array('name' => $row2['name'],'parent' => $row2['parentid']);
}
// show the tree-structure
foreach ($parents as $id => $row){
$pid = $row['parentid'];
while ($pid != 0){ // iterate through all parents until top is reached
echo $parents[$pid]['name'].' -> ';
$pid = $parents[$pid]['parentid'];
}
echo $parents[$id]['name'].' - ';
echo '<br>';
}
To answer your comment:
$parents = array();
$parents[2] = array('ID'=>2,'name'=>'General','parentid'=>0);
$parents[3] = array('ID'=>3,'name'=>'Gadgets','parentid'=>2);
$parents[4] = array('ID'=>4,'name'=>'iPhone','parentid'=>3);
foreach ($parents as $id => $row){
$pid=$id;
$arrTmp= array();
do { // iterate through all parents until top is reached
$arrTmp[]=$pid;
$pid = $parents[$pid]['parentid'];
}while ($pid != 0);
$arrTmp = array_reverse($arrTmp);
foreach($arrTmp as $id){
echo $parents[$id]['name'].' -> ';
}
echo '<br>';
}
Prints out:
General ->
General -> Gadgets ->
General -> Gadgets -> iPhone ->
Maybe easier with OOP. Just sort the query by parentId
Note: The listChildren method and the printout at the bottom is just there to show it is listed correctly. I did not interpret the question that the display was important.
class Element {
public $id;
public $name;
public $parent = null;
public $children = array();
public function __construct($id, $name)
{
$this->id = $id;
$this->name = $name;
}
public function addChild($element)
{
$this->children[$element->id] = $element;
$element->setParent($this);
}
public function setParent($element)
{
$this->parent = $element;
}
public function hasChildren()
{
return !empty($this->children);
}
public function listChildren()
{
if (empty($this->children)) {
return null;
}
$out = array();
foreach ($this->children as $child) {
$data = $child->id . ':' . $child->name;
$subChildren = $child->listChildren();
if ($subChildren !== null) {
$data .= '[' . $subChildren . ']';
}
$out[] = $data;
}
return implode(',', $out);
}
}
$elements = array();
$noParents = array();
while ($row = $connector->fetchArray($result)) {
$elements[$row['id']] = $element = new Element($row['id'], $row['name']);
if (isset($elements[$row['parent']])) {
$elements[$row['parent']]->addChild($element);
} else {
$noParents[] = $element;
}
}
foreach ($noParents as $element) {
if ($element->hasChildren()) {
echo "Element {$element->id} has children {$element->listChildren()}.\n";
} else {
echo "Element {$element->id} has no children.\n";
}
}
If you are using PostgreSQL as the database, you can use the connectby() function to create the record set:
SELECT *
FROM connectby('tableName', 'id', 'parent_id')
AS t(keyid text, parent_keyid text, level int);
I love this function, and use all the time in my code. It can do some very powerful things, very quickly, and you don't have maintain the left/right values like the (adjacency model).