ORMizer :)

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

ORMizer :)

Post by VladSun »

Well, it happened to me - I need an XML data storage %$#
So ... I've decided to write my own ORM like library (using my style weirdnesses :twisted: )
It's still an alpha version, so I'll not provide the code (which will happen after I have the first RC ready in "Coding critique"). Instead I'll provide you its usage.

First my example domain object:

Code: Select all

<?php
 
/**
 * @orm-table   user
 * @orm-storage XML
 * 
 * @orm_storage-file        ./data/db.xml
 * @orm_storage-encoding    UTF-8
 */
class User
{
    /**
     * @orm-column  id
     * @orm-type    int
     * @orm-length  11
     * @orm-primary-key
     * @orm-autoincrement
     */
    public $user_id;
 
    /**
     * @orm-column  fk_id
     * @orm-type    int
     * @orm-length  11
     * @orm-primary-key
     * @orm-autoincrement
     */
    public $friend_id;
 
    /**
     * @orm-column  username
     * @orm-type    char
     * @orm-length  32
     */
    public $user_username;
 
    /**
     * @orm-column  userpass
     * @orm-type    char
     * @orm-length  32
     */
    public $user_password;
 
    /**
     * @orm-column  salt
     * @orm-type    char
     * @orm-length  2
     */
    public $salt = null;
 
    /**
     * @orm-column  secret
     * @orm-type    char
     * @orm-length  20
     */
    public $secret = '';
 
    /**
     * @orm-column  usermap
     * @orm-type    char
     * @orm-length  32
     * @orm-nullable
     */
    public function map()
    {
        return 'map';
    }
 
    /**
     * @return              string Salt'n'pepper password
     * @orm-mutator         user_password
     * @orm-mutator-mode    write
     */
    public function saltAndPepper()
    {
        return $this->user_password.$this->user_username.$this->salt;
    }
 
    /**
     * @return              string Encrypted secret
     * @orm-mutator         secret
     * @orm-mutator-mode    write
     */
    public function encrypt()
    {
        return $this->secret.'encrypted';
    }
 
    /**
     * @return              string Decrypted secret
     * @orm-mutator         secret
     * @orm-mutator-mode    read
     */
    public function decrypt()
    {
        return substr($this->secret, 0, -strlen('encrypted'));
    }
 
    public function __construct()
    {
        $this->salt = rand(10,99);
    }
 
}
You must already noticed the big number of strange PHPDoc comments

Next my index.php:

Code: Select all

 
require_once 'Doconfigurable.php';
require_once('ORM.php');
 
require_once 'User.php';
 
$user1 = new User();
$user1->user_username = 'username1';
$user1->user_password = 'password1';
$user1->secret = 'secret1!';
 
$user2 = new User();
$user2->user_username = 'username2';
$user2->user_password = 'password2';
$user2->secret = 'secret2!';
 
// Insert
ORM::save($user1);
ORM::save($user2);
 
// If the object has a complete PK field set
//ORM::delete($user1);
//
//$user1->user_username = 'username3';
////Update
//ORM::save($user1);
//
//$user3 = new User();
//$user3->id = 2;
//$user3->friend_id = 2;
//$user3 = ORM::load($user3);
 
$rows = ORM::collection('User')->get();
 
print_r($rows);
Its output:

Code: Select all

Array
(
    [0] => User Object
        (
            [user_id] => 1
            [friend_id] => 1
            [user_username] => username1
            [user_password] => password1username149
            [salt] => 49
            [secret] => secret1!
            [map] => map
        )
 
    [1] => User Object
        (
            [user_id] => 2
            [friend_id] => 2
            [user_username] => username2
            [user_password] => password2username214
            [salt] => 14
            [secret] => secret2!
            [map] => map
        )
 
)
and the generated XML "database" file:

Code: Select all

<?xml version="1.0" encoding="UTF-8"?><db>  <users id="3" fk_id="3">    <user id="1" fk_id="1">      <username>username1</username>      <userpass>password1username149</userpass>      <salt>49</salt>      <secret>secret1!encrypted</secret>      <usermap>map</usermap>    </user>    <user id="2" fk_id="2">      <username>username2</username>      <userpass>password2username214</userpass>      <salt>14</salt>      <secret>secret2!encrypted</secret>      <usermap>map</usermap>    </user>  </users></db>
I think, it's clear enough what I am doing :)

