agile data concept introduction

34
Design your business logic correctly with Agile Data

Upload: romans-malinovskis

Post on 22-Jan-2018

406 views

Category:

Software


1 download

TRANSCRIPT

Page 1: Agile Data   concept introduction

Design your business logic correctly

with Agile Data

Page 2: Agile Data   concept introduction

Agile Data‣ Based on "Model" class from Agile Toolkit (est. 2011)

‣ Refactored as independent library under MIT license

‣ Framework for your Business Logic

‣ Persistence and mapping library

‣ Contains Query Builder and DataSet concept

‣ Implements Active Record

‣ Supports SQL and NoSQL vendors. Extensible

Page 3: Agile Data   concept introduction

DataSets

like "VIEW" in SQL

Page 4: Agile Data   concept introduction

DataSet

‣ Always has "ID" field and primary table/collection

‣ Structured. Has set of fields.

‣ Apply conditions

Page 5: Agile Data   concept introduction

DataSetUser

Customer Admin

Field Type Label

idname string Name

surname Take advantage Surname

type enum [client, admin, other]last_access timestamp

Field Type Label

client_ref string

total_order_amount int Ordered

Field Type Label

admin_level int

addCondition('type', 'client') addCondition('type', 'admin')

Page 6: Agile Data   concept introduction

class Model_User extends atk4\data\Model { public $table='user'; function init() { parent::init(); $this->addField('name'); $this->addField('surname'); $this->addFiled('type')->enum(['client','admin','other']); }

}

class Model_Client extends Model_User { function init() { parent::init(); $this->addField('client_ref'); $this->addCondition('type','client'); } }

Page 7: Agile Data   concept introduction

DataSet

Client Admin

User

Page 8: Agile Data   concept introduction

$a = $db->add('Model_Client'); $a -> load(10);

// Success!

$u = $db->add('Model_Admin'); $u -> load(10);

// Failure.

Record Access Control

‣ Conditions are always enforced

Page 9: Agile Data   concept introduction

$a = $db->add('Model_Client'); $a -> load(10);

// Success!

$a['type'] = 'admin'; $a->save();

// Failure.

Record Access Control

‣ Record cannot accidentally go outside.

Page 10: Agile Data   concept introduction

$a = $db->add('Model_User'); $a -> load(10);

// Success!

$a['type'] = 'client'; $a->save();

// Success.

Record Access Control

‣ But it's ok if member of same DataSet

Page 11: Agile Data   concept introduction

Persistence Mapping

save / load

Page 12: Agile Data   concept introduction

Persistence Logic - SQLUser

Customer Admin

table user left join session on session.user_id=user.idand session.ts > '$ts_1h_ago'

join user_admin_permissions `uap` on user.id = `uap`.id where user.type = 'admin'

(select sum(amount) from `order ̀ where `order`.user_id = user.id) as total_order_amount

Page 13: Agile Data   concept introduction

Persistence Logic - MongoUser

Customer Admin

collection.user

collection.admincollection.customer

cache 'total_order_amount'

Page 14: Agile Data   concept introduction

Model Features implemented as separate objects

Page 15: Agile Data   concept introduction

Field‣ Maps to regular column or property in database

‣ Set type, caption, default value, etc

‣ Only save if updated

‣ Cast into SQL expression => `table`.`field`

$model->addField('type')->enum(['client','admin','other']);

Page 16: Agile Data   concept introduction

SQL\Expression‣ Extends Model\Field

‣ Read-only.

‣ Set callback and return your custom expression

$model->addExpression('total_order_amount') ->set($db->dsql()->table('order')->field('sum("amount")'));

$model->addExpression('full_name') ->set($db->expr( "concat([],' ',[])", [$first_name_field, $last_name_field] ));

Page 17: Agile Data   concept introduction

SQL\Join‣ Adds few hooks to insert into 2 tables

‣ supports delete, update.

‣ strong or weak join

if ($model->db->supports('join')) { $join = $model->join('user_admin_permissions'); $join->addField('admin_level')->type('int'); }

Page 18: Agile Data   concept introduction

SoftDelete

‣ Feature built as extension

‣ Alters DataSet

$model->addField('is_deleted')->type('boolean'); $model->addCondition('is_deleted', false);

// plus a hook

Page 19: Agile Data   concept introduction

Relation‣ Records relation between DataSets

‣ Can jump between DBs

‣ Traversing maps "record" into "DataSet"

$user->hasMany(['Order', 'connection'=>$mongo]);

$user->load(10);$user_orders = $user->ref('Order');

Page 20: Agile Data   concept introduction

SQL\Relation‣ Records relation between DataSets

‣ Uses same persistence object

‣ Traversing maps "DataSet" into "DataSet"

$user->addCondition('last_access', '>', $time_1h_ago;$online_user_orders = $user->ref('Order');

$user->hasMany('Order');

Page 21: Agile Data   concept introduction

***‣ Many other features can be implemented

‣ Native or 3rd party support

‣ Example meta-field for image uploading and external storage

$user->add('upload/Image', ['photo_id', 'storage'=>$s3]);

Page 22: Agile Data   concept introduction

Model Expressiveness

Page 23: Agile Data   concept introduction

Cast Model into SQL‣ hasMany() - defines one-to-many relation

‣ $model->sum('field') - returns SQL Expression

‣ No hidden query requests. Uses sub-query.

$user->hasMany('Order'); $user->addExpression('total_order_amount')->set( $user->refSQL('Order')->sum('amount') );

Page 24: Agile Data   concept introduction

Traverse for expressions‣ hasOne() defines many-to-one expression.

‣ fieldQuery() returns expression for the field

‣ No hidden query requests. Uses sub-query.

$user->hasOne('Currency'); $user->addExpression('rate')->set( $user->refSQL('Currency')->fieldQuery('rate') );

Page 25: Agile Data   concept introduction

Mix - n - Match

// Create DataSet for online users $user->addCondition('last_access', '>', $time_1h_ago);

// Get sum of total orders $total_order_by_online_users = $user->sum('amount')->getOne();

Page 26: Agile Data   concept introduction

class Model_CurrentOrder extends Model_Order {

function init() { parent::init(); $this->addCondition('user_id', $this->app->getLoggedUserId()); $this->tryLoadAny(); }

// store order and related records into $db function placeOrder($db) { $db->save($this); foreach($this->ref('Order_Item') as $item){ $db->save($item); $item->delete(); } $this->delete(); // removes from memory } }

$memory_order = $session->add('Model_CurrentOrder'); .. $memory_order->placeOrder($mysql_db);

Page 27: Agile Data   concept introduction

Derived Models

Page 28: Agile Data   concept introduction

Derived Model‣ Read-only model, that uses another model as a source.

‣ Can aggregate data

‣ Can use UNION across multiple models

‣ Ideal for Report Generation

‣ Build advanced query logic on top of your Business Model

‣ inherits conditions, joins etc,

‣ inherits expressions

Page 29: Agile Data   concept introduction

class Model_Report_Profit extends atk4\data\Union {

function init() { parent::init(); $this->addModel('Order', ['amount'=>'-amount']); $this->addModel('Payment', ['amount']);

$this->addAggregate('sum', 'amount'); } }

$report = $db->add('Model_Report_Profit') ->group('month', 'month(date)');

$report->addCondition('date','>',$date_1y_ago); $data = $report->getData(['month','amount']);

Profit Report

Page 30: Agile Data   concept introduction

$on_line_users = $db->add('User'); $on_line_users->addCondition('last_access', '>', $time_1h_ago);

$report->addCondition('user_id',$on_line_users->fieldQuery('id')); $data = $report->getData(['month','amount']);

Profit Report for On-line Users

Page 31: Agile Data   concept introduction

Not powerful enough?

Page 32: Agile Data   concept introduction

Extending

‣ Add Domain Model features

‣ Add Persistence features

‣ use Hooks (beforeSave, afterLoad)

‣ Add more NoSQL vendors

Page 33: Agile Data   concept introduction

Persistence Support‣ SQL

‣ MySQL, PostgreSQL

‣ NoSQL

‣ MongoDB, Memache

‣ Others

‣ RESTful

‣ Session

Page 34: Agile Data   concept introduction

http://github.com/atk4/data

more great things coming..