Check out phpGACL on SourceForge.
| SitePoint Sponsor |


Check out phpGACL on SourceForge.





Thanks.Will give it a go!



My first impression when reading this:
was WHAT THE F UCK?PHP Code:function getProgressReportDeleteLinksFromTaskId( $tId )
{
}
No, really, you should seperate that!
Sorry for the delayed response. Lots of family this weekend.
Working out very nicely actually. The final test will be in 1-2 years when the game is actually released. Then we can step back from the project and reevalute with a better perspective.Hm, tricky...how is it working out?
YeppersPresumeably to be used alongside IM solutions as well.
I think you have nailed it on the head there. Your right, it is more vuage, but also at the the same time gives Tim the freedom to approach it any way he desires. Which is cool, because ultimately the rest of the team is just interested in the final product.To give this thread some kind of closure I'll take a punt at your requirements (only fair) and you can point out possible difficulties.
Thanks again for your help guys, Tim will have to give you a test drive when he gets it all coded. We'll have to look into some of those pre-built solutions too.
Not sure this will help, but TasksPro written by Alex King is the best Task Management software I've found. It might help you nail your requirements a big.
http://www.taskspro.com (commercial)
http://www.alexking.org/index.php?co...ent.php&show=1 (free version)
Mike





Hi...
Actually you should be releasing often, so a test drive should be possible quite quickly, rightOriginally Posted by Wijitmaker
?
BTW there is another spec. guide here for projects whose users are external to an organisation...
http://joelonsoftware.com/articles/fog0000000035.html
...which act as a nice counterbalance to an in-house purely iterative approach.
yours, Marcus
Marcus Baker
Testing: SimpleTest, Cgreen, Fakemail
Other: Phemto dependency injector
Books: PHP in Action, 97 things
When you combine the two, how would it know which class to return (a Task or a Person?)Originally Posted by lastcraft





Would imagine that Composition has something to do with this no ? Would like to see an example myself thougha Task or a Person?![]()





Hi...
It takes the class name in the constructor. Assuming all of the persistent objects have the same constructor signature, all is well.Originally Posted by Radley
We have recently been rethinking persistence libraries in PHP. Most examples are Java based, which is based on the objects being available in memory between each request. This affects the approach and language at a fundamental level that permeates all of the systems I have seen so far. Even the word "persistence" belies that approach. Keeping this illusion of persistent objects is difficultin PHP when everything has to be constantly torn down and rebuilt on each page.
The rethink has produced a radical change in perspective and a much cleaner design. It's possible that every piece of advice I have ever given on this subject up to now has been wrong.
Anyway, I need to refactor our current system over to this new approach and test it before I publicise it futher.
yours, Marcus
Marcus Baker
Testing: SimpleTest, Cgreen, Fakemail
Other: Phemto dependency injector
Books: PHP in Action, 97 things


What do you mean by persistence libraries? Do you mean that you are keeping objects available in memory between requests in php or that by using a mapper you are keeping the illusion of persistent objects? Would love to see a high level example if you are keeping objects between requests.Originally Posted by lastcraft
Very interested in your thoughts on this when you get it all refactored.





Hi...
Keeping an illusion.Originally Posted by Brenden Vickery
Here is roughly what it looks like now...Originally Posted by Brenden Vickery
That would be from three mapped tables: Programmers, LanguageSkills (link table), Languages (has the name). Code generation and other sneakeness maps it to the object model above including the collection (one to many) and the join (many to one).PHP Code:$broker = &new PersistenceBroker('Programmer');
$broker->addCondition("type = 'Web'");
$programmers = &$broker->find();
$count_languages = array();
while ($programmer = &$programmers->next()) {
$languages = &$programmer->getLanguageSkills();
while ($language = &$languages->next()) {
@$count_languages[$language->getName()]++;
}
}
If you make any edits then the appropriate objects have to be committed out. That is easy enough. If you want transactions and you have multiple things going on at once, things get conceptually messy.
I'll post more later. I have a post card that has a big 6 on it. The six refers to the estimated six days work it should take me to refactor to the new scheme. We really are eternal optimists...
yours, Marcus
Marcus Baker
Testing: SimpleTest, Cgreen, Fakemail
Other: Phemto dependency injector
Books: PHP in Action, 97 things
Lets see 6 FTU / .3 realism factor = 20 Days, right on scheduleOriginally Posted by lastcraft
![]()
Jason Sweat ZCE - jsweat_php@yahoo.com
Book: PHP Patterns
Good Stuff: SimpleTest PHPUnit FireFox ADOdb YUI
Detestable (adjective): software that isn't testable.





