How to realize jQuery async treeview in PHP? - php

I want to integrate an async treeview in PHP. Now i want to know how to generate a source php file with PHP.
Now my database structure is like this:
Create table School(
id int(10) NOT NULL AUTO_INCREMENT,
name varchar(50),
primary key(id)
);
Create table Class(
id int(10) NOT NULL AUTO_INCREMENT,
name varchar(50),
school_id int(10),
primary key(id),
foreign key(school_id) reference School(id) on delete cascade
);
Student(
id int(10) NOT NULL AUTO_INCREMENT,
name varchar(50),
class_id int(10),
primary key(id),
foreign key(class_id) reference Class(id) on delete cascade
);
School -> Class -> Student
Now, i want to realize the treeview. Do you have any ideas of implementing it?
Thanks a lot.
Additional question: When i finish the treeview. If i click the items in the treeview, it will generate a result table by clicking. Do you know how to do that?
However, firstly i should finish the treeview.

So basically you need to (pseudo code):
$tree = array();
/**
* the following line essentially executes the Query:
* SELECT * from schools;
* and returns all the rows in an array like
* $schools = Array(0=>array('id'=>1, 'name' => 'name'))
*/
$schools = $db->schools()->selectAll();
foreach($schools as $school)
{
$schoolArr = array('text' => $school['name']);
/**
* Similar to the calls to school above except the query would be:
* SELECT * from class where class.school_id = $school['id']
* $school['id'] is the pk from the particular school record
*/
$classes = $db->classes()->select("school_id = ?", $school['id']);
$classesArr = array();
foreach($classes as $class)
{
$classArr = array('text' => $class['name']);
/**
* Similar to the calls to school above except the query would be:
* SELECT * from student where student.class_id = $class['id']
* $class['id'] is the pk from the particular class record
*/
$students = $db->students()->select('class_id = ?', $class['id']);
$studentsArr = array();
foreach($students as $student)
{
$studentsArr[] = array('text' => $student['name']);
}
$classArr['children'] = $studentsArr;
$classesArr[] = $classArr;
}
$schoolArr['children'] = $classesArr;
$tree[] = $schoolArr;
}
$jsTreeString = json_encode($tree);
Now obviously as you go through each loop you need to be assinging your other tree properties. then when youre all done just json_encode the array and echo it where i needs to be. At least thats how id work it. Note though, that you can probably do this without an individual query using some joins but i didnt want to get into all that - youll definitely wann explore that though if performance is at all an issue.

If you want this treeview to be done with jQuery I would suggest using this plugin. You just need to run one JS function and it will work. And all your PHP part has to do is get data from db and generate a HTML that jQuery plugin can transform into treeview.

It looks like this article/example code might be of interest to you in implementing the tree view.

Related

Eloquent insert id with sequence next value

I would like to create a new record in a PostgreSQL database table with Laravel eloquent but the table id is not auto incremented and it's make my life more difficult.
Here is the sample structure:
CREATE TABLE billing (
id int8,
companyname varchar(255) NOT NULL,
...
PRIMARY KEY (id),
);
The id field isn't auto incremented and I can't change this. Furthermore I can't write triggers.
In Laravel I would like to do something like this:
$billing = new Billing;
$billing->id = DB::raw("nextval('sequence')");
$billing->companyname = $request->companyname;
// ...
$billing->save();
It's working but it seems messy.
How could I simplify the DB (id) part of my code?
Thanks!
Try with
$billing->id = DB::getPdo()->lastInsertId(); // + 1 ?
with this
$nextval=DB::select(DB::raw("SELECT nextval('".(new Billing())->getTable()."_id_seq') as seq"))[0]->seq;
$billing = new Billing;
$billing->id = $nextval;
$billing->companyname = $request->companyname;
// ...
$billing->save();

EditableGrid, "addcolumn" loop

