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-8
PrinceGuru 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 201
Fabien 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 fixtures
Bill 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
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
Fabien Potencier
 
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.4
Fabien Potencier
 
Lithium Best
Lithium Best Lithium Best
Lithium Best
Richard McIntyre
 
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 World
Fabien 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 Symfony2
Fabien 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
 
REST API with CakePHP
REST API with CakePHPREST API with CakePHP
REST API with CakePHP
Anuchit Chalothorn
 
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
 
Faster develoment with CakePHP 3
Faster develoment with CakePHP 3Faster develoment with CakePHP 3
Faster develoment with CakePHP 3
José Lorenzo Rodríguez Urdaneta
 
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

Drupal7 dbtng
Drupal7  dbtngDrupal7  dbtng
Drupal7 dbtng
Nicolas Leroy
 
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 7
chuvainc
 
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 Applications
elliando dias
 
Php & my sql
Php & my sqlPhp & my sql
Php & my sql
Norhisyam Dasuki
 
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

Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Jeffrey Haguewood
 
Azure API Management to expose backend services securely
Azure API Management to expose backend services securelyAzure API Management to expose backend services securely
Azure API Management to expose backend services securely
Dinusha Kumarasiri
 
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
saastr
 
Skybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoptionSkybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoption
Tatiana Kojar
 
leewayhertz.com-AI in predictive maintenance Use cases technologies benefits ...
leewayhertz.com-AI in predictive maintenance Use cases technologies benefits ...leewayhertz.com-AI in predictive maintenance Use cases technologies benefits ...
leewayhertz.com-AI in predictive maintenance Use cases technologies benefits ...
alexjohnson7307
 
Your One-Stop Shop for Python Success: Top 10 US Python Development Providers
Your One-Stop Shop for Python Success: Top 10 US Python Development ProvidersYour One-Stop Shop for Python Success: Top 10 US Python Development Providers
Your One-Stop Shop for Python Success: Top 10 US Python Development Providers
akankshawande
 
Serial Arm Control in Real Time Presentation
Serial Arm Control in Real Time PresentationSerial Arm Control in Real Time Presentation
Serial Arm Control in Real Time Presentation
tolgahangng
 
AWS Cloud Cost Optimization Presentation.pptx
AWS Cloud Cost Optimization Presentation.pptxAWS Cloud Cost Optimization Presentation.pptx
AWS Cloud Cost Optimization Presentation.pptx
HarisZaheer8
 
Nunit vs XUnit vs MSTest Differences Between These Unit Testing Frameworks.pdf
Nunit vs XUnit vs MSTest Differences Between These Unit Testing Frameworks.pdfNunit vs XUnit vs MSTest Differences Between These Unit Testing Frameworks.pdf
Nunit vs XUnit vs MSTest Differences Between These Unit Testing Frameworks.pdf
flufftailshop
 
GraphRAG for Life Science to increase LLM accuracy
GraphRAG for Life Science to increase LLM accuracyGraphRAG for Life Science to increase LLM accuracy
GraphRAG for Life Science to increase LLM accuracy
Tomaz Bratanic
 
Overcoming the PLG Trap: Lessons from Canva's Head of Sales & Head of EMEA Da...
Overcoming the PLG Trap: Lessons from Canva's Head of Sales & Head of EMEA Da...Overcoming the PLG Trap: Lessons from Canva's Head of Sales & Head of EMEA Da...
Overcoming the PLG Trap: Lessons from Canva's Head of Sales & Head of EMEA Da...
saastr
 
Best 20 SEO Techniques To Improve Website Visibility In SERP
Best 20 SEO Techniques To Improve Website Visibility In SERPBest 20 SEO Techniques To Improve Website Visibility In SERP
Best 20 SEO Techniques To Improve Website Visibility In SERP
Pixlogix Infotech
 
Programming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup SlidesProgramming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup Slides
Zilliz
 
Deep Dive: Getting Funded with Jason Jason Lemkin Founder & CEO @ SaaStr
Deep Dive: Getting Funded with Jason Jason Lemkin Founder & CEO @ SaaStrDeep Dive: Getting Funded with Jason Jason Lemkin Founder & CEO @ SaaStr
Deep Dive: Getting Funded with Jason Jason Lemkin Founder & CEO @ SaaStr
saastr
 
Nordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptxNordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptx
MichaelKnudsen27
 
Recommendation System using RAG Architecture
Recommendation System using RAG ArchitectureRecommendation System using RAG Architecture
Recommendation System using RAG Architecture
fredae14
 
Building Production Ready Search Pipelines with Spark and Milvus
Building Production Ready Search Pipelines with Spark and MilvusBuilding Production Ready Search Pipelines with Spark and Milvus
Building Production Ready Search Pipelines with Spark and Milvus
Zilliz
 
Generating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and MilvusGenerating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and Milvus
Zilliz
 
HCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAUHCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAU
panagenda
 
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAUHCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
panagenda
 

Recently uploaded (20)

Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
 
Azure API Management to expose backend services securely
Azure API Management to expose backend services securelyAzure API Management to expose backend services securely
Azure API Management to expose backend services securely
 
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
 
Skybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoptionSkybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoption
 
leewayhertz.com-AI in predictive maintenance Use cases technologies benefits ...
leewayhertz.com-AI in predictive maintenance Use cases technologies benefits ...leewayhertz.com-AI in predictive maintenance Use cases technologies benefits ...
leewayhertz.com-AI in predictive maintenance Use cases technologies benefits ...
 
Your One-Stop Shop for Python Success: Top 10 US Python Development Providers
Your One-Stop Shop for Python Success: Top 10 US Python Development ProvidersYour One-Stop Shop for Python Success: Top 10 US Python Development Providers
Your One-Stop Shop for Python Success: Top 10 US Python Development Providers
 
Serial Arm Control in Real Time Presentation
Serial Arm Control in Real Time PresentationSerial Arm Control in Real Time Presentation
Serial Arm Control in Real Time Presentation
 
AWS Cloud Cost Optimization Presentation.pptx
AWS Cloud Cost Optimization Presentation.pptxAWS Cloud Cost Optimization Presentation.pptx
AWS Cloud Cost Optimization Presentation.pptx
 
Nunit vs XUnit vs MSTest Differences Between These Unit Testing Frameworks.pdf
Nunit vs XUnit vs MSTest Differences Between These Unit Testing Frameworks.pdfNunit vs XUnit vs MSTest Differences Between These Unit Testing Frameworks.pdf
Nunit vs XUnit vs MSTest Differences Between These Unit Testing Frameworks.pdf
 
GraphRAG for Life Science to increase LLM accuracy
GraphRAG for Life Science to increase LLM accuracyGraphRAG for Life Science to increase LLM accuracy
GraphRAG for Life Science to increase LLM accuracy
 
Overcoming the PLG Trap: Lessons from Canva's Head of Sales & Head of EMEA Da...
Overcoming the PLG Trap: Lessons from Canva's Head of Sales & Head of EMEA Da...Overcoming the PLG Trap: Lessons from Canva's Head of Sales & Head of EMEA Da...
Overcoming the PLG Trap: Lessons from Canva's Head of Sales & Head of EMEA Da...
 
Best 20 SEO Techniques To Improve Website Visibility In SERP
Best 20 SEO Techniques To Improve Website Visibility In SERPBest 20 SEO Techniques To Improve Website Visibility In SERP
Best 20 SEO Techniques To Improve Website Visibility In SERP
 
Programming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup SlidesProgramming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup Slides
 
Deep Dive: Getting Funded with Jason Jason Lemkin Founder & CEO @ SaaStr
Deep Dive: Getting Funded with Jason Jason Lemkin Founder & CEO @ SaaStrDeep Dive: Getting Funded with Jason Jason Lemkin Founder & CEO @ SaaStr
Deep Dive: Getting Funded with Jason Jason Lemkin Founder & CEO @ SaaStr
 
Nordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptxNordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptx
 
Recommendation System using RAG Architecture
Recommendation System using RAG ArchitectureRecommendation System using RAG Architecture
Recommendation System using RAG Architecture
 
Building Production Ready Search Pipelines with Spark and Milvus
Building Production Ready Search Pipelines with Spark and MilvusBuilding Production Ready Search Pipelines with Spark and Milvus
Building Production Ready Search Pipelines with Spark and Milvus
 
Generating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and MilvusGenerating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and Milvus
 
HCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAUHCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAU
 
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAUHCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
 

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