際際滷

際際滷Share a Scribd company logo
CakePHP
Build fast, grow solid.
Walther Lalk
CakePHP core team member
Croogo core team member
Lead Software Developer at
Troop Scouter at 9th Pretoria (Irene) Air Scouts
Husband github.com/dakota
@dakotairene
waltherlalk.com
What is CakePHP?
What is CakePHP?
CakePHPis a modern, free, open-source, rapid development framework
for PHP. It's a foundational structure for programmers to create web
applications. Our primary goal is to enable you to work in a structured
and rapid mannerwithout loss of flexibility.CakePHPtakes the
monotony out of web development.
CakePHP?
One of the original PHP frameworks, dating from late 2004
An opinionated MVC framework
Convention over configuration
Encourages DRY coding principles
Aims to solve 80% of the problem, and then stay out of your way
CakePHP?
Active and friendly community
A core team of highly motivated and experienced developers
Long support life cycles for major releases
Backwards compatibility between minor releases
A short history lesson
CakePHP
project started
Early 2005
1.0 released
May 2006
2.0 released
October 2011
3.0 released
March 2015
A new brand for a new era
PHP world has matured greatly since CakePHP 1.0 and 2.0
An updated, modern re-imagining of CakePHP was needed with greater
interoperability with the rest of the PHP eco-system
PHP-FIG (CakePHP was a founding member)
Composer
Components
CakePHP 3.0 was released at CakeFest 2015
A new, modern brand was announced at CakeFest 2016
CakePHP
CakeFest
Annual CakePHP conference
Soon to be twice annually
2 days of workshops (With a
beginner and advanced track)
2 days of talks from industry
experts and local developers
CakePHP Community
Active, supportive and helpful community
CakePHP Forum  discourse.cakephp.org
Slack and IRC  cakesf.herokuapp.com
Stackoverflow
Large eco-system of plugins and packages
Regular live training sessions  training.cakephp.org
An awesome full-time community manager  community@cakephp.org
@cakephp
CakePHP 3
A new ORM that is powerful, flexible and lightweight
Simple Form generator
Internationalization out the box (And it makes sense)
Standards complaint (PSR-2, 3, 4 and soon 7)
Middleware oriented stack
Standalone packages
You can use bits of CakePHP without using CakePHP
Separate components that can be used in any PHP project
cakephp/cache
cakephp/event
cakephp/validation
cakephp/orm
cakephp/collection
Collections
use CakeCollectionCollection;

$items = [
['id' => 1, 'name' => 'foo', 'parent' => 'a'],
['id' => 2, 'name' => 'bar', 'parent' => 'b'],
['id' => 3, 'name' => 'baz', 'parent' => 'a'],
];

$combined = (new Collection($items))->combine('id', 'name', 'parent');

