1

news

2

mtasc

3

obfu

4

ocaml

5

php

6

neko

7

haXe

8

contact

PHP::SPOD

PHP::SPOD

This package provides a database table to object mapping with sql helpers for most common queries. It does not prevent the programmer to use its own queries but incite him to adopt a very specific and well known way of programming his database related classes.

It fits perfectly for small applications with single database (no multiple database connections at this time) and scale -very- well when the application gets bigger (tested with large public websites).

Spod force the separation between application logic and database access splitting them into your classes on the one hand and Spod_Managers containing SQL stuff on the other hand.

The real philosophy behind SPOD is : do it yourself.

Spod, as its name implies, is simple, it won't manage relationships for you and you'll still have some work to do (nothing replace a good coder, robots are doomed).

The Sql package is used for Sql backend.

The SPOD package is licensed under the terms of the LGPL (GNU LESSER GENERAL PUBLIC LICENSE) contained in the COPYING file of this package.

Download

Download the Spod package

Use pear to install it.

pear install http://tech.motion-twin.com/zip/Spod-1.0.2.tar.gz

Documentation

  • first example
  • relationship
  • inheritance

A Spod_Object is your regular php class with public fields named like the database table it represents.

A Spod_Manager is a class which describe in three or four members how to make the relation between the php class and the database table.

There's no php code generation or xml schemes involved. Everything is between your code and your sql. Thus Spod has very little features, it has a driver, it knows which manager manage which php class, and it asks managers to insert, delete, update objects.

Managers extends Spod_Manager which generate at runtime a limited set of SQL queries like insert, update, delete, count, list.

Missing features and queries are implemented 'by hand' in managers. Which you would have done anyway if you wouldn't have used Spod or a similar library.

update(), insert(), delete(), methods can be of course overwritten in your managers and objects to prepare data, trigger things, etc...

First example

require_once 'Spod.php';

class Person extends Spod_Object {
    public $id;
    public $firstname;
    public $lastname;

    public function someLogicMethod()
    {
        // ... the Person is not only a structure, it has a life
    }
}

// all my sql goes into this class
//
class PersonManager extends Spod_Manager {
    // following fields are for Spod
    public $class = 'Person';
    public $table = 'Person';
    public $key   = 'id';
    // auto increment column if any
    public $ai    = 'id'; 

    // i define a custom search method 
    public function search($name)
    {
        // Sql provide a simple method to secure LIKE strings
        $name = Sql::prepareSearch($name);
        
        $q = 'SELECT * FROM Person 
               WHERE firstname LIKE "%%%s%%" 
                  OR lastname LIKE "%%%s%%"';
        $q = sprintf($q, $name, $name);
        return $this->execute($q);
    }

    // i define a custom list method
    public function listByFirstname($start, $limit)
    {
        $q = 'SELECT * FROM Person ORDER BY firstname';
        return $this->executeLimit($q, $start, $limit);
    }
}
  

require_once 'Spod.php';
require_once 'Person.php';

// there can be only one spod instantiated, it is accessible
// throught Spod::$spod

new Spod('mysql://root@localhost/dbname');

// i'm lazy so i get a local reference to the Spod singleton
// PHP5 does not allow us to define static fields on the fly,
// otherwise our life would have been less Spod::$spod. You may
// prefer using:
// 
// global $spod;
// $spod = new Spod('mysql://root@localhost/dbname');
//
// And put global $spod; every time you need to access it but
// at the end, it's the same thing.
//

$spod = Spod::$spod;

// managers must be registered 

Spod::registerManager(new PersonManager());

// our person manager is now accessible throught
// Spod::$spod->Person 
// the 'Person' var name comes from the PersonManager::$table 
// variable, it may be choosen setting a
// PersonManager::$access variable, explained later.
  
$person = new Person();
$person->firstname = 'foo';
$person->lastname = 'bar';
// $person->save() also works
$person->insert(); 

$person->lastname = 'oward';
// $person->save() also works here
$person->update(); 

$person->delete();

$anotherone = $spod->Person->get(120);

// count the number of persons in the table
$count = $spod->Person->count();