Hi...
Actually yeah, although two days (estimated) are already doneOriginally Posted by sweatje
. We have switched to three week iterations and we can divide by .4 these days (giving ten real). Used to be a velocity of three estimated days per fortnight per pair. I am doing this one at home alone though, and so we have scheduled three weeks to go.
Give or take...
yours, Marcus
Marcus Baker
Testing: SimpleTest, Cgreen, Fakemail
Other: Phemto dependency injector
Books: PHP in Action, 97 things





Hey Marcus, one question arose now while refactoring some of this. What I now have is this:
Now finding a task in taskFinder, how'd you do that? Would the db call/xml file call/whatever be there? Should all tasks from the db/xml file/whatever be stored somewhere in the constructor? Speed issues?PHP Code:<?php
require_once( dirname(__FILE__)."/conf_global.php" );
require_once( dirname(__FILE__)."/sources/includes/database.php" );
$DB = &new Cdatabase( $INFO['sqlHost'], $INFO['sqlUser'], $INFO['sqlPass'], $INFO['sqlDBName'] );
$finder = &new taskFinder();
$task = &$finder->findByName($current_task);
$department = &$task->getOwningDepartment();
$people = &$department->getMembers();
$quick_list = &new quickJumpList();
while ($person = &$people->next()) {
$quick_list->addLink( $person->getName(), 'task_list.php?name='.$person->getName());
}
print $quick_list->paint();
class taskFinder {
function taskFinder() {}
function &findByProjectName($project_name) { }
function &findByName($name) { }
}
class taskIterator {
function TaskIterator($database_result) { }
function &next() { }
}
class task {
function Task($row) { }
function getName() { }
function &getOwningDepartment() { }
}
class department {
function Department($row) { }
function &getMembers() { }
}
class personIterator {
function PersonIterator($database_result) { }
function &next() { }
}
class person {
function Person($row) { }
function getName() { }
}
class quickJumpList {
function addLink($label, $url) { }
function paint() { }
}
?>





Hi...
Originally Posted by DarkAngelBGE
PHP Code:class TaskFinder {
...
function &findByName($name) {
$sql = "select * from tasks where name='$name'";
$connection = &$this->getConnection();
$iterator = &$connection->query($sql);
if (! $iterator) {
return false;
}
return new Task($iterator->next());
}
}
It can be quite happily and this is simplest at first. I have used a connection object here and you might consider using an object to wrap the SQL query as well. See what works and try it both ways.Originally Posted by DarkAngelBGE
If you are getting a group of rows then pass the result ID from the query into an iterator. That way you pull the results from the database only as you need them.Originally Posted by DarkAngelBGE
The only real issue is that sometimes mapping from relational data to objects can drive you into sub optimal queries against the database. Wait until you have a problem and then tackle it.Originally Posted by DarkAngelBGE
yours, Marcus
Marcus Baker
Testing: SimpleTest, Cgreen, Fakemail
Other: Phemto dependency injector
Books: PHP in Action, 97 things





So you would always have the DB calls in the task finder instead of having some external queryBuild object that would complicate things (now we have that database layer discussion again).
What if I want to list my tasks and then list Joe's tasks underneath? I'd need to call the taskFinder:findByName twice, but with the same query, only different nameId/name supplied. I could handle that in one query and break the results up. That's what I mean by performance, err, speed issues.





Marcus,
Not sure I follow ? What I do is to create an iterator with a resultset, so are you proposing that instead of using the resultset, use the actual database resource it's self ?If you are getting a group of rows then pass the result ID from the query into an iterator. That way you pull the results from the database only as you need them.
If so, do you have an example as I can't recall seeing an example of this before
Thanks.





