execv
execv

Reputation: 849

PHP OOP: Create a new class?

I have 3 tables:

users:
id
first_name
last_name

courses:
id
name

student_courses:
id
student_id
course_id
paid

Users keeps track of the users, courses keep track of the courses, and student_courses is the table that shows what students have signed up for which courses. I currently have a "users" class and a "courses" class. My question is: Should I create a StudentCourses class to handle the interactions for the student_courses table?

ie: I need to create a function that gets all courses a user has signed up for, mark them as paid, etc.

Is it best to do:

$student = new User($userId); 
$student->getCourses();
$student->markCourseAsPaid($courseId);

OR

$student = new User($userId);
$studentCourses = new StudentCourses($studentId);
$studentCourses->markCourseAsPaid($courseId);

etc.

Upvotes: 3

Views: 466

Answers (5)

Gordon
Gordon

Reputation: 316959

If you think about your student_courses and courses tables in terms of objects, you will notice that the student_courses is the really interesting table as it contains the individual objects for the student. They are what you want to have your Student object connect to. What you have in courses now is just the non-changing part of a course, e.g. it's name and description. Hence, your StudentCourse instances can simply aggregate that. You only need to load that instance once and then share it across StudentCourse instances:

Student hasMany Courses hasOne CourseDescription

For Cohesion, your markAsPaid method should be on the object with the most information required to fulfill it. In other words, it should be on Course. However, you can add a payForCourse proxy method on the Student that then calls markAsPaid on the appropriate Course. You might want to introduce a Courses class that acts as a Repository.

Upvotes: 4

JF Dion
JF Dion

Reputation: 4054

I would create a third class for course_student that would rely on a table on your database AND a view for the following reason, separation of concerns.

You view is used for all the select and the table for insert, update and delete.

Your view would be composed of all the relevant fields of both tables (using 2 inner join) (students and courses) based on the relations in your course_student table

A row will look like :

student_id, student_first_name, student_last_name, courses_id, courses_name, is_paid

If you want to get all the students taking a course you can have a method named getStudentsByCourse(courseId).

If you want to get all the courses of a specific student you can have a method named getStudentCourses(studentId).

If you need to register a set of students for a course (or many) you can have a method named setStudentsCourses(studentId, courseId) (where both parameters can be either integers or array.

Upvotes: 0

Joost
Joost

Reputation: 10413

I'd not create the separate class. My approach would be to use something like the following:

$student = new User($userId);
$course = new Course($courseId);
$student->markCourseAsPaid($course);

As the student_courses table is simply just a relationship, there shouldn't be an extra class. An extra class would imply that it's an entity, which it's not, it's a relationship.

My code differs from yours as I'm first fetching the appropriate Course instance, then passing that instance to the user. In my opinion it's weird to pass just the ID of the course, since then the User object just receives a number as parameter, which has no meaning at all. We might not have to ID (primary key) of the course, but a secondary key. Then this method becomes useless since it expects the PK, not some SK. Because I choose to fetch the Course object first we don't have this problem, as the Course object does know how to retrieve the correct course by a secondary key.

Edit: As this is an objectified relationship, there may be some point in using the extra class. But then I'd go with another approach:

$studentCourse = new StudentCourse($studentId, $courseId);
$studentCourse->markPaid();

As both the student ID and course ID make up for the secondary key of the table, they should both be specified in the constructor.

Upvotes: 0

Furgas
Furgas

Reputation: 2844

If you're going to extend the application in the future, I'd create separate class for StudentCourse. Now it has only one additional attribute except join attributes (paid), but when you will need to add another attributes you'll going to create this class anyway.

Upvotes: 3

Curt Mullin
Curt Mullin

Reputation: 61

Well in this case it looks like either may work.

usually you would make each model/table a class (i.e. a Student, a Course, a User etc.) in an MVC (model-view-controller) paradigm. Then in each class you might have a variable to relate them. I don't see the need for the StudentCourses class even though the table structure shows a relationship there should be no need for another class. The first example looks more object oriented to me. Again you could do it either way but I always opt for more object-oriented code myself.

Upvotes: 0

Related Questions