// list first 20 persons
$list = $spod->Person->listAll(0, 20); 
foreach ($list as $person){
    echo $person->fistname, "\n";
}

// search using query template instance
$q = new Person();
$q->firstname = 'maveric';
$list = $spod->Person->listAllMatching($q);

// use custom methods
$list = $spod->Person->search('maveric');
$list = $spod->Person->listByFirstname(5,10);    

Example: relationship

Because relational code is always managed in an uggly way by do-everything libraries and because PHP is not so fast playing with meta-data, you will have to manage your relations manually (don't worry it is not so hard).

class Car extends Spod_Object {
    public $id;
    // this is a Person(id) foreign key
    public $ownerId; 
    public $color;

    public function getOwner(){
        return Spod::$spod->Person->get($this->ownerId);
    }
}

class CarManager extends Spod_Manager {
    public $class = 'Car';
    public $table = 'Car';
    public $key   = 'id';
    public $ai    = 'id';

    public function getCarsOf($person){
        $q = 'SELECT * FROM Car WHERE ownerId=%d';
        $q = sprintf($q, $person->id);
        return $this->execute($q);
    }
}

Spod::registerManager(new CarManager());

class Person extends Spod_Object {
    // ...

    public function getCars(){
        return Spod::$spod->Car->getCarsOf($this);
    }
}


$person = Spod::$spod->Person->getByName('louis');
$cars = $person->getCars();
foreach ($cars as $car){
    if ($car){
        $car->color = 'red';
        $car->save();
    }
}

Note about inheritance

You may think about extending a User class to provide things like ForumUser or Player in your application. The quickest way is to modify your sql scheme and merge additional columns in the base table.

class User extends Spod_Object {
    public $id;
    public $login;
    public $password;

    public function authentify(...){}
}

class ForumUser extends User {
    public $latestPostId;
    public $frequency;

    public function postMessage(...){}
}

class Player extends User {
    public $score;

    public function playGame(...){}
}

The User table would look like:

CREATE TABLE User (
    id INTEGER PRIMARY KEY AUTO_INCREMENT,
    login VARCHAR(20),
    password VARCHAR(20),
    
    # ForumUser vars
    latestPostId INT, 
    frequency DOUBLE,
    
    # Player vars
    score INT
);

And now for managers:

class UserManager extends Spod_Manager {
    public $table = 'User';
    public $class = 'User';
    public $key   = 'id';
    public $ai    = 'id';
}

class PlayerManager extends UserManager {
    // access using Spod::$spod->Player 
    public $access = 'Player';  
    public $class = 'Player';

    public function listByScore($start, $limit) {
        $q = 'SELECT * FROM User ORDER BY score DESC';
        return $this->executeLimit($q, $start, $limit);
    }
}

class ForumUserManager extends UserManager {   
    // access using Spod::$spod->ForumUser
    public $access = 'ForumUser'; 
    public $class = 'ForumUser';

    // we can define a method named juste like a friend
    // method without any risk here

    public function listByScore($start, $limit) {
        $q = 'SELECT * FROM User ORDER BY frequency DESC';
        return $this->executeLimit($q, $start, $limit);
    }
}

Spod::registerManager(new UserManager());
Spod::registerManager(new PlayerManager());
Spod::registerManager(new ForumUserManager());

$u1 = Spod::$spod->User->get(1);
$u2 = Spod::$spod->ForumUser->get(1);
$u3 = Spod::$spod->Player->get(1);

In this example, $u1 is an instance of User, $u2 is an instance of ForumUser and $u3 is an instance of Player. They have their own manager with a common set of features inherited from UserManager.

Each $u* object will contains fields retrieved from the database (score, latestPostId, frequency), even if they don't use them.

The important thing is to set the $access member in each extension managers to ensure that Spod::$spod->User link won't be overwritten.

The main issue you may encounter is due to naming logic. For example, ForumUser may have a score which means something totally different than the Player's score. If you can't rename one of the fields, then you will have to create another table and separate your logic.

Copyright © 2001-2005 Motion-Twin, all rights reserved