Trying to make a loop for EditableGrid code.
This is how it looks now.
$grid->addColumn('id', 'ID', 'integer');
$grid->addColumn('site', 'Site', 'string');
So if I need to add a new column to the page, I add a new column in MySQL database and also add a new row in this code, like:
$grid->addColumn('newcolumn', 'A brand new column', 'string');
In order to automatically add new columns to the page I want to make a loop, which gets inputs for the first argument (name of the field in the database) taken from the table:
CREATE TABLE price (
id INT(11) NOT NULL AUTO_INCREMENT,
site VARCHAR(50) NOT NULL,
and the other two arguments (label that will be displayed in the header and data type of the column in MySQL) taken from this table:
CREATE TABLE header (
header_name VARCHAR(50) NOT NULL,
header_type VARCHAR(50) NOT NULL,
Ok, think I found the solution. In order to create the loop, we create 2 queries, which are:
$get=$mysqli->query('SELECT header_name, header_type FROM header');
$get1=$mysqli->query('SHOW COLUMNS FROM price');
then we make a loop
while($row = mysqli_fetch_assoc($get) and $row1 = mysqli_fetch_assoc($get1)){
$grid->addColumn(''.$row1['Field'].'', ''.$row['header_name'].'', ''.$row['header_type'].'');}
I, guess, that's it. Also, if you need to exclude some of the columns, use this piece of code:
if($row1 == 'id' || $row1 == 'site')
continue;

Add an other attribute to link function

I would like to insert in relation table an other attribute ("tiers_temps" in my example) that ids, is it possible with the function "link()" or others ?
I use actually this codes, but I must update the filed "tiers_temps" :
$Examen->link('Users', $listAdd);
with the table "user_has_examen" structure :
Field Type Null Key Default Extra
user_id int(11) NO PRI 0
examen_id int(11) NO PRI 0
tiers_temps int(11) YES NULL
There is un error in your proposition. The object $user refers to the table "user" and not "user_has_examen" (not descibe before, that's right) so "tiers_temps" doesn't exist for user.
This solution works but I loop access Doctrine...
foreach($user as $userId){
$UserExam = Doctrine::getTable('UserExamen')->findByDql('user_id = ? AND examen_id = ?', array($userId, $exam))->getFirst();
if($UserExam->tiers_temps != $users[$userId]){
$UserExam->tiers_temps = $users[$userId];
$UserExam->save();
}
}
I didn't find a nice way to interact with an intermediate item. But you can act on the relations to retrieve all user, and then, apply your tiers_temps value before saving your Examen:
$Examen->link('Users', $listAdd);
$users = $Examen->Users;
foreach ($users as $user)
{
$user->tiers_temps = '45';
}
When I find myself in these situations I prefer to give up the table many to many Identifying and move to a structure like this:
id
user_id
examen_id
tiers_temps
because I find it very inconvenient to manage the value tiers_temps in the structure you used.

Recursive Function To Create Array

i use kohana framework and i am trying to code recursive function to create category tree.
My Categories Table
id int(11) NO PRI NULL auto_increment
name varchar(50) NO NULL
parent_id int(11) NO NULL
projects_count int(11) NO NULL
My Example Which Is Not Work
public static function category_list($parent_id = 0)
{
$result = Database::instance()->query('
SELECT name, projects_count
FROM project_categories
WHERE parent_id = ?',
array($parent_id)
);
$project_categories = array();
foreach($result as $row)
{
$project_categories[] = $row;
Project_Categories_Model::factory()->category_list($parent_id + 1);
}
return $project_categories;
}
Using this kind of hierarchical data implementation is highly non-optimal, because to get every subcategory you need do a separate query to the database. Like here you want to create recursion function.
If you still can change your table architecture please check Managing Hierarchical Data in MySQL.
This article describes a solution, how to fetch the whole hierarchy in one time query, so the recursive function will not be necessary.

php infinite loop

This function gives me an infinite loop
function getCats($parent,$level){
// retrieve all children of $parent
$result = "";
$query = "SELECT title,parent_id from t_cats where parent_id = '$parent'";
if($rs = C_DB::fetchRecordset($query)){
while($row = C_DB::fetchRow($rs)){
$result .= str_repeat($parent,$level).$row['title']."\n";
getCats($row['parent_id'],$level+1);
}
}
return $result;
}
here is my db table
CREATE TABLE `db`.`t_cats` (
`ID` int(10) unsigned NOT NULL auto_increment,
`datasource_id` int(10) unsigned default '0',
`version` char(10) character set latin1 default 'edit',
`status` char(10) character set latin1 default 'new',
`modified_date` datetime default NULL,
`modified_by` int(10) unsigned default '0',
`title` char(255) character set latin1 default NULL,
`parent_id` int(11) default NULL,
PRIMARY KEY (`ID`),
KEY `idx_datasource_id` (`datasource_id`)
) ENGINE=MyISAM AUTO_INCREMENT=50 DEFAULT CHARSET=utf8;
I just want to be able to get my list of categories recursive.
But what am i doing wrong?
EDIT:
function getCats($parent,$level){
// retrieve all children of $parent
$result ="";
$query = "SELECT title,parent_id from t_cats where parent_id = '$parent'";
if($rs = C_DB::fetchRecordset($query)){
while($row = C_DB::fetchRow($rs)){
$result.= str_repeat($parent,$level).$row['title']."\n";
getCats($row['id'],$level + 1 );
}
}
return $result;
}
This line looks wrong:
getCats($row['parent_id'],$level+1);
You should be calling it with the current child ID - at the moment you're calling it with the same ID over and over. Something like this (you need to select the id from your table):
getCats($row['id'], $level + 1);
Edit: you need to update your query to select id:
$query = "SELECT id, title, parent_id from t_cats where parent_id = '$parent' AND id != parent_id";
I've also added a bit to stop it getting into a loop if an item is its own parent.
I found this SitePoint article on "Storing Hierarchical Data in a Database" very helpful. It's all PHP examples, and it will improve the performance of what you're trying to do dramatically.
Maybe one of the items in the db has itself as parent?
I don't know C_DB, but I'd bet that the $rs returned by fetchrecordset is a reference, which means that every invocation of getCats is using the same $rs. Exactly what it will do then is unpredictable, depending on how fetchRow is implemented.
If you want to do this (and recursive closures are a pain in SQL, I know), you should open a new connection inside getCats. and be using a separate connection for each access.
correct answer provided by greg ...
2 side notes:
in the case of infinite loops, track recursion depth (you can conveniently use $level here) or overall invocation count (if you are lazy, since this is a oneliner accessing a global counter), and terminate recursion with an exception, when it reaches a maximum value (in general, 10 is already enough to see the problem, but of course that may vary) ... and then get some debug output ... for example $query or something like "calling getCats($parent,$level)" ... would've shown you the problem in no time in this case ... :)
you should minimize the amount of queries ... traversing a tree like that is quite inefficient ... especially, if the database is on another machine ...
greetz
back2dos
Erm shouldnt it be:
$query = "SELECT title,parent_id from t_cats where id = '$parent'";
And not:
$query = "SELECT title,parent_id from t_cats where parent_id = '$parent'";

Categories