Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

What Is Doctrine?

8,450 views

Published on

Beginner presentation introducing the Doctrine ORM and the basic operations. Also talks a bit about some upcoming versions 1.2 and 2.0.

Published in: Technology
  • Be the first to comment

What Is Doctrine?

  1. 1. Nashville LAMP What is Doctrine? What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  2. 2. Nashville LAMP Doctrine is a ORM written in PHP What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  3. 3. Nashville LAMP What is an ORM? What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  4. 4. Nashville LAMP ORM stands for Object Relational Mapper What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  5. 5. Nashville LAMP Manipulate RDBMS as a set of PHP objects What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  6. 6. Nashville LAMP Easy to get started What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  7. 7. Nashville LAMP Doctrine Sandbox What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  8. 8. Nashville LAMP Doctrine Sandbox $ svn co http://svn.doctrine-project.org/branches/1.1 lamp_doctrine $ cd lamp_doctrine/tools/sandbox $ php doctrine.php Command Line What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  9. 9. Nashville LAMP User: Test Schema columns: first_name: lamp_doctrine/tools/sandbox/schema/schema.yml type: string(255) notnull: true Phonenumber: last_name: columns: type: string(255) phonenumber: notnull: true type: string(55) username: notnull: true type: string(255) user_id: unique: true type: integer notnull: true notnull: true password: relations: type: string(255) User: notnull: true foreignAlias: Phonenumbers email_address: onDelete: CASCADE type: string(255) notnull: true email: true unique: true What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  10. 10. Nashville LAMP Test Data lamp_doctrine/tools/sandbox/data/fixtures/data.yml User: jwage: first_name: Jonathan last_name: Wage username: jwage password: changeme email_address: jonathan.wage@sensio.com Phonenumbers: cell: phonenumber: 6155139185 office: phonenumber: 4159925468 What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  11. 11. Nashville LAMP Build All Reload $ php doctrine.php build-all-reload What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  12. 12. Nashville LAMP Running Tests • First DQL Query • Working with objects • Writing DQL Queries – SELECT queries – UPDATE queries – DELETE queries • Custom Accessors/Mutators • Using Migrations What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  13. 13. Nashville LAMP First DQL Query $ php doctrine.php dql quot;FROM User u, u.Phonenumbers pquot; What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  14. 14. Nashville LAMP Working with Objects lamp_doctrine/tools/sandbox/index.php Insert new User $user = new User(); $user->first_name = 'Fabien'; $user->last_name = 'Potencier'; $user->username = 'fabpot'; $user->password = 'changeme'; $user->email_address = 'fabien.potencier@sensio.com'; $user->save(); $ php index.php What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  15. 15. Nashville LAMP Working with Objects lamp_doctrine/tools/sandbox/index.php Edit existing User $userTable = Doctrine::getTable('User'); $user = $userTable->findOneByUsername('jwage'); $user->password = 'newpassword'; $user->save(); $ php index.php What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  16. 16. Nashville LAMP Working with Objects lamp_doctrine/tools/sandbox/index.php Adding Phonenumbers $userTable = Doctrine::getTable('User'); $user = $userTable->findOneByUsername('fabpot'); $user->Phonenumbers[]->phonenumber = '1233451234'; $user->Phonenumbers[]->phonenumber = '9875674543'; $user->save(); $ php index.php What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  17. 17. Nashville LAMP Working with Objects lamp_doctrine/tools/sandbox/index.php Deleting Objects $userTable = Doctrine::getTable('User'); $user = $userTable->findOneByUsername('fabpot'); $user->Phonenumbers[0]->delete(); $ php index.php What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  18. 18. Nashville LAMP Working with Objects lamp_doctrine/tools/sandbox/index.php Deleting Collections $userTable = Doctrine::getTable('User'); $user = $userTable->findOneByUsername('fabpot'); $user->Phonenumbers->delete(); $ php index.php What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  19. 19. Nashville LAMP Writing DQL Queries lamp_doctrine/tools/sandbox/index.php SELECT Queries $q = Doctrine::getTable('User') ->createQuery('u'); $users = $q->execute(); print_r($users->toArray()); $ php index.php What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  20. 20. Nashville LAMP Writing DQL Queries Array ( [0] => Array ( [id] => 1 [first_name] => Jonathan [last_name] => Wage [username] => jwage [password] => changeme [email_address] => jonathan.wage@sensio.com ) [1] => Array ( [id] => 2 [first_name] => Fabien [last_name] => Potencier [username] => fabpot [password] => changeme [email_address] => fabien.potencier@sensio.com ) ) What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  21. 21. Nashville LAMP Writing DQL Queries lamp_doctrine/tools/sandbox/index.php SELECT Queries $q = Doctrine::getTable('User') ->createQuery('u') ->leftJoin('u.Phonenumbers p') ->andWhere('u.username = ?', 'jwage'); $users = $q->execute(); print_r($users->toArray(true)); $ php index.php What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  22. 22. Nashville LAMP Writing DQL Queries Array ( [0] => Array ( [id] => 1 [first_name] => Jonathan [last_name] => Wage [username] => jwage [password] => changeme [email_address] => jonathan.wage@sensio.com [Phonenumbers] => Array ( [0] => Array ( [id] => 1 [phonenumber] => 6155139185 [user_id] => 1 [User] => ) [1] => Array ( [id] => 2 [phonenumber] => 4159925468 [user_id] => 1 [User] => ) ) ) ) What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  23. 23. Nashville LAMP Writing DQL Queries lamp_doctrine/tools/sandbox/index.php UPDATE Queries $q = Doctrine::getTable('User') ->createQuery('u') ->update() ->set('email_address', '?', 'jonwage@gmail.com') ->andWhere('username = ?', 'jwage'); $affectedRows = $q->execute(); echo $affectedRows; // 1 $ php index.php What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  24. 24. Nashville LAMP Writing DQL Queries lamp_doctrine/tools/sandbox/index.php DELETE Queries $q = Doctrine::getTable('User') ->createQuery('u') ->delete() ->andWhere('username = ?', 'jwage'); $affectedRows = $q->execute(); echo $affectedRows; // 1 $ php index.php What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  25. 25. Nashville LAMP Custom Accessors Enable Auto Accessor Override lamp_doctrine/tools/sandbox/config.php // ... $manager = Doctrine_Manager::getInstance(); $manager->setAttribute('auto_accessor_override', true); What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  26. 26. Nashville LAMP Custom Accessors Custom `name` accessor What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  27. 27. Nashville LAMP Custom Accessors lamp_doctrine/tools/sandbox/models/User.php class User extends BaseUser { public function getName() { return trim($this->first_name.' '.$this->last_name); } } What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  28. 28. Nashville LAMP Custom Accessors lamp_doctrine/tools/sandbox/index.php $q = Doctrine::getTable('User') ->createQuery('u') ->andWhere('username = ?', 'jwage'); $user = $q->fetchOne(); echo $user->name; // Jonathan Wage $ php index.php What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  29. 29. Nashville LAMP Custom Mutator MD5 encrypt passwords class User extends BaseUser { // ... public function setPassword($password) { $this->_set('password', md5($password)); } } What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  30. 30. Nashville LAMP Custom Mutator MD5 encrypt passwords $q = Doctrine::getTable('User') ->createQuery('u') ->andWhere('username = ?', 'jwage'); $user = $q->fetchOne(); $user->password = 'changeme'; $user->save(); echo $user->password; // 4cb9c8a8048fd02294477fcb1a41191a What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  31. 31. Nashville LAMP Accessor/Mutator Syntax Object property, function, array access echo $user->name; echo $user->get('name'); echo $user['name']; What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  32. 32. Nashville LAMP Database Migrations What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  33. 33. Nashville LAMP Deploy schema changes What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  34. 34. Nashville LAMP Maintain production data What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  35. 35. Nashville LAMP Programmatic interface for issuing DDL statements What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  36. 36. Nashville LAMP Versions your database What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  37. 37. Nashville LAMP Upgrade your database to new versions Downgrade to previous versions What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  38. 38. Nashville LAMP Database Migrations Add new status column to users What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  39. 39. Nashville LAMP Database Migrations User: columns: # ... status: type: enum values: [Pending, Active, Inactive] What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  40. 40. Nashville LAMP Database Migrations Generate migration class $ php doctrine generate-migrations-diff What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  41. 41. Nashville LAMP Database Migrations Generate migration class class Version1 extends Doctrine_Migration_Base { public function up() { $this->addColumn('user', 'status', 'enum', '', array('values' => array(0 => 'Pending', 1 => 'Active', 2 => 'Inactive'))); } public function down() { $this->removeColumn('user', 'status'); } } What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  42. 42. Nashville LAMP Database Migrations Customize migration class class Version1 extends Doctrine_Migration_Base { public function postUp() { Doctrine::loadModels(realpath(dirname(__FILE__).'/../models')); Doctrine::getTable('User') ->createQuery('u') ->update() ->set('status', '?', 'Active') ->execute(); } // ... } What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  43. 43. Nashville LAMP Database Migrations Executing migration $ php doctrine migrate migrate - migrated successfully to version #1 What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  44. 44. Nashville LAMP Database Migrations Update models from YAML $ php doctrine generate-models-yaml What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  45. 45. Nashville LAMP Database Migrations Inspect migration was successful or not New status column exists Default `Active` value What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  46. 46. Nashville LAMP Future of Doctrine? What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  47. 47. Nashville LAMP New Versions What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  48. 48. Nashville LAMP Doctrine 1.2 What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  49. 49. Nashville LAMP Continued evolution of the 1.x codebase What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  50. 50. Nashville LAMP Doctrine 2.0 What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  51. 51. Nashville LAMP Almost complete re-rewrite What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  52. 52. Nashville LAMP Major version What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  53. 53. Nashville LAMP Requires PHP 5.3 What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  54. 54. Nashville LAMP Performance increases from 5.3 What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  55. 55. Nashville LAMP Test suite runs 20% faster What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  56. 56. Nashville LAMP And uses 30% less memory What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  57. 57. Nashville LAMP Hydration performance improvements What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  58. 58. Nashville LAMP Hydration Performance Doctrine 1.1 4.3435637950897 for 5000 records Doctrine 2.0 1.4314442552312 for 5000 records Doctrine 2.0 3.4690098762512 for 10000 records What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  59. 59. Nashville LAMP Removed Major Limitation No need to extend a base class /** class User extends Doctrine_Record * @DoctrineEntity { * @DoctrineTable(name=quot;userquot;) public function setTableDefinition() */ { class User $this->hasColumn('id', 'integer', null, array( { 'primary' => true, /** 'auto_increment' => true * @DoctrineId )); * @DoctrineColumn(type=quot;integerquot;) * @DoctrineGeneratedValue(strategy=quot;autoquot;) $this->hasColumn('username', 'string', 255); */ } public $id; } /** * @DoctrineColumn(type=quot;varcharquot;, length=255) */ public $username; } What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  60. 60. Nashville LAMP No more crazy cyclic references What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  61. 61. Nashville LAMP print_r() your objects $user = new User(); $user->username = 'jwage'; print_r($user); User Object ( [id] => [username] => jwage ) What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  62. 62. Nashville LAMP Positive effects of removing the base class all around What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  63. 63. Nashville LAMP General Improvements What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  64. 64. Nashville LAMP Code de-coupled What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  65. 65. Nashville LAMP 3 Main Packages What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  66. 66. Nashville LAMP Common What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  67. 67. Nashville LAMP DBAL What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  68. 68. Nashville LAMP ORM What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  69. 69. Nashville LAMP Use Doctrine DBAL separate from the ORM What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  70. 70. Nashville LAMP Easier to extend and override things What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  71. 71. Nashville LAMP Better support for multiple databases What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  72. 72. Nashville LAMP Sequences, schemas and catalogs What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  73. 73. Nashville LAMP Simplified connection information $config = new DoctrineORMConfiguration(); $eventManager = new DoctrineCommonEventManager(); $connectionOptions = array( 'driver' => 'pdo_sqlite', 'path' => 'database.sqlite' ); $em = DoctrineORMEntityManager::create($connectionOptions, $config, $eventManager); What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  74. 74. Nashville LAMP No more DSN nightmares What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  75. 75. Nashville LAMP Connection information specified as arrays What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  76. 76. Nashville LAMP Removed old attribute system What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  77. 77. Nashville LAMP Replaced with simpler string based system What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  78. 78. Nashville LAMP Real Native SQL support What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  79. 79. Nashville LAMP Driver Based Meta Data What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  80. 80. Nashville LAMP PHP Annotations /** * @DoctrineEntity * @DoctrineTable(name=quot;userquot;) */ class User { /** * @DoctrineId * @DoctrineColumn(type=quot;integerquot;) * @DoctrineGeneratedValue(strategy=quot;autoquot;) */ public $id; /** * @DoctrineColumn(type=quot;varcharquot;, length=255) */ public $username; } What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  81. 81. Nashville LAMP PHP Code class User { public $id, $username; } $metadata = new ClassMetadata('User'); $metadata->mapField(array( 'fieldName' => 'id', 'type' => 'integer', 'id' => true )); $metadata->setIdGeneratorType('auto'); $metadata->mapField(array( 'fieldName' => 'username', 'type' => 'varchar', 'length' => 255 )); What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  82. 82. Nashville LAMP YAML class User { public $id, $username; } User: properties: id: id: true type: integer idGenerator: auto username: type: varchar length: 255 What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  83. 83. Nashville LAMP Write your own driver What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  84. 84. Nashville LAMP Cache What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  85. 85. Nashville LAMP Query Cache Cache final SQL that is parsed from DQL What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  86. 86. Nashville LAMP Metadata Cache Cache the parsing of meta data What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  87. 87. Nashville LAMP Result Cache Cache the results of your queries What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  88. 88. Nashville LAMP Inheritance Mapping What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  89. 89. Nashville LAMP Single Table One table per hierarchy What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  90. 90. Nashville LAMP Class Table One table per class What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  91. 91. Nashville LAMP Concrete Table One table per concrete class What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  92. 92. Nashville LAMP Testing What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  93. 93. Nashville LAMP Switched to phpUnit What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  94. 94. Nashville LAMP Better mock testing What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  95. 95. Nashville LAMP Easy to run tests against multiple DBMS What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  96. 96. Nashville LAMP Code de-coupled so it is easier to test What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  97. 97. Nashville LAMP New Features What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  98. 98. Nashville LAMP New DQL Parser What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  99. 99. Nashville LAMP Hand written What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  100. 100. Nashville LAMP Recursive-descent parser What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  101. 101. Nashville LAMP Constructs AST What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  102. 102. Nashville LAMP PHP Class names directly represent DQL language What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  103. 103. Nashville LAMP Every DQL feature has a class to handle parsing What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  104. 104. Nashville LAMP Easy to maintain Easy to add new features Easy to use What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  105. 105. Nashville LAMP Performance? What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  106. 106. Nashville LAMP Final SQL can be easily and effectively cached What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  107. 107. Nashville LAMP Not practical to parse every time What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  108. 108. Nashville LAMP Custom Column Types What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  109. 109. Nashville LAMP Add your own data types What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  110. 110. Nashville LAMP Types are OOP classes What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  111. 111. Nashville LAMP Easy to extend or add new types What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  112. 112. Nashville LAMP Extend DQL What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  113. 113. Nashville LAMP DQL parser can be extended What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  114. 114. Nashville LAMP Add your own DQL functions What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  115. 115. Nashville LAMP When? What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  116. 116. Nashville LAMP First release in September 09` What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  117. 117. Nashville LAMP ALPHA What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  118. 118. Nashville LAMP BETA What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  119. 119. Nashville LAMP RC What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  120. 120. Nashville LAMP Stable - 2010’ ? What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  121. 121. Nashville LAMP What is next? What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  122. 122. Nashville LAMP Publishing of first Doctrine book What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  123. 123. Nashville LAMP Write more documentation What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  124. 124. Nashville LAMP Publish more books What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  125. 125. Nashville LAMP Doctrine community extension repository Symfony has Plugins and Doctrine has Extensions What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  126. 126. Nashville LAMP Default DBAL and ORM in PEAR2? De-facto standard? What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  127. 127. Nashville LAMP It is up to you! :) What is Doctrine? www.doctrine-project.org www.sensiolabs.com
  128. 128. Nashville LAMP Questions? Jonathan H. Wage jonathan.wage@sensio.com +1 415 992 5468 sensiolabs.com | doctrine-project.org | sympalphp.org | jwage.com You can contact Jonathan about Doctrine and Open-Source or for training, consulting, application development, or business related questions at jonathan.wage@sensio.com What is Doctrine? www.doctrine-project.org www.sensiolabs.com

×