SlideShare a Scribd company logo
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 Objects
Wez 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 Frameworks
Nate 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 framework
G Woo
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201Fabien Potencier
 
Quebec pdo
Quebec pdoQuebec pdo
Quebec pdo
Valentine Dianov
 
Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium Apps
Nate 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 Edition
Nate Abele
 
The State of Lithium
The State of LithiumThe State of Lithium
The State of Lithium
Nate Abele
 
Doctrine 2
Doctrine 2Doctrine 2
Doctrine 2
zfconfua
 
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 it
Rafael Dohms
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
Rifat 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 action
Jace Ju
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
Bastian 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 bake
Kazuyuki 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 CakePHP
Ketan Patel
 
Simple search with elastic search
Simple search with elastic searchSimple search with elastic search
Simple search with elastic search
markstory
 
Recursive in CakePHP
Recursive in CakePHPRecursive in CakePHP
Recursive in CakePHP
Ketan Patel
 
CakePHP mistakes made
CakePHP mistakes madeCakePHP mistakes made
CakePHP mistakes made
markstory
 
CakePHP - Admin Acl Controlled
CakePHP - Admin Acl ControlledCakePHP - Admin Acl Controlled
CakePHP - Admin Acl Controlled
Luís Fred
 
Using RequireJS with CakePHP
Using RequireJS with CakePHPUsing RequireJS with CakePHP
Using RequireJS with CakePHP
Stephen Young
 
RESTful Web Development with CakePHP
RESTful Web Development with CakePHPRESTful Web Development with CakePHP
RESTful Web Development with CakePHP
Andru Weir
 
Road to CakePHP 3.0
Road to CakePHP 3.0Road to CakePHP 3.0
Road to CakePHP 3.0
markstory
 
CakePHP REST Plugin
CakePHP REST PluginCakePHP REST Plugin
CakePHP REST Plugin
Kevin van Zonneveld
 
CakePHP Community Keynote 2014
CakePHP Community Keynote 2014CakePHP Community Keynote 2014
CakePHP Community Keynote 2014
James Watts
 
Cake php Mamba Plugin
Cake php Mamba PluginCake php Mamba Plugin
Cake php Mamba Plugin
Riya 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 CakePHP
markstory
 
Ch ch-changes cake php2
Ch ch-changes cake php2Ch ch-changes cake php2
Ch ch-changes cake php2
markstory
 
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
Vipul 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 CakePHP
David 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 preocupados
Luis 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.4
Jeff Carouth
 
Fatc
FatcFatc
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
Michelangelo van Dam
 
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
Michelangelo van Dam
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes
Azim Kurt
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutes
Barang CK
 
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
Pete 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 - 4Developers
Kacper Gunia
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
Michelangelo van Dam
 
WordCamp Portland 2018: PHP for WordPress
WordCamp Portland 2018: PHP for WordPressWordCamp Portland 2018: PHP for WordPress
WordCamp Portland 2018: PHP for WordPress
Alena Holligan
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
Michelangelo 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.5
Leonardo Proietti
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2
Shinya 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 UnCon
Rafael Dohms
 
PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applicationselliando dias
 
Lecture9_OOPHP_SPring2023.pptx
Lecture9_OOPHP_SPring2023.pptxLecture9_OOPHP_SPring2023.pptx
Lecture9_OOPHP_SPring2023.pptx
ShaimaaMohamedGalal
 
PHPSpec BDD for PHP
PHPSpec BDD for PHPPHPSpec BDD for PHP
PHPSpec BDD for PHP
Marcello Duarte
 

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
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutes
 
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

GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
Guy Korland
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
Frank van Harmelen
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
RTTS
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
91mobiles
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Ramesh Iyer
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
Laura Byrne
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Product School
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
Dorra BARTAGUIZ
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Inflectra
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
Elena Simperl
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
Ana-Maria Mihalceanu
 
Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
OnBoard
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
Cheryl Hung
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance
 
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
Product School
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
Prayukth K V
 
PCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase TeamPCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase Team
ControlCase
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 

Recently uploaded (20)

GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
 
Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
 
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
 
PCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase TeamPCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase Team
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 

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