What's New In Doctrine

134
What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com #phpday What’s new in Doctrine

description

Presentation on the Doctrine ORM from phpDay 2009 in Verona, Italy

Transcript of What's New In Doctrine

Page 1: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

What’s newin Doctrine

Page 2: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Doctrine Book

Page 3: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

First official publishedDoctrine documentation

Page 4: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Doctrine 1.1

Page 5: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Doctrine 2.0

Page 6: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Doctrine 1.1

Page 7: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

1.x Evolution

Page 8: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Stability, bugs, features

Page 9: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Zero failing test cases

Page 10: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Dozens of new test cases adding more

code coverage

Page 11: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Fine tuned API

Page 12: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Improved HydrationPerformance

Page 13: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Hydrate largerresult sets in less time

Page 14: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Re-written documentation

Page 15: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Misc. Features

Page 16: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

New configuration options

Page 17: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Better custommutator and accessor

support

Page 18: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Enhanced fromArray()and

synchronizeWithArray()

Page 19: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

HandlesRelationships

Page 20: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

$userData = array( 'username' => 'jwage', 'password' => 'changeme', 'Groups' => array( array( '_identifier' => 1, ), array( '_identifier' => 2 ), array( 'name' => 'New Group' ) ));

$user = new User();$user->fromArray($userData);

Page 21: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Generate phpDocproperty tags

Page 22: What's New In Doctrine

/** * BaseUser * * This class has been auto-generated by the Doctrine ORM Framework * * @property string $username * @property string $password * * @package ##PACKAGE## * @subpackage ##SUBPACKAGE## * @author ##NAME## <##EMAIL##> * @version SVN: $Id: Builder.php 5441 2009-01-30 22:58:43Z jwage $ */abstract class BaseUser extends Doctrine_Record{ public function setTableDefinition() { $this->setTableName('user'); $this->hasColumn('username', 'string', 255, array('type' => 'string', 'length' => '255')); $this->hasColumn('password', 'string', 255, array('type' => 'string', 'length' => '255')); }}

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Page 23: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Used for IDEautocomplete, etc.

Page 24: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Migrations

Page 25: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

General improvementsall around to make

things more intuitive

Page 26: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Brand New Diff tool

Page 27: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Generate migration classes

Page 28: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

By comparing twoDoctrine schemas

Page 29: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Automate deploymentof database changes

Page 30: What's New In Doctrine

User: columns: username: string(255) password: string(255)

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

From Schema

Page 31: What's New In Doctrine

User: columns: username: string(255) password: string(255) email_address: string(255)

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

To Schema

Page 32: What's New In Doctrine

$from = 'schema/from.yml';$to = 'schema/to.yml';$migrationsDir = 'migrations';$diff = new Doctrine_Migration_Diff($from, $to, $migrationsDir);$changes = $diff->generateChanges();

print_r($changes);

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Generating Changes

Array( [created_columns] => Array ( [user] => Array ( [email_address] => Array ( [type] => string [length] => 255 )

)

))

Page 33: What's New In Doctrine

$from = 'schema/from.yml';$to = 'schema/to.yml';$migrationsDir = 'migrations';$diff = new Doctrine_Migration_Diff($from, $to, $migrationsDir);$diff->generateMigrationClasses();

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Generating Classes

Page 34: What's New In Doctrine

// migrations/1239913213_version1.php

class Version1 extends Doctrine_Migration_Base{ public function up() { $this->addColumn('user', 'email_address', 'string', '255', array('email' => '1')); }

public function down() { $this->removeColumn('user', 'email_address'); }}

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Generating Classes

Page 35: What's New In Doctrine

$migration = new Doctrine_Migration('migrations');$migration->migrate();

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Migrating ChangesMigrate from version 0 to version 1

Page 36: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Migrating up executes up() methods

Migrating down executes down() methods

Page 37: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

$migration = new Doctrine_Migration('migrations');$migration->migrate(0);

Reversing ChangesMigrate from version 1 to version 0

Page 38: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

New DataHydration

Types

Page 39: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Scalar

Page 40: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Flat, rectangularresult set

Page 41: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Faster to execute

Page 42: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Harder to work with

Page 43: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Can contain duplicate data

Page 44: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Like normal SQLresult set

Page 45: What's New In Doctrine

$q = Doctrine::getTable('User') ->createQuery('u') ->leftJoin('u.Phonenumbers p');

$results = $q->execute(array(), Doctrine::HYDRATE_SCALAR);

print_r($results);

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Scalar Example

Page 46: What's New In Doctrine

Array( [0] => Array ( [u_id] => 1 [u_username] => jwage [u_password] => changeme [u_email_address] => [email protected] [p_id] => 1 [p_user_id] => 1 [p_phonenumber] => 16155139185 )

[1] => Array ( [u_id] => 1 [u_username] => jwage [u_password] => changeme [u_email_address] => [email protected] [p_id] => 2 [p_user_id] => 1 [p_phonenumber] => 14159925468 )

) What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Scalar Example

Page 47: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Single Scalar

Page 48: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Sub-type of Scalar

Page 49: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Returns singlescalar value

Page 50: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Useful for retrievingsingle value for

aggregate/calculated results

Page 51: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Very fastNo need to hydrate

objects

Page 52: What's New In Doctrine

$q = Doctrine::getTable('User') ->createQuery('u') ->select('COUNT(p.id) as num_phonenumbers') ->leftJoin('u.Phonenumbers p');

