Archive for October, 2006

Zend Framework 0.20 Preview Released

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

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:

interface Redux_Map_Star_Position_Interface
{

    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:

interface Redux_Map_Star_Generate_Interface
{

    public function generate($number, array$names);

}

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:

class Redux_Map_Star_Position_Random implements Redux_Map_Star_Position_Interface
{
   
    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.

class Redux_Map_Grid
{
 
    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 ;-)).

class Redux_Map_Star_Generate_Simple implements Redux_Map_Star_Generate_Interface
{

    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…