简体   繁体   中英

Best Practice approach to relating MySQL join queries to OOP and Objects

I'm working on a PHP web application where users can create trips to destinations, and invite other users on these trips.

I have MySql tables for Destinations , Trips , and Users , and a table called Invites to resolve the many-to-many relationship between Users and Trips .

For each of these tables, I've created a class within my application (so Destinations is a class, Trips is a class, etc.). I've written a static function for each of these classes that enables objects to be instantiated and their properties assigned from a MySQL query (so each row returned from a SELECT * query results in an object being instantiated and properties assigned).

I'm trying to create a page where my user can view details of all of the trips they have planned. This page will show the destination (from Destinations ), trip details (such as date from Trips ) and details of the users they have invited (such as username from Users ) and put all of this data in an html table where each trip is a row.

To achieve this, so far I've been instantiating Trips which relate to the user's user_id , Destinations and Invites which relate to those Trips , and Users which relate to those Invites . I've then used nested foreach loops to display these as necessary, such as the below:

foreach($trips as $trip) {
 foreach($invites as $invite) {
   foreach($invited_users as $invited_user) {
      if($invite->trip_id == $trip->id && $invite->guest_id == $invited_user->id) {
        echo $invited_user->name;
                  } } } }

Which I can see is horrible and no way to do this.

From reading around, I think I want to use MySQL to join the 4 tables, and then select only data relating to my relevant trips. What I'm not sure of though is:

a) How do I instantiate the objects and assign their properties correctly from this MySQL result?

b) Even with that done, how do I avoid the expensive foreach loops to display the correct data alongside the correct trip?

Is there a "best practice" way of displaying data from multiple related database tables in an object oriented way?

Firstly, "good practice" is one of those phrases people use to give their prejudices a veneer of respectability. It's better to ask how to achieve specific goals with a design.

Having said that: you've stumbled into a problem that's common in mapping an RDBMS to an object-oriented system. Google "Lazy Loading" for lots of discussion. The question comes down to the question of how many "relations" you load at any one time. In your example, trips are linked to destinations and users; when loading a "trip", should you also load the destinations and users? And if you do, should you then also load the other information for a user (eg the other trips they're on?). And if you do, do you load the trip data for all the trips the user is on? And so on - if you're not careful, you end up loading the entire database.

The downside of not loading all of the related entities is that performance can become very poor if you load the data for each object at a time.

For a detailed description of what I believe is best practice, buy and read "Domain driven design" by Evans.

As a shortcut, consider creating a "repository" layer which knows how to map database records to objects, and create custom methods for searching what you want. For instance, you might invoke:

$repository::getTripsForUser($userID);

That method would execute a SQL query joining the 4 tables together, and turn the results into an object tree.

You may want to take advantage of the work that others have done in solving this problem; there are a number of "object relational mapping" frameworks which solve this problem. I think the jury is still out on whether ORM solutions make life easier - but it's worth looking at.

I think you are complicating things, you don't need to load all the data at once.

Why iterate over all trips, while you need to display the trips of one user ?

A naïve but simple approach with OOP : a User class with a method to retrieve user's related trips.

It could return an array of Trip , having itself references of invited users :

class User {
    private $id;
    public function __construct($id) {
        $this->id = $id;
    }
    public function getTrips() {
        $trips = array();
        // Run your query using $this->id to build the WHERE clause
        return $trips;
    }
}

class Trip {

    // Array of User objects invited to the trip        
    private $invited = array();

    // Other methods here to add/retrieve invited users

}

$user = new User(1);
foreach ($user->getTrips() as $trip) {
    // Do something with $trip
}

Ideally a User instance would be stored in session

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM