PHP, Zend Framework and Other Crazy Stuff
Posts tagged astrum futura
Astrum Futura Redux
Dec 7th
For the cool folk who have followed the Solar Empire legacy through thick and thin since 1999, those cute .php3 file suffixes, Moriarty’s continuing denegration of all other developers, the revolution that open source brought, the sudden push towards OOP, and the…err…security and bug population… Working on anything hitting it’s 9th anniversary in PHP is really interesting - 9 times the fun and games .
Astrum Futura was envisaged as a desperately needed update to the long running open source Solar Empire franchise, where players engage each other across a galaxy of 500+ star systems mining resources, building colonies, and generally screaming bloody murder at each other. It’s not the most impressive or ambitious of online games, but it’s always been tenacious and attracted roaming users who like a quick dash of destruction in their daily diet.
In January 2008, the oft delayed development process will once again creak into action. The current tracer code was built originally using the Zend Framework 0.2-0.6 and famously led that Spring to my long running “Complex Views With The Zend Framework” blog series that gave birth to the Zend_View Enhanced proposal, and maybe gave Ralph Schindler a few headaches . Building anything more complex than a login page was pure heart ache previously.
Now that time is available, the Zend Framework significantly more mature, and we have a lot of legwork carried over from 2006 in the Quantum Game Library (thanks to Jacob Santos), it’s about time we got something concrete done. The usual suspects, if interest levels are high enough, can report to the shiny updated phpBB3 forums at http://forums.astrumfutura.com - same domain as this blog you’re reading.
And we will be applying XP this time - the random running process that usually prevails just doesn’t work out well. So get your Selenium gear in place.
Quantum_Db: The QGL Data Access Object Implementation
Feb 13th
Back in 2005, the Quantum Star SE project caught the Object Relational Mapping (ORM) bug and I took a first stab at implementing something that was simple, fast and easy to use. Until this stage I was a regular user of the Data Mapper pattern (among others) but since switching to PHP and developing open source projects found it to be largely unnecessary. The root problem is akin to hammering nails with a sledgehammer - too much complexity being implemented for a simple underwhelming task.
Here in 2007, with the QGL in development I found myself re-assessing my previous experiences and finding it attractive to develop something less complex and hopefully faster than a full scale ORM solution. Taking some previous work I did, I opened a branch in the QGL subversion repository and set to work. The results are slowly coming to fruition - the DAO, Row and part of the Driver families are shaping up going by the unit tests.
So what is Quantum_Db (in practice)? It will be a family of classes which form a Data Access Object (DAO) Framework when complete. This post is largely a ramble about current progress and intentions - so if looking for a complete solution you’re in the wrong place as the current code is strictly in-progress. For reference though, the source code is under the New BSD License. It’s incomplete, but available from its subversion branch at: http://quantumstar.svn.sourceforge.net/viewvc/quantumstar/branches/Quantum_Db/ and the forums can be found for the QGL in general at http://forums.astrumfutura.com/viewforum.php?f=25.
In this specific implementation of Quantum_Db, the DAO class (Quantum_Db_Access) is a Singleton which attempts to offer relatively basic CRUD methods capable of use on any valid database table record. A large part of its responsibility is generating CRUD type SQL. So you could have a User record, which could be saved by passing it to a DAO save() method. It’s not quite as clear cut, since to reduce the mass of code a DAO implementation often needs the “record” is encapsulated in a container called Quantum_Db_Row. This Row class can represent a single table record, but also doubles as a data container for setting up SQL conditions (think of WHERE, IN and INSERT clauses).
One of the goals intentionally targets simplicity, so there is no Propel-style Criteria object to mess about with. There will be in the future, but for simple needs, a simple DAO framework is sufficient as an initial start. A simplistic use case is adding a new User record. Some code showing this task:
[geshi lang=php]require_once ‘Models/User.php’;
// Fields are public properties handled by __get/__set in the
// Quantum_Db_Row class. The User class is actually a simple
// subclass defining valid fields and primary key(s).
//
// We do not specify an Id value for new Users. The DAO class will
// assign this assuming Id is an auto-incrementing value for MySQL
// or a Sequence for PostgreSQL.
$user = new User;
$user->name = ‘Pádraic’;
$user->email = ‘[email protected]’;
$user->password = sha1(‘password’);
$user->country = ‘ie’;
// Call on DAO to save this record to the database. Obviously any
// database errors will result in Exceptions thrown by the DAO so
// the database table rules (primary key, unique key, etc.) all apply.
$user->save();[/geshi]
The first thing you can note is that the DAO class (called Quantum_Db_Access is not directly called. Instead all Row objects carry a reference to the Quantum_Db_Access singleton so Quantum_Db_Row::save() proxies to Quantum_Db_Access::save() - we only need one generic DAO object. If one desperately needed the DAO they could just place a call to Quantum_Db_Access::getInstance().
[geshi lang=php]$dao = Quantum_Db_Access::getInstance();
$dao->save($user);[/geshi]
In fact, you can equally access the underlying database extension driver to run queries directly using the following. Of course Singletons have their own evil uses, so ideally you’d pass around the object reference instead of litering source code with static getInstance() calls which explicitly refer to the class name.
[geshi lang=php]// Example of accessing the driver to drop the User table
$driver = Quantum_Db_Access::getInstance->getDriver()->exec(“DROP TABLE user”);[/geshi]
Retrieving records is more interesting. It’s relatively simple to extract a record based on a primary key:
[geshi lang=php]$user = new User;
$user->getByPk(1);
var_dump($user->asArray()); // echo array of User (Id=1) data[/geshi]
It’s much more complex to fetch rows of a very specific nature. Even worse, without a Criteria object using the MySQL IN clause is a challenge. However for those where the SQL values depend solely on simple field values a neat solution is “named queries”. A Named Query (check the excellent introduction at: http://www.tonybibbs.com/article.php/PropelDAO regarding something similar for Propel) is an SQL string containing value placeholders (e.g. for use in a PDO::prepare()) stored in some central file. This has a few benefits and disadvantages.
The main benefit is the centralisaton - like OOP, centralising logic (in this case non-generated SQL strings) reduces duplication and encourages reuse. Allowing the named queries to be indexed (for example, within an XML hierarchy) by a name and model allows them to be easily located and prepared by the Data Access Object. The disadvantages are of course that it’s still limited. For example, use of a MySQL “SELECT id, name, email FROM user_table WHERE id IN(1,2,3,4)” isn’t likely a storeable named query since the IN() range of id values is too variable. But for many queries it’s a good fit in the absence of some form of Criteria class.
Enough of the DAO class however. After beating it to death, there are still pieces to be completed when it comes to allowing complex SQL clauses. The main point is that for simple use cases it is a good match - and simple use cases are extremely common in many of my open source endeavors.
To backup the Data Access Class Quantum_Db also implements a Driver and Results class family. Again simplicity is key, so it’s being written under the presumption that PHP5′s PDO extension is available. The Quantum_Db_Driver_Interface file actually mirrors the PDO interface for this reason. Of course we can’t forget mysqli (the most popular PHP5 database extension) or pgsql and the rest. Quantum_Db_Driver defines an interface to enable additional extension type support. Personally I only intend adding a light abstraction over ADOdb-Lite - it’s not worth duplicating Mark’s already existing library.
The Results class, the one part no code exists for yet - don’t be worried I develop using TDD and unit testing so it’s perfectly normal . Quantum_Db_Results will aggregate the results of queries into a class implementing PHP5′s SPL Iterator. To be specific, the Iterator methods will be tied to each underlying Driver’s fetch* methods. This should allow continued use of Lazy Loading during iterations, and allow continued use of foreach() etc.
Here ends my ramble for now. For those working on the QGL or similar code maybe it will provide a few of my thoughts on the topic - assuming you can summarise the rambling of course .