// Result will look like this when converted to array
[
'a' => [1 => 'foo', 3 => 'baz'],
'b' => [2 => 'bar']
];
Collections
<?php
$items = ['a' => 1, 'b' => 2, 'c' => 3];
$collection = new Collection($items);
$new = $collection->map(function ($value, $key) {
return $value * 2;
});
// $result contains ['a' => 2, 'b' => 4, 'c' => 6];
$result = $new->toArray();
Powerful ORM and query builder
Looks and feels like SQL (Mostly)
$query->select(['name', 'email'])->where(['status IN' => ['active', 'pending']])->orderDesc('created');
$premium = $users->find('active')->find('premium'));
$subscribers = $users->find('active')->find('subscribedToNewsletter');
$query = $users->find()->select(['id'])->where(['is_active' => true]);
$anotherQuery->innerJoin(['stuff' => $query]);
$anotherQuery->where(['id IN' => $query]);
$recipients = $premium->append($subscribers)->extract('email');
Queries can be composed
Everything can be an expression
Queries are collections
Filtering by associations
// UsersTable
public function findWithArticlesNewerThanUser(Query $query, $options)
{
$userDate = $this->find()
->select(['created'])
->where(['id' => $options['userId']]);

return $query
->matching('Articles', function ($q) use ($userDate) {
return $q->where(['created >=' => $userDate]); 
});
}
Post-processing
public function findInContinentGroups(Query $query)
{
$query->formatResults(function ($results) {
return $results->groupBy('continent');
});

return $query;
}
"Africa": [
{
"name": "Angola"
},
{
"name": "Burundi"
},
{
"name": "Benin"
},
{
"name": "Burkina Faso"
},
],
"America": [...
Map-reduce
$mapper = function ($article, $key, $mapReduce) {
if (stripos('cakephp', $article['body']) === false) {
return;
}

$words = array_map('strtolower', explode(' ', $article['body']));
foreach ($words as $word) {
$mapReduce->emitIntermediate($article['id'], $word);
}
};

$reducer = function ($occurrences, $word, $mapReduce) {
$mapReduce->emit(count($occurrences), $word);
}

$articlesByStatus = $articles->find()->mapReduce($mapper, $reducer);
Map-reduce
// Result
[
'cakephp' => 100,
'awesome' => 39,
'impressive' => 57,
'outstanding' => 10,
'mind-blowing' => 83
]
PSR-7 support
3.3 introduced a PSR-7 compatible middleware stack
Both request and response objects are immutable
Application level request/response objects are not PSR-7 (Yet!)
Middleware
CORS
Exceptions
Assets
Routes
App
Middleware
CORS
Exceptions
Assets
Routes
App
Request
Response
Middleware
CORS
Exceptions
Assets
Routes
AppRequest
Response
Rules to follow
Must accept a Request, Response and next
Must return a Response or call next
Doesnt have to be limited to the CakePHP eco-system
For example, https://github.com/oscarotero/psr7-middlewares has a collection of
generic middleware classes.
Middleware setup
$middleware = new CakeHttpMiddlewareQueue();

$middleware
// Catch any exceptions in the lower layers,
// and make an error page/response
->add(new ErrorHandlerMiddleware())

// Handle plugin/theme assets like CakePHP normally does.
->add(new AssetMiddleware())

// Apply routing
->add(new RoutingMiddleware());

// Apply CORS as the first middleware
$middleware->prepend(new CorsMiddleware());
Middleware setup
// Oh wow, closures
$ohWow = function ($req, $res, $next) {
$res = $res->withHeader('X-WOW', 'Oh wow!');

return $next($req, $res);
};

// Add to the middleware stack
$middleware->add($ohWow);
Middleware setup
class OhWowMiddleware
{
public function __invoke($req, $res, $next)
{
$res = $res->withHeader('X-WOW', 'Oh wow!');

return $next($req, $res);
}
}

// Add to the middleware stack
$middleware->add(new OhWowMiddleware());
Easy, one-liner pagination (Even for complex queries)
Automatic association saving
Flexible association strategies
Result streaming
Query caching
Finder callbacks
Composite key support (Including foreign keys)
Tree structures
CSRF protection
Form tampering protection
Mailer classes
Authentication
Code generation
Advanced date and time support (Thanks to the Chronos library)
The future
The future*
3.4  Early 2017
PSR-7 request objects
Conditional Middlewares (aka Pipelines)
3.5  Probably middle 2017
PSR-7 response objects
Migrating certain bits of functionality into middleware
3.6  Probably end 2017
Hard deprecate the soft deprecated functionality
4.0  Maybe early 2018
Clean-up by removing all deprecated functionality
https://github.com/cakephp/cakephp/wiki
* Subject to change depending on community feedback
Lets get baking
Install CakePHP
Full virtual environment available https://
github.com/FriendsOfCake/vagrant-chef
$ composer create-project cakephp/app
$ cd app && bin/cake server
Easier than baking a cake!
Initial database migration
$ bin/cake migrations create Initial
$ bin/cake migrations migrate
Create an empty migration file
$ bin/cake bake migration_snapshot Initial
Create a migration based on an existing database
$ bin/cake bake migration CreateBookmarks user_id:integer title:string[50]
description:text url:text created modified
Build a migration in the console
Run migrations
Initial database migration
$this->table('bookmarks')
->addColumn('user_id', 'integer')
->addColumn('title', 'string', ['limit' => 50])
->addColumn('description', 'text')
->addColumn('url', 'text')
->addColumn('created', 'datetime')
->addColumn('modified', 'datetime')
->create();

$this->table('bookmarks_tags', ['id' => false, 'primary_key' =>
['bookmark_id', 'tag_id']])
->addColumn('bookmark_id', 'integer')
Skipping the hard work
$ bin/cake bake all users
$ bin/cake bake all bookmarks
$ bin/cake bake all tags
$ bin/cake bake all --everything
Fixing broken stuff
Interactive stack trace
Method argument inspection
Possible solution hints
DebugKit
CakePHP 3 comes with a debug
toolbar pre-installed
Facilitates in-depth application
inspection
Putting the rapid into RAD
How do we prevent repetitive controller code?
How do we have both a web and REST interface?
How do we do this without creating messy spaghetti code?
The CRUD plugin
Dynamic, event-driven and production ready scaffolding
Automatic REST API generation
Single responsibility action classes
Installing CRUD
Remove all code from your controllers
Go on holiday, your work is done
class AppController extends Controller
{
use CrudControllerControllerTrait;

public function initialize()
{
$this->loadComponent('Crud.Crud', [
'actions' => [
'Crud.Index',
'Crud.Add',
'Crud.Edit',
'Crud.View',
'Crud.Delete'
]
]);
}
}
$ composer require friendsofcake/crud
Creating a REST API
Converts all actions into a web service capable of responding in JSON or XML
Takes care of all error handling and validation errors
Automatically adds a layout to your responses
// config/routes.php
$routes->extensions(['json', 'xml']);
public function initialize()
{
...
$this->loadComponent('RequestHandler');

$this->Crud->addListener('Crud.Api');
$this->Crud->addListener('Crud.ApiPagination');
$this->Crud->addListener('Crud.ApiQueryLog');
}
$ curl X GET localhost:8765/tags.json
Extending Crud with events
Limiting records by user
Remembering the bookmark creator
$this->Crud->on('beforePaginate', function (CakeEventEvent $event) {
$event->subject()->query->where(['Bookmarks.user_id' => $this->Auth->user('id')]);
});
$this->Crud->on('beforeSave', function (CakeEventEvent $event) {
$event->subject()->entity->user_id = $this->Auth->user('id');
});
Other awesome plugins
TinyAuth  Light weight role based authentication
Friends of Cake Search  Simple interface for creating paginate-able filters
FractalTransformerView  Use Fractal to render API responses
TwigView  Use Twig for your templates
Liquid  Use Liquid for your templates
CakePDF  Easily create PDF files
The Queue plugin  Dependency-free worker queues
Many many more available from https://github.com/friendsofcake/awesome-cakephp
Also keep an eye on the @cakephp twitter feed for weekly featured plugins!
Thank You.
github.com/dakota
@dakotairene
waltherlalk.com

More Related Content

CakePHP

  • 2. Walther Lalk CakePHP core team member Croogo core team member Lead Software Developer at Troop Scouter at 9th Pretoria (Irene) Air Scouts Husband github.com/dakota @dakotairene waltherlalk.com
  • 4. What is CakePHP? CakePHPis a modern, free, open-source, rapid development framework for PHP. It's a foundational structure for programmers to create web applications. Our primary goal is to enable you to work in a structured and rapid mannerwithout loss of flexibility.CakePHPtakes the monotony out of web development.
  • 5. CakePHP? One of the original PHP frameworks, dating from late 2004 An opinionated MVC framework Convention over configuration Encourages DRY coding principles Aims to solve 80% of the problem, and then stay out of your way
  • 6. CakePHP? Active and friendly community A core team of highly motivated and experienced developers Long support life cycles for major releases Backwards compatibility between minor releases
  • 7. A short history lesson CakePHP project started Early 2005 1.0 released May 2006 2.0 released October 2011 3.0 released March 2015
  • 8. A new brand for a new era PHP world has matured greatly since CakePHP 1.0 and 2.0 An updated, modern re-imagining of CakePHP was needed with greater interoperability with the rest of the PHP eco-system PHP-FIG (CakePHP was a founding member) Composer Components CakePHP 3.0 was released at CakeFest 2015 A new, modern brand was announced at CakeFest 2016
  • 10. CakeFest Annual CakePHP conference Soon to be twice annually 2 days of workshops (With a beginner and advanced track) 2 days of talks from industry experts and local developers
  • 11. CakePHP Community Active, supportive and helpful community CakePHP Forum discourse.cakephp.org Slack and IRC cakesf.herokuapp.com Stackoverflow Large eco-system of plugins and packages Regular live training sessions training.cakephp.org An awesome full-time community manager community@cakephp.org @cakephp
  • 12. CakePHP 3 A new ORM that is powerful, flexible and lightweight Simple Form generator Internationalization out the box (And it makes sense) Standards complaint (PSR-2, 3, 4 and soon 7) Middleware oriented stack
  • 13. Standalone packages You can use bits of CakePHP without using CakePHP Separate components that can be used in any PHP project cakephp/cache cakephp/event cakephp/validation cakephp/orm cakephp/collection
  • 14. Collections use CakeCollectionCollection; $items = [ ['id' => 1, 'name' => 'foo', 'parent' => 'a'], ['id' => 2, 'name' => 'bar', 'parent' => 'b'], ['id' => 3, 'name' => 'baz', 'parent' => 'a'], ]; $combined = (new Collection($items))->combine('id', 'name', 'parent'); // Result will look like this when converted to array [ 'a' => [1 => 'foo', 3 => 'baz'], 'b' => [2 => 'bar'] ];
  • 15. Collections <?php $items = ['a' => 1, 'b' => 2, 'c' => 3]; $collection = new Collection($items); $new = $collection->map(function ($value, $key) { return $value * 2; }); // $result contains ['a' => 2, 'b' => 4, 'c' => 6]; $result = $new->toArray();
  • 16. Powerful ORM and query builder Looks and feels like SQL (Mostly) $query->select(['name', 'email'])->where(['status IN' => ['active', 'pending']])->orderDesc('created'); $premium = $users->find('active')->find('premium')); $subscribers = $users->find('active')->find('subscribedToNewsletter'); $query = $users->find()->select(['id'])->where(['is_active' => true]); $anotherQuery->innerJoin(['stuff' => $query]); $anotherQuery->where(['id IN' => $query]); $recipients = $premium->append($subscribers)->extract('email'); Queries can be composed Everything can be an expression Queries are collections
  • 17. Filtering by associations // UsersTable public function findWithArticlesNewerThanUser(Query $query, $options) { $userDate = $this->find() ->select(['created']) ->where(['id' => $options['userId']]); return $query ->matching('Articles', function ($q) use ($userDate) { return $q->where(['created >=' => $userDate]); }); }
  • 18. Post-processing public function findInContinentGroups(Query $query) { $query->formatResults(function ($results) { return $results->groupBy('continent'); }); return $query; } "Africa": [ { "name": "Angola" }, { "name": "Burundi" }, { "name": "Benin" }, { "name": "Burkina Faso" }, ], "America": [...
  • 19. Map-reduce $mapper = function ($article, $key, $mapReduce) { if (stripos('cakephp', $article['body']) === false) { return; } $words = array_map('strtolower', explode(' ', $article['body'])); foreach ($words as $word) { $mapReduce->emitIntermediate($article['id'], $word); } }; $reducer = function ($occurrences, $word, $mapReduce) { $mapReduce->emit(count($occurrences), $word); } $articlesByStatus = $articles->find()->mapReduce($mapper, $reducer);
  • 20. Map-reduce // Result [ 'cakephp' => 100, 'awesome' => 39, 'impressive' => 57, 'outstanding' => 10, 'mind-blowing' => 83 ]
  • 21. PSR-7 support 3.3 introduced a PSR-7 compatible middleware stack Both request and response objects are immutable Application level request/response objects are not PSR-7 (Yet!)
  • 25. Rules to follow Must accept a Request, Response and next Must return a Response or call next Doesnt have to be limited to the CakePHP eco-system For example, https://github.com/oscarotero/psr7-middlewares has a collection of generic middleware classes.
  • 26. Middleware setup $middleware = new CakeHttpMiddlewareQueue(); $middleware // Catch any exceptions in the lower layers, // and make an error page/response ->add(new ErrorHandlerMiddleware()) // Handle plugin/theme assets like CakePHP normally does. ->add(new AssetMiddleware()) // Apply routing ->add(new RoutingMiddleware()); // Apply CORS as the first middleware $middleware->prepend(new CorsMiddleware());
  • 27. Middleware setup // Oh wow, closures $ohWow = function ($req, $res, $next) { $res = $res->withHeader('X-WOW', 'Oh wow!'); return $next($req, $res); }; // Add to the middleware stack $middleware->add($ohWow);
  • 28. Middleware setup class OhWowMiddleware { public function __invoke($req, $res, $next) { $res = $res->withHeader('X-WOW', 'Oh wow!'); return $next($req, $res); } } // Add to the middleware stack $middleware->add(new OhWowMiddleware());
  • 29. Easy, one-liner pagination (Even for complex queries) Automatic association saving Flexible association strategies Result streaming Query caching Finder callbacks Composite key support (Including foreign keys) Tree structures CSRF protection Form tampering protection Mailer classes Authentication Code generation Advanced date and time support (Thanks to the Chronos library)
  • 31. The future* 3.4 Early 2017 PSR-7 request objects Conditional Middlewares (aka Pipelines) 3.5 Probably middle 2017 PSR-7 response objects Migrating certain bits of functionality into middleware 3.6 Probably end 2017 Hard deprecate the soft deprecated functionality 4.0 Maybe early 2018 Clean-up by removing all deprecated functionality https://github.com/cakephp/cakephp/wiki * Subject to change depending on community feedback
  • 33. Install CakePHP Full virtual environment available https:// github.com/FriendsOfCake/vagrant-chef $ composer create-project cakephp/app $ cd app && bin/cake server Easier than baking a cake!
  • 34. Initial database migration $ bin/cake migrations create Initial $ bin/cake migrations migrate Create an empty migration file $ bin/cake bake migration_snapshot Initial Create a migration based on an existing database $ bin/cake bake migration CreateBookmarks user_id:integer title:string[50] description:text url:text created modified Build a migration in the console Run migrations
  • 35. Initial database migration $this->table('bookmarks') ->addColumn('user_id', 'integer') ->addColumn('title', 'string', ['limit' => 50]) ->addColumn('description', 'text') ->addColumn('url', 'text') ->addColumn('created', 'datetime') ->addColumn('modified', 'datetime') ->create(); $this->table('bookmarks_tags', ['id' => false, 'primary_key' => ['bookmark_id', 'tag_id']]) ->addColumn('bookmark_id', 'integer')
  • 36. Skipping the hard work $ bin/cake bake all users $ bin/cake bake all bookmarks $ bin/cake bake all tags $ bin/cake bake all --everything
  • 37. Fixing broken stuff Interactive stack trace Method argument inspection Possible solution hints
  • 38. DebugKit CakePHP 3 comes with a debug toolbar pre-installed Facilitates in-depth application inspection
  • 39. Putting the rapid into RAD How do we prevent repetitive controller code? How do we have both a web and REST interface? How do we do this without creating messy spaghetti code? The CRUD plugin Dynamic, event-driven and production ready scaffolding Automatic REST API generation Single responsibility action classes
  • 40. Installing CRUD Remove all code from your controllers Go on holiday, your work is done class AppController extends Controller { use CrudControllerControllerTrait; public function initialize() { $this->loadComponent('Crud.Crud', [ 'actions' => [ 'Crud.Index', 'Crud.Add', 'Crud.Edit', 'Crud.View', 'Crud.Delete' ] ]); } } $ composer require friendsofcake/crud
  • 41. Creating a REST API Converts all actions into a web service capable of responding in JSON or XML Takes care of all error handling and validation errors Automatically adds a layout to your responses // config/routes.php $routes->extensions(['json', 'xml']); public function initialize() { ... $this->loadComponent('RequestHandler'); $this->Crud->addListener('Crud.Api'); $this->Crud->addListener('Crud.ApiPagination'); $this->Crud->addListener('Crud.ApiQueryLog'); } $ curl X GET localhost:8765/tags.json
  • 42. Extending Crud with events Limiting records by user Remembering the bookmark creator $this->Crud->on('beforePaginate', function (CakeEventEvent $event) { $event->subject()->query->where(['Bookmarks.user_id' => $this->Auth->user('id')]); }); $this->Crud->on('beforeSave', function (CakeEventEvent $event) { $event->subject()->entity->user_id = $this->Auth->user('id'); });
  • 43. Other awesome plugins TinyAuth Light weight role based authentication Friends of Cake Search Simple interface for creating paginate-able filters FractalTransformerView Use Fractal to render API responses TwigView Use Twig for your templates Liquid Use Liquid for your templates CakePDF Easily create PDF files The Queue plugin Dependency-free worker queues Many many more available from https://github.com/friendsofcake/awesome-cakephp Also keep an eye on the @cakephp twitter feed for weekly featured plugins!