PHP, Zend Framework and Other Crazy Stuff
Archive for October, 2006
Zend Framework 0.20 Preview Released
Oct 31st
Just in time for An Samhain (that’s Halloween for non-Irish folk
).
The new preview contains a raft of changes to almost all components. Of particular interest are the major changes incl. the new MVC implementation and the addition of some much welcome components like a Request, Response, Session and Registry. The list posted to the mailing list follows…
* New MVC implementation
* New HTTP request and response objects make it easy to automate
unit testing for web apps without a web server, and also make it
possible to use MVC for command-line and PHP-GTK application development
* Enhanced pure PHP Lucene-compatible search engine component
* New Mysqli DB adapter
* New JSON server
* New REST client and server
* New XmlRpc client and server
* New Acl component
* New Session component
* New Web Services clients for Delicious and Audioscrobbler
* New Registry component
* Significant improvements to many other components
* Lots of new documentation and translations
A lot of these are only available in the incubator (not in the core library directory) but are quite ready for trial and testing. If you are upgrading, the fact that many new components have not moved directly to the core should give all a better chance of coming to grips with the changes to commonly used components from 0.15 before looking in the deep end called “Incubator” for everything on the list above.
I would advise users to check the updated Manual for changes to the core components. Zend Framework Manual
Extending the Mapper: Stars and Planets
Oct 23rd
Introduction
Planets and Stars (“Bodies”) form the central hub around which the majority of a player’s activity will center. This planning document addresses the generation and mapping of these entities, and not their individual contents, facilities or uses.
Laying a Foundation
Before we start generating anything, we should recognise this task contain two discrete stages. Generation of a Body and Mapping of a Body. This indicates the addition of two new class families. Using the established convention:
# Map_Body_Position
# Map_Body_Generate
We also recognise that these two stages may have varying implementations. One could map Bodies through varying algorithms such as clustering, random distributions, etc. Similar variations occur in actual generation of Bodies.
To bind all these variations together we will require all varying classes to implement the same interface. This leads us to making two Interfaces.
# Map_Body_Position_Interface
# Map_Body_Generate_Interface
Now we may add as many variations as we need, all implementing the same interface. For this document we will focus on the simplest classes possible.
Adding Stars
Stars are the basic building blocks of the Redux galaxy. To start of on a simple implementation we will add two classes, implementing the establish interfaces:
# Map_Star_Position_Random
# Map_Star_Generate_Simple
Position_Random will randomly assign a Star to a Sector. We are ignoring distance between stars for the moment – taking a unit testing approach we start with minimal functionality and simply build it up as we go.
Generate_Simple will generate a Star adding only a Name and Id. As before, we add basics and leave complicated logic until later.
Skeleton Map_Star Interfaces
The Class family for Stars is “Map_Star”, i.e. it’s part of the Map subpackage. Bear in mind that all classes must share a common prefix in the absence of Namespacing from PHP5. We’ll start with the interface for Map_Star_Position:
{
public function position(Redux_Map_Grid $grid, array$stars);
}
Yep, we’re into complicated stuff here…
. In theory, the position class will accept two parameters. One will be the current Map_Grid object, the other is the array of Stars to be positioned on that Grid. Since position relies on x,y coordinates we need to ensure our Grid class can return its height and width.
The interface also specifies allowable parameters by defining valid Type Hinting for each parameter. See Type Hinting.
As a final note, we made the Interface specific to stars – planets are by their nature more complex and will require additional public methods.
Since we’re on a roll, let’s suggest a Generate interface:
If we keep this up, OOP is going to look simple…
The generate() method will require two parameters. The number of stars required and an array of Names to be utilised.
Implementing the Map_Star Interfaces
With interfaces in place, we can examine a sample implementation. As we mentioned earlier, we selected:
# Map_Star_Position_Random
# Map_Star_Generate_Simple
Position Random
The Random positioner is not a complex animal:
{
public function __construct()
{
}
public function position(Redux_Map_Grid $grid, array$stars)
{
$starCount = count($stars);
$gridWidth = $grid->getWidth();
$gridHeight = $grid->getHeight();
$centreX = floor($gridWidth/2);
$centreY = floor($gridHeight/2);
for($starIndex=0;$starIndex<$starCount;++$starIndex)
{
$stars[$starIndex][‘x’] = mt_rand(0, $gridWidth-1);
$stars[$starIndex][‘y’] = mt_rand(0, $gridHeight-1);
$stars[$starIndex][‘coord’] =
$stars[$starIndex][‘x’] . ‘,’ . $stars[$starIndex][‘y’];
}
return$stars;
}
}
The implementation above, notes a few requirements. It assumes the Grid is passed as an object and not an array. This requires changing Map_Grid to more of a Transfer Object type class.
{
private $height = 0;
private $width = 0;
private $grid = array();
public function __construct($height, $width)
{
$this->height = (int)$height – 1;
$this->width = (int)$width – 1;
if($this->width == 0 || $this->height == 0)
{
throw new Redux_Map_Exception(‘Invalid height or width supplied.’);
}
}
public function generate()
{
for($i=0;$i<=$this->height;$i++)
{
for($j=0;$j<=$this->width;$j++)
{
$this->grid[] = $i . ‘,’ . $j;
}
}
return$this;
}
public function getGrid()
{
return$this->grid;
}
public function getHeight()
{
return$this->height + 1;
}
public function getWidth()
{
return$this->width + 1;
}
}
After establishing the updated Grid component (and verifying it passes the updated Unit Tests), we carry on to verify the Postion class’s unit tests. The one I wrote before even starting the class should now run green (i.e. pass).
public function testPosition()
{
// a single item multidimensional array…
$stars = array(new Star );
// in a 2×2 grid max coord is 1, min is 0…
$grid = new Redux_Map_Grid(2,2);
$pos = new Redux_Map_Star_Position_Random();
$posstars = $pos->position($grid, $stars);
$this->assertEqual(count($posstars), 1);
$this->assertTrue($posstars[0]->x>= 0&& $posstars[0]->x<= 1);
$this->assertTrue($posstars[0]->y>= 0&& $posstars[0]->y<= 1);
$this->assertEqual(strlen($posstars[0]->coord), 3);
$this->assertEqual(count(explode(‘,’, $posstars[0]->coord)), 2);
}
// …
All we have done is add postioning information to the Stars array – only here we’ve altered it to use a Star object given the changes required by Generate_Simple. Of course we first need to generate Stars… Our next stop is Redux_Map_Star_Generate_Simple.
Generate Simple
Since all we care about is the Star Id and Name, this will not take long. To keep stars stored, we start using the Star class – a Row class for use with the Parth_Db_Access class. We’ll have to modify the preceeding Position class to use the Star class…(done already on the Wiki
).
{
public function __construct()
{
}
public function generate($number, array$starNames, $stdclass = false)
{
$stars = array();
$starNameCount = count($starNames);
if($number< 1 || $starNameCount< 1)
{
throw new Redux_Map_Exception(‘Invalid number of stars or star names.’);
}
if($stdclass === false)
{
$rowClass = ‘stdClass’;
}
else
{
$rowClass = $stdclass;
}
for($createId=0;$createId<$number;++$createId)
{
$stars[] = new$rowClass();
$stars[$createId]->id = $createId + 1;
$stars[$createId]->name = $starNames[mt_rand(0, $starNameCount-1)];
}
return$stars;
}
As luck (and forward planning) would have it, this also passes the relevant unit test:
public function testGenerate()
{
$names = array(‘beta’);
$gen = new Redux_Map_Star_Generate_Simple();
$stars = $gen->generate(1, $names);
$this->assertEqual(count($stars), 1);
$this->assertIsA($stars[0], ‘stdClass’);
$this->assertEqual($stars[0]->id, 1);
$this->assertEqual($stars[0]->name, ‘beta’);
}
// …
Conclusion
This concludes the section on Stars. We have implemented two simple schemes for generating and positioning Stars. The unit of data is the Star class – a Row Data object which can be stored to the database using Parth_Db_Access.
The next stage would be to assess more complex schemes, in addition to improvements to the current ones, and add these as implementing the specified interfaces. This allows a system of interchangeable strategies.
Even more fun can be had by adding a Factory Class to contain the logic required to select a specific strategy for positioning and generating. This could feed off a configuration value and remove any need for classes to be bound to specific implementations…
Redux: First Official Code!
Oct 19th
I guess you can call it the first foundation stone of this project. It’s nothing special, but it is the first piece of code written specifically for the project. ![]()
The code sets the stage for the Redux mapping system. Basically, we’re aiming at a grid-based map with each grid coordinate representing a Sector. Sectors are not Star Systems – a full Star System could occupy up to 100 Sectors leaving plenty of scope for exploration, manouvering, tactics, and my hoped for use of technology such as Satelites, Probes, Sensor Grids, etc. to have a decent space worth using them in. Enough of the banter – say hello to the code…
This represents a skeletal class structure. Redux_Map is a manager class which is the main class the client code would interact with to generate a map. Redux_Map_Grid is a simple grid generator – it creates an array of all sector coordinates. As you’ll see it’s stick simple which may explain why it took so little time to write…
. Unit Tests are appended. I guess it’s important to note the use of Unit Tests – I’ve adopted the Test Driven Development practice with a lot of enthusiasm since last Spring and find it a pretty powerful technique in developing well designed, easy to extend OOP code.
In case any malefactors from the Solar Empire camp decide to comment – it’s not within the project goals at this time to optimise early. I appreciate that OOP has its performance issues, but my personal goals are easy to maintain code within a testable framework. Optimisation at such an early stage hurts those two objectives more often than not unless the developer has the experience to avoid it. So yes, it is my intention to factor unique reuseable logic into small classes like dirt simple Redux_Map_Grid…
The code!
private $grid = array();
private $options = array(
‘height’=>100,
‘width’=>100
);
public function __construct()
{
}
public function map()
{
$grid = new Redux_Map_Grid(
$this->options[‘height’],
$this->options[‘width’]
);
$this->grid = $grid->generate();
}
private function __set($key, $val)
{
if(array_key_exists($key, $this->options))
{
$this->options[$key] = $val;
}
}
public function __get($key)
{
if(isset($this->options[$key]))
{
return$this->options[$key];
}
returnnull;
}
private function __isset($name)
{
returnisset($this->options[$name]);
}
private function __unset($name)
{
unset($this->options[$name]);
}
public function getGrid()
{
return$this->grid;
}
}
And we have our specialised Map_Grid class for generating the coordinate array…
private $height = 0;
private $width = 0;
public function __construct($height, $width)
{
$this->height = (int)$height – 1;
$this->width = (int)$width – 1;
if($this->width<= 0 || $this->height<= 0)
{
throw new Exception(‘Invalid height or width supplied.’);
}
}
public function generate()
{
$grid = array();
for($i=0;$i<=$this->height;$i++)
{
for($j=0;$j<=$this->width;$j++)
{
$grid[] = $i . ‘,’ . $j;
}
}
return$grid;
}
}
Finally, let’s never release code unless accompanied by unit tests! Unit tests are written for Simpletest 1.0.1beta (available from CVS only). We need this version since it avoid future deprecated methods and allows the new expectException() method for checking if an exception is thrown.
public function __construct(){
$this->UnitTestCase(‘Test of Redux_Map’);
}
public function testMapGrid()
{
$map = new Redux_Map;
$map->height = 2;
$map->width = 2;
$map->map();
$this->assertEqual(count($map->getGrid()), 4);
$this->assertIdentical($map->getGrid(), array(
0=>’0,0′,
1=>’0,1′,
2=>’1,0′,
3=>’1,1′,
));
}
public function testMapGridException()
{
$map = new Redux_Map;
$map->height = 0;
$map->width = 0;
$this->expectException();
$map->map();
}
}
Et voilá! Nothing complicated. Next up – adding actual entities (Planets, Facilities, etc.) to those sector coordinates – hopefully approximating star systems with a simple clustering algorithm. Onwards!
QS Redux: Part Deux
Oct 13th
Just a quick update. After the past days of planning QS Redux and searching for a name for the project I’ve settled on a few libraries to use as standard. I hunted low and high for AJAX libraries but the winner was Prototype. I actually like developing in Javascript so that quickly ruled out the PHP based libraries like xajax and Joshua Eichorn’s HTML_AJAX.
I think HTML_AJAX is one of the better PHP solutions and if you haven’t read Joshua’s book "Understanding AJAX" I can recommend it. Grabbed a copy a few days ago and it was good reading. But as I said, I leaned towards pure Javascript solutions early on.
So Prototype it is. To make Prototype even more attractive, some brave soul actually went and documented the entire library. Why this is not the official documentation hosted on the official website escapes me – it’s clean, clear, concise and in-depth. The other javascript libraries I looked at continue to have anywhere from zero to minimal documentation… The only missing thing is an AJAX request queue. I toured a mailing list or two and apparently few ever read Harry Fueck on the php blog over on Sitepoint – many queue requests were met with "Why would you want that?" type questions and a blank stare. Harry has been banging on about AJAX and network latency and the problems it causes for months now. It should be fairly simple to implement a FIFO queue so I’ll see where that leads…
Of course the Zend Framework is a definite building block. I’ve been watching the mailing list for a while now and a lot of improvements are coming on stream. 0.2 is due a release by month end, and the next version following that may be called 0.7 – since 0.3 does not justify the amount of work done since the 0.15 preview release. Might even see 0.2 renumbered to 0.5 going by some recent mailing list suggestions.
The Name Game
Oct 9th
As part of the Quantum Star Revival, we are seeking a new game name. If you think you can come up with ideas suitable for a space strategy online game then why not check out the topic and post some ideas? The game is open source – so all you get is fame and a little piece of PHP game history…![]()
http://forums.quantum-star.com/viewtopic.php?t=663
Name that game!
