SlideShare a Scribd company logo
1 of 34
Download to read offline
Agile Database Access with
CakePHP 3
Agenda
1. Types of ORMs
2. What I need from ORMs
3. What is agile for me?
4. A simple setup
5. Simple analytical queries
6. More complex examples
7. Query composition and collections
8. Formatting results
9. A last minute tip
10. Debugging Queries
11. Working with JSON
12. Value objects
1
2
Types of ORMs
Infuriating ORMs
3
Types of ORMs
Toy ORMs
4
Types of ORMs
Hipster ORMs
5
Types of ORMs
Awesome ORMs
6
Some wise words
7
What I need from an ORM
To stop me from repeating the same over and over.
Help me modularize my common searches.
Stay out of the way when I want to create complex stuff.
Testability.
Ways to hook in and change any default behavior.
To not hide the Relational aspect of a Relational database.
8
What is Agile?
Quick feedback loop.
Low friction,
Easy to debug.
Easy to track.
Few requirements.
Ability to scale up.
9
The Setup
class ManagersTable extends Table
{
public function initialize(array $config = [])
{
$this->table('departments_managers');
$this->primaryKey(['department_id', 'employee_id']);
$this->belongsTo('Employees', ['joinType' => 'INNER']);
$this->belongsTo('Departments', ['joinType' => 'INNER']);
}
public function beforeFind($event, $query, $options)
{
$query->andWhere(['to_date IS' => NULL]);
}
}
10
The Setup
class EmployeesTable extends Table
{
/**
* Initialize method
*
* @param array $config The configuration for the Table.
* @return void
*/
public function initialize(array $config)
{
$this->hasMany('Salaries');
$this->hasMany('Titles');
$this->belongsToMany('Departments');
}
}
11
Simple analytical queries
Average historic salary
// In SalariesTable.php
public function findAverage(Query $query, $options = [])
{
return $query->select(['average' => $query->func()->avg('Salaries.salary')]);
}
{
"average": 63810.74
}
12
Simple analytical queries
Currently hired female managers
public function findFemale(Query $query, $options = [])
{
return $query->contain(['Employees'])->where(['Employees.gender' => 'F']);
}
SELECT Managers.*, Employees.*
FROM department_managers Managers
INNER JOIN employees Employees ON Employees.id = (Managers.employee_id)
WHERE Employees.gender = 'F' AND to_date IS NULL
13
A more complex example
Percentage of currently hired female
managers
public function findFemaleRatio(Query $query, $options = [])
{
$allManagers = $this->find()->select($query->func()->count('*'));
$ratio = $query
->newExpr($query->func()->count('*'))
->type('/')
->add($allManagers)
return $query
->find('female')
->select(['female_ratio' => $ratio]);
}
{
"female_ratio": 0.4444
}
14
Queries can be composed
Average salary of currently hired
employees by gender
public function findOfHired(Query $query, $options = [])
{
return $query->contain(['Employees'])->where(['Salaries.to_date IS' => null]);
}
public function findAveragePerGender(Query $query, $options = [])
{
return $query
->select(['gender' => 'Employees.gender'])
->find('average')
->contain(['Employees'])
->group(['Employees.gender']);
}
$salariesTable
->find('ofHired')
->find('averagePerGender')
->indexBy('gender');
15
Queries are Collections
Yearly salary average per department and
gender
public function findAveragePerDepartment(Query $query, $options = [])
{
return $query
->select(['department' => 'Departments.name'])
->find('average')
->matching('Employees.Departments')
->where([
'Salaries.from_date < DepartmentsEmployees.to_date',
'Salaries.from_date >= DepartmentsEmployees.from_date',
])
->group(['Departments.id']);
}
16
Queries are Collections
Yearly salary average per department and
gender
public function findAveragePerYear(Query $query, $options = [])
{
$year = $query->func()->year(['Salaries.from_date' => 'literal']);
return $query
->select(['year' => $year])
->find('average')
->group([$year]);
}
$averages = $salariesTable
->find('averagePerYear')
->find('averagePerDepartment')
->find('averagePerGender');
17
Queries are Collections
Yearly salary average per department and
gender
$averages->groupBy('year')->each(function ($averages, $year) {
displayYear($year);
collection($averages)->groupBy('department')->each(function ($d, $averages) {
displayDepartment($d);
collection($averages)->each('displayAverage');
})
});
18
Result Formatters
Pack common post-processing into
custom finders
public function findGroupedByYearAndDepartment($query)
{
return $query->formatResults(function ($results) {
return $results->groupBy('year');
})
->formatResults(function ($years) {
return $years->map(function ($results) {
return collection($results)->groupBy('department');
});
});
}
$salariesTable
->find('averagePerYear')
->find('averagePerDepartment')
->find('averagePerGender')
->find('groupedByYearAndDepartment');
19
Result Formatters
They look sexier in HackLang
public function findGroupedByYearAndDepartment($query)
{
return $query
->formatResults($results ==> $results->groupBy('year'))
->formatResults($years ==> $years->map(
$results ==> collection($results)->groupBy('department')
);
}
20
Associations in another
database
Use tables from other databases by
specifying the strategy
public function initialize(array $config)
{
$this->hasOne('LinkedEmployee', [
'className' => 'ExternalSystemEmployeesTable',
'strategy' => 'select'
]);
}
A gotcha: It will not be possible to use matching()
21
Debugging Queries
debug($query) Shows the SQL and bound params, does not show results
debug($query->all()) Shows the ResultSet properties (not the results)
debug($query->toArray()) An easy way to show each of the results
debug(json_encode($query, JSON_PRETTY_PRINT)) More human readable results.
debug($query->first()) Show the properties of a single entity.
debug((string)$query->first()) Show the properties of a single entity as JSON.
22
Debugging Queries
Pro tip: create a dj() function
function dj($data)
{
debug(json_encode($data, JSON_PRETTY_PRINT), null, false);
}
dj($query);
[
{
"average": 0.4444
}
]
23
Modifying JSON output
I don't want to show primary keys or
foreign keys
class Employee extends Entity
{
protected $_hidden = [
'id'
];
}
class Manager extends Entity
{
protected $_hidden = [
'employee_id',
'department_id'
];
}
24
Modifying JSON output
I want to show employees' full name
class Employee extends Entity
{
protected $_virtual = [
'full_name'
];
protected function _getFullName()
{
return $this->name . ' ' . $this->last_name;
}
}
25
Custom serialization
Let's try to do HAL
public function index()
{
$managers = $this->paginate($this->Managers);
$managers = $managers->map(new LinksEnricher($this->Managers));
$this->set('managers', $managers);
$this->set('_serialize', ['managers']);
}
26
Custom Serialization
Let's try to do HAL
class LinksEnricher
{
...
public function __invoke(EntityInterface $row)
{
$primaryKey = array_values($row->extract((array)$this->table->primaryKey()));
$row->_links = [
'self' => [
'href' => Router::url([
'controller' => $row->source(),
'action' => 'view',
] + $primaryKey)
],
];
return $this->enrich($row); // Recurse for associations
}
...
}
27
{
"managers": [
{
"from_date": "1996-01-03T00:00:00+0000",
"to_date": null,
"department": {
"name": "Customer Service",
"_links": {
"self": {
"href": "/departments/view/d009"
}
}
},
"employee": {
"birth_date": "1960-03-25T00:00:00+0000",
"first_name": "Yuchang",
"last_name": "Weedman",
"gender": "M",
"hire_date": "1989-07-10T00:00:00+0000",
"_links": {
"self": {
"href": "/employees/view/111939"
}
},
"full_name": "Yuchang Weedman"
},
"_links": {
"self": {
"href": "/managers/d009/111939"
}
}
}
}
28
Value Objects
Why?
Allow to add custom logic to dumb data.
Help with custom serialization
Make translation and localization easier
Auto-validation
Greater integrity.
29
Value Objects
Adding logic to plain data
class Gender implements JsonSerializable
{
private static $genders = [];
protected $short;
protected $name;
protected function __construct($gender)
{
$this->short = $gender;
$this->name = $gender === 'F' ? 'Female' : 'Male';
}
public static function get($gender)
{
...
return $genders[$gender] = new static($gender);
}
...
30
Value Objects
Accepting value objects
class Employee extends Entity
{
protected function _setGender($gender)
{
return Gender::get($gender);
}
$employeeEntity->gender = 'F';
get_class($employeeEntity->gender); // AppModelValueGender
$employeeEntity->gender = Gender::get('F');
31
Value Objects
Wiring them to the database
class GenderType extends Type
{
...
}
Type::build('gender', 'AppModelDatabaseType');
class EmployeesTable extends Table
{
...
protected function _initializeSchema(Schema $schema)
{
$schema->columnType('gender', 'gender');
return $schema;
}
}
32
Value Objects
Using them in Queries
$employee->gender = Gender::get('F');
$result = $employeesTable->find()->where([['gender' => $employee->gender]])->first();
$employee->gender === $result->gender;
You can use objects as values in where conditions (or any query expression)
33
Thanks for your time
Questions?
https://github.com/lorenzo/cakephp3-advanced-examples

More Related Content

What's hot

PHP Data Objects
PHP Data ObjectsPHP Data Objects
PHP Data ObjectsWez Furlong
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksNate Abele
 
Corephpcomponentpresentation 1211425966721657-8
Corephpcomponentpresentation 1211425966721657-8Corephpcomponentpresentation 1211425966721657-8
Corephpcomponentpresentation 1211425966721657-8PrinceGuru MS
 
PHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkG Woo
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201Fabien Potencier
 
Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium AppsNate Abele
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixturesBill Chang
 
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionLithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionNate Abele
 
The State of Lithium
The State of LithiumThe State of Lithium
The State of LithiumNate Abele
 
Doctrine 2
Doctrine 2Doctrine 2
Doctrine 2zfconfua
 
Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4Fabien Potencier
 
You code sucks, let's fix it
You code sucks, let's fix itYou code sucks, let's fix it
You code sucks, let's fix itRafael Dohms
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency InjectionRifat Nabi
 
News of the Symfony2 World
News of the Symfony2 WorldNews of the Symfony2 World
News of the Symfony2 WorldFabien Potencier
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in actionJace Ju
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownpartsBastian Feder
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Fabien Potencier
 

What's hot (20)

PHP Data Objects
PHP Data ObjectsPHP Data Objects
PHP Data Objects
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate Frameworks
 
Corephpcomponentpresentation 1211425966721657-8
Corephpcomponentpresentation 1211425966721657-8Corephpcomponentpresentation 1211425966721657-8
Corephpcomponentpresentation 1211425966721657-8
 
PHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php framework
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201
 
Quebec pdo
Quebec pdoQuebec pdo
Quebec pdo
 
Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium Apps
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixtures
 
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionLithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
 
The State of Lithium
The State of LithiumThe State of Lithium
The State of Lithium
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 
Doctrine 2
Doctrine 2Doctrine 2
Doctrine 2
 
Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4
 
Lithium Best
Lithium Best Lithium Best
Lithium Best
 
You code sucks, let's fix it
You code sucks, let's fix itYou code sucks, let's fix it
You code sucks, let's fix it
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
 
News of the Symfony2 World
News of the Symfony2 WorldNews of the Symfony2 World
News of the Symfony2 World
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2
 

Viewers also liked

Customize CakePHP bake
Customize CakePHP bakeCustomize CakePHP bake
Customize CakePHP bakeKazuyuki Aoki
 
Top 50 Interview Questions and Answers in CakePHP
Top 50 Interview Questions and Answers in CakePHPTop 50 Interview Questions and Answers in CakePHP
Top 50 Interview Questions and Answers in CakePHPKetan Patel
 
Simple search with elastic search
Simple search with elastic searchSimple search with elastic search
Simple search with elastic searchmarkstory
 
Recursive in CakePHP
Recursive in CakePHPRecursive in CakePHP
Recursive in CakePHPKetan Patel
 
CakePHP mistakes made
CakePHP mistakes madeCakePHP mistakes made
CakePHP mistakes mademarkstory
 
CakePHP - Admin Acl Controlled
CakePHP - Admin Acl ControlledCakePHP - Admin Acl Controlled
CakePHP - Admin Acl ControlledLuís Fred
 
Using RequireJS with CakePHP
Using RequireJS with CakePHPUsing RequireJS with CakePHP
Using RequireJS with CakePHPStephen Young
 
RESTful Web Development with CakePHP
RESTful Web Development with CakePHPRESTful Web Development with CakePHP
RESTful Web Development with CakePHPAndru Weir
 
Road to CakePHP 3.0
Road to CakePHP 3.0Road to CakePHP 3.0
Road to CakePHP 3.0markstory
 
CakePHP Community Keynote 2014
CakePHP Community Keynote 2014CakePHP Community Keynote 2014
CakePHP Community Keynote 2014James Watts
 
Cake php Mamba Plugin
Cake php Mamba PluginCake php Mamba Plugin
Cake php Mamba PluginRiya Kapoor
 
DivyaJoshi_CV(Android)
DivyaJoshi_CV(Android)DivyaJoshi_CV(Android)
DivyaJoshi_CV(Android)Divya Joshi
 
Evented applications with RabbitMQ and CakePHP
Evented applications with RabbitMQ and CakePHPEvented applications with RabbitMQ and CakePHP
Evented applications with RabbitMQ and CakePHPmarkstory
 
Ch ch-changes cake php2
Ch ch-changes cake php2Ch ch-changes cake php2
Ch ch-changes cake php2markstory
 
Role of Business Research in Mining & Metal industry
Role of Business Research in Mining & Metal industryRole of Business Research in Mining & Metal industry
Role of Business Research in Mining & Metal industryVipul Saxena
 
How I built web services in CakePHP
How I built web services in CakePHPHow I built web services in CakePHP
How I built web services in CakePHPDavid Yell
 
Segurança de APIs HTTP, um guia sensato para desenvolvedores preocupados
Segurança de APIs HTTP, um guia sensato para desenvolvedores preocupadosSegurança de APIs HTTP, um guia sensato para desenvolvedores preocupados
Segurança de APIs HTTP, um guia sensato para desenvolvedores preocupadosLuis Cipriani
 

Viewers also liked (20)

Customize CakePHP bake
Customize CakePHP bakeCustomize CakePHP bake
Customize CakePHP bake
 
Top 50 Interview Questions and Answers in CakePHP
Top 50 Interview Questions and Answers in CakePHPTop 50 Interview Questions and Answers in CakePHP
Top 50 Interview Questions and Answers in CakePHP
 
Simple search with elastic search
Simple search with elastic searchSimple search with elastic search
Simple search with elastic search
 
Recursive in CakePHP
Recursive in CakePHPRecursive in CakePHP
Recursive in CakePHP
 
REST API with CakePHP
REST API with CakePHPREST API with CakePHP
REST API with CakePHP
 
CakePHP mistakes made
CakePHP mistakes madeCakePHP mistakes made
CakePHP mistakes made
 
CakePHP - Admin Acl Controlled
CakePHP - Admin Acl ControlledCakePHP - Admin Acl Controlled
CakePHP - Admin Acl Controlled
 
Using RequireJS with CakePHP
Using RequireJS with CakePHPUsing RequireJS with CakePHP
Using RequireJS with CakePHP
 
RESTful Web Development with CakePHP
RESTful Web Development with CakePHPRESTful Web Development with CakePHP
RESTful Web Development with CakePHP
 
Road to CakePHP 3.0
Road to CakePHP 3.0Road to CakePHP 3.0
Road to CakePHP 3.0
 
CakePHP REST Plugin
CakePHP REST PluginCakePHP REST Plugin
CakePHP REST Plugin
 
CakePHP Community Keynote 2014
CakePHP Community Keynote 2014CakePHP Community Keynote 2014
CakePHP Community Keynote 2014
 
Cake php Mamba Plugin
Cake php Mamba PluginCake php Mamba Plugin
Cake php Mamba Plugin
 
Faster develoment with CakePHP 3
Faster develoment with CakePHP 3Faster develoment with CakePHP 3
Faster develoment with CakePHP 3
 
DivyaJoshi_CV(Android)
DivyaJoshi_CV(Android)DivyaJoshi_CV(Android)
DivyaJoshi_CV(Android)
 
Evented applications with RabbitMQ and CakePHP
Evented applications with RabbitMQ and CakePHPEvented applications with RabbitMQ and CakePHP
Evented applications with RabbitMQ and CakePHP
 
Ch ch-changes cake php2
Ch ch-changes cake php2Ch ch-changes cake php2
Ch ch-changes cake php2
 
Role of Business Research in Mining & Metal industry
Role of Business Research in Mining & Metal industryRole of Business Research in Mining & Metal industry
Role of Business Research in Mining & Metal industry
 
How I built web services in CakePHP
How I built web services in CakePHPHow I built web services in CakePHP
How I built web services in CakePHP
 
Segurança de APIs HTTP, um guia sensato para desenvolvedores preocupados
Segurança de APIs HTTP, um guia sensato para desenvolvedores preocupadosSegurança de APIs HTTP, um guia sensato para desenvolvedores preocupados
Segurança de APIs HTTP, um guia sensato para desenvolvedores preocupados
 

Similar to Agile database access with CakePHP 3

Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Jeff Carouth
 
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
 
How to write code you won't hate tomorrow
How to write code you won't hate tomorrowHow to write code you won't hate tomorrow
How to write code you won't hate tomorrowPete McFarlane
 
DrupalCamp Foz - Novas APIs Drupal 7
DrupalCamp Foz - Novas APIs Drupal 7DrupalCamp Foz - Novas APIs Drupal 7
DrupalCamp Foz - Novas APIs Drupal 7chuvainc
 
PHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4DevelopersPHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4DevelopersKacper Gunia
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11Michelangelo van Dam
 
WordCamp Portland 2018: PHP for WordPress
WordCamp Portland 2018: PHP for WordPressWordCamp Portland 2018: PHP for WordPress
WordCamp Portland 2018: PHP for WordPressAlena Holligan
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxMichelangelo van Dam
 
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
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Shinya Ohyanagi
 
Your code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConYour code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConRafael Dohms
 
PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applicationselliando dias
 

Similar to Agile database access with CakePHP 3 (20)

Drupal7 dbtng
Drupal7  dbtngDrupal7  dbtng
Drupal7 dbtng
 
Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4
 
Fatc
FatcFatc
Fatc
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
Spl Not A Bridge Too Far phpNW09
Spl Not A Bridge Too Far phpNW09Spl Not A Bridge Too Far phpNW09
Spl Not A Bridge Too Far phpNW09
 
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
 
How to write code you won't hate tomorrow
How to write code you won't hate tomorrowHow to write code you won't hate tomorrow
How to write code you won't hate tomorrow
 
DrupalCamp Foz - Novas APIs Drupal 7
DrupalCamp Foz - Novas APIs Drupal 7DrupalCamp Foz - Novas APIs Drupal 7
DrupalCamp Foz - Novas APIs Drupal 7
 
PHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4DevelopersPHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4Developers
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
 
WordCamp Portland 2018: PHP for WordPress
WordCamp Portland 2018: PHP for WordPressWordCamp Portland 2018: PHP for WordPress
WordCamp Portland 2018: PHP for WordPress
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
 
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
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2
 
Your code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConYour code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnCon
 
PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applications
 
Php & my sql
Php & my sqlPhp & my sql
Php & my sql
 
Lecture9_OOPHP_SPring2023.pptx
Lecture9_OOPHP_SPring2023.pptxLecture9_OOPHP_SPring2023.pptx
Lecture9_OOPHP_SPring2023.pptx
 
PHPSpec BDD for PHP
PHPSpec BDD for PHPPHPSpec BDD for PHP
PHPSpec BDD for PHP
 

Recently uploaded

Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESmohitsingh558521
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersRaghuram Pandurangan
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 

Recently uploaded (20)

Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information Developers
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 

Agile database access with CakePHP 3

  • 1. Agile Database Access with CakePHP 3
  • 2. Agenda 1. Types of ORMs 2. What I need from ORMs 3. What is agile for me? 4. A simple setup 5. Simple analytical queries 6. More complex examples 7. Query composition and collections 8. Formatting results 9. A last minute tip 10. Debugging Queries 11. Working with JSON 12. Value objects 1
  • 8. 7 What I need from an ORM To stop me from repeating the same over and over. Help me modularize my common searches. Stay out of the way when I want to create complex stuff. Testability. Ways to hook in and change any default behavior. To not hide the Relational aspect of a Relational database.
  • 9. 8 What is Agile? Quick feedback loop. Low friction, Easy to debug. Easy to track. Few requirements. Ability to scale up.
  • 10. 9 The Setup class ManagersTable extends Table { public function initialize(array $config = []) { $this->table('departments_managers'); $this->primaryKey(['department_id', 'employee_id']); $this->belongsTo('Employees', ['joinType' => 'INNER']); $this->belongsTo('Departments', ['joinType' => 'INNER']); } public function beforeFind($event, $query, $options) { $query->andWhere(['to_date IS' => NULL]); } }
  • 11. 10 The Setup class EmployeesTable extends Table { /** * Initialize method * * @param array $config The configuration for the Table. * @return void */ public function initialize(array $config) { $this->hasMany('Salaries'); $this->hasMany('Titles'); $this->belongsToMany('Departments'); } }
  • 12. 11 Simple analytical queries Average historic salary // In SalariesTable.php public function findAverage(Query $query, $options = []) { return $query->select(['average' => $query->func()->avg('Salaries.salary')]); } { "average": 63810.74 }
  • 13. 12 Simple analytical queries Currently hired female managers public function findFemale(Query $query, $options = []) { return $query->contain(['Employees'])->where(['Employees.gender' => 'F']); } SELECT Managers.*, Employees.* FROM department_managers Managers INNER JOIN employees Employees ON Employees.id = (Managers.employee_id) WHERE Employees.gender = 'F' AND to_date IS NULL
  • 14. 13 A more complex example Percentage of currently hired female managers public function findFemaleRatio(Query $query, $options = []) { $allManagers = $this->find()->select($query->func()->count('*')); $ratio = $query ->newExpr($query->func()->count('*')) ->type('/') ->add($allManagers) return $query ->find('female') ->select(['female_ratio' => $ratio]); } { "female_ratio": 0.4444 }
  • 15. 14 Queries can be composed Average salary of currently hired employees by gender public function findOfHired(Query $query, $options = []) { return $query->contain(['Employees'])->where(['Salaries.to_date IS' => null]); } public function findAveragePerGender(Query $query, $options = []) { return $query ->select(['gender' => 'Employees.gender']) ->find('average') ->contain(['Employees']) ->group(['Employees.gender']); } $salariesTable ->find('ofHired') ->find('averagePerGender') ->indexBy('gender');
  • 16. 15 Queries are Collections Yearly salary average per department and gender public function findAveragePerDepartment(Query $query, $options = []) { return $query ->select(['department' => 'Departments.name']) ->find('average') ->matching('Employees.Departments') ->where([ 'Salaries.from_date < DepartmentsEmployees.to_date', 'Salaries.from_date >= DepartmentsEmployees.from_date', ]) ->group(['Departments.id']); }
  • 17. 16 Queries are Collections Yearly salary average per department and gender public function findAveragePerYear(Query $query, $options = []) { $year = $query->func()->year(['Salaries.from_date' => 'literal']); return $query ->select(['year' => $year]) ->find('average') ->group([$year]); } $averages = $salariesTable ->find('averagePerYear') ->find('averagePerDepartment') ->find('averagePerGender');
  • 18. 17 Queries are Collections Yearly salary average per department and gender $averages->groupBy('year')->each(function ($averages, $year) { displayYear($year); collection($averages)->groupBy('department')->each(function ($d, $averages) { displayDepartment($d); collection($averages)->each('displayAverage'); }) });
  • 19. 18 Result Formatters Pack common post-processing into custom finders public function findGroupedByYearAndDepartment($query) { return $query->formatResults(function ($results) { return $results->groupBy('year'); }) ->formatResults(function ($years) { return $years->map(function ($results) { return collection($results)->groupBy('department'); }); }); } $salariesTable ->find('averagePerYear') ->find('averagePerDepartment') ->find('averagePerGender') ->find('groupedByYearAndDepartment');
  • 20. 19 Result Formatters They look sexier in HackLang public function findGroupedByYearAndDepartment($query) { return $query ->formatResults($results ==> $results->groupBy('year')) ->formatResults($years ==> $years->map( $results ==> collection($results)->groupBy('department') ); }
  • 21. 20 Associations in another database Use tables from other databases by specifying the strategy public function initialize(array $config) { $this->hasOne('LinkedEmployee', [ 'className' => 'ExternalSystemEmployeesTable', 'strategy' => 'select' ]); } A gotcha: It will not be possible to use matching()
  • 22. 21 Debugging Queries debug($query) Shows the SQL and bound params, does not show results debug($query->all()) Shows the ResultSet properties (not the results) debug($query->toArray()) An easy way to show each of the results debug(json_encode($query, JSON_PRETTY_PRINT)) More human readable results. debug($query->first()) Show the properties of a single entity. debug((string)$query->first()) Show the properties of a single entity as JSON.
  • 23. 22 Debugging Queries Pro tip: create a dj() function function dj($data) { debug(json_encode($data, JSON_PRETTY_PRINT), null, false); } dj($query); [ { "average": 0.4444 } ]
  • 24. 23 Modifying JSON output I don't want to show primary keys or foreign keys class Employee extends Entity { protected $_hidden = [ 'id' ]; } class Manager extends Entity { protected $_hidden = [ 'employee_id', 'department_id' ]; }
  • 25. 24 Modifying JSON output I want to show employees' full name class Employee extends Entity { protected $_virtual = [ 'full_name' ]; protected function _getFullName() { return $this->name . ' ' . $this->last_name; } }
  • 26. 25 Custom serialization Let's try to do HAL public function index() { $managers = $this->paginate($this->Managers); $managers = $managers->map(new LinksEnricher($this->Managers)); $this->set('managers', $managers); $this->set('_serialize', ['managers']); }
  • 27. 26 Custom Serialization Let's try to do HAL class LinksEnricher { ... public function __invoke(EntityInterface $row) { $primaryKey = array_values($row->extract((array)$this->table->primaryKey())); $row->_links = [ 'self' => [ 'href' => Router::url([ 'controller' => $row->source(), 'action' => 'view', ] + $primaryKey) ], ]; return $this->enrich($row); // Recurse for associations } ... }
  • 28. 27 { "managers": [ { "from_date": "1996-01-03T00:00:00+0000", "to_date": null, "department": { "name": "Customer Service", "_links": { "self": { "href": "/departments/view/d009" } } }, "employee": { "birth_date": "1960-03-25T00:00:00+0000", "first_name": "Yuchang", "last_name": "Weedman", "gender": "M", "hire_date": "1989-07-10T00:00:00+0000", "_links": { "self": { "href": "/employees/view/111939" } }, "full_name": "Yuchang Weedman" }, "_links": { "self": { "href": "/managers/d009/111939" } } }
  • 29. } 28 Value Objects Why? Allow to add custom logic to dumb data. Help with custom serialization Make translation and localization easier Auto-validation Greater integrity.
  • 30. 29 Value Objects Adding logic to plain data class Gender implements JsonSerializable { private static $genders = []; protected $short; protected $name; protected function __construct($gender) { $this->short = $gender; $this->name = $gender === 'F' ? 'Female' : 'Male'; } public static function get($gender) { ... return $genders[$gender] = new static($gender); } ...
  • 31. 30 Value Objects Accepting value objects class Employee extends Entity { protected function _setGender($gender) { return Gender::get($gender); } $employeeEntity->gender = 'F'; get_class($employeeEntity->gender); // AppModelValueGender $employeeEntity->gender = Gender::get('F');
  • 32. 31 Value Objects Wiring them to the database class GenderType extends Type { ... } Type::build('gender', 'AppModelDatabaseType'); class EmployeesTable extends Table { ... protected function _initializeSchema(Schema $schema) { $schema->columnType('gender', 'gender'); return $schema; } }
  • 33. 32 Value Objects Using them in Queries $employee->gender = Gender::get('F'); $result = $employeesTable->find()->where([['gender' => $employee->gender]])->first(); $employee->gender === $result->gender; You can use objects as values in where conditions (or any query expression)
  • 34. 33 Thanks for your time Questions? https://github.com/lorenzo/cakephp3-advanced-examples