SlideShare ist ein Scribd-Unternehmen logo
1 von 69
Downloaden Sie, um offline zu lesen
Doctrine for Beginners
Who am I?
- CTO of MoreCommerce.com
- Using PHP for 15 years
- Involved with Doctrine and
Symfony development for 10
years
What is MoreCommerce?
- E-commerce seller tools and
consumer marketplaces.
- Wholly owned subsidiary of
Alibaba Group
- 100,000 Sellers
- 80M Active Shoppers
- Billions in GMV runs through
MoreCommerce platforms
● Open source PHP project started in 2006
● Initially only an Object Relational Mapper
● Evolved to become a collection of high
quality PHP packages focused on
databases and persistence related
functionality
What is Doctrine?
+
$ composer create-project symfony/skeleton:4.1.*
doctrine-for-beginners
$ cd doctrine-for-beginners
Create New Symfony Project
$ composer require symfony/orm-pack
Install Doctrine
$ composer require symfony/maker-bundle --dev
Install MakerBundle
DATABASE_URL=mysql://username:password@127.0.0
.1:3306/doctrine-for-beginners
Configure Database URL
Customize the DATABASE_URL environment variable in the .env file in the
root of your project. In this example we are connecting to MySQL.
Supported Databases
● MySQL
● MariaDB
● SQLite
● PostgreSQL
● SQL Server
● Oracle
● SQL Anywhere
● DB2
DATABASE_URL=sqlite:///%kernel.project_dir%/va
r/data.db
Using SQLite
Change the DATABASE_URL in the .env file to look like this if you want to
use SQLite.
$ php bin/console doctrine:database:create
Created database `doctrine-for-beginners`
for connection named default
Create Your Database
Database Migrations
$ php bin/console doctrine:migrations:generate
A database migration is an incremental, reversible change to a relational
database schema.
You define the change to your database schema in a PHP class. Use the
doctrine:migrations:generate command to generate a new blank migration.
What is a Database Migration?
Generated Database Migration
final class Version20181012002437 extends AbstractMigration
{
public function up(Schema $schema) : void
{
// this up() migration is auto-generated, please modify it to your needs
}
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
}
}
Write Your Migration
public function up(Schema $schema) : void
{
$usersTable = $schema->createTable('user');
$usersTable->addColumn('id', 'integer', ['autoincrement' => true, 'notnull' => true]);
$usersTable->addColumn('username', 'string', ['length' => 255]);
$usersTable->setPrimaryKey(['id']);
}
public function down(Schema $schema) : void
{
$schema->dropTable('user');
}
Write Your Migration
public function up(Schema $schema) : void
{
$this->addSql('CREATE TABLE user (id INT AUTO_INCREMENT NOT NULL,
username VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET
utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB');
}
public function down(Schema $schema) : void
{
$this->addSql('DROP TABLE user');
}
$ php bin/console doctrine:migrations:migrate
Application Migrations
WARNING! You are about to execute a database migration that could result in schema
changes and data loss. Are you sure you wish to continue? (y/n)y
Migrating up to 20181012002437 from 0
++ migrating 20181012002437
-> CREATE TABLE user (id INT AUTO_INCREMENT NOT NULL, username VARCHAR(255) NOT
NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE
= InnoDB
++ migrated (0.04s)
------------------------
++ finished in 0.04s
++ 1 migrations executed
++ 1 sql queries
Run Your Migration
$ php bin/console doctrine:migrations:migrate prev
Application Migrations
WARNING! You are about to execute a database migration that could result in schema
changes and data loss. Are you sure you wish to continue? (y/n)y
Migrating down to 0 from 20181012002437
-- reverting 20181012002437
-> DROP TABLE user
-- reverted (0.05s)
------------------------
++ finished in 0.05s
++ 1 migrations executed
++ 1 sql queries
Revert Your Migration
$ php bin/console make:controller UsersController
Generate Controller
We need a place to play around so let’s use the MakerBundle to generate a
UsersController
AppControllerUsersController
class UsersController extends AbstractController
{
/**
* @Route("/users", name="users")
*/
public function index()
{
return $this->json([
'message' => 'Welcome to your new controller!',
'path' => 'src/Controller/UsersController.php',
]);
}
}
Create Users
class UsersController extends AbstractController
{
/**
* @Route("/users/create", name="users_create")
*/
public function create(Connection $connection, Request $request)
{
$connection->insert('user', ['username' => $request->request->get('username')]);
return $this->json([
'success' => true,
'message' => sprintf('Created %s successfully!', $request->request->get('username')),
]);
}
}
$ curl --data "username=jon"
http://localhost/users/create
{
"success":true,
"message":"Created jon successfully!"
}
$ curl --data "username=ryan"
http://localhost/users/create
{
"success":true,
"message":"Created ryan successfully!"
}
Create Users
Read Users
class UsersController extends AbstractController
{
/**
* @Route("/users", name="users")
*/
public function users(Connection $connection)
{
$users = $connection->fetchAll('SELECT * FROM user');
return $this->json($users);
}
}
$ curl http://localhost/users
[
{
"id":"1",
"username":"jon"
},
{
"id":"2",
"username":"ryan"
}
]
Read Users
Read Single User
class UsersController extends AbstractController
{
/**
* @Route("/users/{username}", name="user")
*/
public function user(Connection $connection, string $username)
{
$users = $connection->fetchAll(
'SELECT * FROM user WHERE username = "' . $username . '"'
);
return $this->json($users);
}
}
STOP! SQL Injection
class UsersController extends AbstractController
{
/**
* @Route("/users/{username}", name="user")
*/
public function user(Connection $connection, string $username)
{
$users = $connection->fetchAll(
'SELECT * FROM user WHERE username = "' . $username . '"'
);
return $this->json($users);
}
}
SQL
Injection
Use Parameter Placeholders
class UsersController extends AbstractController
{
/**
* @Route("/users/{username}", name="user")
*/
public function user(Connection $connection, string $username)
{
$users = $connection->fetchAll(
'SELECT * FROM user WHERE username = :username',
['username' => $username]
);
return $this->json($users);
}
}
ORM: Entities
$ php bin/console make:entity User
Generating a User Entity
Generate a User entity with property named username that is a string and
has a max length of 255 characters.
Generates the following files/classes:
- src/Entity/User.php (AppEntityUser)
- src/Repository/UserRepository.php (AppRepositoryUserRepository)
AppEntityUser
/**
* @ORMEntity(repositoryClass="AppRepositoryUserRepository")
*/
class User
{
/**
* @ORMId()
* @ORMGeneratedValue()
* @ORMColumn(type="integer")
*/
private $id;
/**
* @ORMColumn(type="string", length=255)
*/
private $username;
// getters and setters
}
ORM: Entity Manager
Inject EntityManager
/**
* @Route("/users/create/{username}", name="users_create")
*/
public function create(EntityManagerInterface $em, Request $request)
{
$user = new User();
$user->setUsername($request->request->get('username'));
$em->persist($user);
$em->flush();
// ...
}
persist() and flush()
- persist() - schedules an object to be tracked by Doctrine
- flush() - calculates changes made to objects and commits
the changes to the database with SQL INSERT, UPDATE
and DELETE queries.
How does flush() work?
$trackedObjects = getTrackedObjects();
$changesets = [];
foreach ($trackedObjects as $trackedObject)
{
$oldValues = getOldValues($trackedObject);
$newValues = getNewValues($trackedObject);
$changesets[] = calculateChangeset($oldValues, $newValues);
}
commitChangesets($changesets);
ORM: Entity Repositories
AppRepositoryUserRepository
class UserRepository extends ServiceEntityRepository
{
public function __construct(RegistryInterface $registry)
{
parent::__construct($registry, User::class);
}
/*
public function findOneBySomeField($value): ?User
{
return $this->createQueryBuilder('u')
->andWhere('u.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}
Inject the UserRepository
/**
* @Route("/users", name="users")
*/
public function users(UserRepository $userRepository)
{
$users = $userRepository->findAll();
return $this->json(array_map(function(User $user) {
return [
'username' => $user->getUsername(),
];
}, $users));
}
Entity Repository: Magic Methods
$user = $userRepository->findOneByUsername('jwage');
$user = $userRepository->findByFieldName('value');
Magic methods are implemented using __call(). When a method that does
not exist is called, the method name is parsed and a query is generated,
executed, and the results are returned.
Entity Repository: Find By
$users = $userRepository->findBy(['active' => 1]);
Entity Repository: Find One By
$users = $userRepository->findOneBy(['active' => 1]);
Entity Repository: Custom Methods
class UserRepository extends ServiceEntityRepository
{
/**
* @return User[]
*/
public function findActiveUsers() : array
{
return $this->createQueryBuilder('u')
->andWhere('u.active = 1')
->getQuery()
->execute();
;
}
}
$ php bin/console make:entity User
Modify Your Entity
Modify your User entity and add a property named twitter that is a string and
has a max length of 255 characters.
Modify Your Entity
class User
{
// ...
/**
* @ORMColumn(type="string", length=255, nullable=true)
*/
private $twitter;
// ...
}
$ php bin/console make:migration
Generate Migration
Now that we’ve modified our User class and mapped a new twitter property,
when we run make:migration, a migration will be generated with the SQL
necessary to add the twitter column to the user table.
public function up(Schema $schema) : void
{
$this->addSql('ALTER TABLE user ADD twitter VARCHAR(255) DEFAULT
NULL');
}
$ php bin/console doctrine:migrations:migrate
Application Migrations
WARNING! You are about to execute a database migration that could result in
schema changes and data loss. Are you sure you wish to continue? (y/n)y
Migrating up to 20181012041720 from 20181012002437
++ migrating 20181012041720
-> ALTER TABLE user ADD twitter VARCHAR(255) DEFAULT NULL
++ migrated (0.07s)
------------------------
++ finished in 0.07s
++ 1 migrations executed
++ 1 sql queries
Run Your Migration
Update Entities
/**
* @Route("/users/update/{username}", name="users_update")
*/
public function update(UserRepository $userRepository, EntityManagerInterface $em, Request $request, string
$username)
{
$user = $userRepository->findOneByUsername($username);
$user->setUsername($request->request->get('username'));
$user->setTwitter($request->request->get('twitter'));
$em->flush();
return $this->json([
'success' => true,
'message' => sprintf('Updated %s successfully!', $username),
]);
}
$ curl --data "username=ryan&twitter=weaverryan"
http://localhost/users/update/ryan
{
"Success":true,"message":
"Updated ryan successfully!"
}
Update Entities
Use Twitter Property
/**
* @Route("/users", name="users")
*/
public function users(UserRepository $userRepository)
{
$users = $userRepository->findAll();
return $this->json(array_map(function(User $user) {
return [
'username' => $user->getUsername(),
'twitter' => $user->getTwitter(),
];
}, $users));
}
$ curl http://localhost/users
[
{
"username":"jon",
"twitter":null
},
{
"username":"ryan",
"twitter":"weaverryan"
}
]
Use Twitter Property
Read Single User
/**
* @Route("/users/{username}", name="user")
*/
public function user(UserRepository $userRepository, string $username)
{
$user = $userRepository->findOneByUsername($username); // magic method
return $this->json([
'username' => $user->getUsername(),
'twitter' => $user->getTwitter(),
]);
}
$ curl http://localhost/users/ryan
{
"username":"ryan",
"twitter":"weaverryan"
}
Read Single User
Programmatic Schema Inspection
Inspect your Database Schema
/**
* @Route("/schema", name="schema")
*/
public function schema(Connection $connection)
{
$schemaManager = $connection->getSchemaManager();
$tables = $schemaManager->listTables();
$data = [];
foreach ($tables as $table) {
$data[$table->getName()] = [
'columns' => [],
];
$columns = $schemaManager->listTableColumns($table->getName());
foreach ($columns as $column) {
$data[$table->getName()]['columns'][] = $column->getName();
}
}
return $this->json($data);
}
$ curl http://localhost/schema
{
"migration_versions":{
"columns":["version"]
},
"user":{
"columns":["id","username","twitter"]
}
}
Inspect your Database Schema
Transactions
When To Use Transactions
When you have a unit of work that needs to be
ALL OR NOTHING. Meaning, if one part of a
larger process fails, all changes made to the
database are rolled back.
$connection->beginTransaction();
try {
$connection->executeQuery('UPDATE users SET twitter = :twitter WHERE username = :username', [
'twitter' => 'jwage',
'username' => 'jwage'
]);
// execute other updates
// do something that throws an Exception and both updates will be rolled back
$connection->commit();
} catch (Exception $e) {
$connection->rollBack();
throw $e;
}
Example Transaction
$connection->transactional(function(Connection $connection) {
$connection->executeQuery('...');
// do some stuff
// do something that throws an exception
});
Example Transaction
DQL: Doctrine Query Language
DQL: Doctrine Query Language
Query language similar to SQL except in DQL
you think in terms of your mapped entities and
class properties instead of tables and columns.
The DQL language is parsed and transformed
to platform specific SQL queries.
What is it?
DQL: Query Builder
$qb = $entityManager->createQueryBuilder()
->select('u')
->from(User::class, 'u')
->where('u.username = :username')
->setParameter('username', 'jwage');
/** @var User[] $users */
$users = $qb->getQuery()->execute();
DQL -> SQL
SELECT u FROM AppEntitiesUser u WHERE u.status = :status
SELECT u0_.id AS id_0, u0_.username AS username_1,
u0_.twitter AS twitter_2 FROM user u0_ WHERE u0_.username =
?
DQL
SQL
Writing DQL Manually
$query = $entityManager->createQuery(
'SELECT u FROM AppEntityUser u WHERE u.username = :username'
);
/** @var User[] $users */
$users = $query->execute([
'username' => 'jon',
]);
DQL: Advanced
Advanced DQL Examples
SELECT u FROM User u WHERE u.phonenumbers IS EMPTY
SELECT u FROM User u WHERE SIZE(u.phonenumbers) > 1
SELECT u.id FROM User u WHERE :groupId MEMBER OF
u.groups
SELECT u.id FROM User u WHERE EXISTS (SELECT
p.phonenumber FROM Phonenumber p WHERE p.user = u.id)
DQL: Data Transfer Objects
class CustomerDTO
{
public function __construct($name, $email, $city, $value = null)
{
// Bind values to the object properties.
}
}
$query = $em->createQuery('SELECT NEW CustomerDTO(c.name, e.email, a.city)
FROM Customer c JOIN c.email e JOIN c.address a');
/** @var CustomerDTO[] $users */
$users = $query->getResult();
Native Raw SQL
use DoctrineORMEntityManagerInterface;
$rsm = new ResultSetMapping();
$rsm->addEntityResult(User::class, 'u');
$rsm->addFieldResult('u', 'id', 'id');
$rsm->addFieldResult('u', 'username', 'username');
$rsm->addFieldResult('u', 'twitter', 'twitter');
$query = $em->createNativeQuery(
'SELECT id, username, twitter FROM user WHERE username = :username', $rsm
);
$query->setParameter('username', 'ryan');
/** @var User[] $user */
$users = $query->getResult();
Questions?
Connect with me
https://twitter.com/jwage
https://github.com/jwage
https://jwage.com

Weitere ähnliche Inhalte

Was ist angesagt?

TRANSITIONING from ACCOUNT GENERATOR SLA
TRANSITIONING from ACCOUNT GENERATOR SLA TRANSITIONING from ACCOUNT GENERATOR SLA
TRANSITIONING from ACCOUNT GENERATOR SLA Navin Chaitanya
 
DHS ICS Security Presentation
DHS ICS Security PresentationDHS ICS Security Presentation
DHS ICS Security Presentationguest85a34f
 
Estudio Cuantitativo de la Población Indígena de Puerto Ayora
Estudio Cuantitativo de la Población Indígena de Puerto AyoraEstudio Cuantitativo de la Población Indígena de Puerto Ayora
Estudio Cuantitativo de la Población Indígena de Puerto AyoraKurijerez Jerez
 
Direct SGA access without SQL
Direct SGA access without SQLDirect SGA access without SQL
Direct SGA access without SQLKyle Hailey
 
MySQL 5.7 String Functions
MySQL 5.7 String FunctionsMySQL 5.7 String Functions
MySQL 5.7 String FunctionsFrancesco Marino
 
modelo de arquitectura del software
 modelo de arquitectura del software modelo de arquitectura del software
modelo de arquitectura del softwareRosita Falen
 
Building large scale applications in yarn with apache twill
Building large scale applications in yarn with apache twillBuilding large scale applications in yarn with apache twill
Building large scale applications in yarn with apache twillHenry Saputra
 
Purchase Order Approval Using Approval Management Engine
Purchase Order Approval Using Approval Management EnginePurchase Order Approval Using Approval Management Engine
Purchase Order Approval Using Approval Management EngineAh_Ismail
 

Was ist angesagt? (11)

TRANSITIONING from ACCOUNT GENERATOR SLA
TRANSITIONING from ACCOUNT GENERATOR SLA TRANSITIONING from ACCOUNT GENERATOR SLA
TRANSITIONING from ACCOUNT GENERATOR SLA
 
DHS ICS Security Presentation
DHS ICS Security PresentationDHS ICS Security Presentation
DHS ICS Security Presentation
 
SSIS control flow
SSIS control flowSSIS control flow
SSIS control flow
 
Estudio Cuantitativo de la Población Indígena de Puerto Ayora
Estudio Cuantitativo de la Población Indígena de Puerto AyoraEstudio Cuantitativo de la Población Indígena de Puerto Ayora
Estudio Cuantitativo de la Población Indígena de Puerto Ayora
 
Direct SGA access without SQL
Direct SGA access without SQLDirect SGA access without SQL
Direct SGA access without SQL
 
MySQL 5.7 String Functions
MySQL 5.7 String FunctionsMySQL 5.7 String Functions
MySQL 5.7 String Functions
 
modelo de arquitectura del software
 modelo de arquitectura del software modelo de arquitectura del software
modelo de arquitectura del software
 
Building large scale applications in yarn with apache twill
Building large scale applications in yarn with apache twillBuilding large scale applications in yarn with apache twill
Building large scale applications in yarn with apache twill
 
Purchase Order Approval Using Approval Management Engine
Purchase Order Approval Using Approval Management EnginePurchase Order Approval Using Approval Management Engine
Purchase Order Approval Using Approval Management Engine
 
Oracle eam configuration guide for chemical industry
Oracle eam configuration guide for chemical industryOracle eam configuration guide for chemical industry
Oracle eam configuration guide for chemical industry
 
Oracle Fixed Assets Testscripts
Oracle Fixed Assets TestscriptsOracle Fixed Assets Testscripts
Oracle Fixed Assets Testscripts
 

Ähnlich wie Doctrine For Beginners

How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony AppsKris Wallsmith
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hackingJeroen van Dijk
 
Bag Of Tricks From Iusethis
Bag Of Tricks From IusethisBag Of Tricks From Iusethis
Bag Of Tricks From IusethisMarcus Ramberg
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ EtsyNishan Subedi
 
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)arcware
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutesBarang CK
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 MinutesAzim Kurt
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsMichael Peacock
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful softwareJorn Oomen
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Leonardo Proietti
 
Как получить чёрный пояс по WordPress? v2.0
Как получить чёрный пояс по WordPress? v2.0Как получить чёрный пояс по WordPress? v2.0
Как получить чёрный пояс по WordPress? v2.0Yevhen Kotelnytskyi
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patternsSamuel ROZE
 
Introduction to Zend Framework web services
Introduction to Zend Framework web servicesIntroduction to Zend Framework web services
Introduction to Zend Framework web servicesMichelangelo van Dam
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologyDaniel Knell
 
Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium AppsNate Abele
 
Как получить чёрный пояс по WordPress?
Как получить чёрный пояс по WordPress?Как получить чёрный пояс по WordPress?
Как получить чёрный пояс по WordPress?Yevhen Kotelnytskyi
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hackingJeroen van Dijk
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐいHisateru Tanaka
 

Ähnlich wie Doctrine For Beginners (20)

How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hacking
 
Bag Of Tricks From Iusethis
Bag Of Tricks From IusethisBag Of Tricks From Iusethis
Bag Of Tricks From Iusethis
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
 
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutes
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful software
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5
 
Как получить чёрный пояс по WordPress? v2.0
Как получить чёрный пояс по WordPress? v2.0Как получить чёрный пояс по WordPress? v2.0
Как получить чёрный пояс по WordPress? v2.0
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patterns
 
Introduction to Zend Framework web services
Introduction to Zend Framework web servicesIntroduction to Zend Framework web services
Introduction to Zend Framework web services
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
 
Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium Apps
 
Как получить чёрный пояс по WordPress?
Как получить чёрный пояс по WordPress?Как получить чёрный пояс по WordPress?
Как получить чёрный пояс по WordPress?
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hacking
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
 
Zend framework service
Zend framework serviceZend framework service
Zend framework service
 

Mehr von Jonathan Wage

OpenSky Infrastructure
OpenSky InfrastructureOpenSky Infrastructure
OpenSky InfrastructureJonathan Wage
 
Doctrine In The Real World sflive2011 Paris
Doctrine In The Real World sflive2011 ParisDoctrine In The Real World sflive2011 Paris
Doctrine In The Real World sflive2011 ParisJonathan Wage
 
Symfony2 from the Trenches
Symfony2 from the TrenchesSymfony2 from the Trenches
Symfony2 from the TrenchesJonathan Wage
 
Doctrine in the Real World
Doctrine in the Real WorldDoctrine in the Real World
Doctrine in the Real WorldJonathan Wage
 
ZendCon2010 Doctrine MongoDB ODM
ZendCon2010 Doctrine MongoDB ODMZendCon2010 Doctrine MongoDB ODM
ZendCon2010 Doctrine MongoDB ODMJonathan Wage
 
ZendCon2010 The Doctrine Project
ZendCon2010 The Doctrine ProjectZendCon2010 The Doctrine Project
ZendCon2010 The Doctrine ProjectJonathan Wage
 
Symfony Day 2010 Doctrine MongoDB ODM
Symfony Day 2010 Doctrine MongoDB ODMSymfony Day 2010 Doctrine MongoDB ODM
Symfony Day 2010 Doctrine MongoDB ODMJonathan Wage
 
Doctrine MongoDB Object Document Mapper
Doctrine MongoDB Object Document MapperDoctrine MongoDB Object Document Mapper
Doctrine MongoDB Object Document MapperJonathan Wage
 
Symfony2 and Doctrine2 Integration
Symfony2 and Doctrine2 IntegrationSymfony2 and Doctrine2 Integration
Symfony2 and Doctrine2 IntegrationJonathan Wage
 
Doctrine 2 - Enterprise Persistence Layer For PHP
Doctrine 2 - Enterprise Persistence Layer For PHPDoctrine 2 - Enterprise Persistence Layer For PHP
Doctrine 2 - Enterprise Persistence Layer For PHPJonathan Wage
 
Introduction To Doctrine 2
Introduction To Doctrine 2Introduction To Doctrine 2
Introduction To Doctrine 2Jonathan Wage
 
Doctrine 2 - Not The Same Old Php Orm
Doctrine 2 - Not The Same Old Php OrmDoctrine 2 - Not The Same Old Php Orm
Doctrine 2 - Not The Same Old Php OrmJonathan Wage
 
Doctrine 2: Enterprise Persistence Layer for PHP
Doctrine 2: Enterprise Persistence Layer for PHPDoctrine 2: Enterprise Persistence Layer for PHP
Doctrine 2: Enterprise Persistence Layer for PHPJonathan Wage
 
Sympal A Cmf Based On Symfony
Sympal   A Cmf Based On SymfonySympal   A Cmf Based On Symfony
Sympal A Cmf Based On SymfonyJonathan Wage
 
Symfony 1.3 + Doctrine 1.2
Symfony 1.3 + Doctrine 1.2Symfony 1.3 + Doctrine 1.2
Symfony 1.3 + Doctrine 1.2Jonathan Wage
 
Sympal - The flexible Symfony CMS
Sympal - The flexible Symfony CMSSympal - The flexible Symfony CMS
Sympal - The flexible Symfony CMSJonathan Wage
 
What's new in Doctrine
What's new in DoctrineWhat's new in Doctrine
What's new in DoctrineJonathan Wage
 
Sympal - Symfony CMS Preview
Sympal - Symfony CMS PreviewSympal - Symfony CMS Preview
Sympal - Symfony CMS PreviewJonathan Wage
 

Mehr von Jonathan Wage (20)

OpenSky Infrastructure
OpenSky InfrastructureOpenSky Infrastructure
OpenSky Infrastructure
 
Doctrine In The Real World sflive2011 Paris
Doctrine In The Real World sflive2011 ParisDoctrine In The Real World sflive2011 Paris
Doctrine In The Real World sflive2011 Paris
 
Symfony2 from the Trenches
Symfony2 from the TrenchesSymfony2 from the Trenches
Symfony2 from the Trenches
 
Doctrine in the Real World
Doctrine in the Real WorldDoctrine in the Real World
Doctrine in the Real World
 
ZendCon2010 Doctrine MongoDB ODM
ZendCon2010 Doctrine MongoDB ODMZendCon2010 Doctrine MongoDB ODM
ZendCon2010 Doctrine MongoDB ODM
 
ZendCon2010 The Doctrine Project
ZendCon2010 The Doctrine ProjectZendCon2010 The Doctrine Project
ZendCon2010 The Doctrine Project
 
Symfony Day 2010 Doctrine MongoDB ODM
Symfony Day 2010 Doctrine MongoDB ODMSymfony Day 2010 Doctrine MongoDB ODM
Symfony Day 2010 Doctrine MongoDB ODM
 
Doctrine MongoDB Object Document Mapper
Doctrine MongoDB Object Document MapperDoctrine MongoDB Object Document Mapper
Doctrine MongoDB Object Document Mapper
 
Libertyvasion2010
Libertyvasion2010Libertyvasion2010
Libertyvasion2010
 
Symfony2 and Doctrine2 Integration
Symfony2 and Doctrine2 IntegrationSymfony2 and Doctrine2 Integration
Symfony2 and Doctrine2 Integration
 
Doctrine 2 - Enterprise Persistence Layer For PHP
Doctrine 2 - Enterprise Persistence Layer For PHPDoctrine 2 - Enterprise Persistence Layer For PHP
Doctrine 2 - Enterprise Persistence Layer For PHP
 
Introduction To Doctrine 2
Introduction To Doctrine 2Introduction To Doctrine 2
Introduction To Doctrine 2
 
Doctrine 2 - Not The Same Old Php Orm
Doctrine 2 - Not The Same Old Php OrmDoctrine 2 - Not The Same Old Php Orm
Doctrine 2 - Not The Same Old Php Orm
 
Doctrine 2: Enterprise Persistence Layer for PHP
Doctrine 2: Enterprise Persistence Layer for PHPDoctrine 2: Enterprise Persistence Layer for PHP
Doctrine 2: Enterprise Persistence Layer for PHP
 
Sympal A Cmf Based On Symfony
Sympal   A Cmf Based On SymfonySympal   A Cmf Based On Symfony
Sympal A Cmf Based On Symfony
 
Symfony 1.3 + Doctrine 1.2
Symfony 1.3 + Doctrine 1.2Symfony 1.3 + Doctrine 1.2
Symfony 1.3 + Doctrine 1.2
 
Sympal - The flexible Symfony CMS
Sympal - The flexible Symfony CMSSympal - The flexible Symfony CMS
Sympal - The flexible Symfony CMS
 
What's new in Doctrine
What's new in DoctrineWhat's new in Doctrine
What's new in Doctrine
 
What Is Doctrine?
What Is Doctrine?What Is Doctrine?
What Is Doctrine?
 
Sympal - Symfony CMS Preview
Sympal - Symfony CMS PreviewSympal - Symfony CMS Preview
Sympal - Symfony CMS Preview
 

Kürzlich hochgeladen

Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park masabamasaba
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...Shane Coughlan
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...masabamasaba
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...masabamasaba
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnAmarnathKambale
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdfPearlKirahMaeRagusta1
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...masabamasaba
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplatePresentation.STUDIO
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrainmasabamasaba
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfkalichargn70th171
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...masabamasaba
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech studentsHimanshiGarg82
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesVictorSzoltysek
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsArshad QA
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyviewmasabamasaba
 

Kürzlich hochgeladen (20)

Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 

Doctrine For Beginners

  • 2. Who am I? - CTO of MoreCommerce.com - Using PHP for 15 years - Involved with Doctrine and Symfony development for 10 years
  • 3. What is MoreCommerce? - E-commerce seller tools and consumer marketplaces. - Wholly owned subsidiary of Alibaba Group - 100,000 Sellers - 80M Active Shoppers - Billions in GMV runs through MoreCommerce platforms
  • 4. ● Open source PHP project started in 2006 ● Initially only an Object Relational Mapper ● Evolved to become a collection of high quality PHP packages focused on databases and persistence related functionality What is Doctrine?
  • 5. +
  • 6. $ composer create-project symfony/skeleton:4.1.* doctrine-for-beginners $ cd doctrine-for-beginners Create New Symfony Project
  • 7. $ composer require symfony/orm-pack Install Doctrine
  • 8. $ composer require symfony/maker-bundle --dev Install MakerBundle
  • 9. DATABASE_URL=mysql://username:password@127.0.0 .1:3306/doctrine-for-beginners Configure Database URL Customize the DATABASE_URL environment variable in the .env file in the root of your project. In this example we are connecting to MySQL.
  • 10. Supported Databases ● MySQL ● MariaDB ● SQLite ● PostgreSQL ● SQL Server ● Oracle ● SQL Anywhere ● DB2
  • 11. DATABASE_URL=sqlite:///%kernel.project_dir%/va r/data.db Using SQLite Change the DATABASE_URL in the .env file to look like this if you want to use SQLite.
  • 12. $ php bin/console doctrine:database:create Created database `doctrine-for-beginners` for connection named default Create Your Database
  • 14. $ php bin/console doctrine:migrations:generate A database migration is an incremental, reversible change to a relational database schema. You define the change to your database schema in a PHP class. Use the doctrine:migrations:generate command to generate a new blank migration. What is a Database Migration?
  • 15. Generated Database Migration final class Version20181012002437 extends AbstractMigration { public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs } public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs } }
  • 16. Write Your Migration public function up(Schema $schema) : void { $usersTable = $schema->createTable('user'); $usersTable->addColumn('id', 'integer', ['autoincrement' => true, 'notnull' => true]); $usersTable->addColumn('username', 'string', ['length' => 255]); $usersTable->setPrimaryKey(['id']); } public function down(Schema $schema) : void { $schema->dropTable('user'); }
  • 17. Write Your Migration public function up(Schema $schema) : void { $this->addSql('CREATE TABLE user (id INT AUTO_INCREMENT NOT NULL, username VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB'); } public function down(Schema $schema) : void { $this->addSql('DROP TABLE user'); }
  • 18. $ php bin/console doctrine:migrations:migrate Application Migrations WARNING! You are about to execute a database migration that could result in schema changes and data loss. Are you sure you wish to continue? (y/n)y Migrating up to 20181012002437 from 0 ++ migrating 20181012002437 -> CREATE TABLE user (id INT AUTO_INCREMENT NOT NULL, username VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB ++ migrated (0.04s) ------------------------ ++ finished in 0.04s ++ 1 migrations executed ++ 1 sql queries Run Your Migration
  • 19. $ php bin/console doctrine:migrations:migrate prev Application Migrations WARNING! You are about to execute a database migration that could result in schema changes and data loss. Are you sure you wish to continue? (y/n)y Migrating down to 0 from 20181012002437 -- reverting 20181012002437 -> DROP TABLE user -- reverted (0.05s) ------------------------ ++ finished in 0.05s ++ 1 migrations executed ++ 1 sql queries Revert Your Migration
  • 20. $ php bin/console make:controller UsersController Generate Controller We need a place to play around so let’s use the MakerBundle to generate a UsersController
  • 21. AppControllerUsersController class UsersController extends AbstractController { /** * @Route("/users", name="users") */ public function index() { return $this->json([ 'message' => 'Welcome to your new controller!', 'path' => 'src/Controller/UsersController.php', ]); } }
  • 22. Create Users class UsersController extends AbstractController { /** * @Route("/users/create", name="users_create") */ public function create(Connection $connection, Request $request) { $connection->insert('user', ['username' => $request->request->get('username')]); return $this->json([ 'success' => true, 'message' => sprintf('Created %s successfully!', $request->request->get('username')), ]); } }
  • 23. $ curl --data "username=jon" http://localhost/users/create { "success":true, "message":"Created jon successfully!" } $ curl --data "username=ryan" http://localhost/users/create { "success":true, "message":"Created ryan successfully!" } Create Users
  • 24. Read Users class UsersController extends AbstractController { /** * @Route("/users", name="users") */ public function users(Connection $connection) { $users = $connection->fetchAll('SELECT * FROM user'); return $this->json($users); } }
  • 26. Read Single User class UsersController extends AbstractController { /** * @Route("/users/{username}", name="user") */ public function user(Connection $connection, string $username) { $users = $connection->fetchAll( 'SELECT * FROM user WHERE username = "' . $username . '"' ); return $this->json($users); } }
  • 27. STOP! SQL Injection class UsersController extends AbstractController { /** * @Route("/users/{username}", name="user") */ public function user(Connection $connection, string $username) { $users = $connection->fetchAll( 'SELECT * FROM user WHERE username = "' . $username . '"' ); return $this->json($users); } } SQL Injection
  • 28. Use Parameter Placeholders class UsersController extends AbstractController { /** * @Route("/users/{username}", name="user") */ public function user(Connection $connection, string $username) { $users = $connection->fetchAll( 'SELECT * FROM user WHERE username = :username', ['username' => $username] ); return $this->json($users); } }
  • 30. $ php bin/console make:entity User Generating a User Entity Generate a User entity with property named username that is a string and has a max length of 255 characters. Generates the following files/classes: - src/Entity/User.php (AppEntityUser) - src/Repository/UserRepository.php (AppRepositoryUserRepository)
  • 31. AppEntityUser /** * @ORMEntity(repositoryClass="AppRepositoryUserRepository") */ class User { /** * @ORMId() * @ORMGeneratedValue() * @ORMColumn(type="integer") */ private $id; /** * @ORMColumn(type="string", length=255) */ private $username; // getters and setters }
  • 33. Inject EntityManager /** * @Route("/users/create/{username}", name="users_create") */ public function create(EntityManagerInterface $em, Request $request) { $user = new User(); $user->setUsername($request->request->get('username')); $em->persist($user); $em->flush(); // ... }
  • 34. persist() and flush() - persist() - schedules an object to be tracked by Doctrine - flush() - calculates changes made to objects and commits the changes to the database with SQL INSERT, UPDATE and DELETE queries.
  • 35. How does flush() work? $trackedObjects = getTrackedObjects(); $changesets = []; foreach ($trackedObjects as $trackedObject) { $oldValues = getOldValues($trackedObject); $newValues = getNewValues($trackedObject); $changesets[] = calculateChangeset($oldValues, $newValues); } commitChangesets($changesets);
  • 37. AppRepositoryUserRepository class UserRepository extends ServiceEntityRepository { public function __construct(RegistryInterface $registry) { parent::__construct($registry, User::class); } /* public function findOneBySomeField($value): ?User { return $this->createQueryBuilder('u') ->andWhere('u.exampleField = :val') ->setParameter('val', $value) ->getQuery() ->getOneOrNullResult() ; } */ }
  • 38. Inject the UserRepository /** * @Route("/users", name="users") */ public function users(UserRepository $userRepository) { $users = $userRepository->findAll(); return $this->json(array_map(function(User $user) { return [ 'username' => $user->getUsername(), ]; }, $users)); }
  • 39. Entity Repository: Magic Methods $user = $userRepository->findOneByUsername('jwage'); $user = $userRepository->findByFieldName('value'); Magic methods are implemented using __call(). When a method that does not exist is called, the method name is parsed and a query is generated, executed, and the results are returned.
  • 40. Entity Repository: Find By $users = $userRepository->findBy(['active' => 1]);
  • 41. Entity Repository: Find One By $users = $userRepository->findOneBy(['active' => 1]);
  • 42. Entity Repository: Custom Methods class UserRepository extends ServiceEntityRepository { /** * @return User[] */ public function findActiveUsers() : array { return $this->createQueryBuilder('u') ->andWhere('u.active = 1') ->getQuery() ->execute(); ; } }
  • 43. $ php bin/console make:entity User Modify Your Entity Modify your User entity and add a property named twitter that is a string and has a max length of 255 characters.
  • 44. Modify Your Entity class User { // ... /** * @ORMColumn(type="string", length=255, nullable=true) */ private $twitter; // ... }
  • 45. $ php bin/console make:migration Generate Migration Now that we’ve modified our User class and mapped a new twitter property, when we run make:migration, a migration will be generated with the SQL necessary to add the twitter column to the user table. public function up(Schema $schema) : void { $this->addSql('ALTER TABLE user ADD twitter VARCHAR(255) DEFAULT NULL'); }
  • 46. $ php bin/console doctrine:migrations:migrate Application Migrations WARNING! You are about to execute a database migration that could result in schema changes and data loss. Are you sure you wish to continue? (y/n)y Migrating up to 20181012041720 from 20181012002437 ++ migrating 20181012041720 -> ALTER TABLE user ADD twitter VARCHAR(255) DEFAULT NULL ++ migrated (0.07s) ------------------------ ++ finished in 0.07s ++ 1 migrations executed ++ 1 sql queries Run Your Migration
  • 47. Update Entities /** * @Route("/users/update/{username}", name="users_update") */ public function update(UserRepository $userRepository, EntityManagerInterface $em, Request $request, string $username) { $user = $userRepository->findOneByUsername($username); $user->setUsername($request->request->get('username')); $user->setTwitter($request->request->get('twitter')); $em->flush(); return $this->json([ 'success' => true, 'message' => sprintf('Updated %s successfully!', $username), ]); }
  • 48. $ curl --data "username=ryan&twitter=weaverryan" http://localhost/users/update/ryan { "Success":true,"message": "Updated ryan successfully!" } Update Entities
  • 49. Use Twitter Property /** * @Route("/users", name="users") */ public function users(UserRepository $userRepository) { $users = $userRepository->findAll(); return $this->json(array_map(function(User $user) { return [ 'username' => $user->getUsername(), 'twitter' => $user->getTwitter(), ]; }, $users)); }
  • 51. Read Single User /** * @Route("/users/{username}", name="user") */ public function user(UserRepository $userRepository, string $username) { $user = $userRepository->findOneByUsername($username); // magic method return $this->json([ 'username' => $user->getUsername(), 'twitter' => $user->getTwitter(), ]); }
  • 54. Inspect your Database Schema /** * @Route("/schema", name="schema") */ public function schema(Connection $connection) { $schemaManager = $connection->getSchemaManager(); $tables = $schemaManager->listTables(); $data = []; foreach ($tables as $table) { $data[$table->getName()] = [ 'columns' => [], ]; $columns = $schemaManager->listTableColumns($table->getName()); foreach ($columns as $column) { $data[$table->getName()]['columns'][] = $column->getName(); } } return $this->json($data); }
  • 57. When To Use Transactions When you have a unit of work that needs to be ALL OR NOTHING. Meaning, if one part of a larger process fails, all changes made to the database are rolled back.
  • 58. $connection->beginTransaction(); try { $connection->executeQuery('UPDATE users SET twitter = :twitter WHERE username = :username', [ 'twitter' => 'jwage', 'username' => 'jwage' ]); // execute other updates // do something that throws an Exception and both updates will be rolled back $connection->commit(); } catch (Exception $e) { $connection->rollBack(); throw $e; } Example Transaction
  • 59. $connection->transactional(function(Connection $connection) { $connection->executeQuery('...'); // do some stuff // do something that throws an exception }); Example Transaction
  • 61. DQL: Doctrine Query Language Query language similar to SQL except in DQL you think in terms of your mapped entities and class properties instead of tables and columns. The DQL language is parsed and transformed to platform specific SQL queries. What is it?
  • 62. DQL: Query Builder $qb = $entityManager->createQueryBuilder() ->select('u') ->from(User::class, 'u') ->where('u.username = :username') ->setParameter('username', 'jwage'); /** @var User[] $users */ $users = $qb->getQuery()->execute();
  • 63. DQL -> SQL SELECT u FROM AppEntitiesUser u WHERE u.status = :status SELECT u0_.id AS id_0, u0_.username AS username_1, u0_.twitter AS twitter_2 FROM user u0_ WHERE u0_.username = ? DQL SQL
  • 64. Writing DQL Manually $query = $entityManager->createQuery( 'SELECT u FROM AppEntityUser u WHERE u.username = :username' ); /** @var User[] $users */ $users = $query->execute([ 'username' => 'jon', ]);
  • 66. Advanced DQL Examples SELECT u FROM User u WHERE u.phonenumbers IS EMPTY SELECT u FROM User u WHERE SIZE(u.phonenumbers) > 1 SELECT u.id FROM User u WHERE :groupId MEMBER OF u.groups SELECT u.id FROM User u WHERE EXISTS (SELECT p.phonenumber FROM Phonenumber p WHERE p.user = u.id)
  • 67. DQL: Data Transfer Objects class CustomerDTO { public function __construct($name, $email, $city, $value = null) { // Bind values to the object properties. } } $query = $em->createQuery('SELECT NEW CustomerDTO(c.name, e.email, a.city) FROM Customer c JOIN c.email e JOIN c.address a'); /** @var CustomerDTO[] $users */ $users = $query->getResult();
  • 68. Native Raw SQL use DoctrineORMEntityManagerInterface; $rsm = new ResultSetMapping(); $rsm->addEntityResult(User::class, 'u'); $rsm->addFieldResult('u', 'id', 'id'); $rsm->addFieldResult('u', 'username', 'username'); $rsm->addFieldResult('u', 'twitter', 'twitter'); $query = $em->createNativeQuery( 'SELECT id, username, twitter FROM user WHERE username = :username', $rsm ); $query->setParameter('username', 'ryan'); /** @var User[] $user */ $users = $query->getResult();