Search code examples
model-view-controllerorganizationcakephp-1.3

CakePHP, organize site structure around groups


So, I'm not quite sure how I should structure this in CakePHP to work correctly in the proper MVC form.

Let's, for argument sake, say I have the following data structure which are related in various ways:

  • Team
  • Task
  • Equipment

This is generally how sites are and is quite easy to structure and make in Cake. For example, I would have the a model, controller and view for each item set.

My problem (and I'm sure countless others have had it and already solved it) is that I have a level above the item sets. So, for example:

  • Department
    • Team
    • Task
    • Equipment
  • Department
    • Team
    • Task
    • Equipment
  • Department
    • Team
    • Task
    • Equipment

In my site, I need the ability for someone to view the site at an individual group level as well as move to view it all together (ie, ignore the groups).

So, I have models, views and controls for Depart, Team, Task and Equipment.

How do I structure my site so that from the Department view, someone can select a Department then move around the site to the different views for Team/Task/Equipment showing only those that belong to that particular Department.

In this same format, is there a way to also move around ignoring the department associations?

Hopefully the following example URLs clarifies anything that was unclear:

// View items while disregarding which group-set record they belong to
http://www.example.com/Team/action/id
http://www.example.com/Task/action/id
http://www.example.com/Equipment/action/id

http://www.example.com/Departments

// View items as if only those associated with the selected group-set record exist
http://www.example.com/Department/HR/Team/action/id
http://www.example.com/Department/HR/Task/action/id
http://www.example.com/Department/HR/Equipment/action/id

Can I get the controllers to function in this manner? Is there someone to read so I can figure this out?

Thanks to those that read all this :)


Solution

  • I think I know what you're trying to do. Correct me if I'm wrong:

    I built a project manager for myself in which I wanted the URLs to be more logical, so instead of using something like

    http://domain.com/project/milestones/add/MyProjectName I could use http://domain.com/project/MyProjectName/milestones/add

    I added a custom route to the end (!important) of my routes so that it catches anything that's not already a route and treats it as a "variable route".

    Router::connect('/project/:project/:controller/:action/*', array(), array('project' => '[a-zA-Z0-9\-]+'));
    

    Whatever route you put means that you can't already (or ever) have a controller by that name, for that reason I consider it a good practice to use a singular word instead of a plural. (I have a Projects Controller, so I use "project" to avoid conflicting with it.)

    Now, to access the :project parameter anywhere in my app, I use this function in my AppController:

    function __currentProject(){
    // Finding the current Project's Info
        if(isset($this->params['project'])){
            App::import('Model', 'Project');
            $projectNames = new Project;
            $projectNames->contain();
            $projectInfo = $projectNames->find('first', array('conditions' => array('Project.slug' => $this->params['project'])));
            $project_id = $projectInfo['Project']['id'];
            $this->set('project_name_for_layout', $projectInfo['Project']['name']);
            return $project_id;
        }
    }
    

    And I utilize it in my other controllers:

    function overview(){
        $this->layout = 'project';
    
        // Getting currentProject id from App Controller
        $project_id = parent::__currentProject();
    
        // Finding out what time it is and performing queries based on time.
        $nowStamp = time();
    
        $nowDate = date('Y-m-d H:i:s' , $nowStamp);
        $twoWeeksFromNow = $nowDate + 1209600;
    
        $lateMilestones = $this->Project->Milestone->find('all', array('conditions'=>array('Milestone.project_id' => $project_id, 'Milestone.complete'=> 0, 'Milestone.duedate <'=> $nowDate)));
        $this->set(compact('lateMilestones'));
    
        $currentProject = $this->Project->find('all', array('conditions'=>array('Project.slug' => $this->params['project'])));
        $this->set(compact('currentProject'));
    }
    

    For your project you can try using a route like this at the end of your routes.php file:

    Router::connect('/:groupname/:controller/:action/*', array(), array('groupname' => '[a-zA-Z0-9\-]+'));
    

    // Notice I removed "/project" from the beginning. If you put the :groupname first, as I've done in the last example, then you only have one option for these custom url routes.

    Then modify the other code to your needs.