Redundant MySQL queries in different classes - php

I'm creating a PHP Webapplication which uses 8 classes (more to come). I realized that all of those classes have pretty much the same functions to access the database: A get_single, a get_list, an insert, update and delete.
Which database table is addressed and which fields are selected is different for every class of course.
For example:
function get_single($conn) {
$sql = $conn->prepare('SELECT id_person, join_date, img_profile, img_header, firstname, familyname, nationality, mail, password, birthday FROM person WHERE id_person = ?');
$sql->bind_param('i', $this->id);
$sql->execute();
$sql->bind_result($this->id, $this->join_date, $this->profile_img, $this->header_img, $this->firstname, $this->familyname, $this->nationality, $this->mail, $this->password, $this->birthday);
$sql->fetch();
return $this;
}
I asked myself if I could or should write a single function for all the classes, something like this:
function get_single($id, $conn, $query) {
$sql = $conn->prepare($query);
$sql->bind_param('i', $id);
$sql->execute();
$sql->bind_result(/* ??? */);
$sql->fetch();
return /* ??? */ ;
}
... and then call
$foo = new Foo(array('id' => $bar));
$foo = get_single($foo->id, $conn, $qry_single_foo);
This way I could
store all the SQL queries centrally
reduce the overall amount of code
increase readability... maybe?
Or should I have a parent class which those classes inherit from?
Or use a design pattern? Maybe the decorator? (Sorry my knowledge there is quite inexistent)
Now that I realized that it might be easier to do it differently I'm a bit overwhelmed by the possibilities.
Ideas?
Thanks

You can use a web MVC framework or ORM library.
Please check some ORM libraries you can integrate with your application.
ORM
Doctrine
Propel
PHP Activerecord

Related

PHP - Would i need to create 2 separate objects to hold database data from 2 separate tables?

I may no be asking this questions right but here goes... I have a database with 2 tables "users" (for users name/password/etc) and "usersInfo" (users first name/last/address/etc). I only have 1 Users.php class- do i need 2 separate classes to create 2 objects from to hold the "users" & "usersInfo" data for the same user or will 1 class work (and still make 2 objects?)?
some of my Users.php class/
public function __construct($user = null) {
$this->_db = DB::getInstance();
$this->_sessionName = Config::get('session/session_name');
$this->_cookieName = Config::get('remember/cookie_name');
if(!$user) {
if(Session::exists($this->_sessionName)) {
$user = Session::get($this->_sessionName);
if($this->find($user) || $this->findUserInfo($user)) {
$this->_isLoggedIn = true;
} else {
//logout
}
}
} else {
$this->find($user);
$this->findUserInfo($user);
}
}
public function find($user = null) {
if($user) {
$field = (is_numeric($user)) ? 'id' : 'username';
$data = $this->_db->get('users', array($field, '=', $user));
if($data->count()) {
$this->_data = $data->first();
return true;
}
}
return false;
}
public function findUserInfo($user = null) {
if($user) {
$test3 = $this->_db->get('users', array('username', '=', $user));
$userId = $test3->first()->id;
$data2 = $this->_db->get('usersInfo', array('user_id', '=', $userId));
if($data2->count()) {
$this->_userInfoData = $data2->first();
return true;
}
}
return false;
}
public function data() {
return $this->_data;
}
public function userInfoData() {
return $this->_userInfoData;
}
Currently I have to create 2 objects to use all the data i need for the same user.
for example, in on of my pages.php i have:
$user = new User();
$user1 = new User($user->data()->username);
$userNane = $user->data()->username; //holds users username form "users" table
$userName1 = $user1->userInfoData()->first_name; // holds users first name from "usersInfo" table
It works but doesnt look right... is it efficient/ok practice/etc. If not, suggestions?
Also, first post, take it easy :)
What is the relationship between the 2 tables?
1-1 ? 1-*? Can a user have multiple persona? Can a persona correspond to many user accounts? Will this relation change in the future?
Depending on your answers, you might see which solution fit better your plans.
1-1 relation: you can afford to have a single class to hold related records. It will be easier to manage from the perspective of your application
Otherwise, you'll need at one time or another to handle a record separately from related records in the other table. You'll be better off with 2 distincts objects.
if you plan to change things later on for the second situation, you should keep things as they are.
In the specific case of user data, your comment bring the insight that certain data are more sensitive than others. In retrospect, I guess that's the reason you made these two tables separate. From that point of view, it is certainly better to keep both objects separate, even in a 1-1 relationship.
Regarding your code, indeed, having a dedicated UserInfo class, rather than piggy backing on another instance of User, would clearly be a good thing. A very important idea of good design is separation of concerns: you want each class to handle one and only one purpose, so that any modification to a class will have a limited scope of impact on the rest of the code.
As an example, the only thing you need to retreive a userinfo row, and therefore construct an object wrapping it, is the user id. Instead of delegating the whole job to a method of User, I would probably extract the iout of the User instance, and pass it to the adhoc UserInfo constructor or static method: there, each class only deals with things in its own perimeter. Of course, findUserInfo could also delegate to that same function.
IMO, on of the most important steps in designing/developing an app is creating a sound schema and model. Not sure how much database design experience you have, but you will want to read up on First Normal Form (1NF), and eventually (2NF and 3NF).
Part of the schema design stage is to identify all the nouns which you will reference in your app, in your case a user is a perfect example. Each of these identified nouns will then have attributes, which you will want to consider, in how each will be stored.
The problem in your situation is that you have user and user_info. As you stated user is for name, password, etc, whereas user_info is for first_name, last_name, address etc. Part of the design stage is to determine which of these attributes are directly attributable to the user object, and which are more ancillary in nature. Using your example: name, password, first_name, last_name are each directly attributable to the user noun (object), however address is more ancillary in nature, and there may be more than one address per user (billing address, vs physical address), so you may want to consider adding a user_address table. As you can see, by logically separating the attributes of the user noun (object), you start to identify relationships which make more sense (user, user_address) vs (user, user_info).
Once you identify the nouns, and separate their attributes, you can create your schema. From your schema you can use an Object Relational Mapper (ORM) like Doctrine, which will introspect your schema, and generate objects for you to use throughout your app. In your example you would end up with two objects; User and UserAddress. Also it's important that when developing your schema that you identify relationships between tables by implementing a foreign key constraints. For example, your user_address table should have a user_id column, which links to your user table. This way when doctrine introspects your schema, it will also identify these relationships, which makes coding much easier.
Once you have your ORM in place, you can then make code references like this:
// In your controller
$this->user = UserTable::findById($_SESSION['user_id']);
// Then in your view
Welcome <?php echo $user->getFirstName() ?>, to our wonderful app.
We have your addresses listed as follows:
<?php foreach ($user->getUserAddress() as $userAddress) ?>
<div>
<?php echo $address->getStreet() ?>
</div>
<?php endforeach ?>
Yes, it's a very simplistic example, but should properly demonstrate that if you design your schema properly, the code becomes semantic, which makes it easier to write, and maintain.

