This is an OOP question and probably answerable even if you don’t have PHP knowledge. (A side note – we are learning PHP OOP and decided to create a github to hopefully help others learn this and other best practices a bit easier, https://github.com/nizamani/PHPBestPractices1-OOP if you are interested. PRs, issues etc are very welcome)
I think we have two questions that are intertwined, but if you think I should split this up into a single question please let me know.
Overview
A simple app with 3 database tables, containing users’ name, age, favorite food and favorite restaurant.
Goal/Output
Our current goal (exact question will be listed below) is to use OOP and a user
object to get and display a single user's name, age, favorite food, and favorite restaurant.
Example output:
"User's name is Jenn, age is 28, favorite restaurant is KFC and favorite food is Fried Chicken"
Database
To make this as simple as possible for beginners to try out, we’ve created a "fake db" using php arrays. The db “tables” are:
users
id name age favoriteRestaurantId favoriteFoodId
1 Mike 30 1 1
2 Jenn 28 3 3
restaurants
id name
1 McDonalds
2 Taco Bell
3 KFC
foods
id name
1 French Fries
2 Hamburger
3 Fried Chicken
Faked as php arrays:
// this represents a sql table named `users`
$users = array(
array("id" => 1, "name" => "Mike", "age" => 30, "favoriteRestaurantId" => 1, "favoriteFoodId" => 1),
array("id" => 2, "name" => "Jenn", "age" => 28, "favoriteRestaurantId" => 3, "favoriteFoodId" => 3)
);
// this represents a sql table named `restaurants`
$resturants = array(
array("id" => 1, "name" => "McDonalds"),
array("id" => 2, "name" => "Taco Bell"),
array("id" => 3, "name" => "KFC")
);
// this represents a sql table named `foods`
$foods = array(
array("id" => 1, "name" => "French Fries"),
array("id" => 2, "name" => "Hamburger"),
array("id" => 3, "name" => "Fried Chicken")
);
(https://github.com/nizamani/PHPBestPractices1-OOP/blob/master/src/fakedatabase/db.php)
Classes
Three classes, one for each table. Each column (except id) in the db maps to a property of the object.
class User
{
private $name;
private $age;
private $favoriteRestaurantId;
private $favoriteFoodId;
//...setter and getter methods, nothing more
}
class Restaurant
{
private $name;
//...setter and getter methods, nothing more
}
class Food
{
private $name;
//...setter and getter methods, nothing more
}
(https://github.com/nizamani/PHPBestPractices1-OOP/blob/master/src/classes/Domain/User/User.php
https://github.com/nizamani/PHPBestPractices1-OOP/blob/master/src/classes/Domain/Food/Food.php)
Current Usage
On a simple page, we want to display user 2's info. Their name, age, name of their favorite food and name of their favorite restaurant. This is how we do that, which we think is way too "manual" of a process:
// create user object
$userObject = UserFactory::createUser();
// get user data from the db and set to User object
$userRow = $this->usersTransactions->getUserById(2);
$userObject->setName($userRow["userRow"]["name"]);
$userObject->setAge($userRow["userRow"]["age"]);
$userObject->setFavoriteRestaurantId($userRow["userRow"]["favoriteRestaurantId"]);
$userObject->setFavoriteFoodId($userRow["userRow"]["favoriteFoodId"]);
// create restaurant object
$restaurantObject = RestaurantFactory::createResturant();
// get restaurant data from the db and set to Restaurant object
$userfavoriteRestaurantIdRow = $this->restaurantsTransactions->getRestaurantById($userObject->getFavoriteResturantId());
$restaurantObject->setName($userfavoriteRestaurantIdRow["restaurantRow"]["name"]);
// create food object
$foodObject = FoodFactory::createFood();
// get food data from the db and set to Food object
$userfavoriteFoodIdRow = $this->foodsTransactions->getFoodById($userObject->getFavoriteFoodId());
$foodObject->setName($userfavoriteFoodIdRow["foodRow"]["name"]);
// this will display the user's information
$this->response->setView('displayUserInformation/index.php');
$this->response->setVars(
array(
"name" => $userObject->getName(),
"age" => $userObject->getAge(),
"restaurant" => $restaurantObject->getName(),
"food" => $foodObject->getName()
)
);
Questions
Question #1 Would you agree that modifying the user object to contain favorite restaurant name and favorite food name would be best? That is the primary information we are going to be concerned with displaying throughout the app, so we think it logical:
class User
{
private $name;
private $age;
private $favoriteRestaurantId;
private $favoriteFoodId;
private $favoriteRestaurantName;
private $favoriteFoodName;
//...setter and getter methods, nothing more
}
Question #2 Currently, anywhere we want a user's info, we have to do a lot manually to create a user object, food object, and restaurant object. Seems ripe for mistakes. Imagining a new page where we want to display info of all of the users in our db, we will loop through user ids and then have all this manual stuff inside that loop. That doesn't seem logical, doesn't seem DRY. We think something like this would be very useful to, for example, get user id 2's info:
$user = createUserObjectByUserId(2);
Then on our hypothetical page where we want to display every user's info, we simply loop through user ids and call this createUserObjectById method. Would you agree? We don't know how best to do this. In our codebase we have a UsersTransactions class, but it is concerned with getting info from the users
table. What is the best practice here? We want to follow dependency injection best practices and OOP best practices, and can't really come up with a good way to accomplish this.
--
Thank you for taking the time to read all of that, and please feel free to tell us everything you would do differently here and in our github if you want to take a look at that. We want to learn best practices and get this right, and hopefully have a decent example for others to learn from.