Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.

Agile data presentation 3 - cambridge

191 Aufrufe

Veröffentlicht am

Agile Data (http://git.io/ad) is my new open-source framework that fills the growing gap between ORM and Raw SQL queries. In this presentation I explain why have I started Agile Data project and how can it enable PHP developer to generate more sophisticated queries when they need them.

Veröffentlicht in: Software
  • Als Erste(r) kommentieren

  • Gehören Sie zu den Ersten, denen das gefällt!

Agile data presentation 3 - cambridge

  1. 1. WARNING This presentation may contain: ‣ Alternattive opinions ‣ Mention of phrase "new framework" ‣ Mention of paid services and/or software ‣ Out-of PHP concepts (Java, Scala, Ruby)
  2. 2. Love and Hate between ORM and Query Builders
  3. 3. Myself ‣ Love Web Apps ‣ 25 years of coding ‣ Entrepreneur ‣ I buy Software My PHP Startup ‣ Helps developers ‣ Open-source ‣ PHP in Enterprise ‣ Code Sharing About Me
  4. 4. Query ‣ Control ‣ Advanced Features ‣ Multi-Record ORM ‣ 10+ tables ‣ SoftDelete, Audit ‣ Domain Model Database Interaction Today
  5. 5. MapperEntity Query ORM: How it should work Database Business Logic ORM
  6. 6. MapperEntity SQL Query The Reality SQL Database Business Logic ORM
  7. 7. SQL Query Why Bother… SQL Database Business Logic
  8. 8. Love Compatibility
  9. 9. Query Builder ‣ Query ‣ Conditions ‣ Statements ‣ Expressions ORM ‣ Entity ‣ Property ‣ Operations (C.R.U.D.) What do we work with?
  10. 10. Love Compatibility Entity Property Operations Query ❤️ Condition Statements Expression ORM Components QueryComponents
  11. 11. Love Compatibility Entity Property Operations Query ❤️ 😔 😔 Condition Statements Expression ORM Components QueryComponents
  12. 12. Love Compatibility Entity Property Operations Query ❤️ 😔 😔 Condition 😐 ❤️ Statements Expression ORM Components QueryComponents
  13. 13. Love Compatibility Entity Property Operations Query ❤️ 😔 😔 Condition 😐 😔 ❤️ Statements Expression ORM Components QueryComponents
  14. 14. Love Compatibility Entity Property Operations Query ❤️ 😔 😔 Condition 😐 😔 ❤️ Statements 💀 💀 💀 Expression ORM Components QueryComponents
  15. 15. Love Compatibility Entity Property Operations Query ❤️ 😔 😔 Condition 😐 😔 ❤️ Statements 💀 💀 💀 Expression 💀 💀 💀 ORM Components QueryComponents
  16. 16. Reimagine a better data access framework. With fresh start. Agile Data
  17. 17. Agile Data Entity Property Operations Query Condition Statements Expression ORM Components QueryComponents
  18. 18. Properties /** @Column(type="datetime", name="posted_at") */ private $postedAt; protected $casts = [ 'is_admin' => 'boolean', ]; public function setFirstNameAttribute($value) { $this->attributes['first_name'] = strtolower($value); }
  19. 19. Fields in Agile Data $book->addField('total_cost', ['type'=>'money']); Like properties, but smarter.
  20. 20. Property ‣ Handy and Native ‣ No type ‣ No logic ‣ No meta-info Field ‣ Array-access ‣ Type enforcing ‣ Extensible logic ‣ Meta-info Fields
  21. 21. Fields class Document extends atk4dataModel { public $table = 'document'; function init() { parent::init(); $this->addField('ref_no', ['type'=>'string']); $this->addField('date', ['type'=>'date']); $this->addField('type', ['enum'=>['invoice','payment']]); $this->hasOne('contact_id', new Contact()); $this->addField('is_archived', ['type'=>'boolean']); } }
  22. 22. Generic UI $form = new uiForm(); $form->setModel(new smboModel_Job($db)); echo $form->render(); Fastest imaginable way to build good looking data entry form?
  23. 23. Generic UI
  24. 24. Expression $client->addExpression( 'balance', 'coalesce([total_invoice]-[total_paid],0)' ); Define custom SQL code for your field.
  25. 25. Aggregate Field $client->hasMany('Order') ->addField('total_orders', [ 'field'=>'amount', 'aggregate'=>'sum' ]); Express related model aggregate as sub-query.
  26. 26. Agile Data Entity Field Operations Query ❤️ Condition ❤️ Statements ❤️ Expression ❤️ ORM Components QueryComponents
  27. 27. Entity Client name address_id Order title total_order Expression SubQuery hasMany hasOne 6 objects
  28. 28. Is this slow? 6 objects 5 rows*
  29. 29. Object representing collection of records Data Sets
  30. 30. Record Mapping ‣ Active Record and ORM map individual records ‣ Multiple records require Multiple objects in memory Model_Client object user type=client user type=client user type=client user type=client user type=admin user type=admin tableuser Model_Client object
  31. 31. DataSet Mapping ‣ Agile Data works with DataSets ‣ Multiple records require Single objects in memory Model_Client object user type=client user type=client user type=client user type=client user type=admin user type=admin tableuser
  32. 32. DataSet Client Admin User
  33. 33. Conditions class Client extend User { function init() { parent::init(); $this->addCondition('type', 'client'); } } Narrow the scope of accessible records
  34. 34. Conditions $client = new Client($db); $client->load(12); $client['type'] = 'admin'; $client->save(); // <== Exception Prevent human error
  35. 35. Project DataSet $m = new Project($db);
  36. 36. Project $m = new Project($db); $m->addCondition( 'client_id', $c_id ); client=$c_id
  37. 37. Project $m = new Project($db); $m->addCondition( 'client_id', $c_id ); $m->addCondition( 'is_cancelled', false ); client=1 client=$c_id is_cancelled = "N"
  38. 38. Conditions $client = new Client($db); $client->load($_GET['user_id']); $project = $client->ref('Project'); $project->insert($_POST); Prevent human error
  39. 39. Conditions $profitable_client = new Client($db); $profitable_client->addCondition($this->expr( '[income]>[expense]' )); $data = $profitable_client->export(); Dynamically add expressions for reports.
  40. 40. Deep Traversal foreach( $author->withID(20) ->ref('App') ->ref('Review') ->addCondition('rating', 1) as $bad_review ) { $bad_review->sendApologyEmail(); } Traverse without querying
  41. 41. QRM->Q.B. ‣ Static scope ‣ Limited inheritance ‣ Persistence layer DataSet Model ‣ Dynamic scope ‣ Fully OOP ‣ References infer conditions ‣ Domain layer Model
  42. 42. Agile Data Model (DataSet ) Field Operations Query ❤️ ❤️ Condition ❤️ ❤️ Statements ❤️ ❤️ Expression ❤️ ❤️ ORM Components QueryComponents
  43. 43. ORM limit multi-record features and other database capabilities. N+1 problem
  44. 44. foreach (Client::all() as $client) { foreach($client->orders() as $order){ $sum += $order->amount; } } N+1 problem ‣ 20 users in database ‣ 20 extra queries to fetch orders
  45. 45. foreach (Client::all() as $client) { foreach($client->orders() as $order){ $sum += $order->amount; } } Memory Problem ‣ 20 users in database ‣ array of 20 objects ‣ other properties are also fetched
  46. 46. foreach (Client::all() as $client) { foreach($client->orders() as $order){ $sum += $order->amount; } } Lazy-loading; ID Stuffing ‣ only load IDs ‣ trigger loading on property access ‣ select from `order` where user in (1,2,3,…)
  47. 47. Action $client = new Client($db); $sum = $client->ref('Order') ->action('fx', ['sum', 'amount']) ->execute(); Event from Domain Model to your database
  48. 48. Multi-record operations $author->withID(20) ->ref('App') ->ref('Review') ->addCondition('rating', 1) ->action('delete') ->execute(); Delete all entries in data-set
  49. 49. Multi-record operations $author->withID(20) ->ref('App') ->ref('Review') ->addCondition('rating', '<', 3) ->action('update') ->set('rating=rating+1') ->execute(); or just update rating
  50. 50. Aggregation $q = $client->action('field', ['industry']); $q->field('count(*)', 'c'); $q->group('industry'); $data = $q->get(); Create any query around Model
  51. 51. Union $q_inv = $client->ref('Invoice') ->action('field',['date','total']); $q_pay = $client->ref('Payment') ->action('field',['date','paid']); foreach($db->expr( 'select * from ([] UNION []) u1', $q_inv, $q_pay ) as $row) { /// } Prepare client statement
  52. 52. ORM ‣ Emit query-builder ‣ Limited scope support ‣ SQL only ‣ Fully Persistence logic Agile Actions ‣ Emit DSQL ‣ All conditions applied ‣ Extensible to NoSQL ‣ Domain model support Multi-record operations
  53. 53. Agile Data Model (DataSet ) Field Operations Query ❤️ ❤️ ❤️ Condition ❤️ ❤️ ❤️ Statements ❤️ ❤️ ❤️ Expression ❤️ ❤️ ❤️ ORM Components QueryComponents
  54. 54. Summary ‣ ORM and Query Builders has a bumpy relationship ‣ Luckily there are other patterns ‣ Consider query latency ‣ Consider flexibility ‣ Consider abstraction
  55. 55. Execute less queries Design a beautiful API Friendly with UIExtensions Agile Data
  56. 56. Download
  57. 57. Result
  58. 58. Make UI better
  59. 59. git.io/ad ✓ Works in any framework / PHP app ✓ Lightweight and Agile ✓ Integrates with UI frameworks (like ATK) ✓ Commercial Support Agile Data is Open- Source
  60. 60. Join my OSS project ‣ Agile Data v1.1.5 git.io/ad ‣ Agile UI (developing) github.com/atk4/ui My other topics ‣ Agile Toolkit Full-stack PHP UI
  61. 61. More examples if there is time
  62. 62. Query into Field $client->addExpression('last_sale', function($m){ return $m->refLink('Invoice') ->setLimit(1) ->setOrder('date desc') ->action('field',['total']); }, 'type'=>'money' ); Convert Entity into Query then use inside Field / Expression.
  63. 63. Join on Expression $invoice->hasOne('client_id', new Client()) ->addField('client_country_id', 'country_id'); $invoice->join('country', 'client_country_id') ->addFields([ 'country_short_code'=>'short_code', 'country_is_eu'=>'is_eu', 'country'=>'name' ]); If you need country data inside your Invoice report, but country_id is defined through Client.
  64. 64. Aliasing
  65. 65. Self-referencing class Folder extends atk4dataModel { public $table = 'folder'; public function init() { parent::init(); $this->addField('name'); $this->hasMany('SubFolder', [ new Folder(), 'their_field'=>'parent_id'] )->addField('count', [ 'aggregate'=>'count', 'field'=>$this->expr('*')] ); $this->hasOne('parent_id', new Folder()) ->addTitle(); } }
  66. 66. Unique Aliases select `id`,`name`, (select count(*) from `folder` `S` where `parent_id` = `folder`.`id`) `count`, `folder`.`parent_id`, (select `name` from `folder` `p` where `id` = `folder`.`parent_id`) `parent` from `folder`
  67. 67. ✓ ACL, Audit, Undo, Logging, .. ✓ File Management ✓ Import/Export utility ✓ RestAPI server Commercial Extensions git.io/ad

×