Lithium PHP framework - How to run db transaction on mysql?

I have been working on an e-commerce website in PHP Lithium framework, actually this one is upgraded from CakePHP, we have to use transaction operation on db in mysql. Just don't know how to do db transaction in PHP Lithium framework.
Since Lithium uses PDO, you can just get the PDO object and call the beginTransaction() method.
$foo = app\models\Foo::create();
$pdo = Connections::get('default')->connection;
$pdo->beginTransaction();
$foo->bar = 'Hello';
$foo->save();
$pdo->commit();
https://github.com/UnionOfRAD/lithium/issues/1004#issuecomment-23690165
http://www.php.net/manual/en/pdo.begintransaction.php
It doesn't seem like it is supported, unfortunately. See source of lithium/data/source/database/adapter/MySql.php.
An alternative may be to manually execute your queries.
Within your model, you can do:
static::connection->read($sql, $placeholders);
Where $sql is your raw SQL like:
$sql = 'SELECT * FROM users WHERE id = {:id}';
and $placeholders (optional) are your placeholders:
$placeholders = [
'id' => 5
];
Using that knowledge, you should be able to set up a transaction.

Implement sorting/filtering business logic into DDD aggregates

I am fairly new to DDD and for me I search in practical terms to a good function for an aggregate. I have a long list of users (User) and a create an aggregate (UserAggregate) for that.
Now in my view I might display users based on different criteria. Let's assume here I don't sort the list in my database query, it is OK to have sorting in an aggregate? I cannot come up with another part of the application where I can do this properly, but I might misunderstand the function of an aggregate.
$users = new UserAggregate(array(
$user1, $user2, $user3, $user4
));
foreach ($users->sortBySurname(), $user) {
//
}
foreach ($users->sortByLastLoggedIn(), $user) {
//
}
The same holds for filtering by the way. When I read about DDD aggregates, I immediately thought of the Doctrine\Common\Collections\Collection (link). That sort-of looks like an aggregate to me. So DDD experts, please enlighten me :-)
Update
The only way I was thinking btw was making aggregates rather immutual and have helpers to create new aggregates. But this seems not the way to go:
$aggregate = new UserAggregate(array($user1, $user2));
$helper = new FilterSomething;
$aggregate = $helper->filter($aggregate);
The second aggregate is a new instance, so the helper looks like this:
class FilterSomething
{
public function filter(Aggregate $aggregate)
{
$items = $aggregate->getItems();
$items = $this->doFilter($items);
return new Aggregate($items);
}
}
A root aggregate is not a repository. A root aggregate represents a single user and all of it's domain specific information.
That sorting and filtering should be applied in a repository.

active record vs bare sql

