SitePoint Sponsor

User Tag List

Page 1 of 5 12345 LastLast
Results 1 to 25 of 116
  1. #1
    SitePoint Wizard
    Join Date
    May 2003
    Location
    Berlin, Germany
    Posts
    1,829
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Task Manager - what is your first impression of this API?

    Any comments or criticism that you want to shoot? Would be most appreciated.

    PHP Code:
    <?php

    /*
    +--------------------------------------------------------------------------
    | by Tim Koschuetzki
    | Date started: 11th November 2003
    +--------------------------------------------------------------------------
    */

    class CtaskSystem
    {
        var 
    $DB;
        var 
    $SITE;
        var 
    $INFO;
        var 
    $URL;
        
        var 
    $skin;
        var 
    $lang;
        var 
    $heading;
        var 
    $content;
        var 
    $breadCrumb;

        var 
    $taskUserIds = array();

        var 
    $subTasks = array();
        var 
    $subTaskUserIds = array();
        var 
    $subTaskHeadings = array();
        var 
    $subTaskLinks = array();

        var 
    $progressReports = array();

        function 
    CtaskSystem$INFO, &$SITE, &$URL )    {
        }
        
    //---------------------------------------------------------------------------------------------------------------------------------
    //---------------------------------------------------------------------------------------------------------------------------------
    // MAIN FUNCTIONALITY METHODS
    //---------------------------------------------------------------------------------------------------------------------------------
    //---------------------------------------------------------------------------------------------------------------------------------

        
    function emailReminder()    {
        }

        function 
    addTask()    {
        }

        function 
    editTask()    {
        }

        function 
    editProgressBar()    {
        }

        function 
    viewTasks()    {
        }

        function 
    deleteTask()    {
       }

        function 
    acceptTask()    {
       }

        function 
    addProgressReport()    {
        }

        function 
    editProgressReport() {
        }

        function 
    deleteProgressReport()    {
       }

        function 
    discussTask() {
        }

        function 
    editTaskComment() {
        }
        
        function 
    deleteTaskComment()    {
       }

    //---------------------------------------------------------------------------------------------------------------------------------
    //---------------------------------------------------------------------------------------------------------------------------------
    // HELP METHODS
    //---------------------------------------------------------------------------------------------------------------------------------
    //---------------------------------------------------------------------------------------------------------------------------------

        
    function getTaskBasedOnId$taskId$wrapTableAroundIt 0$parentTask )    {
        }

        function 
    fillSubTasksArray()    {
        }
        
        function 
    getSubTaskLinks$taskId$callStack$subTaskLinks = array() )    {
        }
        
        function 
    getSubTaskIDsOfTaskId$taskId$subTaskIDs = array() )    {
        }

        function 
    isSubTask$taskId )    {
        }
        
        function 
    getNumberTasks$uId )    {
        }

        function 
    storeProgressReports()    {
        }

        function 
    getProgressReportsFromTaskId$tId )    {
        }

        function 
    getProgressReportEditLinksFromTaskId$tId )    {
        }

        function 
    getProgressReportDeleteLinksFromTaskId$tId )    {
        }

        function 
    getNewTaskMemberlist$dropDownBoxName$selectedMember = -)    {
         }

        function 
    getNewTaskDepartmentlist$dropDownBoxName$selectedDept = -)    {
         }

         function 
    mayAddTask$userId$projId$deptId )     {
        }

         function 
    mayEditTask$userId$taskId$projId$deptId )     {
        }

         function 
    mayDeleteTask$userId$taskId$projId$deptId )     {
        }
    }

    $TASK_SYSTEM = &new CtaskSystem$INFO$SITE$URL );
    ?>

  2. #2
    Non-Member
    Join Date
    Jan 2004
    Location
    Planet Earth
    Posts
    1,764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    A God class

    My impression is that you should seperate (encapsulate) the Email, Task and ProgressReport functionality into their own classes

  3. #3
    SitePoint Wizard
    Join Date
    May 2003
    Location
    Berlin, Germany
    Posts
    1,829
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    A God Class? How do you mean that Widow? Positive or Negative?

    Thanks for the feedback.

  4. #4
    SitePoint Wizard
    Join Date
    May 2003
    Location
    Berlin, Germany
    Posts
    1,829
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I am also thinking about encapsulating the task discussion system (task comments).

  5. #5
    SitePoint Zealot Overunner's Avatar
    Join Date
    Mar 2004
    Location
    Sweden
    Posts
    180
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    My first is impression is: God Class
    It does way too much. I would separate atleast the 'ProgressReports' and the 'Tasks'. It is better to have classes which are responsible for smaller things, than having one large (and thus maybe bloated) class. I am sure there are quite a few posts (about OOP) which could help you. (tip: Search)

  6. #6
    SitePoint Wizard
    Join Date
    May 2003
    Location
    Berlin, Germany
    Posts
    1,829
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ah, that's what you mean by god classes. Well I will think of something.

    Any recommendations concerning how I shall encapsulate comments, progress reports, and tasks?

  7. #7
    SitePoint Enthusiast
    Join Date
    Jun 2003
    Location
    Chicago
    Posts
    73
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by DarkAngelBGE
    Ah, that's what you mean by god classes. Well I will think of something.

    Any recommendations concerning how I shall encapsulate comments, progress reports, and tasks?
    I would make them completely seperate classes; I don't really see the need for inheritance in this example.

    Then again, I dont claim to know a lot of OOP theory or anything...

  8. #8
    Non-Member
    Join Date
    Jan 2004
    Location
    Planet Earth
    Posts
    1,764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I shall encapsulate comments, progress reports, and tasks?
    Depends really on what each one does in it's self yes ? Maybe if you could (unordered list) list some functions per each one first ?

    Though I'm no expert, I'll try to help you

  9. #9
    Non-Member
    Join Date
    Jan 2004
    Location
    Planet Earth
    Posts
    1,764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    ie

    PHP Code:
    ...
    function 
    addProgressReport()    { 
        } 

        function 
    editProgressReport() { 
        } 

        function 
    deleteProgressReport()    { 
       } 
    ... 
    It's obvious what these 3 methods do, though what with ? Database ? XML ? Plain Text ? Not sure myself

  10. #10
    SitePoint Enthusiast
    Join Date
    Jun 2003
    Location
    Chicago
    Posts
    73
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Widow Maker
    ie

    PHP Code:
    ...
    function 
    addProgressReport()    { 
        } 

        function 
    editProgressReport() { 
        } 

        function 
    deleteProgressReport()    { 
       } 
    ... 
    It's obvious what these 3 methods do, though what with ? Database ? XML ? Plain Text ? Not sure myself
    I may just be complicating things, but wouldn't the real OOP idea be to use an interface and abstract the data access so it wouldnt matter which of those it was?

  11. #11
    Non-Member
    Join Date
    Jan 2004
    Location
    Planet Earth
    Posts
    1,764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yep, maybe use a Factory to sort out which storage format you'd need

  12. #12
    SitePoint Wizard
    Join Date
    May 2003
    Location
    Berlin, Germany
    Posts
    1,829
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    That's true Asthetic.

    Well, I will post the complete AddProgressReport method here:

    PHP Code:
        //---------------------------------------------------------------------------------------------------------------------------------
        //---------------------------------------------------------------------------------------------------------------------------------
        // addProgressReport
        //
        //---------------------------------------------------------------------------------------------------------------------------------
        //---------------------------------------------------------------------------------------------------------------------------------

        
    function addProgressReport()
        {
            
    $txt '';

            if( !isset( 
    $this->URL->input['submit'] ) )
            {
                
    // task id was appended to url?
                
    if( isset( $this->URL->input['4'] ) )
                    
    $taskId $this->URL->input['4'];
                else
                {
                    
    $txt .= $this->SITE->error$this->lang['invalidTaskId'] );
                    return 
    $txt;
                }

                
    // get task which we want to add a progress report to
                
    $singleTask $this->getTaskBasedOnId$taskId$wrapTableAroundIt true$ParentTask false );
                
    $txt .= $this->skin->formAddProgressReport$singleTask$taskId );
            }
            else
            {
                
    // insert the report
                
    $sql $this->DB->compileDBInsertString(
                    array(
                        
    'date' => time(),
                        
    'report' => $this->URL->input['report'],
                        
    'task_id' => $this->URL->input['taskId']
                    )
                );
                
    $this->DB->query"INSERT INTO ".TABLE_TASK_PROGRESS_REPORTS." ({$sql['FIELD_NAMES']}) VALUES ({$sql['FIELD_VALUES']})" );

                
    // Redirect to task list of this user 
                
    $this->SITE->headerLocation "task/{$this->URL->current['projAbbrev']}/view/{$this->URL->current['deptAbbrev']}/{$this->SITE->USER->vars['id']}/";
            }

            return 
    $txt;
        } 
    Thanks guys (especially Widow). Your help means a lot to me.

    As for the "what with": You see the data is loaded from the DB and passed to some skinning functions that will wrap the necessary markup around the data.

  13. #13
    SitePoint Wizard
    Join Date
    May 2003
    Location
    Berlin, Germany
    Posts
    1,829
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I will post some new API draft soon.

  14. #14
    SitePoint Wizard
    Join Date
    May 2003
    Location
    Berlin, Germany
    Posts
    1,829
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Here it is, what do you think?

    PHP Code:
    <?php

    /*
    +--------------------------------------------------------------------------
    | by Tim Koschuetzki
    | Date started: 11th November 2003
    +--------------------------------------------------------------------------
    */

    class CtaskSystem
    {
        var 
    $DB;
        var 
    $SITE;
        var 
    $INFO;
        var 
    $URL;
        
        var 
    $skin;
        var 
    $lang;
        var 
    $heading;
        var 
    $content;
        var 
    $breadCrumb;

        var 
    $taskUserIds = array();

        var 
    $subTasks = array();
        var 
    $subTaskUserIds = array();
        var 
    $subTaskHeadings = array();
        var 
    $subTaskLinks = array();

        var 
    $progressReports = array();

        function 
    CtaskSystem$INFO, &$SITE, &$URL )    {
        }
    }
        
    class 
    emailReminder {
        function 
    emailReminder()    {
        }
    }

    class 
    task {
        function 
    add()    {
        }
        function 
    edit()    {
        }
        function 
    delete()    {
        }
        function 
    fetch() {
        }
        function 
    accept()    {
        }
        function 
    mayAdd()    {
        }
        function 
    mayEdit()    {
        }
        function 
    mayDelete()    {
        }
        function 
    getTaskBasedOnId$taskId$wrapTableAroundIt 0$parentTask )    {
        }
        function 
    totalCount() {
        }
    }

    class 
    subtask {
        function 
    store()    {
        }
        function 
    getLinks$taskId "" )    {
        }
        function 
    getIDs$taskId "" )    {
        }
        function 
    isSubtask$taskId "" )    {
        }
        function 
    totalCount$taskId "" )    {
        }
    }
        
    class 
    progressReport {
        function 
    store() {
        }
        function 
    add()    {
        }
        function 
    edit()    {
        }
        function 
    delete()    {
        }
        function 
    fetch() {
        }
        function 
    totalCount$taskId "" )    {
        }
    }

    class 
    comment {
        function 
    add()    {
        }
        function 
    edit()    {
        }
        function 
    delete()    {
        }
        function 
    view() {
        }
    }


    class ??? {
        function 
    getNewTaskMemberlist$dropDownBoxName$selectedMember = -)    {
         }

        function 
    getNewTaskDepartmentlist$dropDownBoxName$selectedDept = -)    {
         }

    }

    $TASK_SYSTEM = &new CtaskSystem$INFO$SITE$URL );
    ?>

  15. #15
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by DarkAngelBGE
    Any comments or criticism that you want to shoot? Would be most appreciated.
    I think one problem is that you are trying to design it. The other problem is that I don't yet know what "it" is, but that's more my problem.

    I'll try to explain . You have declared 29 operations now spread over several classes. That is a lot of interactions. Even if you aren't overwhelmed by this level of complexity, I certainly am .

    Even then all the skills available on this forum won't be enough to solve this . Without a clear idea of what the software is meant to accomplish anything we suggest will still be guesswork. Twenty nine features will multiply even the slightest error into a big pile of...er...confusion pretty quickly.

    How about we start with just one?

    Can you come up with one operation that your customer would perform. It has to have value to them (logging in is useless in itself). Either recording information, querying information or doing some calculation. With one clear goal we can write just enough code to meet that target and no more.

    After that one is designed add another. You can shuffle the methods around or split them into classes to meet this goal as well as the first. Add a third. This will require more shuffling and maybe even some deep thought. If it can get this bad at 3 (it will) no wonder 29 is difficult. This process can be repeated until your confidence level in the design drops to the point where you want to start testing it with code.

    But first we need just one. Game?

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  16. #16
    SitePoint Wizard
    Join Date
    May 2003
    Location
    Berlin, Germany
    Posts
    1,829
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Game.

    I am building a task manager. There are projects, departments and divisions. Each project may have some departments. Each department may have some division.

    Users are assigned to divisions, or if the department they should be in has no divisions then they will be assigned directly to this department (here I think one could make it simpler...always having divisions).

    A divisions is assigned to a department, a department is assigned to a project.

    Users have tasks...but since they can be members of various departments in various projects the task has some relation to the project, dept and div, too.

    Now one thing the code should do is displaying all tasks of a project. But that's only a task quickjump list..listing all department and divisions with their members and the member names are clickable (the link will guide you to their personal task list).

    When you are there, there will be the same quickjump again, but it will only show the other members of your department (not division!). The task list basically shows all tasks with their attributes (priority, deadline, difficulty, goal, why it is important,..).

    Now the next entity are the progress reports. Only related to a task implementing them should be easy. A task can have many progress reports, there is no other relation (other than the relation to a user that adds them to HIS task).

    Reports are show as list within each task.

    Now that be good for a start?

  17. #17
    SitePoint Wizard
    Join Date
    May 2003
    Location
    Berlin, Germany
    Posts
    1,829
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks a lot guys that you are helping me out with this. I think after this refactoring I will have a level up in OOP.

  18. #18
    Non-Member
    Join Date
    Jan 2004
    Location
    Planet Earth
    Posts
    1,764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I see, well a division (your term) is to me a group, much the same thing really

    So to make things a lot simpler (for us all ) to design, why not reduce the number of actual tasks, by this I mean actions by user from the UI perspective yes ?

    For example, when you generate a list of data, ie Groups, only list the revelant data, that being

    1) Groups,
    2) Department(s) a Group belongs to

    Then when you list users, list the revelant data again, ie

    1) User,
    2) Their Group(s) - note, not thier Department(s)
    3) Tasks, by the task ID only

    So if you need to dig deeper, ie to list a task report, you'd click on a link (task ID) to get to it yes ? I wouldn't for the life of me list anymore detail than that.

    Going by the generated lists you have, you're just asking for trouble in my view, ie normalising the database table(s) to query to get to all your data ?

    Hope this makes some sense, so what I'm basically saying is that you only display the revelant data (minimum) required, then provide other means (Primary Keys) like links to get to the data that's ''underneath'' so to speak

    Doing it this way will also help you design your OOP as well I'd say as well

  19. #19
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by DarkAngelBGE
    Now that be good for a start?
    A bit too much information .

    Quote Originally Posted by DarkAngelBGE
    Now one thing the code should do is displaying all tasks of a project.
    Aha! OK, let's start with that. How about this possible code...
    PHP Code:
    <?php
    require_once('tasks.php');

    $finder = &new TaskFinder();
    $tasks = &$finder->findByProjectName($_GET['project']);
    ?>
    <html><body><ul>
    <?php while ($task = &$tasks->next()) { ?>
        <li><?php print $task->getName(); ?></li>
    <?php ?>
    ?>
    </ul></body></html>
    This forces...
    PHP Code:
    class TaskFinder {
        function &
    findByProjectName($project_name) { }
    }

    class 
    TaskIterator {
        function 
    TaskIterator($database_result) { }
        function &
    next() { }
    }

    class 
    Task {
        function 
    Task($row) { }
        function 
    getName() { }

    Now we need another complete operation, from your previous post f you like. You choose...give me another

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  20. #20
    SitePoint Wizard
    Join Date
    May 2003
    Location
    Berlin, Germany
    Posts
    1,829
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    @Marcus: Generate the quick jump list above the task list... quick jump list has all members of the department the user whose task it is belongs to.

    @Widow: Yeah I see, well let's see.

  21. #21
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by DarkAngelBGE
    Generate the quick jump list above the task list... quick jump list has all members of the department the user whose task it is belongs to.
    Something like...
    PHP Code:
    $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(); 
    Now it looks like...
    PHP Code:
    class 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() { }

    I am starting to see commonality already. The two iterators differ only in class name and their construction is hidden from the public code. These two can be merged into...
    PHP Code:
    class DataAccessorIterator {
        function 
    DataAccessorIterator($database_result$class) { }
        function &
    next() { }

    Another?

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  22. #22
    Non-Member
    Join Date
    Jan 2004
    Location
    Planet Earth
    Posts
    1,764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Can we have a pause, so we can take all this in ?

  23. #23
    Non-Member
    Join Date
    Jan 2004
    Location
    Planet Earth
    Posts
    1,764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Paying more attention to your examples Marcus, I see this statement, below

    PHP Code:
    ...
    $department = &$task->getOwningDepartment(); 
    ... 
    Which of course makes some sense, however, looking at your class interfaces, the class method belongs to the class Task, although going by your example, the object $task is comprised from the TaskFinder class ??

    Not sure therefore, how you would be able to use the class method belonging to class Task ?

    Maybe you could explain some more

  24. #24
    SitePoint Wizard
    Join Date
    May 2003
    Location
    Berlin, Germany
    Posts
    1,829
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Exactly my thoughts, Widow. Just noticed it myself.

  25. #25
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by Widow Maker
    Which of course makes some sense, however, looking at your class interfaces, the class method belongs to the class Task, although going by your example, the object $task is comprised from the TaskFinder class ??
    Yep. There are several considerations here in order of likelyhood:
    1) We are just fleshing out the design at this stage and how the task does it's work is not yet a consideration.
    2) What you are describing is package level decoupling, but I think they are in the same conceptual package.
    3) It might be fine.
    4) I might have got it wrong.

    Here is the kind of short term code I am thinking of...
    PHP Code:
    class Task {
        ...
        function &
    getOwningDepartment() {
            
    $owner = &$this->getOwner();
            return 
    $owner->getDepartment($task->getName());
        }
        function &
    getOwner() {
            if (! 
    $this->_owner) {
                
    $finder = &new PersonFinder();
                
    $this->_owner = &$finder->findByName(
                        
    $this->getOwnerName());
            }
            return 
    $this->_owner;
        }

    If you want to decouple the domain objects from the finders (not yet necessary) then the easiest way is for the finders to inherit from some core code. This is a partial solution, but you can decouple it further by creating all the finders from a factory (LayerSupertype)...
    PHP Code:
    class Repository {
        ...
        function &
    createFinder($class) { ... }

    This way also means that such things as connection handling can be handled here as well, passing a connection into the finder constructor when it is created. Generally nicer, but more complex.

    I haven't had a requirement for this yet and I find it hard enough to design an application in the first place, without making it super decoupled as I go .

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •