Should I be extending this class? (PHP) - php

I'm creating an ORM in PHP, and I've got a class 'ORM' which basically creates an object corresponding to a database table (I'm aiming for similar to/same functionality as an ActiveRecord pattern.) ORM itself extends 'Database', which sets up the database connection.
So, I can call: $c = new Customer();
$c->name = 'John Smith';
$c->save();
The ORM class provides this functionality (sets up the class properties, provides save(), find(), findAll() etc. methods), and Customer extends ORM. However, in the future I may be wanting to add extra public methods to Customer (or any other model I create), so should this be extending ORM or not?
I know I haven't provided much information here, but hopefully this is understandable on a vague explanation, as opposed to posting up 300+ lines of code.

I agree with the other answers here - put the additional methods into a descendant class. I'd also add an asterisk to that though: each time you extend the class with extra methods, think about what you are trying to achieve with the extension, and think about whether or not it can be generalised and worked back into the parent class. For example:
// Customer.class.php
function getByName($name) {
// SELECT * FROM `customer` WHERE `name` = $name
}
// ** this could instead be written as: **
// ORM.class.php
function getByField($field, $value) {
// SELECT * FROM `$this->table` WHERE `$field` = $value
}

You're certainly thinking correctly to put your business logic in a new class outside your 'ORM'. For me, instead simply extending the ORM-class, I'd rather encapsulate it with a new, value object class to provide an additional degree of freedom from your database design to free you up to think of the class as a pure business object.

Nope. You should use composition instead of inheritance. See the following example:
class Customer {
public $name;
public function save() {
$orm = new ORM('customers', 'id'); // table name and primary key
$orm->name = $this->name;
$orm->save();
}
}
And ORM class should not extend Database. Composition again is best suited in this use case.

Yes, place your business logic in a descendant class. This is a very common pattern seen in most Data Access Layers generation frameworks.

You should absolutely extend the ORM class. Different things should be objects of different classes. Customers are very different from Products, and to support both in a single ORM class would be unneeded bloat and completely defeat the purpose of OOP.
Another nice thing to do is to add hooks for before save, after save, etc. These give you more flexibility as your ORM extending classes become more diverse.

Given my limited knowledge of PHP I'm not sure if this is related, but if you're trying to create many business objects this might be an incredibly time consuming process. Perhaps you should consider frameworks such as CakePHP and others like it. This is nice if you're still in the process of creating your business logic.

You're definitely thinking along the right lines with inheritance here.
If you're building an ORM just for the sake of building one (or because you don't like the way others handle things) than go for it, otherwise you might look at a prebuilt ORM that can generate most of your code straight from your database schema. It'll save you boatloads of time. CoughPHP is currently my favorite.

