Alright, I'm working on making a Member class for my website. I want to make it as optimized as possible. Currently, the constructor can take ($resource) either an int (to grab info from one member in the database, based on id) or an array of ints (to grab multiple members from the database, and store them in an array member variable).
I would like to know if there are any inprovements I can make with my block of code below, before I move on to creating more parts of my website. What could be changed to make it better? Is there a better layout I should follow for doing this kind of thing?
public function __construct($resource) {
global $database;
if (is_string($resource) || is_int($resource)) {
$resource = (int)$resource;
$query = $database->query("SELECT * FROM members WHERE member_id = {$resource} LIMIT 1");
$row = $database->get_row($query);
foreach ($row as $key => $value) {
$this->field[$key] = $value;
}
} else if (is_array($resource)) {
$query = $database->query("SELECT * FROM members WHERE member_id IN(" . implode(",",$resource) . ")");
while ($member = $database->get_row($query)) {
$this->member_list[$member['member_id']] = $member;
}
}
}
Some thoughts:
Globals are bad
Database calls should be isolated to a data access layer, ideally of the ORM variety so that you aren't writing manual SQL.
What if $resource is "ddd", do you want the member with a member_id of 1 ?
You aren't protecting against SQL injection.
Shouldn't your member_list be creating new Member objects (or whatever this class is called) rather than simply appending the row data?
Firstly, don't do work in a constructor. Secondly, there are many packages out there that do exactly what you're trying to do, and do it VERY well.
What you're trying to write is called a Model. It's a class that mirrors a table in the database. Use a mature ORM (Object Relational Mapper) package such as Propel or Doctrine for automatically generating classes based off of database schemas. I personally recommend Propel over Doctrine (though they are both great packages).
Also, I'd recommend that you use the symfony php framework, which integrates Propel as its ORM (again, you can use Doctrine as an alternative ORM with Symfony).
Lastly, don't use globals. Write a class around any resource that access. Making a static call to retrieve its singleton instance such as Database::getInstance() is a much preferred way of accessing the database (or any other) resource.
Best of luck
Related
Am i misunderstanding something?
Say i have model method below:
public function product($user_id,$action){
$this->db->select('product_id');
$this->db->from('products');
$this->db->where('user_id', $user_id);
$query = $this->db->get();
$counter = 0;
switch($action){
case 'ids':
foreach($query->result() as $row){
data['ids'][$counter] = $row->product_id;}
return $data;
break;
case 'count':
return $query->num_rows();
break;
}
}
Is the above considered a reusable method since i can use it for 2 purposes?
Or is it not, and is it better to just separate them into two single methods?
Is a reusable method more like this:
public function get_id($table,$value){
$id = $table.'_id';
$query = $this->db->get_where($table, array($id => $value));
}
I use simple names for my table and the PK(ID). For example, 'user' table would have 'user_id'. 'product' table would have 'product_id'
To be honest I've never heard of a method being called reusable. I've heard of classes (CI context: models and libraries) but never just particular methods. Generally the hallmark of something being reusable is that dependencies are managed and preventing tight coupling. For classes in CI that is kind of difficult to do and can also depend on your code structure as CI apps tend to be inherently tightly coupled.
What I can tell you is that a hallmark of good code from methods to classes is separation of principles. A class that performs CRUD operations on a user shouldn't handle auth functions like logging a user in - the two can interact but shouldn't be together. By extension, a method shouldn't try and do too much. In your case you are not only making your code more verbose by using a switch statement, but also making it harder to maintain down the line by having two different and distinct operations handled by the same method.
Code like this can also be a problem:
public function get_id($table,$value){
$id = $table.'_id';
$query = $this->db->get_where($table, array($id => $value));
}
Because if you decide to change one table to not have _id at the end then you would have to either (1) introduce a new function only for that table (2) remove the _id marker and update the parameter $table for every item using this method. Why not just pass the $table name in its entirety and forgo this extra step here?
So in my opinion although all methods are reusable as long as dependencies are managed, other coding practices should be taken into consideration. Introducing new methods costs you nothing.
So I've just started coding in classes and I haven't quite got my head around it yet. So I understand the concept of OOP but I have a question.
I have "users" stored in a database, and I want a user class that will get information I might want about a user and do things related to a "user" object. I understand that.
So say I have a user class, with properties username and email I have the following code
<?php
class User {
private $username;
private $email;
public function __construct($username,$email) {
$this->username=$username;
$this->email=$email;
}
}
?>
Now I know I should have getters and setters to access username and email. Getters, I understand. But setters - do I need these? And if I do, should these update that field in the database for that user? Would my setter for email update the database as well as the $this->email ? It may seem like a silly question but I want to get this right.
Then finally what is the best way to get users from the database and create objects? Say elsewhere I want to create a user object from ID 50 - which would get user with ID 50 from the database and construct a user object with the database email and username fields, what is the best way to do this?
Thanks!
But setters - do I need these?
It depends. If you do not have to do anything more than setting the property, you may not use one. You can ohwever need one if you need to check if the provided value matches, for example, a reg exp, or isn't too long/short, etc. You might also need one if you have setters for other properties and want to keep a uniform interface not to remember which property has or hasn't a setter.
And if I do, should these update that field in the database for that user?
If you are to modify several properties, it is better to only access the database a single time. Some database abstraction libraries do it that way :
$user->name = 'whatever';
$suer->email = 'whatever';
$user->save(); // Execute the modify query.
Accessing/modifying data in a database is expensive.
Then finally what is the best way to get users from the database and create objects?
If you are using, for example, mysql, you can use :
$users = [ ];
while($row = $result->fetch_assoc()) {
$user = new User;
foreach($row as $field => $value) {
$user->$field = $value;
}
$users[] = $user;
}
But there might be more elegant ways to do that though.
Setters are used to set object properties values and in most cases this is it. There are many ways of achieving what you want and basically there are books written about that. I personally tend to have a scenario like follows:
1) Set object properties using setters
2) Call a separate function commit()/save()/whatever() that will write all values to the database
As of creating an object from a row, you'd better have separate factory classes (nice question and answer in stackOverflow - What is a Factory Design Pattern in PHP?). The idea of factory classes is that objects are not mutable and merely serve the purpose of data container. I included PDO just for demonstration purposes but of course there are other ways (it just seems good for a simple users table)
class UserFactory
{
private $db;
public function __construct($db)
{
$this->db = $db;
}
public function fromID($id)
{
$userObject = new User();
$q = $this->db->prepare("SELECT * FROM user WHERE u_id = :id");
$q->bindValue(":id", $id);
$q->setFetchMode( PDO::FETCH_INTO, $userObject);
$q->execute();
$q->fetch(PDO::FETCH_INTO);
return $userObject;
}
public static function fromRow($row)
{
$userObject = new User();
$userObject->setName($row['name']);
$userObject->setEmail($row['name']);
return $userObject;
}
}
And as of collection of objects
class UserCollection
{
public static function getAllUsers($db)
{
$users = array();
$q = $db->query("SELECT * FROM user");
while($row = $q->fetch()){
$users[] = UserFactory::fromRow($row);
}
return $users;
}
}
The idea behind is to pass the DB connection to the static method that will return an array holding all User objects initialized from the database.
getAllUsers method here is static for demontration purposes and of course the same can be achieved by creating a contstructor that takes the database connection variable as an argument
Your first decision is whether or not to get the user's properties from the database within the class or to do it from outside the class. Lets say you do it outside the class, then you would not have any argument in the construct and you could have:
$users = array();
while($row = $result->fetch_assoc()) {
$user = new User();
for($row as $field => $value) {
$camelField = strtoupper(substr($field,0,1) . strtolower(substr($field, 1);
$fieldClass = 'set' . $camelField;
$user->{$fieldClass}($value);
}
$users[] = $user;
}
in your class you would have setters like
public function setName(value) {
$this-<name = $value;
}
There are mainly two approaches on how to persist your objects:
Active Record / Table Gateway
Using this approach, each property in a class is mapped to a certain field on a database table.
Since you're using PHP, you may be already used this pattern if you used Zend_Db or CodeIgniter Active Record.
The problems with this pattern are that it may not be suitable for complex domain where heavy inheritance is in-use and an in-depth mapping is required. also, it usually tightly-couple your classes with a database which may exacerbate testing.
See also: Wikipedia, Fowler
Object-Relational Mapper (ORM)
'ORM' is a much heavier solution and it let you work purely with 'objects' and completely abstracts away the table/database layer.
It also need to be able to handle Objects Inheritance, Composition, Polymorphism and usually provide some functionality for 'Lazy Loading' of referenced objects.
Notable 'ORM's for PHP are (for example): Doctrine and Propel.
See also: Wikipedia
I've been digging around for an ORM to use in a php/mysql application. However none quite grab my attention past "hello world" tests. So, I decided to do some research and try to code my own custom ORM. However I haven't been able to find resources that explain at code level how to handle db relationships. The concept of how an ORM works is clear but when trying to lay it out in code I don't know what the best approach is. Is it best to build several small queries or to build one complex query for every posible scenario? Any insight into the algorithm or architecture of an ORM is welcome!
Well let us make some ORM framework on the fly. As you marked php tag let us code it in PHP.
But before we write it we must know some basic concepts or some basic terminology
about orm related subjects. In this example we will have:
ORM framework - ORM framework takes responsibility to take care about server connections and server connection abstractions. (Full orm frameworks also support automatic class to table mappings).
Data layer - This part is responsible for mapping classes to tables.
For example data access layer knows how to save specific class object to actual table and how to load specific table to specific class object. (NOTE: Almost any recent ORM framework can avoid you from this layer. For example http://dbphp.net or Doctrine will support every aspect of this layer plus relations and even auto table generation).
Business layer - This layer contains your actual working classes business layer often stands for model or model includes business layer
Let us begin our example from Business layer or model. Our very very simple project which saves and loads users will have one class business layer:
<?php
class user
{
public $id;
public $name
public function __construct ($name=null)
{
$this->name = $name;
}
}
?>
As you see your business layer or model knows nothing about where and how it is saved or loaded. It just does only handle project related business. That's the point the layer name comes from.
Second, let us make a simple ORM framework:
<?php
//The connection link which can be changed any time
class link
{
public $link;
public function __construct ($hostname, $database, $username, $password)
{
$this->link = new \PDO ('mysql:host='.$hostname.';dbname='.$database, $username, $password);
$this->link->query('use '.$database);
}
public function fetch ($query)
{
$result = $this->link->query($query)->fetch();
}
public function query ($query)
{
return $this->link->query($query);
}
public function error ()
{
return $this->link->errorInfo();
}
}
//A structure which collects all link(s) and table/class handlers togather
class database
{
public $link;
public $tables = array ();
public function __construct ($link)
{
$this->link = $link;
table::$database = $this;
}
}
//A basic table handler class
//In recent ORM frameworks they do all the default mappings
class table
{
public static $database;
}
?>
As you noticed our table class in our ORM framework seems very poor. But if this framework was a
complex framework it would support also data layer and had all functionality to work with any table.
But because you need to know how ORM frameworks work in this case we will make data layer
handlers for every class in our business layer.
So this is your data layer. It is so self descriptive that I think it does not
need any documentation:
<?php
class users extends table
{
public function create ($row)
{
$return = new user ();
$return->id = $row[0];
$return->name = $row[1];
var_export($row);
return $return;
}
public function load ($id=null)
{
if ($id==null)
{
$result = self::$database->link->fetch("select * from users");
if ($result)
{
$return = array();
foreach ($result as $row)
{
$return[$row[0]] = $this->create($row);
}
return $return;
}
}
else
{
$result = self::$database->link->fetch("select * from users where id='".$id."'");
if ($result)
{
return $this->create(reset($result));
}
else
{
echo ("no result");
}
}
}
public function save ($user)
{
if (is_array($save))
{
foreach ($save as $item) $this->save ($item);
}
if ($user->id==null)
{
return self::$database->link->query("insert into users set
name='".$user->name."'");
}
else
{
return self::$database->link->query("update users set name='".$user->name."'
where id='".$user->id."'");
}
}
public function delete ($user)
{
self::$database->link->query ("delete from users where id='".$user->id."'");
}
}
?>
At last let us init $database object
Establish some to some sql server link.
Add user class handler to database.
Use it.
Here is it in work:
<?
$database = new database (new link('127.0.0.1', 'system_db', 'root', '1234'));
$database->tables['users'] = new users();
if (!$database->tables['users']->save (new user('Admin')))
{
var_export($database->link->error());
}
var_export($database->tables['users']->load(2));
?>
If you need to dive in other concepts of php ORM's feel free to visit
Doctrine - http://www.doctrine-project.org/ - Full functional complex php ORM framework
db.php - http://dbphp.net/ - Full functional but very easy php ORM framework.
Many ORMs these days are built around the Active Record pattern or variations thereof. In this scheme, you usually have automatically generated classes that correspond to each table in the database, each of those classes return an instance of themselves or of a subclass that correspond to each row in the table:
For example, if you have a Users table:
$user_list = Users.getAllUsers(); //SELECT * FROM Users
//foreach row, create a new User() instance
$user_list[0].name = "Peter";
//UPDATE Users SET name = 'Peter' WHERE user_id = <$user_list[0].id>
$user_list[0].commit();
About implementation, it's best to try to minimize the amount of queries sent to the server, but it's not always trivial nor desirable.
ORMs are not simple. Your ORM will be neither simple or efficient. If it's either of these then your application is simple enough to not need one in the first place, or you're punting when the problem gets hard and simply not using it.
Simple CRUD mapping an object to a table is easy. Start adding in relationships or collections, and everything goes to pot. Then there's queries, etc. The complexity increases in a non-linear, accelerating fashion.
Then the inevitable need for caching just to get it to perform adds even more fun and excitement to the project.
Pretty soon your project is consumed in tweaking, maintaining, and debugging the internal ORM, instead of advancing your project. If you took the time you invested in your ORM and simply wrote a DAO layer with SQL, your project would be farther along, simpler, and more efficient.
Frankly, adopting an ORM is hard enough to justify, depending on the project scale. Writing your own is even more likely not worth the investment.
I just recently dove into OOP & now MVC and am using this template engine : http://www.milesj.me/resources/script/template-engine
I am curious about one question on where to put my DB calls (I'm using a basic database wrapper class).
I've seen two ways done.
class Cart
public static function count() {
require_once(DATABASE .'cartext.php');
$info = User::getInfo();
$count = CartExt::inCart($info['0']['userid']);
return $count;
}
Then in class CartExt
public static function inCart($shopperID) {
$db = Database::getInstance();
$query = $db->execute("SELECT * FROM Listing WHERE shopperid = '$shopperID'");
$count = 0;
while ($row = $db->fetchAll($query)) {
$count++;
}
return $count;
}
With large functions I can see the advantage of separating the two, but a lot of the time it's as mundane as the example above, or worse: the base class just calls upon the Ext and returns its value! Also, I am doing a require_once from within the function to lower http requests if anyone is asking.
Anyway, I just want some thoughts on this.
Also, am I correct in that I should handle $_POST['data'] in the controller and pass it as an param to my functions there, opposed to handling it within the class? (I'm not using a form object/class yet if it matters).
Looking forward to hearing your thoughts on this.
Database calls should be executed from the Model.
If this goes via:
mysql_query()
a database wrapper
an ORM like Doctrine
doesn't matter as far as MVC is concerned. Although I can recommend the latter.
Reasoning
When you are storing data in a database that data usually represents model data: a User, an Order, etc.
Exceptions
If your storing sessions in the database or use the database for caching. These belong more to the Controller than the Model classes.
In my codeigniter project I have
<?php
class User_model extends Model {
function user_model()
{
parent::Model();
}
// should we use instance method?
function get_total_users_count(){
$results = $this->db->query("SELECT * FROM bhr_users GROUP BY userid");
if($results){
return $results->num_rows();
}
return 0;
}
// or class method?
public static function get_total_users_count(){
$obj =& get_instance();
$results = $obj->db->query("SELECT * FROM bhr_users GROUP BY userid");
if($results){
return $results->num_rows();
}
return 0;
}
}
?>
I feel like this should be a class level method because it operates on multiple users. Do you agree? Is get_instance the proper way to do this in codeigniter?
Honestly, I don't think there's one right way for this. I'd say the instance method is the most common way, but that's not to say that it's right or wrong.
One big difference between CodeIgniter and some other frameworks is that models can be whatever you want them to be. According to the CI manual "The Model represents your data structures." it than says that models will "typically" interact with your database.
I like the loose definition that CodeIgniter uses for models, because it allows me to create models for dealing with any dataset. Want to use an RSS feed as a data source? You could use a model for that. Want to pull data from a webservice? You could use a model for that. You have the freedom to define how you use models.
I'd say the most important thing is consistency. Choose one method and use it consistently throughout your project. If you're working with other developers on the project, it may be better to use the instance methods. That way they won't get confused about what's going on when they compare working code on your site to the CodeIgniter documentation. That, of course, depends on the skill level of the devs you work with.
To answer your question directly - the get_instance() function call is the proper way to do what you're trying to do from within a static function.
You should be using
$results = $this->db->query("SELECT * FROM bhr_users GROUP BY userid");
Unless you are getting an instance of another class, you should do it this way.