I've seen how powerful OOP is in c++ so I started reading up on OOP for PHP. This made me want to revamp one of my sites so it would use OOP PHP to clean up the royal mess that it's in now. I already know the basic concepts of OOP, but I'm struggling a bit with applying it.
So far, all the sites I've seen that use OOP PHP have some sort of mySQL DB class. I can definitely see its benefits (cleaner code when you want to access something in the DB) but I'm not entirely sure how to set mine up. Here's what I'm wondering:
What are the first things I should do
when building this class from the
ground up? (How should this class be
set up? What's the idea behind that
structure? What does it look like
when set up like that?)
What kinds of methods should be in my
DB class? (What kind of functionality
should my DB class offer? SQL
Inserts? SQL Updates? plain ole' SQL
queries? What data should these
methods return?)
How do I determine when I need to add
a new method to the class?
How should I use those methods in my other code?
Thanks.
If you mean a class to connect to the database, prepare and run queries, use PDO (try "Writing MySQL Scripts with PHP and PDO" for a tutorial). If you mean a Data Access Object (DAO), which is a class (or classes) to function as a bridge between the database records and your application objects, try the data mapper or active record patterns. Note that the active record pattern is a little older and falling out of favor with some, so the articles about active record in PHP tend to be older and are a bit out of date.
Whatever pattern you apply, the four basic operations your class(es) should provide are create, read, update and delete (CRUD). Create and read return application objects, and update and delete can return values indicating success or failure.
Using the class(es) is fairly straightforward: whenever you need an object, use create or read rather than the object constructor. When to use update or delete depends on your business logic. For example, you may need to update whenever you're done with an object (i.e. when the object is destroyed). What's trickier is how an object or function gets a reference to DAOs. Reading Martin Fowler's article on dependency injection for a few different approaches.
Further reading:
Persistence Patterns
Practical PHP Patterns: Data Mapper
Implementing the Data Mapper Design Pattern in PHP 5
Implementing The Domain Model: Entries and Authors
Using the Active Record Pattern with PHP and MySQL
There are several ways to go about this, firstly you can "integrate" a system into a native system such as mysqli or you can go about creating your own system / structure from scratch using drivers.
With the first method your a little limited as you have to abide by the internal structure of the native API.
My personal approach is usually the second as i can create a driver based system and decide what native system to use depending on the host operating system and several other factors.
When creating a database API for your applications to run on you do not want it to be specifically for that application, you should be able to grab the libraries drop them into a new project and everything should work as expected, so making it abstract is the first issue we will have to get around.
The next obstacle is to make the code extendible, the programming world changes radically so we should be prepared for changes, although the code would only suffice for a few years, it would be beneficial if we thought about thus years and was prepared.
imagine if next week a new database layer was created that was 50x faster then the current mysql(i) layer that's integrated into PHP, you would want to switch to that api ASAP, thinking about these factors is always a good thought to have during the development stages.
Firstly we should decide on the structure, with traditional abstraction layers the code is usually all built into 1 large class file, this can be bad programming as it should be broken down into its purposes.
We should be separating the classes / objects so that they perform the task there specifically designed for.
We should have 1 global "controller" which would be the main Database Class, this would control all operations sent to and from the sub classes.
We would be designing for PHP 5.3 as minimum, so lets get started:
What i tend to do is create some pseudo code of what the end-result would be like, this way i will have an understanding of what should be implemented.
$Connection = new DatabaseConnectionDetails(array(
"hostname" => "localhost",
"username" => "root",
"password" => "n/a",
"charset" => "UTF-8",
"database" => "my_database",
"driver" => "MySQL",
));
$Database = Database::getInstnace($Connection);
$Query = $Database->Query("SELECT * FROM {?:table} WHERE id = {?:id}",array(
"table" => "posts",
"id" => 22
));
if($Query->Execute())
{
$Results = $Query->GetResults();
foreach($Results as $Result)
{
echo $Result->data; //trims, converts to int, returns;
}
}
This would be how I would like to connect to my database, so this is how I would start working with the base class
class Database
{
private static $_DBInstance;
public static function getInstance(IDatabaseConnectionDetails $ConnectionDetails)
{
if(self::$_DBInstance === null)
{
self::$_DBInstance = new Database($ConnectionDetails);
}
return self::$_DBInstance;
}
public function __construct(IDatabaseConnectionDetails $ConnectionDetails)
{
//We will come back to this.
}
}
Looking at the class above you will see that firstly it has a create instance (singleton) that would help in using the database throughout any application, you would also note that im specifically defining what parameters are required.
Keeping the above factors in place throughout the whole abstraction layer will make life much easier.
Let me just explain a little about the the directory structure, you would have to seperate the following class
Database
Query Classes
Interfaces
Drivers
Helpers
and I would go for a structure a little like so:
includes
DBAL
Database.class.php
DatabaseConnectionDetails.class.php
Drivers
Interfaces
Result
As stated above would require a IDatabaseConnectionDetails interface, the purpose of this is so that the separation of credentials and the main database are made, therefore the IDatabaseConnectionDetails has a primary role of looking after the users credentials.
class DatabaseConnectionDetails implements IDatabaseConnectionDetails
{
public $hostname = "localhost";
public $username = "";
public $password = "";
public $charset = "UTF-8";
public $driver = "mysqli";
public function __construct($params)
{
//Set Params here
}
}
Now the beauty of creating a class for your configuration was mentioned above, the extensibility of the class, for example:
class MyCustomConfig extends DatabaseConnectionDetails
{
public $hostname = "host.domain.tld";
public $username = "my_other_user";
public $password = "IJH87b&OTIT8fh";
public $driver = "mssql";
}
This way as the classes are interfaced you can send any class into the main database object, being custom or not as the interface allows you to be extensible.
Now the drivers that are required, you should note that each driver should be part of an driver interface, that forces a set of methods to be within the driver itself.
interface IDatabaseDriver
{
public function setConnectionDetails(IDatabaseConnectionDetails $ConnectionDetails);
public function connect();
public function escape($string);
public function query($string);
/*
all the methods here that will allow the main class can access, such as:
- next()
- prev()
- reset()
ect ect
*/
}
The main database class would then be able to load the correct driver depending on $Config->driver.
you would create generic functions in the Main Database Class that would mimic a typical database system such as fetchObject,fetchArray() etc, these methods would then use the driver object to select, prepare, sanitize the data and then return the results using another object/class such as QueryResult which would have a set a dedicated methods that are solely for the purpose of traversing a result set.
Hope you enjoyed this long read but should get you started with an idea in your head.
Regards:
Robert
Related
I'm not new to PHP or programming at all. But recently I was thinking about website programming in PHP and how easier it was before the OOP. Anyway, I prefer OOP than the old procedural style.
I want to implement a website but it seems I always have to use a global or a static variables. And I'm starting to wonder, how can I do it without those?
Anyway, what I'm talking about is having a class for each "component" of the website.
For example if it was an url shortener website it would be: links, members, database.
What I'm talking about is way more complicated, at least 8 classes.
Anyway, my current approach is the following:
$database = new Database(...);
$links = new Links($db);
$users = new Users($db);
Anyway, for example I want to get all the links a user posted by its ID, I need to use both links and both users components.
Is there any other way I could do this? Any other approach? except passing them as constructor parameters.
You should have the following components:
Business objects, which model and express one particular "thing" in your app:
class Link { ... }
class User { ... }
These don't "do" anything, they're just there to formalise your data structures. These objects have getter and setter methods to get and set individual attributes, which are also validated there:
public function setUrl($url) {
if (!/* validate the URL here*/) {
throw new InvalidArgumentException("$url is not a valid URL");
}
$this->url = $url;
}
Minimum required data is part of the constructor. This ensures your data integrity application-wide. It allows you to assert that when you have an instance of Link, the data expressed by it is minimum valid data for a link.
A database link. Only the bare necessary thing to connect to a database, nothing more, nothing less. A raw PDO or mysqli object will do just fine.
A data-object mapper, which takes a database link and knows how to store business objects in the database and how to retrieve them:
class LinkStorage {
protected $db;
public function __construct(PDO $db) {
$this->db = $db;
}
}
This class has all the various methods of how to retrieve things from your database:
public function getById($id) {
$stmt = $this->db->prepare('SELECT ... FROM ... WHERE id = :id');
$stmt->execute(compact('id'));
if (!$data = $stmt->fetch()) {
throw new RuntimeException("Record with id $id does not exist");
}
return new Link($data['url']);
}
You can have all sorts of different queries encapsulated this way, e.g.:
/**
* Returns all links by a particular user.
* #param User $user
* #return Link[]
*/
public function getAllFromUser(User $user) {
...
}
The usage is then simple:
$db = new PDO(...);
$linkStorage = new LinkStorage($db);
$userStorage = new UserStorage($db);
$user = $userStorage->getById($id);
$links = $linkStorage->getAllFromUser($user);
This kind of code would then be encapsulated in a service class, which holds all the possible "actions" you can do in your app. registerUser(array $data), getLinksOfUser($id), newLinkFromPostData(array $data) etc.
What I've just described is basically the model portion of an MVC-style application. The other two parts would be controllers which call the service methods, and views which output data retrieved from service methods. This approach keeps responsibilities separate and isolated and allows you to put higher-level logic and functionality together like building blocks. Business objects are the lowest building block, their structure needs to be solid and well defined for the rest to work. Data-object mappers just concern themselves with putting those objects into the database and getting them back out again. Services then put all this together in various complex ways and make things happen.
You shouldn't have any cyclic dependencies with this, as responsibilities are well separated. Your individual dependencies may still be somewhat complex. If it becomes too cumbersome to instantiate classes, you'll want to look into Factories:
$factory = new Factory;
$userStorage = $factory->newUserStorage();
All the complexity of instantiation is encapsulated in this factory. One step further are dependency injection containers, who you can configure in, for example, an XML file to specify which class depends on what, and then the DI container will take care of it for you.
I was thinking about website programming in PHP and how easier it was
before the OOP
Well, stick to procedural then. If it is easier to write a well written website in a procedural or functional way then opposed to the ojbect-oriented way. Stick ti what you are used to. OO isn't better then functional. It's just a different approach.
the public void main() in php
In the lanuage Java every piece of software we write has a single entry point. The public void main() method. This method fires up the entire application and passes in the arguments provided on startup. It is also the only exit point in the application. the application ends in this method (unless it crashes).
In php, there is no single entry point. We have a bunch of files that run some scripts that do some more stuff and then somewhere along the line another script decides to return stuff and die();
Dependency injection and how IoC libraries can help
When using dependency injection, it becomes a real pain in the a$$ when creating objects and passing arround the correct instance of a class. We start solving this problem with ugly solutions: Singleton, globals, statics, ... Making our software more and more tightly coupled and harder to maintain.
Inversion of Control can help here. there are some really greate articles on the webz.
You can use autoloading in PHP for a better solution:
http://php.net/manual/en/language.oop5.autoload.php
Moving from C#/C++ to PHP OOP has proven a bit problematic as I am not sure it is standard to design the code layout in the same manner. As that is the case, I am curious if the following would be considered problematic or wrong when it comes to PHP.
CDeviceManager class (1 initiated)
CDevice class
Keep a private array of CDevice in the CDeviceManager class
Use public methods to fetch devices, search devices, etc.
The most problematic question however is populating each CDevice from a MySQL Database. Would it be safe to include my Database class directly into CDeviceManager and Populate CDevice Array in CDeviceManager Construct?
A lot of what I have read says it is smart to separate the business logic from the view, where I feel this method would do just that. I have not seen many other projects that appear to use this approach though, why I am worried I may be missing something.
It would be best to separate your business logic from data storage system. I recommend using dependency injection to get your job done. The exact implementation would depend on your needs (and project size), but to get an idea here's would be what I would do:
class CDeviceManager
{
private $db; //holder for your database
private $cdevices = array();
//more properties here
public function __construct(Database $db)
{
$this->db = $db; //database connection has now been injected into your class
}
//more methods here
}
Then somewhere along the line when you create your CDeviceManager object you can inject the database connection.
$cdm = new CDeviceManager( new Database(...) );
Your Database class would likely be a wrapper for PDO or MySQLi or whatever database API you would want to use. You could also go farther and have CDeviceManager implement some kind of interface that relate to various CRUD functions in your database. Best part though, is you can test this a whole lot easier because now you can swap out your database connection with a mock/test database so you don't inadvertently screw up your production database.
$cdm = new CDeviceManager( new MockDatabase(...) );
or
$testdb = new TestDatabase(...);
$cdm = new CDeviceManager( $testdb );
So yes, in the end it is good to separate the database connection from your domain models. Some recommend going even farther and making sure that your domain models are completely ignorant to the storage mechanism in general, this way you could be flexible on your storage system/persistence layer. E.g:
$cdm = new CDeviceManager( new FileRetriever() ); //Maybe you are storing stuff in a flat file
Hope that helps clear things up a little bit.
I've been told that it's a common practice to separate MySQL code from PHP code, is this true? Is this like a new coding standard? Are there any benefits of doing such?
Can someone direct me what are best coding practices (PHP/MySQL) when writing for masses (open source script for example).
Thanks!
Good question!
I've been told that it's a common practice to separate MySQL code from PHP code, is this true?
absolutely true!
Is this like a new coding standard?
and old old concept. there is no standard, but defacto exists
Are there any benefits of doing such?
many benefits
benefits from de-coupling between Layers.
when business logic is de-coupled from Presentation logic, if requirement changes you can change it easily.
so not only separate sql from php, also separate HTML code from php logic
using sqlMap
in the Java world there is MyBatis SqlMapper. This is very commonly used and this is what you want exactly if you are Java programmer.
But in PHP, hard to find something like MyBatis, the only thing I have found is PRADO http://www.pradosoft.com/
using ORM
ORM = Object Relation Map. http://en.wikipedia.org/wiki/Object-relational_mapping
This is also used. but i don't know there is ORM framework for PHP. if anyone knows, please let me know. #jszobody has suggested http://www.doctrine-project.org/projects/orm.html (Thanks)
thanks.
I've been told that it's a common practice to separate MySQL code from
PHP code, is this true?
I think, you are talking about Loose coupling, Separating your application logic in parts (Building a good architecture), so you can keep things organized, maintainable. Actually, this is too broad discussion and I may not properly describe everything but to answer your question, Yes, it's a good (recommended) practice and a design principle in software development.
In an application, the most important part is the domain/business logic, which serves the application and this should be kept separate from other logics, such as presentation logic (UI). For example, if your application, deals with creating of users, products then you may keep them in a separate place each one as an entity of your application. For example
User management
class User {
public function createUser()
{
// ...
}
}
Product management
class Product {
public function addProduct()
{
// ...
}
}
This are your business logic and you may use/call these from a separate class/place like
$user = new User;
$user->create();
Now, think about the data storage mechanism, if you create a new user, you may need to put all the information in a place, it maybe a database, a flat file or ccould be an xml file, so, what should you do in your createUser() function, you should use a data access layer between your data storage and business logic, which means, whatever data storage you use, you should not use any code in your createUser() function (business logic) directly, instead you access the data storage via another layer (DAL), for example, your createUser() function may look like something like this
class User {
protected $storage = null;
public function __construct($storage)
{
$this->storage = $storage;
}
public function createUser()
{
$userData = $_POST['first_name'];
$userData = $_POST['user_name'];
// more fields...
// data validation
$this->storage->save($userData);
}
}
Now, to create a user and save it in a database, you can use it like
$storage = new DbStorage();
$user = new User($storage);
Maybe, you want to use a flat file to store data instead of a database, no problem, just change the data storage, i.e.
$storage = new FileStorage();
$user = new User($storage);
Now, see the difference, Your save method doesn't know about storage mechanism, it just calls storage->save() and each storage has it's own save mechanism, things are organized, clean and easy to maintain, change the storage mechanism without making any changes in your code. So, it's like
Business Logic --> Data Access layer --> Data Storage
Here in data access layer, you should write code according to your storage mechanism, if you have a database as a storage then you write code according to that and in this case, your DbStorage may have it's own abstract database layer (different drivers for different Database, i.e. mysql, oracle etc), here ORM comes in action.
So, main thing is to keep things loosely coupled, which help you to build a clean and maintainable application. This is a little idea only. These links may help you
Separation of concerns
SOLID
Software design pattern
PHP - The Right Way
Data access layer
ORM
Update : I think I should add a bit about database abstraction layer's example
So, when you use a database for storage mechanism, you may use
$storage = new DbStorage();
$user = new User($storage);
But, this DbStorage should contain another layer for different types of databases, i.e. myaql, oracle etc. In this case, your DbStorage may look like this
class DbStorage{
protected $db = null;
public function __construct($database)
{
$this->db = $database;
}
public function save($data)
{
$this->db->insert($data);
}
}
To use it, you may use code like this
$config = array('hostname' =>'localhost', 'username'=>'root', 'password'=>'123456', 'database'=>'myDatabase');
$storage = new DbStorage(new MySqlDriver($config));
$user = new User($storage);
Or for another database engine, you may use
$config = array('hostname', 'username', 'password');
$storage = new DbStorage(new OracleDriver($config));
$user = new User($storage);
Now, your different database drivers may look something like this
class MySqlDriver(){
public $connection;
public $database;
public function __construct($config)
{
$this->connection = mysql_connect($config['hostname'], $config['username'], $config['password'], $config['database']);
mysql_select_db($db);
}
public function insert($data)
{
// code for insert (mysql)
}
}
For oracle you may have another class as OracleDriver
class OracleDriver(){
// ...
public function __construct($config)
{
// ...
}
public function insert($data)
{
// code for insert (oracle)
}
}
This is just an idea of database abstraction layer and in most cases, configuration for each database (MySqlDriver, OracleDriver) may contain in configuration file, i.e. database.php and it my contains array like
return array(
'mysql' => array(
'hostname'=>'localhost',
...
),
'oracle' => array(
'hostname'=>'localhost',
...
)
);
This is just a rough idea, you may find better examples online and there are lots of open source libraries to use in live projects.
Yeah, this is standard across many programming languages. Typically you would write stored procedures and have your php code leverage those to do the database work. This separation makes it easier to manage your code base and helps with maintenance and extensability.
Don't take this advise too literally.
Because there is no way to follow it.
As you can see, noone provided you with example script. That's quite a problem with this site. Too much knowledge I'd call it. And lack of practice.
So, It cannot be used as a rule of thumb. Using stored procedures, where you can do single primary-key based lookup, is just an overkill. And ORM cannot create whatever complex query for you. So, it's rather good intentions than "coding standard".
Yet there is a rule of thumb you can easily follow: never let your SQL and HTML to meet in a same file. This one is quite easy to follow and way more practical, because you have to change appearance more often than database backends.
I'm building a web application that needs to be able to write data to either a mysql db or an xml file, depending on the online status of the application.
In my model, I have a super class (Dao is data access object)...
abstract class Dao {
static function getInstance($online_status) {
if $online_status = 'online' {
return new DaoMySQL;
} else {
return new DaoXML;
}
}
abstract function dao_select();
abstract function dao_insert();
abstract function dao_update();
abstract function dao_delete();
}
Now, here is the part I'm confused about. I have a domain model/entity class that selects the appropriate Dao using:
$this->dao = Dao::getInstance($online_status);
So, now I have the correct data access object selected. But, the problem is I still two implementations of dao_select() and the other functions. Now, the main implementations are in the respective classes DaoMySQL and DaoXML, but dao_select() in each of those classes require different things. i.e. the DaoMySQL version needs two parameters, $table and $where_statement. DaoXML (which I haven't implemented) will need the element name, and maybe another argument, I don't know.
So, in my domain model class, after calling
$this->dao = Dao::getInstance($online_status);
is this where I need to include two separate local implementations (pertaining to the domain model/entity class only) of dao_select(), or this wrong? It just seems like I'm taking the elegance out of the process by doing something like this:
class EntityModel {
$this->dao = Dao::getInstance($online_status);
if($this->dao->type = 'mysql') {
$result = $this->dao->dao_select($table, $where);
} else {
$result = $this->dao->dao_select($xml_params);
}
}
I feel like I'm taking the simplicity out of the system... Does this approach make sense, or is there a better one?
You are doing it wrong.
Few notes to begin with:
in OOP the extends statement signifies is a relationship. Which means that, while class Duck extends Bird is all fine, writing class User extends Table is NOT.
in MVC the Model is not a class or an instance of a class. Instead it is a layer of application, mostly made of two types of elements:
domain objects: containing domain business rules and logic
data access structures: usually datamapper dealing with storage and retrieval of information
I would argue, that the third significant part of Model layer are services. But there are options on whether it is part-of or above Model.
Currently what you are trying to do is forcing a ActiveRecord (which is fine for small things, but as project grows, it becomes a burden on architecture .. which is what you are face with now) patterns to work with dynamic data sources. And to do so you are resorting to procedural calls.
Anyway, the point is that you should inject your DAO instance into your Domain Objects (what you calls "models"). And you should leave the creating of your DAO to a separate factory instance, which would be responsible for initializing them and providing them with data source (instance of PDO or file path). This way you can, not only separate the responsibilities, but also swap the storage destination "on fly".
To learn more you should investigate what is dependency injection. Here are few video that might help:
Don't Look For Things!
Global State and Singletons
My question is how does one abstract a database connection from the model layer of an application? The primary concern is to be able to easily change from different types of databases. Maybe you start with a flat file, comma-delimited database. Then you want to move to a SQL database. Then later you decide an LDAP implementation would be better. How can a person easily plan for something like this?
For a simple example, let's say you have a user with a first name, last name, and email. A very simple PHP class representing it might look like this (please ignore the problems with public instance variables):
<?php
class User {
public $first;
public $last;
public $email;
}
?>
I have frequently seen where people have a DAO class which has the SQL embedded in it as such:
<?php
class UserDAO {
public $id;
public $fist;
public $last;
public $email;
public function create( &$db ) {
$sql = "INSERT INTO user VALUES( '$first', '$last', '$email' )";
$db->query( $sql );
}
}
?>
My problem with strategies like this is when you want to change your database, you have to change every DAO class' create, update, load, delete functions to deal with your new type of database. Even if you have a program to auto-generate them for you (which I am not particularly a fan of), you would have to edit this program to make it work now.
What are your suggestions for how to handle this?
My current idea is to create a super class for DAO objects with its own create, delete, update, load functions. However, these functions would take arrays of the attributes of the DAO and generate the query itself. In this manner, the only SQL is in the SuperDAO class rather than being scattered about several classes. Then if you wanted to change your database layer, you would only have to change how the SuperDAO class generates the queries. Advantages? Disadvantages? Foreseeable problems? The good, the bad, and the ugly?
You can use various frameworks such as PDO, PEAR::MDB2 or Zend_Db, but to be honest in 12 years of PHP development, I've never had to transition from one type of data storage infrastructure to another.
Its exceedingly rare to even go from something quite similar like Sqlite, to MySQL. If you did do more than that, you'd have far larger problems anyway.
Using an ORM is usually the preferred way of abstracting the database. An incomplete list of PHP implementations is available on Wikipedia.
The best way is to use an ORM (Object-relational mapping) library. There are plenty of them for PHP. I've personally used and can recommend doctrine orm (I've used it in combination with silex, which is a minimalistic php framework).
Here is an StackOverflow thread about PHP ORMs where you can find some alternatives if you like: Good PHP ORM Library?
I came up with an interesting concept that would allow developer to create database-agnostic code, but unlike ORM will not sacrifice performance:
simple to use (like ORM)
db-agnostic: works with SQL, NoSQL, files etc
always optimize queries if vendor allows (sub-select, map-reduce)
The result is Agile Data - database access framework (see video for detailed explanation).
Solving real-life task with DB-agnostic code and Agile Data
Start by describing business models.
Create persistence driver $db (a fancy word for DB connection), which could be CSV file, SQL or LDAP.
Associate model with $db and express your Action
Execute Action
At this point framework will determine best strategy given the capabilities of the database, will map your fields declaration, prepare and execute queries for you, so that you don't have to write them.
Code Example
My next code snippet solves a rather complex problem of determining what is the current total debt of all our VIP clients. Schema:
Next is the vendor-independent code:
$clients = new Model_Client($db);
// Object representing all clients - DataSet
$clients -> addCondition('is_vip', true);
// Now DataSet is limited to VIP clients only
$vip_client_orders = $clients->refSet('Order');
// This DataSet will contain only orders placed by VIP clients
$vip_client_orders->addExpression('item_price')->set(function($model, $query){
return $model->ref('item_id')->fieldQuery('price');
});
// Defines a new field for a model expressed through relation with Item
$vip_client_orders->addExpression('paid')
->set(function($model, $query){
return $model->ref('Payment')->sum('amount');
});
// Defines another field as sum of related payments
$vip_client_orders->addExpression('due')->set(function($model, $query){
return $query->expr('{item_price} * {qty} - {paid}');
});
// Defines third field for calculating due
$total_due_payment = $vip_client_orders->sum('due')->getOne();
// Defines and executes "sum" action on our expression across specified data-set
The resulting query if $db is SQL:
select sum(
(select `price` from `item` where `item`.`id` = `order`.`item_id` )
* `order`.`qty`
- (select sum(`payment`.`amount`) `amount`
from `payment` where `payment`.`order_id` = `order`.`id` )
) `due` from `order`
where `order`.`user_id` in (
select `id` from `user` where `user`.`is_client` = 1 and `user`.`is_vip` = 1
)
For other data sources, the execution strategy might heavy-lift some more data, but would work consistently.
I think my approach is a great way to abstract database and I'm working to implement it under MIT license:
https://github.com/atk4/data
You should look into the PDO library.
PDO provides a data-access abstraction layer, which means that, regardless of which database you're using, you use the same functions to issue queries and fetch data.
PDO does not provide a database abstraction; it doesn't rewrite SQL or emulate missing features. You should use a full-blown abstraction layer if you need that facility.
It sounds good in theory but in all likelyhood YAGNI.
You would be better off using an SQL library such as PDO and not worrying about LDAP until you get there.
Generally speaking, if you're going to the trouble of using a database then your application will benefit by using features specific to a "brand" of database, and will be a more solid app for it.
It is very rare to move from one database system to another. The only time you might realistically consider that aa feature worth implementing is if you're writing some kind of loosely coupled system or framework intended for mass consumption (like Zend Framework, or Django).
I always liked using ADOdb. From what I've seen, it looks like it's capable of switching between vastly different platforms.
http://adodb.sf.net
In fact solution for the topic "where to implement data access logic?" is not complex. All you have to remember is that your model code must be separate from your data access code.
Like:
Model layer with some business logic User::name() method
class User
{
public $first;
public $last;
public $email;
public function name ()
{
return $this->first." ".$this->last;
}
}
Data access layer:
class Link
{
$this->connection;
public function __construct ()
{
$this->connection = PDO_Some_Connect_Function();
}
public function query ($query)
{
PDO_Some_Query ($this->connection, $query);
}
}
class Database
{
public $link;
public function __construct ()
{
$this->link = new Link();
}
public function query ($query)
{
$this->link->query ($query);
}
}
class Users
{
public $database;
public function __construct (&$database)
{
$this->database = &$database;
}
public save ($user)
{
$this->database->link->query ("INSERT INTO user VALUES( '$user->first', '$user->last', '$user->email' ))";
}
Usage:
$database = new Database();
$users = new Users();
$users->save (new User());
In this example it is obvious that you can always change your data access class Link which will run queries on whatever (It means you can save your users on any server as you change link).
In the same time you have clean model layer code which lives independently and has no idea who and where is saving its objects.
Also Database class here seems unnecessary but it in fact it can give birth to great ideas like collecting many links one instance for many db connections in one project.
Also there is single file simplest and almighty framework called db.php(http://dbphp.net) which is built on the pattern I described here and even creates tables automatically with ability to fully control its standard sql field/table settings and synch database structure to your model every time you wish.
Axon ORM automatically detects changes in your schema without requiring you to rebuild your code.