问题
I am just posting this question so some of you might be able to point me in the right way. I am slowly warming up to OOP, starting to understand the concept. I want to make a good solid core or foundation to be used as a CMS backend. It will also use MVC. I have been using http://gilbitron.github.com/PIP/ as the MVC- base.
The thing I cant figure out is the following:
Say, on the projectpage in the backend I have 2 sections: htmltext and projects and I should be able to edit them both. The uri would be something like: //domain/backend/projects (the method would be the index and show the 2 sections)
When i click on projects how should it be handled? //domain/backend/projects/projects/ or //domain/backend/projects/list/
One step further, a project will hold some images or a gallery: //domain/backend/projects/edit/5/gallery/2
My question here is, first: would this be a good way to go and even more important how would this be implemented in OOP
the main projects controller:
class projects {
function index(){
// view index
}
function edit{
$project = new Project();
$projectdata = $project->load(5);
}
}
A single project controller
class project {
function __construct(){
$this->projectmodel = $this->loadModel('project_model'); // prepare the model to be used
}
function load($id){
$this->projectmodel->loadproject($id);
}
}
project model
class project_model extends model { //extends for DB access and such
function __construct(){
// do stuff
}
function loadproject($id){
return $this->db->query("SELECT * FROM projects where id=" . $id . " LIMIT 1");
}
}
Now my question. If this project has images, where should I load the image class to handle those? Should I load it in the project_model like $this->images = new Images(); and have a function inside the model
function loadimages($id){
$this->images->load($id);
}
and then images would be something like:
class image extends model { //extends for DB access and such
function __construct(){
}
function load($id){
return $this->db->query("SELECT * FROM project_images where id=" . $id . " LIMIT 1");
}
}
It seems controllers and models gets mixed up this way. Yet in a logical way a project is a container that holds projectinfo, which could be text, images and maybe video's. How would I go about to set that up logically as well.
回答1:
The original question
The first part, about the URLs is something called: Routing or Dispatching. There is quite good article about it in relationship with Symfony 2.x, but the the idea behind it is what matters. Also, you might looks at ways how other frameworks implement it.
As for your original URL examples, galleries will be stored in DB. Won't they? And they will have a unique ID. Which makes this, /backend/projects/edit/5/gallery/2
quite pointless. Instead your URL should look more like:
/backend/gallery/5/edit // edit gallery with ID 5
/backend/project/3 // view project with ID 3
/backend/galleries/project/4 // list galleries filtered by project with ID 4
The URL should contain only the information you really need.
This also would indicate 3 controllers:
- single gallery management
- single project management
- dealing with lists of galleries
And the example URLs would have pattern similar to this:
/backend(/:controller(/:id|:page)(/:action(/:parameter)))
Where the /backend
part is mandatory, but the controller
is optional. If controller is found , then id
( or page, when you deal with lists ) and action
is optional. If action is found, additional parameter
is optional. This structure would let you deal with majority of your routes, if written as a regular expression.
OOP beyond classes
Before you start in on using or writing some sort of PHP framework, you should learn how to write proper object oriented code. And that does not mean "know how to write a class". It means, that you have to actually understand, what is object oriented programming, what principles it is based on, what common mistakes people make and what are the most prevalent misconceptions. Here are few lecture that might help you with it:
- Inheritance, Polymorphism, & Testing
- Advanced OO Patterns (slides)
- Unit Testing
- The Principles of Agile Design
- Global State and Singletons
- Don't Look For Things!
- Beyond Frameworks (slide)
- Agility and Quality (slides)
- Clean Code I: Arguments
- Clean Code III: Functions
This should give you some overview of the subject .. yeah, its a lot. But is suspect that you will prefer videos over books. Otherwise, some reading materials:
- PHP Object-Oriented Solutions
- Design Patterns Explained
- Patterns of Enterprise Application Architecture
You will notice that a lot of materials are language-agnostic. That's because the theory, for class-based object oriented languages, is the same.
P.S.
Be careful with extends
keyword in your code. It means "is a". It is OK, if class Oak extends Tree
, because all oaks are trees. But if you have class User extends Database
, someone might get offended. There is actually an OOP principle which talks about it: Liskov substitution principle .. also there is a very short explanation
回答2:
If this project has images, where should I load the image class to handle those? Should I load it in the project_model like $this->images = new Images(); and have a function inside the model
Yes. The goal of the model is to encapsulate business logic so that you only need to write the algorithms once, and share them multiple times. What I would do if I were you is to add a getImages()
method to the Project model as the images are a direct attribute to a project, this makes it so that each project knows how to retrieve it's own images.
Your code is missing a few key concepts compared to ORMS I have worked with (hydration and peer/table) classes, so I will try to stick with your code. You can retrieve the images through the Project object, then reference the images via the view 1 of 2 ways:
// Controller
$this->project = new Project();
$this->projectImages = $project->getImages(); // Implemenation #2
// View
// Implemenation #1 (reference to object initialized in controller)
<?php foreach ($project->getImages() as $image): ?>
<img src="<?php echo $image['path'] ?>" />
<?php endforeach ?>
// Implemenation #2 (reference to separate variable initialized in controller)
<?php foreach ($projectImages as $image): ?>
<img src="<?php echo $image['path'] ?>" />
<?php endforeach ?>
Above is demonstrative only, but should give you an idea. I would suggest that you take a look at Doctrine. It is a proven and stable ORM which provides much of what you are attempting to write, plus it adds the missing components that I mentioned earlier; hydration, object relations, and Table classes, along with many other features such as nested sets.
回答3:
(since the question was long enough by itself I didn't want to extend it so I've added this as an answer)
projects.php this controller extends the project controller. the main purpose is to handle the multiple getAllProjects() using its own model and then pass it on to the project controller getProject()
class Projects extends Project{
public function __construct()
{
parent::__construct();
$this->projects_model = new Projects_model();
}
public function getAllProjects()
{
$res = $this->projects_model->getAllProjects();
if($res) foreach($res as $v) $projects[] = $this->getProject($v);
return $projects;
}
}
project.php
the project_model does nothing more than getting projectdata and related data like images
class Project{
public function __construct()
{
$this->project_model = new Project_model;
$this->images = new Images();
}
public function getProject($data=NULL)
{
if($data==NULL) $data = $this->project_model->loadProject($data['id']);
$images = $this->project_model->loadProjectImages($data['id']);
return array('project_id' => $data, 'project' => $data, 'images' => $images);
}
public function getProjectByID($id)
{
$data = $this->project_model->loadProject($id);
return getProject($data);
}
}
The upside of this approach, I can use the project class on it own and it will work. I can encapsulate it in projects and it can be used as well.
Is this a good (and the right) approach to do stuff? Or would it be better to put this all together in one controller and one model class?
来源:https://stackoverflow.com/questions/9846220/php-oop-core-framework