I'm kind of proud not to accept concepts if there is no good reason. But I'm in doubt about using active record pattern. Currently I'm using zend but say code Igniter has active record.
I dont use.Because
sql is sql it has own syntax.
you can copy to sql editor and it works (if it is working!)
you dont learn another syntax
you dont need to kill your script to gather if active record is writing sql the way you expected
but active record has
you pretend writing like objective php.
When you need to move another db(oracle>mysql :p), you dont need to change rand function to random, active record can make it for you.
does active record have much more capability that I am missing? Can you give some example cases where active record could be a life saver?
An ActiveRecord is
An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data.
This is not what CodeIgniter uses. CI's AR is a basic query object.
The main benefit of an ActiveRecord is it's simplicity. If your application is mainly doing simple CRUD operations and your Table structure matches the ActiveRecord very closely, then it's a good choice. It's easy to abstract CRUD in that case. And you can still add handcrafted SQL to it for certain more complex row manipulations.
class User
{
protected static $dbAdapter;
protected $username;
…
public static function findById($id)
{
$result = self::$dbAdapter->query(
sprintf('SELECT * FROM users WHERE id = %d', $id)
);
if($result) {
return new User($result);
}
}
public function create()
{
try {
return self::$dbAdapter->query(
sprintf(
'INSERT into users …',
$this->username,
…
);
);
} catch …
}
…
}
You'd use that in your application like this:
$john = User::findById(123);
echo $user->username; // John
$jane = new User(array(
'username' => 'Jane'
));
$jane->create();
You definitely don't want to use ActiveRecord if the your rows and the AR don't match closely. AR is an object representing a database row. AR couples the object design to the database design. AR is not an ORM. Trying to put that into it is not practical. If you find you are in need of more juicy Domain Models, you won't be happy with it, because it will ultimately hamper your development due to object-relational impedance mismatch.
Additional readings:
Kore Nordmann: Why Active Record sucks
Bill Karwin: ActiveRecord does not suck

PHP Inheritance and MySQL

So I'm trying to adopt good object oriented programming techniques with PHP. Most (read all) of my projects involve a MySQL database. My immediate problem deals with the users model I need to develop.
My current project has Agents and Leads. Both Agents and Leads are Users with much of the same information. So, obviously, I want a class Agents and a class Leads to extend a common class Users. Now, my question is as follows:
How should the SQL best be handled for loading these objects? I don't want to execute multiple SQL statements when I instantiate an Agent or a Lead. However, logic tells me that when the Users constructor is fired, it should execute a SQL statement to load the common information between Agents and Leads (username, password, email, contact information, etc). Logic also tells me that when the Agents or Leads constructor is fired, I want to execute SQL to load the data unique to the Agents or Leads class....But, again, logic also tells me that it's a bad idea to execute 2 SQL statements every time I need an Agent or Lead (as there may be thousands of each).
I've tried searching for examples of how this is generally handled with no success...Perhaps I'm just searching for the wrong thing?
You basically have three approaches to this problem (one of which I'll eliminate immediately):
One table per class (this is the one I'll eliminate);
A record type with optional columns; and
A record type with a child table depending on type that you join to.
For simplicity I generally recommend (2). So once you have your table:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
type VARCHAR(10),
name VARCHAR(100)
);
where type can be 'AGENT' or 'LEAD' (for example). Alternatively you can use one character type codes. You can then start to fill in the blanks with the object model:
You have a User parent class;
You have two child classes: Lead and Agent;
Those children have a fixed type.
and it should fall into place quite easily.
As for how to load in one statement, I would use some kind of factory. Assuming these barebones classes:
class User {
private $name;
private $type;
protected __construct($query) {
$this->type = $query['type'];
$this->name = $query['name'];
}
...
}
class Agent {
private $agency;
public __construct($query) {
parent::constructor($query);
$this->agency = $query['agency'];
}
...
}
class Lead {
public __consruct($query) {
parent::constructor($query);
}
...
}
a factory could look like this:
public function loadUserById($id) {
$id = mysql_real_escape_string($id); // just in case
$sql = "SELECT * FROM user WHERE id = $id";
$query = mysql_query($sql);
if (!query) {
die("Error executing $sql - " . mysql_error());
}
if ($query['type'] == 'AGENT') {
return new Agent($query);
} else if ($query['type'] == 'LEAD') {
return new Lead($query);
} else {
die("Unknown user type '$query[type]'");
}
}
Alternatively, you could have the factory method be a static method on, say, the User class and/or use a lookup table for the types to classes.
Perhaps polluting the classes with the query result resource like that is a questionable design in the strictest OO sense, but it's simple and it works.
Will you ever have a user that's not a Lead or Agent? Does that class really need to pull data from the database at all?
If it does, why not pull the SQL query into a function you can override when you create the child class.
Could you not inherit say a skeleton of the SQL, then use a function in each sub-class to complete the query based on its needs?
Using a really basic example:
<?php
//our query which could be defined in superclass
$query = "SELECT :field FROM :table WHERE :condition";
//in our subclass
$field = "user, password, email";
$table = "agent";
$condition = "name = 'jim'";
$dbh->prepare($query);
$sth->bindParam(':field', $field);
$sth->bindParam....;//etc
$sth->execute();
?>
As you can see my example isn't amazing, but should allow you to see what I am getting at. If your query is very similar between subclasses then I think my suggestion could work.
Obviously it will need some tweaking but it is probably the approach I would take.

Categories