How does this look to you Marcus? Obviously I would need a ton of queries if I want to store the people of the owning departments of 20 tasks. That would crash every server...
PHP Code:<?php
require_once( dirname(__FILE__)."/conf_global.php" );
require_once( dirname(__FILE__)."/sources/includes/database.php" );
$DB = &new Cdatabase( $INFO['sqlHost'], $INFO['sqlUser'], $INFO['sqlPass'], $INFO['sqlDBName'] );
$finder = &new taskFinder();
$task = &$finder->findByName($current_task);
$department = &$task->getOwningDepartment();
$people = &$department->getMembers();
class taskFinder {
function taskFinder() {}
function &findByProjectName($project_name) { }
function &findByName($name) {
$sql = "select title, member_id, department_id from tasks where name='$name'";
$connection = &$this->getConnection();
$iterator = &$connection->query($sql);
if (! $iterator) {
return false;
}
return new task($iterator->next());
}
}
class taskIterator {
function taskIterator($database_result) { }
function &next() { }
}
class task {
var $title = '';
var $owningMember = '';
var $owningDepartment = '';
function task($row) {
$connection = &$this->getConnection();
$this->title = $row['title'];
$sql = "select name from members where id='$row['member_id']'";
$iterator = &new personIterator( &$connection->query($sql) );
$this->owningMember = &new person($iterator->next());
$sql = "select name from departments where id='$row['department_id']'";
$iterator = &new departmentIterator( &$connection->query($sql) );
$this->owningDepartment = &new department($iterator->next());
}
function getOwningMember() {
return $this->owningMember;
}
function &getOwningDepartment() {
return $this->owningDepartment;
}
}
class departmentIterator {
function departmentIterator($database_result) { }
function &next() { }
}
class department {
function department($row) { }
function &getMembers() { }
}
class personIterator {
function personIterator($database_result) { }
function &next() { }
}
class person {
function person($row) { }
function getName() { }
}
?>


Hey guys, interesting stuff picking back up in this thread...Originally Posted by DarkAngelBGE
I'd use the db to do the job it's intended to do: have JOINS do the logic of finding the owning member and department, then loop through the resultset in your findByProjectName() method, building your Task objects and populating their member variables accordingly.
Cheers,
jay





So you would do this instead, Jay? :
PHP Code:class taskFinder {
function taskFinder() {}
function &findByProjectName($project_name) { }
function &findByName($name) {
$sql = "select t.title, m.memId, d.id as deptId".
" m.name as memName, m.email as memMail".
" d.name as deptName".
" from tasks as t".
" left join members as m on (t.mem_id = m.id)".
" left join departments as d on (t.dept_id = d.id)".
" where t.name='$name'";
$connection = &$this->getConnection();
$iterator = &$connection->query($sql);
if (! $iterator) {
return false;
}
return new task($iterator->next());
}
}
class taskIterator {
function taskIterator($database_result) { }
function &next() { }
}
class task {
var $title = '';
var $owningMember = '';
var $owningDepartment = '';
function task($row) {
$connection = &$this->getConnection();
$this->title = $row['title'];
$this->owningMember = &new person($row['memName'], $row['memMail'], $row['memId']);
$this->owningDepartment = &new department($row['deptName'], $row['deptId']);
}
function getOwningMember() {
return $this->owningMember;
}
function &getOwningDepartment() {
return $this->owningDepartment;
}
}





Going back to your previous posting, I was pondering on why you created an iterator just to pass over a single resultset ?
This is much better, even though in this case you have no need to pass over an actual resultset it's selfPHP Code:...
$this->owningMember = &new person($row['memName'], $row['memMail'], $row['memId']);
$this->owningDepartment = &new department($row['deptName'], $row['deptId']);
...
Maybe you can explain your reasoning behind the iterators though ?





I had no reasoning.
What do you guys think how this looks now?![]()





Well okay, ahving thought of it again ... what if I want to use the classes department and person without the task finder in some other context? Their constructors will always wait for the id/name/email/etc. parameters.
So supplying a resultset would allow them classes to be used in other contextes, too, yes?





I seeIn that case though, wouldn't a raw resultset be better, rather than an iterator ?
That being the case, the class constructor going to use the resultset could implement the iterator it's self, in the event that the constructor has to filter the resultset ?
Would an iterator cause hinderance ?





I don't think so.Could you support your code by a code sample, Widow?
![]()
Bookmarks