/dja_orm

django like orm

Primary LanguagePHPApache License 2.0Apache-2.0

Dja - simple way of doing 80% routine work

Best things from Django on our favourite php

Install

With composer

{
    "require": {
        "buldezir/dja_orm": "dev-master"
    }
}        
php composer.phar install

or php composer.phar require buldezir/dja_orm:dev-master

Usage

Create models manual

use Dja\Db\Model\Model;

class User extends Model
{
    protected static $fields = array(
        'user_id'       =>['Auto'],
        'email'         =>['Char'],
        'password'      =>['Char'],
        'full_name'     =>['Char', 'default' => ''],
        'date_added'    =>['DateTime', 'autoInsert' => true],
        'date_updated'  =>['DateTime', 'autoUpdate' => true],
        'is_active'     =>['Bool'],
        'timezone'      =>['Char'],
        'role'          =>['ForeignKey', 'relationClass' => 'Role'],
    );
}
class Role extends Model
{
    protected static $fields = array(
        'role_id'       =>['Auto'],
        'name'          =>['Char'],
        'is_active'     =>['Bool'],
        'can_do_smth1'  =>['Bool', 'default' => false],
        'can_do_smth2'  =>['Bool', 'default' => false],
        'can_do_smth3'  =>['Bool', 'default' => false],
    );
}
$creation = new \Dja\Db\Creation($dbConn, ['User', 'Role']);
$creation->processQueueCallback(function (\Dja\Db\Model\Metadata $metadata, \Doctrine\DBAL\Schema\Table $table, array $sql, \Doctrine\DBAL\Connection $db) {
    foreach ($sql as $sqlstmt) {
        $db->exec($sqlstmt);
    }
});

Or from database structure

$dbConn = \Doctrine\DBAL\DriverManager::getConnection(array(
    'driver' => 'pdo_pgsql',
    'dbname' => '',
    'user' => '',
    'password' => '',
    'host' => 'localhost',
));
$dbi = new Dja\Db\Introspection($dbConn, $dbConn->getSchemaManager()->listTableNames());
$dbi->setPrefix('Model');

$dbi->processQueueCallback(function ($tableName, $modelClassName, $code) {
    file_put_contents('models.php', $code, FILE_APPEND);
});

Lookup

// single object
$user1 = User::objects()->get(1);

// queryset
$allUsers = User::objects()->all();

// queryset with auto join and filters
$activeUsersWithRoles = User::objects()->selectRelated(['depth' => 3])->filter(['is_active' => 1, 'user_id__in' => [1,2,3,4,5]]);

foreach ($activeUsersWithRoles as $user) {
    // Role object without quering db
    $role = $user->role;
    $role->is_active = 1;
    $role->save();
}

// auto backwards relation
$role1 = Role::objects()->get(1);
$roleUsers = $role1->users_set; // this is queryset
$roleUsersWithOrdering = $roleUsers->order('-full_name');

// get result as key=>val list
$dict = User::objects()->filter(['is_active' => true])->valuesList('name', 'user_id');
foreach($dict as $userId => $userName){}

// raw query 
$iteratorOverModels = User::objects()->raw('SELECT * FROM users');
$iteratorOverArrays = User::objects()->raw('SELECT * FROM users')->returnValues();
// raw query with placeholders and autoreplacements
$iteratorOverArrays = User::objects()->raw('SELECT :pk, :role FROM :t WHERE :pk < :maxPK', [':maxPK' => 10])->returnValues(); // = 'SELECT user_id, role_id FROM users WHERE user_id < 10'

// iterate fetching $chunkSize chunks
$chunkSize = 1000;
foreach (chunkedIterator($allUsers, $chunkSize) as $k => $v) {
    // for example if we have 5000 users there will be 5 db queries, in this foreach
}

U can write your own fields

class JsonField extends BaseField
{
    public function cleanValue($value)
    {
        return is_array($value) ? $value : json_decode($value);
    }

    public function dbPrepValue($value)
    {
        return json_encode($value);
    }
    
    public function getDefault()
    {
        return [];
    }
}
class TestModel
{
    protected static $fields = array(
        ...
        'options' =>['JsonField'],
    );
}
$obj = new TestModel;
$obj->options['ololo'] = 'jjjjjj';
$obj->save(); // will store json string in text field

And getters and setters of course

class TestModel2 extends TestModel
{
    ...
    public function setOptions($value)
    {
        if (!is_array($value)) {
            throw new \Exception('GTFO');
        }
        $this->_set('options', $value);
    }
    
    public function getOptions()
    {
        return array_merge($this->_get('options'), get_global_options());
    }
}

Abstract models

abstract class BaseObjectModel
{
    protected static $fields = array(
        'date_added'   => ['DateTime', 'autoInsert' => true],
        'date_updated' => ['DateTime', 'autoUpdate' => true],
        'user'         => ['ForeignKey', 'relationClass' => 'User'],
    );
}

class Article extends BaseObjectModel
{
    protected static $fields = array(
        'header' => ['Char'],
        'text'   => ['Text'],
        'slug'   => ['Slug', 'prepopulate_field' => 'header'],
    );
}
// So Article model will have fields: header, text, slug, date_added, date_updated, user