$results = $q->execute(array(), Doctrine::HYDRATE_SINGLE_SCALAR);

echo $results; // 2

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Single Scalar Example

Page 53: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Doctrine 2.0

Page 54: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

PHP 5.3

Page 55: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Performance increases from 5.3

Page 56: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Test suite runs20% faster

Page 57: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

And uses 30%less memory

Page 58: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Re-Design

Page 59: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Simplified thepublic API

Page 60: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Heavily influencedby JPA, Java Hibernate

Page 61: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Smaller footprint

Page 62: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Un-necessaryclutter removed

Page 63: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

RemovedLimitations

Page 64: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

class User extends Doctrine_Record{ public function setTableDefinition() { $this->hasColumn('id', 'integer', null, array( 'primary' => true, 'auto_increment' => true ));

$this->hasColumn('username', 'string', 255); }}

No need to extendDoctrine 1

/** * @DoctrineEntity * @DoctrineTable(name="user") */class User{ /** * @DoctrineId * @DoctrineColumn(type="integer") * @DoctrineGeneratedValue(strategy="auto") */ public $id;

/** * @DoctrineColumn(type="varchar", length=255) */ public $username;}

Doctrine 2

Page 65: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

No more crazy cyclic references

Page 66: What's New In Doctrine

User Object( [id] => [username] => jwage)

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

print_r() your objects

$user = new User();$user->username = 'jwage';print_r($user);

Page 67: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Positive effects of removing the base

class all around

Page 68: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

No more shared identitymap across connections

Page 69: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

GeneralImprovements

Page 70: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Code de-coupled

Page 71: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

3 Main Packages

Page 72: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Common

Page 73: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

DBAL

Page 74: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

ORM

Page 75: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Use Doctrine DBALseparate from the ORM

Page 76: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Easier to extend and override things

Page 77: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Better support formultiple databases

Page 78: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Sequences, schemasand catalogs

Page 79: What's New In Doctrine

$config = new \Doctrine\ORM\Configuration();$eventManager = new \Doctrine\Common\EventManager();$connectionOptions = array( 'driver' => 'pdo_sqlite', 'path' => 'database.sqlite');$em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config, $eventManager);

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Simplified connectioninformation

Page 80: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

No more DSN nightmares

Page 81: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Connection informationspecified as arrays

Page 82: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Removed oldattribute system

Page 83: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Replaced with simplerstring based system

Page 84: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Real Native SQL support

Page 85: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Driver BasedMeta Data

Page 86: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

/** * @DoctrineEntity * @DoctrineTable(name="user") */class User{ /** * @DoctrineId * @DoctrineColumn(type="integer") * @DoctrineGeneratedValue(strategy="auto") */ public $id;

/** * @DoctrineColumn(type="varchar", length=255) */ public $username;}

PHP Annotations

Page 87: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

PHP Codeclass 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));

Page 88: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

YAML

User: properties: id: id: true type: integer idGenerator: auto username: type: varchar length: 255

class User{ public $id, $username;}

Page 89: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Write your own driver

Page 90: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Cache

Page 91: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Query CacheCache final SQL that is parsed from DQL

Page 92: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Metadata CacheCache the parsing of meta data

Page 93: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Result CacheCache the results of your queries

Page 94: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

InheritanceMapping

Page 95: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Single TableOne table per hierarchy

Page 96: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Class TableOne table per class

Page 97: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Concrete TableOne table per concrete class

Page 98: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Testing

Page 99: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Switched to phpUnit

Page 100: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Better mock testing

Page 101: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Easy to run tests against multiple DBMS

Page 102: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Code de-coupled soit is easier to test

Page 103: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

New Features

Page 104: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

New DQL Parser

Page 105: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Hand written

Page 106: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Recursive-descentparser

Page 107: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Constructs AST

Page 108: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

PHP Class namesdirectly represent

DQL language

Page 109: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Every DQL featurehas a class to handle

parsing

Page 110: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Easy to maintainEasy to add new features

Easy to use

Page 111: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Performance?

Page 112: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Final SQL can beeasily and effectively

cached

Page 113: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Not practical to parseevery time

Page 114: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

CustomColumn Types

Page 115: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Add your own data types

Page 116: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Types are OOP classes

Page 117: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Easy to extendor add new types

Page 118: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Extend DQL

Page 119: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

DQL parser canbe extended

Page 120: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Add your ownDQL functions

Page 121: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

When?

Page 122: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

First releasein September

Page 123: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

ALPHA

Page 124: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

BETA

Page 125: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

RC

Page 126: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Stable - 2010’ ?

Page 127: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

What is next?

Page 128: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Publishing of firstDoctrine book

Page 129: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Write more documentation

Page 130: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Publish more books

Page 131: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Doctrine communityextension repository

Symfony has Plugins

and

Doctrine has Extensions

Page 132: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Default DBALand ORM in PEAR2?

De-facto standard?

Page 133: What's New In Doctrine

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

It is up to you! :)

Page 134: What's New In Doctrine

You can contact Jonathan about Doctrine and Open-Source or for training, consulting, application development, or business related

questions at [email protected]

What’s new in Doctrine www.doctrine-project.org www.sensiolabs.com

#phpday

Jonathan H. [email protected]+1 415 992 5468

sensiolabs.com | doctrine-project.org | sympalphp.org | jwage.com

Questions?