I'm mostly a designer and don't have a lot of experience with OOP in PHP, so please be kind as my terminology may not be exactly precise. It's the PHP/OOP syntax that I need the most help with, and I've searched for a solution several times here and on Google as I imagined this would be a pretty straight forward question but haven't found anything to help.
I'm trying to create a class method that pulls client account data from a database using the client's account ID. There are about 20 variables I want to pull and have access to on various pages on my site.
Here's my class file (classfile.php):
class Accounts{
// Function to get client data from database.
public function getAccount($acctId){
require("/var/www/vhosts/aqios.com/httpdocs/00omvat/dbinfo.php");
mysql_connect("localhost","user","password") or die();
mysql_select_db("database") or die();
$query = "SELECT * FROM clients WHERE id='$acctId' LIMIT 1";
$result = mysql_query($query) or die();
while($row = mysql_fetch_array($result)){
$this->$firstName = $row["firstName"];
$this->$lastName = $row["lastName"];
$this->$address1 = $row["address1"];
$this->$address2 = $row["address2"];
$this->$city = $row["city"];
$this->$state = $row["state"];
//etc., etc.
}
mysql_close();
}
}
Here's one of my pages (index.php):
include_once('classfile.php');
$acctId = 111111;
$object = new Accounts();
$object->getAccount($acctId); //Script dies unless I comment this line out.
First of all, the script dies unless I comment out that last line, so something must be wrong with my syntax there. But what I really need to know is how to call and place the city or any other of these variables into my page? I don't know the proper syntax. I can't imagine it would be $object->getAccount($acctId)->$city. I know that's wrong. How would I call the city or any other variable from this object?
Also, I do know that I should be using another method to connect to my database, and I will do that once I get this figured out first.
Thank you in advance for any help you can offer!
Jason
This is incorrect
$this->$firstName = $row["firstName"];
^---remove the $
It should be
$this->firstName = $row['firstName'];
And the same for the subsequent lines.
As mentioned by others, you should use $this->firstName instead of $this->$firstName
$this refers to the object, not to the method
It will work without explicit initialization, but you should define for better reading all your object fields as public (or private/protected and write getter methods):
class Accounts {
public $firstName;
public $lastName
...
}
With variables defined as in 3, you should be able to refer to their values with $object->firstName
You should probably consider splitting classes into two - Accounts (as a DB proxy) and Account (as a single account data) and in Accounts->getAccount you will create Account object and return it - but this is more of a architectual discussion
Related
I want to make a list of Best selling prints in my store.
I have a table (print_for_sale) which has fk_sale_id and fk_print_id where I can see how many prints have been bought.
I came up with this code to print out an organized list, from most bought to least (not sure it is entirely correct):
<?php
$sql = "SELECT fk_print_id as printId, COUNT(print_for_sale_id) as saleCount
FROM print_for_sale
GROUP BY fk_print_id
ORDER BY saleCount DESC";
$result = mysql_query($sql);
while ($row = mysql_fetch_assoc($result)) {
echo $row['printId']; echo $row['saleCount']; }
?>
I'm trying to make a transition of this to my model, controller and view (mvc) but I'm having a lot of trouble. I'm new to this and I've tried in so many different ways, none of which seem to work. I'm lost. Right now I have it like this (and it prints out nothing) or the only thing it prints out is "Notice undefined variable arr" when I make an echo in my view
model.php
function getBestSelling() {
$sql = "SELECT fk_print_id as printId, COUNT(print_for_sale_id) as saleCount
FROM print_for_sale
GROUP BY fk_print_id
ORDER BY saleCount DESC";
$result = $this->conn->query($sql);
return $this->buildArr($result);
}
controller.php
function bestselling() {
$arr = $this->model->getBestSelling();
print_r($arr);
include 'view.php';
}
view.php
<?php echo $arr['printId'] ?>
I want to print out the result of the query but nothing is working. I'm sorry if this isn't an appropriate question but I could really use some help understanding this.
I'm not using any framework.
In my model I do have a class model { }, a function __construct() and a function __destruct(). I also have a function to build the arrays.
function buildArr($result) {
$arr = array();
while ($row = $result->fetch_assoc()) {
array_push($arr, $row);
}
return $arr;
}
In my controller I include 'model.php'; and have a class Controller {} and function __construct() { $this->model = new model();}.
I also have a index.php where I start the session and define("BASE_URL", 'http://' . $_SERVER['SERVER_NAME'] . '/printstore/index.php/');
The app is working. I can already register users, login and make purchases. I just can't seem to get this part of the code right.
Would appreciate some help! Sorry for the long post and thank you in advance.
The included file is not behaving as you expect it to. To pull this off you will have to create a global out of the variable (but don't do it!). You can print_r() the array in the controller, because you're fetching it from the model. But after that you include the view. When you place that array in an included file, without defining it in the file itself, you're not going to get a result because only the including file has access to any defined variables. Not the other way around.
So if you want this to work you're going to either have to make the variable $arr global (not recommended), or include the controller in view.php. (Note that this is not MVC!) If you want this to be MVC you'll have to use classes for the controllers and use those objects in the view. To find a better explanation for this please refer to the links down below.
I am personally fond of using of a templating engines (also not MVC related). I'm quite fond of Smarty, but I've heard good stories about mustache too.
These templating engines provide you with a way to pass variables to your templates, without including the controller file. For example in Smarty:
PHP:
$variable = 'Hello World!';
$smarty->assign('variable', $variable);
$smarty->display('helloworld.tpl');
Smarty, helloworld.tpl:
{$variable}
Output:
Hello World!
I'd also recommend you to read these, they might help you out more than I've been able to explain.
Setting up MVC in PHP: http://www.sitepoint.com/the-mvc-pattern-and-php-1/
Including files in PHP: Passing a variable from one php include file to another: global vs. not
Edit
Teresko is right that you should not be using globals. I just specified them here, because it's possible to use them (definitely not recommended).
Read this question for a couple of why's: Stop using `global` in PHP
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).
I'm currently creating a simple CMS for my small website in PHP5. This is my first 'larger' project in PHP. First I'm creating the needed classes that would simplify me the work a little bit, and there I'm stuck. I need your opinions about the following function inside my UserInfo class:
public function setUser($id) {
if(!isset($id)) {
return false;
}
session_start();
$conn = new mysql($_SESSION['DBCONNINFO']);
$sql = "SELECT
usr.ID,
usr.USERNAME as TUSERNAME,
usr.FIRST_NAME,
usr.LAST_NAME,
usr.PHONE,
usr.MOBILE,
usr.EMAIL,
usr.ADDITIONAL_INFO,
usr.LAST_LOGIN_DATE,
usr.USER_GROUP_ID
FROM cms_users usr
WHERE usr.id = " . $id;
$result = $conn->query_cust($sql);
$conn=null;
foreach ($result as $row) {
$this->id = $row['usr']['ID'];
$this->username = $row['usr']['TUSERNAME'];
$this->firstname = $row['usr']['FIRST_NAME'];
$this->lastname = $row['usr']['LAST_NAME'];
$this->phone = $row['usr']['PHONE'];
$this->mobile = $row['usr']['MOBILE'];
$this->email = $row['usr']['EMAIL'];
$this->additional_info = $row['usr']['ADDITIONAL_INFO'];
$this->last_login_date = $row['usr']['LAST_LOGIN_DATE'];
$this->user_group = $row['usr']['USER_GROUP_ID'];
}
return true;
}
Am I doing it the right way, I'm not talking about the syntax, for now I focus on the class structure, design and best practices - any opinion would be appreciated.
Could I call the session_start(), for example, in the class constructor and use the vars inside it without calling it each time in a function !?
Should I close the DB connection via the close() function or is $conn=null acceptable !?
Is it a bad practice to store the database information in the session class !? If yes, where to store it as a 'global' variable - $_GLOBAL !?
If there is a 'PHP bes practice class structures in 5 minutes for dummies' please notify me :)
Thanks in advance.
Use define to define all of your constants.
For example:
define('DBCONNINFO', "something");
Also you only have to call session_start() once, it can be done anywhere in your script.
It doesn't make a lot of sense to fetch the data from the database for every request if you're using sessions anyway. In which case, why is session_start() being called inside the setUser() method?
And we can't really comment on the class structure when you've only provided a single method.
Also, since the representation of data leaving PHP should be appropriate to the substrate where that data is going (to prevent SQL injection, email header injection, CSS....) then it's good practice to defer changes to the representation of the data until just before the point where it leaves PHP. e.g.
$sql = "SELECT
....
WHERE usr.id = " . mysql_real_escape_string($id);
(or use bound parameters)
However since users are usually identify themselves by their username rather than their userid, it rather implies that $id came from somewhere other than user supplied data - in which case where? And why are you using this as the identifier when you've already got an identifier for the session (which is where this data should be getting stored).
Or do you want to use this class for processing data relating to users other than the user of the current session - in which case there is no way that there should be a session_start() in there.
Sorry - but this is not well thought out code and not a well presented question.
BTW, setting the connection to null does not close the database connection.
I'm trying to integrate the FedEx tracking class into my application. The class takes a SOAP response and puts it into a hierarchical class structure. I access the values like this:
$city = $response->TrackDetails->Events[$i]->Address->City;
This works fine for most cases. The problem I am having is when there is just one event for a given shipment, I get an error saying that I cannot treat the class as an array. Since there is just one event, I need to access it without the array index using:
$city = $response->TrackDetails->Events->Address->City;
Is there a way to deal with this without doing something like this:
if($num_events==1){
$city = $response->TrackDetails->Events->Address->City;
}else{
$city = $response->TrackDetails->Events[$i]->Address->City;
}
There are a ton of data fields that fall into this issue, so I don't want to use something so cumbersome if I can avoid it. Any ideas?
if ($num_events == 1) {
$response->TrackDetails->Events = array($response->TrackDetails->Events);
}
This can be done with a loop over all the fields in your answer, automatically putting each loner into an array of length 1.
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.