I have solved it like this in my Pork.dbObject. Make sure to check it out and snag some of the braincrunching I already did :P
class Poll extends dbObject // dbObject is my ORM. Poll can extend it so it gets all properties.
{
function __construct($ID=false)
{
$this->__setupDatabase('polls', // db table
array('ID_Poll' => 'ID', // db field => object property
'strPollQuestion' => 'strpollquestion',
'datPublished' => 'datpublished',
'datCloseDate' => 'datclosedate',
'enmClosed' => 'enmclosed',
'enmGoedgekeurd' => 'enmgoedgekeurd'),
'ID_Poll', // primary db key
$ID); // primary key value
$this->addRelation('Pollitem'); //Connect PollItem to Poll 1;1
$this->addRelation('Pollvote', 'PollUser'); // connect pollVote via PollUser (many:many)
}
function Display()
{
// do your displayĆ­ng for poll here:
$pollItems = $this->Find("PollItem"); // find all poll items
$alreadyvoted = $this->Find("PollVote", array("IP"=>$_SERVER['REMOTE_ADDR'])); // find all votes for current ip
}
Note that this way, any database or ORM functionality is abstracted away from the Poll object. It doesn't need to know. Just the setupdatabase to hook up the fields / mappings. and the addRelation to hook up the relations to other dbObjects.
Also, even the dbObject class doesn't know much about SQL. Select / join queries are built by a special QueryBuilder object.

Related

PHP + MVC - my domain model is confused

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

CRUD and OOD. How to approach this?

Please be brutally honest, and tear my work apart if you have to.
So I'm re-writing a small web-application that I recently made. The reason for this is simply that the code got pretty messy and I want to learn and apply better OO design. What this application should do is just simple CRUD.
I have a database with 3 tables, companies and partners which are in no relation to each other and city which has a 1:n relation with companies and partners. Very simple, really. Now, I have several questions which i will state at the end of my post. Here i'll just try to explain:
My first approach was that I created classes company, partner and city, fetched all datasets from the database and created objects from that:
class company {
private $id = null;
private $name = null;
private $city = null;
//many more attributes
function __construct( $id, $name, $city, [...] ) {
$this->id = $id;
$this->name = $name;
$this->city = $city;
//huge constructor
}
/*
* getters + setters here
*
* no need to paste the partner class as it looks just like this one
*
*/
}
And that is all these classes did. I fetched every dataset from the database and constructed company, partner and city objects (the attribute city within these classes is an object with several attributes itself) and saved them into two arrays arr_companies and arr_partners, which then held these objects...and it worked fine like that.
Now, what I wanted is to update, insert, delete into the database, and all 3 classes (city, company, partner) need this functionality. My approach was that I created a new class with a constructor that would basically take 2 strings command and object, e.g. ('update', 'company') and it would then update the company directly in the database leaving my objects untouched. That made me really sad, because I had such nicely constructed objects and I didn't know how to make use of them.
Questions:
Is it bad to have such huge constructors (my biggest one would take
28 parameters)?
Should you have a separate class for database
operations or is it better to have maybe an abstract class or
interface for it and let the subclasses themselves handle update, delete, insert?
Is it common to just write, delete from the database whenever or should I just apply these changes to my objects and only execute the commands to the database later, for example when the session ends?
I figure an application like this must have been done a fantastillion times before. What is the proper approach here? create objects, work with objects, save them to the database?
I have so many questions but I think many of them I just don't know how to ask.
Please note that if possible I would not like to use an ORM at this point.
Thank you very much for your time.
Questions posed in OP:
"Is it bad to have such huge constructors (my biggest one would take 28 parameters)"?
Yes. Imagine the calling code. You would have to pass 28 different values, not to mention each call would have to respect the exact order specified in the constructor. If one parameter was out of place, you could wreck havoc with parameter dependent algorithms. If you really need to pass a large number of parameters, I would recommend passing them in as an array (posted an example to another SO question).
"Should you have a separate class for database operations or is it better to have maybe an abstract class or interface for it and let the subclasses themselves handle update, delete, insert?"
Generally speaking, when creating classes, you want to try to identify the nouns that best represent your business needs. In your specific case you would probably have three classes; Company, Partner, and City.
Now within each class (noun), your methods would be in the form of verbs, so symantically your calling code makes sense: if ($company->getName() === 'forbes')
As you mentioned, each class needs a database object (dbo) to work with, so you could implement any number of patterns to expose datase connections to your classes; singleton, singleton with factory, or dependency injection, etc.
Abstract (parent) classes are great for sharing common algorithms across child classes, and should be identified when you are in the psuedo-code stage of your design. Parent classes also allow you to force child classes to have methods by declaring abstract methods within the parent.
Interfaces are a useful tool in certain situations, but I find they are less flexible than declaring abstract methods in parent class. But are good in situations where classes do not share a common parent.
"Is it common to just write, delete from the database whenever or should I just apply these changes to my objects and only execute the commands to the database later, for example when the session ends"?
CRUD activity should happen at the time the action is executed. If you wait for the session to end, you may run into situations where a session is pre-maturely ended due to a user closing a browser, for example. To better protect your data you can wrap your CRUD activity within transactions.
If you are running a high-traffic application, you can implement a queuing system and queue up the work to be done.
"I figure an application like this must have been done a fantastillion times before. What is the proper approach here? create objects, work with objects, save them to the database"?
You are correct, this has been done before, and are commonly referred to as ORMs (object relation mappers). Basically, an ORM will introspect your database schema, and create objects (and relations) which represent your schema. So instead of working with native SQL, you are working with objects. Although you can use SQL for custom business needs, but in the case of Doctrine, you would use Doctrine Query Language (DQL) vs native SQL.
An ORM I would highly recommend is Doctrine.
If you do not want to use an ORM, you can add CRUD methods to your primary classes. I Opted for an interface so your classes don't have to extend from a parent comprised of database operations. Also, check out this post on using a singleton/factory for exposing your classes database object(s).
Consider the following:
// Company.php
class Company implements iDatabaseOperation
public function delete()
{
// Lets use a DBO singleton/factory for DB access
// Uses PDO, which is strongly recommended
$dbo = Database::factory(Database::DATABASE_NAME);
$dbo->beginTransaction();
try {
$sql =
"DELETE FROM " .
" company " .
"WHERE " .
" id = :companyId " .
"LIMIT 1";
$stmt = $dbo->prepare($sql);
$stmt->bindValue(':companyId', $this->getId());
$stmt->execute();
$dbo->commit();
} catch (Exception $e) {
$dbo->rollback();
error_log($e->getMessage();
$e = null; // Php's garbage collection sucks
}
}
}
// iDatabaseOperation.php
interface iDatabaseOperation
{
public function delete();
public function update();
public function insert();
}
It is realy bad. Code is completele unreadable in this case. You have options
to use setters (can add validation logic inside, better readability, no need to fill empty fields with null)
to have separate class builder for each domain class (takes some memory for additional object). Example in java hope you can understand:
class CompanyBuilder {
private final Company c;
public CompanyBuilder() {
c = new Company();
}
CompanyBuilder addId(String id){c.id = id;}
// id should be package visible and class should be located in the same package with builder
CompanyBuilder addName(String name){...}
CompanyBuilder addCity(String city){...}
Company build(){ return c;}
}
hybrid solution to have methods to organise chain(worse debugging, better readability). In java will be methods:
class Company {
...
Company addId(String id){
this.id = id;
return this;
}
Company addName(String name){...}
...
}
Usage:
Company c = new Company().addId("1").addName("Name1");
maybe you can create more granular objects to reuse them later and add specific logic in correct place. For instance it can be Address(Location) object for company.
Follow single responsibility principle. SOLID description on wiki.
It helps to change database specific code without affection of other part of system in your case. Well, separate domain and database specific code, have common interface or abstract class(if you have common logic for all of domain classes - liskov principle). In subclasses implement domain specific part.
If you do not want to lose data you should save them each time or have cluster of servers or have distributed cache. If it is ok to lose save them in the end of session as batch. It will increase youre performance. Also you should save in transaction each time if you have concurrent updates.
Approach is get data from database/construct objects from this data or new objects/ work(update) objects/write data from objects to database
just write more code and read stackoverflow
Finally I suggest to read "Clean Code: A Handbook of Agile Software Craftsmanship" R.Martin.
You are essentially writing your own ORM. So, I wouldn't discount just switching to one that's already been written for you. The advantage to rolling your own is that you gain an understanding of how it works as your write it. But the disadvantage is that someone else has probably already done it better. But assuming you want to continue on...
General Advice: Remember to always break the problem down into simpler and simpler pieces. Each class should only perform a simple function. Also, you should not have to worry about caching updates... unless perhaps your database is on the other end of a remote connection over a modem.
Specific Advice follows:
I would setup your entity instance classes to house data and not to do a lot of data loading. Use other classes and logic for loading the data. I would use the constructor of the entity class only to populate the data that pertains to the class (and it's children).
A simple thing to do is to use static methods on the entity class for loading and saving data. E.g.
class city {
private $id = null;
private $name = null;
function __construct( $id, $name ) {
$this->id = $id;
$this->name = $name;
}
// getters and setters
...
// ---------------------
// static functions
// ---------------------
public static function loadById($cityId) {
// pull up the city by id
$retval = new city(row["id"], row["name"]);
// close db connection
return $retval;
}
public static function loadByCustomerId($customerId) {
// pull up multiple cities by customer id
// loop through each row and make a new city object
// return a hash or array of cities
}
public static function update($city) {
// generate your update statement with $city->values
}
// other methods for inserting and deleting cities
...
}
So now the code to get and update cities would look something like this:
// loading city data
$city = city::loadById(1); // returns a city instance
$cities = city::loadByCustomerId(1); // returns an array of city instances
// updating city data
$city->name = "Chicago"; // was "chicago"
city::update($city); // saves the change we made to $city
The static methods are not the best way to implement this, but it gets you pointed in the right direction. A repository pattern would be better, but that's beyond the scope of this one answer. I find that often I don't see the merit in a more involved solution like the repository pattern until I run into problems with the simpler solutions.
What you are doing looks greate. What you can add is an intermediate layer which maps your business object to your database(object relation mapping). There are a lot of object relational mapping api out there. Check this wikipedia list for ones you can use for PHP
I think a constructor with 28 parameters is too much, you should others classes managing some attributes having some stuff in common. You should give us what kind of others attributes you instanciated, and it could help you to find a way to make more common objects.
I think you should also create a class managing the operations and the database like a DBHandler with delete, update, and so on..
In my opinion, do modifications on tuples in your database directly after functions are called are important.
Why? Because it could avoid conflict, like the case you try to update an object which is supposed to be deleted for example, if you do modifications on your database at the end.
You might want to look at ruby on rails.
You don't necessarily have to switch over to it, but look at how they implement the MVC pattern and achieve CRUD.

PHP Structure - Interfaces and stdClass vars

I'm building a class to handle Paypal IPNs as part of a project, and since I already know i'm going to need to use it again in at least two more upcoming jobs - I want to make sure I structure it in a way that will allow me to re-use it without having to recode the class - I just want to have to handle changes in the business logic.
The first part of the question is re. interfaces. I haven't quite grasped their usefulness and when/where to deploy them. If I have my class file ("class.paypal-ipn.php"), do I implement the interface in that file?
Here's what i'm working with so far (the function list is incomplete but its just for illustration):
CLASS.PAYPAL-IPN-BASE.PHP
interface ipn_interface {
//Database Functions
// Actual queries should come from a project-specific business logic class
// so that this class is reusable.
public function getDatabaseConnection();
public function setDatabaseVars($host="localhost",$user="root",$password="",$db="mydb");
public function dbQuery($SQL);
//Logging Functions
public function writeLog($logMessage);
public function dumpLogToDatabase();
public function dumpLogToEmail();
public function dumpLogToFile();
//Business Logic Functions
private function getTransaction($transactionID);
//Misc Functions
public function terminate();
}
class paypal_ipn_base {
//nothing to do with business logic here.
public function getDatabaseConnection() {
}
public function setDatabaseVars($host="localhost",$user="root",$password="",$db="mydb") {
}
public function dbQuery($SQL) {
}
}
CLASS.PAYPAL-IPN.PHP
final class paypal_ipn extends paypal_ipn_base implements ipn_interface {
//business logic specific to each project here
private function getTransaction($transactionID) {
$SQL = "SELECT stuff FROM table";
$QRY = this->dbQuery($SQL);
//turn the specific project related stuff into something generic
return $generic_stuff; //to be handled by the base class again.
}
}
Usage
In this project:
Require the class files for both the base, and the business logic class.
Instatiate *paypal_ipn*
Write code
In other projects:
Copy over the base IPN class
Edit/rewrite the business logic class *paypal_ipn* within the constraints of the interface.
Instantiate *paypal_ipn*
Write code
So as you can see i'm literally just using it to define groups of related functions and add comments. It makes it easier to read, but of what (if any) other benefit is it to me - is it so that I can pull the extender and the base class together and force errors if something is missing?
stdClass Question
The second part of the question is building on the readability aspect. Within the class itself there is an ever increasing number of stored variables, some are set in the constructor, some by other functions - they relate to things such as holding the database connection vars (and the connection resource itself), whether the code should run in test mode, the settings for logging and the log itself, and so on...
I had started to just build them as per usual (again, below incomplete & for illustration):
$this->dbConnection = false;
$this->dbHost = "";
$this->dbUser = "";
$this->enableLogging = true;
$this->sendLogByEmail = true;
$this->sendLogTo = "user#domain.com";
But then I figured that the ever growing list could do with some structure, so I adapted it to:
$this->database->connection = false;
$this->database->host = "";
$this->database->user = "";
$this->logging->enable = true;
$this->logging->sendByEmail = true;
$this->logging->emailTo = "user#domain.com";
Which gives me a much easier to read list of variables when I dump the entire class out as I code & test.
Once complete, I then plan to write a project specific extension to the generic class where i'll keep the actual SQL for the queries - as from one project to another, Paypal's IPN procedure and logic won't change - but each project's database structure will, so an extention to the class will sanitize everything back into a single format, so the base class doesn't have to worry about it and will never need to change once written.
So all in all just a sanity check - before I go too far down this road, does it seem like the right approach?
if you are using a class autoloader, which I highly recommend, you would not want to keep the interface and the class in the same file so that the interface can autoload without needing to first load this one class that implements it.
For more info on autoloading:
http://php.net/manual/en/language.oop5.autoload.php
another thing you may want to consider is that a given class may impliment multiple interfaces, and multiple classes may implement the same interface.
interfaces are primarily used for various design patterns, to enforce rules, and to decouple a class from any dependent classes. when you decouple a class from its dependencies, it makes it much easier to modify code at a later time.
for instance, let's say you have a class A that takes in another class B as an argument, and this class is spread throughout your code. you want to enforce that only a class with a specific subset of methods can be accepted as this argument, but you do not want to limit the input to one concrete class and it's decendants. in the future, you may write an entirely different class that does not extend class B, but would be useful as an input for class A. this is why you would use an interface. it is a reusable contract between classes.
some would argue that since PHP is a dynamic language, interfaces are an unecessary complication, and that duck typing may be used instead. I find in large multi-user code bases however, that interfaces can save a lot of time, letting you know more about how one class uses another, without having to study the code in depth.
if you find yourself with a large list of variables that you have to pass around between objects or functions, they often do end up deserving a class of their own, but each case is different.
-- dependency injection example --
class A implements AInterface {
public function foo($some_var) {}
}
interface AInterface {
public function foo($some_var);
}
class B {
protected $localProperty;
// inject into the constructer. usually used if the object is saved in a property and used throughout the class
public function __construct(AInterface $a_object) {
$this->localProperty = $a_object;
}
// inject into a method. usually used if the object is only needed for this particular method
public function someMethod(AInterface $a_object) {
$a_object->foo('some_var');
}
}
you can now see that you can write another class that impliments a foo method (and the AInterface) and use that within class B as well.
as a real world example (used often), say you have a database class with particular methods that interact with the database (getRecord, deleteRecord). now lets say at a later time you find a reason to switch database rdbms. you now need to use entirely different SQL statements to accomplish the same goals, but since you used an interface for your type hinting, you can simply create a new class that impliments that interface, but impliments those same methods in entirely different ways as it interacts with a different rdbms. when creating this new class, you will know exactly what methods need to be written for this new class in order to fit into the same objects that need to use a database object. if you use a container class that you use to create objects and inject them into other objects, you would not need to change too much application code in order to switch databases classes, and therefore switch database rdbms. you could even use a factory class, which could limit your changes to one line of code to make this type of change (in theory).

PHP - mySQL DB class

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

What's the best way to abstract the database from a PHP application?

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.

Categories