So had some great feedback, went back and read through a lot on OOP. So would you say this is correct? Where I've set variables in index.php you could use pdo to query the database to grab the user data and then say loop the objects?
index.php
<?php
// This is where you could query the db?
$firstname = "Vaughan";
$lastname = "Slater";
$age = 20;
// Create two new users
$user1 = new user($firstname, $lastname, $age); // From variables
$user2 = new user("Tom", "Jones", 41); // Static set
// Output new users & could you then loop this to pull a list of users from a query
echo print_r($user1, TRUE);
echo print_r($user2, TRUE);
?>
class.php
class user
{
private $_firstname;
private $_lastname;
private $_age;
public function __construct($firstname, $lastname, $age)
{
$this->_firstname = $firstname;
$this->_lastname = $lastname;
$this->_age = $age;
}
}
I think I'm making progress, just want to make sure I'm doing doing it wrong again.. It kind of reminds me of the relationship between things like html and css.
The basics are layed out, but now comes the complex part.
You'll have to query the DB. You'll get a collection to cycle over. For each item you get you'll have to copy the data into your objects and put them together into a collection (say, an array):
$users[] = new user($row['firstname'], $row['lastname'], $row['age']);
Note you can instruct with `pdo_mysql' to directly get objects instead of rows, so that copying will be done automatically.
Next, you'll cycle over that collection you have built and render it.
These passages are not necessary, you can directly render the database queries result.
This is a quick pointer to a wiki showing how to use pdo_mysql.
You'll have to do those passages if you want to stratify the application, which is a good (best?) practice.
This way, each cycle will be done in a different stratum and data is passed from one stratum to the next:
persistence (queries DB and populates $users[] array)
|
v
business (process data according to business logic)
|
v
presentation (render the results in HTML)
From top to bottom is the way data is passed trhough the strata.
Normally, though, the strata are shown in exactly the opposite way (bottom to top).
Related
The problem is not exactly passing arrays to objects per se, but distributing the initial values acquired from the database correctly in their related objects. Here's the situation. I have a forum member class and I need to pass only the values relevant to that class and also make it so it would assume certain array keys are one and the same, specifically the user ID key.
Example of a member class:
class Member {
private $id;
private $username;
public function __construct($row) {
foreach($row as $key => $value) {
$this->$key = $value;
}
public function getUserURL() {
return '' . $this->username . '';
}
}
Now imagine there is a posts table too and I need to get both post and user/author data from that:
$res = $db->query("SELECT posts.id, posts.author_id, users.username FROM posts JOIN users ON author_id = users.id");
$row = $res->fetch_assoc();
And now I need to inject the user data into the member class for instantiation:
$author = new Member($row);
And there goes the first problem. I'm not really injecting only the author data but also post data into it. This could be solved in a number of dubious ways. One of them is injecting the relevant values separately instead of entire array like this:
$author = new Member($row["author_id"], $row["username"], ...);
But this isn't very convenient as there could be more to author values than just these two, plus they can vary in number and position, which means I'd have to remember their positions and sometimes fill in the gaps with empty values or NULLs.
Of course, I could just ignore the fact I'm passing foreign data along, memory is cheap, but you may have noticed that there is still one more problem on top of it, which is the user ID key (author_id!= id). Depending on a page/table it can be "id", "uid", "author_id", "from_id", etc. Using an alias for user/author ID in the queries isn't an option either, because sometimes I need those foreign keys to be exactly what they are as they provide more leverage to the code logic.
A potential solution to both issues could be the following:
$author = new Member($row["author_id"]);
$author->getUserURL($row["username"]);
This way I don't have to worry about either foreign data or varying user/author ID keys as all are strictly defined and just once. However, the problem with this scenario is that it makes the member class hardly useful now that most of it has to be done manually. Passing values to each method for one thing. And if previously it would use existing object properties to concoct the needed result, now they mostly just return what's already in the array. What I really want is just inject an array and do something as simple as this:
$author->getUserURL();
$author->getUserAvatar();
$author->getUserHomepage();
...etc. But it seems unachievable unless two conditions are met: 1) Fixed user ID key, 2) Strictly user data. It obviously works on profile and members pages (no foreign data), but not anywhere else. Of course, I could ignore all that foreign data in object and just use array_key_exists() to check for all possible variants of author/user ID like this:
public function __construct($row) {
if(array_key_exists("author_id", $row)) {
$this->id = $row["author_id"];
}
if(array_key_exists("from_id", $row)) {
$this->id = $row["from_id"];
}
...
}
...but this is just not elegant enough. I need a more refined approach and I can't seem to come up with one. It appears that to get it right I have to at least partially break the class or somehow split the array into posts and user data, but I don't see how this could be done without too much work. It's at times like this that I just want to run two DB queries to get two separate arrays of data out of the box, which could solve everything, but everyone knows that that, too, is a bad practice.
So, has anyone got better ideas? I do realize that this isn't the best of questions as it's mostly about efficiency and not "how", but it's small things like this that could lead to bad coding in the long run and I'm still fresh to OOP.
I'm working on an application written in PHP. I decided to follow the MVC architecture.
However, as the code gets bigger and bigger, I realized that some code gets duplicated in some cases. Also, I'm still confused whether I should use static functions when quering the database or not.
Let's take an example on how I do it :
class User {
private id;
private name;
private age;
}
Now, inside this class I will write methods that operate on a single user instance (CRUD operations). On the other hand, I added general static functions to deal with multiple users like :
public static function getUsers()
The main problem that I'm facing is that I have to access fields through the results when I need to loop through users in my views. for example :
$users = User::getUsers();
// View
foreach($users as $user) {
echo $user['firstname'];
echo $user['lastname'];
}
I decided to do this because I didn't feel it's necessary to create a single user instance for all the users just to do some simple data processing like displaying their informations. But, what if I change the table fields names ? I have to go through all the code and change those fields, and this is what bothers me.
So my question is, how do you deal with database queries like that, and is it fine to use static functions when querying the database. And finally, where is it logical to store those "displaying" functions like the one I talked about ?
Your approach seems fine, howerver I would still use caching like memcached to cache values and then you can remove static.
public function getUsers() {
$users = $cacheObj->get('all_users');
if ($users === false) {
//use your query to grab users and set it to cache
$users = "FROM QUERY";
$cacheObj->set('all_users', $users);
}
return $users;
}
(M)odel (V)iew (C)ontroller is a great choice choice, but my advice is look at using a framework. The con is they can have a step learning curve, pro is it does a lot of heavy lifting. But if you want to proceed on your own fair play, it can be tough to do it yourself.
Location wise you have a choice because the model is not clearly define:
You'll hear the term "business logic" used, basically Model has everything baring views and the controllers. The controllers should be lean only moving data then returning it to the view.
You model houses DB interaction, data conversions, timezone changes, general day to day functions.
Moudle
/User
/Model
/DB or (Entities and Mapper)
/Utils
I use Zend and it uses table gateways for standard CRUD to avoid repetition.
Where you have the getUsers() method you just pass a array to it, and it becomes really reusable and you'd just have different arrays in various controller actions and it builds the queries for you from the array info.
Example:
$data = array ('id' => 26)
$userMapper->getUsers($data);
to get user 26
enter code here
$data = array ('active' => 1, 'name' => 'Darren')
$userMapper->getUsers($data);`
to get active users named Darren
I hope this help.
I am writing a small framework where my goal is to make it easy for my developers to set up a redirect to the details page of a resource after adding/inserting one.
Ordinarily this would be as easy as PDO::lastInsertID(), but I am using more than just the ID to identify the resource, I am also using a formatted version of the resource's name/title.
For example a new tournament might be called "Test Tournament" and therefore it's resource URI will be domain.com/tournament/328-test-tournament.
So when I redirect after inserting, I need to redirect to '328-test-tournament' and not just '328'. This is by design for URL integrity purposes. I don't want people accessing individual resources with mis-matched IDs and titles.
So that said, after I insert, I would like to be able to automatically return not just the ID, but the entire data set for what I entered, so that I can then format the title and redirect.
I could do this in the controller:
$this->TournamentModel->insert();
$id = PDO::lastInsertID();
$title = my_title_formatting_function($_POST['title']);
#header("Location: domain.com/tournament/{$id}-{$title}");
But I want a solution that's slightly more elegant like this:
$id = $this->TournamentModel->lastInsert();
Where lastInsert is actually a public method in the core model by retrieving not just the id of the last insert, but the entire row. I would then handle the title formatting and id concatenation right there.
Does something like this exist? Or at the very least is there a PDO method that returns the table that was inserted into so that I could construct a query using the table name and the id?
Check Doctrine or Propel.
They are two very famous Object Relational Mapper's, which have as base PDO.
ORM's can do what you asked, and have lots of other features you will enjoy, check it up.
Does a 'title' not belong to a Tournament object? i.e.
class TournamenentModel {
private $id;
private $title;
public function setTitle($title) {
$this->title = $title;
}
public function getTitleFormatted() {
return my_title_formatting_function($this->title);
}
}
in which case, your insert method might look something like
PDO::save(array('title' => $this->title));
and your workflow would be along the lines of:
$tournament = new TournamentModel();
$tournament->setTitle($_POST['title']);
$tournament->insert();
$title = $tournament->getTitleFormatted();
#header("Location: domain.com/tournament/{$id}-{$title}");
The title is persisted in memory until you release the object, there is no need to save and then retrieve it from a database?
I'm looking for a way to prevent repeated calls to the database if the item in question has already been loaded previously. The reason is that we have a lot of different areas that show popular items, latest releases, top rated etc. and sometimes it happens that one item appears in multiple lists on the same page.
I wonder if it's possible to save the object instance in a static array associated with the class and then check if the data is actually in there yet, but then how do I point the new instance to the existing one?
Here's a draft of my idea:
$baseball = new Item($idOfTheBaseballItem);
$baseballAgain = new Item($idOfTheBaseballItem);
class Item
{
static $arrItems = array();
function __construct($id) {
if(in_array($id, self::arrItems)){
// Point this instance to the object in self::arrItems[$id]
// But how?
}
else {
// Call the database
self::arrItems[id] = $this;
}
}
}
If you have any other ideas or you just think I'm totally nuts, let me know.
You should know that static variables only exist in the page they were created, meaning 2 users that load the same page and get served the same script still exist as 2 different memory spaces.
You should consider caching results, take a look at code igniter database caching
What you are trying to achieve is similar to a singleton factory
$baseball = getItem($idOfTheBaseballItem);
$baseballAgain =getItem($idOfTheBaseballItem);
function getItem($id){
static $items=array();
if(!isset($items[$id])$items[$id]=new Item($id);
return $items[$id];
}
class Item{
// this stays the same
}
P.S. Also take a look at memcache. A very simple way to remove database load is to create a /cache/ directory and save database results there for a few minutes or until you deem the data old (this can be done in a number of ways, but most approaches are time based)
You can't directly replace "this" in constructor. Instead, prepare a static function like "getById($id)" that returns object from list.
And as stated above: this will work only per page load.
In PHP I know many people will use a class to SET and GET session variables, I am doing this now in many classes, I need to know if I am doing it wrong though.
So for example lets pretend I have A class that need to use this
$session->get('user_id')
Which gets this value
$_SESSION['user_id']
Now in this class if I have 15 methods and in each method I need to access this value several time, currently I am calling $session->get('user_id') 20 times in a class if it is needed 20 times, should I be setting this 1 time per class to a local variable for that class and then access it? I am not sure if it makes any difference or not, my theory is that the way I am doing it now is 20 extra function calls that could be avoided?
If my theory is correct, what would be the best way to store these values inside a class? Like a private or public or protected variable?
Thanks, sorry for any confusio, classes and objects are taking me a while to learn.
Also note that $session->get('user_id') is just 1 of many DIFFERENT variables I would need to do the same thing to as well.
UPDATE
After reading Chacha102's post about using an array() ... here is what I have tried, does this look like a good way or still can be improved a lot?
class file
<?PHP
class User
{
// Load user details into an Array
public function load_user()
{
$this->user_id = $this->session->get('user_id');
//if user ID is already set, then Load the cached urser data
if(isset($this->user_id) && $this->user_id != ''){
// set user data to an array
$this->user['user_id'] = $this->user_id;
$this->user['user_name'] = $this->session->get('user_name');
$this->user['pic_small'] = $this->session->get('pic_small');
$this->user['sex'] = $this->session->get('sex');
$this->user['user_role'] = $this->session->get('user_role');
$this->user['location_lat'] = $this->session->get('location_lat');
$this->user['location_long'] = $this->session->get('location_long');
$this->user['new_user'] = $this->session->get('new_user');
return $this->user;
}
}
}
?>
main page file
<?PHP
require 'user.class.php';
$user = new User;
// if a user_id is set into a session variable then we return an array of other user related data
$user->account = $user->load_user();
// would show the user's ID from our array
echo $user->account['user_id'];
?>
If you are doing something like this:
if($session->get('user_id')==1)
{
$prefs = get_prefs($session->get('user_id'));
$info = get_info($session->get('user_id'));
}
then I would replace it with a since local variable
$id = $session->get('user_id');
if($id == 1)
{
//.....
}
It increases clarity for one. It probably isn't a big deal to call a simple function like that over and over again, but I still wouldn't do it.
I try to reduce the number of functions I call in a single method. If you are doing something like:
$user_id = $session->get('user_id');
$name = $session->get('name');
// ... etc ...
You might just want to grab an array of all the session variables instead.
$user = $session->get_array();
echo $user['user_id'];
This reduces the function calls, and you get all the data in one fell swoop.
Just one thing on clarity, using an array of user data is probably easier to read than to create a variable for each thing ($user_name, $user_id, etc).
For accesses distributed over a number of methods, as long as you're just using the function to access the variable, I'd say stay with the function. The additional cost is minuscule, and it's better for long term maintainability.
Within the same method, you would make one function call, populating a local variable, as Chacha102 suggests.
Even if the function does resource-intensive things like database calls, I would prefer giving the function some internal caching before adding a member to your class.
Adding the variable as a member to your class doesn't really make sense in the OOP way, because it's not a logical, legitimate member of the class but just a temporary variable.