Thoughts?

PS:
Some of the features:
- composite primary keys allowed;
- autoincrement columns allowed (should be a PK);
- not nullable fields restrictions;
- type/length validation;
- possible to have an SQL "storage";
TODO:
- foreign keys and constraints;
- collection filters;
Last edited by VladSun on Mon Sep 13, 2010 2:08 am, edited 3 times in total.
There are 10 types of people in this world, those who understand binary and those who don't
User avatar
Weirdan
Moderator
Posts: 5978
Joined: Mon Nov 03, 2003 6:13 pm
Location: Odessa, Ukraine

Re: ORMizer :)

Post by Weirdan »

And how do you plan to solve concurrency issues? By locking entire file?
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

Re: ORMizer :)

Post by VladSun »

Well, I plan to use this in a software for "embedded" devices - i.e. most probably only one administrator registered/logged. So, file locking is OK :)
In my particular case, it's a software for a network administration.

Also, it may be considered that putting all of the data into the memory is not a problem (because it's a small piece of data and concurrency is not a problem).
There are 10 types of people in this world, those who understand binary and those who don't
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

Re: ORMizer :)

Post by VladSun »

In fact, I can't see any other solution for concurrency issues, other than file locking in this case - maybe some kind of CVS :) ... Putting data in memory involves even more concurrency issues ...
Last edited by VladSun on Thu Jan 07, 2010 6:20 am, edited 2 times in total.
There are 10 types of people in this world, those who understand binary and those who don't
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: ORMizer :)

Post by Christopher »

If you "ORM" implement a Lock then that would deal with the concurrency issues.
(#10850)
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

Re: ORMizer :)

Post by VladSun »

arborint wrote:If you "ORM" implement a Lock then that would deal with the concurrency issues.
Yes, for the XML "backend storage" it's the obvious solution.

It won't be an issue if an SQL "backend storage" is used.

Changing to SQL backend should be as easy as changing these lines in User.php:

Code: Select all

<?php
 
/**
 * @orm-table   user
 * @orm-storage XML
 * 
 * @orm_storage-file        ./data/db.xml
 * @orm_storage-encoding    UTF-8
 */
class User
{
....
to

Code: Select all

<?php
 
/**
 * @orm-table   user
 * @orm-storage SQL
 * 
 * @orm_storage-db          orm_example
 * @orm_storage-encoding    UTF-8
 */
class User
{
....
Probably, it will be useful if there is a way to set global settings for the ORM class instead of fetching them from PHPDoc comments for every class.
There are 10 types of people in this world, those who understand binary and those who don't
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

Re: ORMizer :)

Post by VladSun »

TODO: ORM configurations (per domain object definition) caching
There are 10 types of people in this world, those who understand binary and those who don't
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: ORMizer :)

Post by Christopher »

VladSun wrote:It won't be an issue if an SQL "backend storage" is used.
It still is if you need to lock records why the script is doing some processing, and another request could ask to read the record.
(#10850)
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

Re: ORMizer :)

Post by VladSun »

arborint wrote:
VladSun wrote:It won't be an issue if an SQL "backend storage" is used.
It still is if you need to lock records why the script is doing some processing, and another request could ask to read the record.
So, probably it's better to use transparent timestamp checking in order to detect concurrency changes, instead of locking ...

PS: In fact, I can't see any major difference between my "ORM" and advanced ORM systems like Doctrine - even Doctrine uses the "timestamp" optimistic approach and locking is the pessimistic approach.
There are 10 types of people in this world, those who understand binary and those who don't
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: ORMizer :)

Post by Christopher »

Those are two good ways to lock records...
(#10850)
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

Re: ORMizer :)

Post by VladSun »

:) OK, besides concurrency issues and schema caching issues, what other problems do you see in my approach?
There are 10 types of people in this world, those who understand binary and those who don't
Post Reply