New in CakePHP 3
March 22, 2015
3.0.0 is released
Frequent Releases
Bugfixes every 2-4 weeks
PHP 5.4 +
Soon to be PHP 5.5+
All the PSRs
Zero through Four
Clean up
Rabid conventions removed.
Standalone
Components
We have a few.
I18n
// Message formatting
echo __("Hello, my name is {0}, I'm {1} years old",
['Sara', 12]);
>>> Hello, my name is Sara, I’m 12 years old
// Decimals and integers
echo __('You have traveled {0,number,decimal}
kilometers in {1,number,integer} weeks',
[5423.344, 5.1]);
>>> You have traveled 5,423.34 kilometers in 5 weeks
Messages
echo __('{0,plural,
=0{No records found}
=1{Found 1 record}
other{Found # records}}',
[1]);
>>> Found 1 record
// Simpler message ids.
echo __('records.found', [1]);
>>> Found 1 record
Plurals
msgid "One file removed"
msgid_plural "{0} files removed"
msgstr[0] "jednom datotekom je uklonjen"
msgstr[1] "{0} datoteke uklonjenih"
msgstr[2] "{0} slika uklonjenih"
Catalog Files
use CakeI18nTime;
use CakeI18nNumber;
$date = new Time('2015-04-05 23:00:00');
echo $date;
>>> 05/04/2015 23:00
echo Number::format(524.23);
>>> 524.23
Numbers & Dates
Locale::setDefault(‘fr-FR’);
$date = new Time('2015-04-05 23:00:00');
echo $date;
>>> 5 avril 2015 23:00:00 UTC
echo Number::format(524.23);
>>> 524,23
Numbers & Dates
Use Alone
Use the i18n libs anywhere with composer.
Routing
Router::scope(‘/u‘, function ($routes) {
$routes->connect(‘/name/:username’, [‘controller’ => ‘Users’, ’action’ => ‘show’]);
});
// Use namespace prefixed controllers.
Router::prefix(‘admin’, function ($routes) {
$routes->connect(‘/articles/:action’, [‘controller’ => ‘Articles’]);
});
Routing Scopes
// Classic array format.
echo $this->Url->build([
‘controller’ => ‘Users’,
‘action’ => ‘show’,
‘username’ => ‘thewoz’
]);
>>> /u/name/thewoz
echo $this->Url->build([
‘prefix’ => ‘Admin’,
‘controller’ => ‘Articles’,
‘action’ => ‘index’
]);
>>> /admin/articles/index
Reverse Routing
Router::scope(‘/u‘, function ($routes) {
// Explicit name
$routes->connect(‘/friends’, [‘controller’ => ‘Friends’], [‘_name’ => ‘u:friends’]);
});
echo $this->Url->build([‘_name’ => ‘u:friends’]);
>>> /u/friends
Named Routes
Router::scope('/', function ($routes) {
$routes->extensions(['json']);
$routes->resources('Articles');
});
>>> /articles and /articles/:id are now connected.
// Generate nested resources
Router::scope('/', function ($routes) {
$routes->extensions([‘json’]);
$routes->resources('Articles', function ($routes) {
$routes->resources('Comments');
});
});
>>> /articles/:article_id/comments is now connected.
Resource Routing
Collections
Jose Lorenzo
Rodriguez
Iterator Master
Immutable
Mutator methods make new collections.
$items = ['a' => 1, 'b' => 2, 'c' => 3];
$collection = new Collection($items);
// Create a new collection containing elements
// with a value greater than one.
$big = $collection->filter(function ($value, $key, $iterator) {
return $value > 1;
});
// Search data in memory. match() makes a new iterator
$collection = new Collection($comments);
$commentsFromMark = $collection->match(['user.name' => 'Mark']);
Improved Arrays
$people = new Collection($peopleData);
// Find all the non-blondes
$notBlond = $people->reject(function ($p) {
return $p->hair_colour === ‘blond’;
});
// Get all the people named jose
$joses = $notBlond->filter(function ($p) {
return strtolower($p->first_name) === ‘jose’;
});
// Count by their hair colour
$counts = $joses->countBy(function ($p) {
return $p->hair_colour;
});
Pipeline Example
class JoseFinder {
public function __invoke($person) {
return strtolower($person->first_name) === ‘jose’;
}
}
$joses = $people->filter(new JoseFinder());
$notBlond = $people->reject(new NotBlondFilter());
Pipeline ++
Use Alone
Collections can be used in any project.
ORM
It is not 2005
anymore
ActiveRecord Datamapper
// Get a table gateway/mapper.
$connection = ConnectionManager::get(‘default’);
$articles = new ArticlesTable([‘connection’ => $connection]);
// Basic query building
$query = $articles->find()
->where([‘Articles.author_id’ => $userid])
->order([‘Articles.created’ => ‘DESC’]);
// Find some published, promoted articles
$query = $articles->find(‘promoted’)
->find(‘published’);
Finding Records
// Find articles and eager load relations (1 query)
$query = $articles->find()
->contain([‘Authors’, ‘Categories’]);
// Load deeply nested relations (2 queries)
$query = $articles->find()
->contain([‘Authors.RecentActivities’]);
Eager Loading
// Find all the articles tagged with ‘Cat’
$query = $articles->find()->matching(‘Tags’, function ($q) {
return $q->where([‘Tags.name’ => ‘Cat’]);
});
// Find all the articles without the tag ‘Cat’
$query = $articles->find()->notMatching(‘Tags’, function ($q) {
return $q->where([‘Tags.name’ => ‘Cat’]);
});
Matching
// Do extraction and transformations
$result = $articles->find()
->all()
->extract(‘title’)
->map(function ($item) { return strtoupper($item); });
// Extract and reduce
$query = $articles->find()->contain([‘Tags’]);
$uniqueTags = $articles->all()
->extract(‘tags.{*}.name’)
->reduce(function ($out, $tag) {
if (!in_array($tag, $out) {
$out[] = $tag;
}
return $out;
}, []);
Collections+
Entities
Just vanilla PHP objects for the most part.
namespace AppModelEntity;
use CakeORMEntity;
class Article extends Entity
{
protected $_accessible = [‘title’, ‘body’, ‘author_id’];
}
Article Entity
namespace AppModelEntity;
use CakeORMEntity;
class User extends Entity
{
protected function _getFullName()
{
return $this->_properties['first_name'] . ' ' .
$this->_properties['last_name'];
}
}
echo $user->full_name;
Virtual Fields
Inspired By
SQLAlchemy
The best ORM I’ve ever used.
No Proxies,
No Annotations,
No Identity Map,
No Runtime Reflection
No Lazy Loading
Use alone
Use the ORM anywhere with composer.
What’s Next?
What’s Next
• New DateTime library, replacing Carbon
• Polymorphic Associations
• PSR7 Support
• Value Objects
Thank You.
https://joind.in/14774
Twitter - mark_story
Github - markstory

New in cakephp3

  • 1.
  • 3.
  • 4.
  • 5.
    PHP 5.4 + Soonto be PHP 5.5+
  • 6.
    All the PSRs Zerothrough Four
  • 7.
  • 8.
  • 9.
  • 10.
    // Message formatting echo__("Hello, my name is {0}, I'm {1} years old", ['Sara', 12]); >>> Hello, my name is Sara, I’m 12 years old // Decimals and integers echo __('You have traveled {0,number,decimal} kilometers in {1,number,integer} weeks', [5423.344, 5.1]); >>> You have traveled 5,423.34 kilometers in 5 weeks Messages
  • 11.
    echo __('{0,plural, =0{No recordsfound} =1{Found 1 record} other{Found # records}}', [1]); >>> Found 1 record // Simpler message ids. echo __('records.found', [1]); >>> Found 1 record Plurals
  • 12.
    msgid "One fileremoved" msgid_plural "{0} files removed" msgstr[0] "jednom datotekom je uklonjen" msgstr[1] "{0} datoteke uklonjenih" msgstr[2] "{0} slika uklonjenih" Catalog Files
  • 13.
    use CakeI18nTime; use CakeI18nNumber; $date= new Time('2015-04-05 23:00:00'); echo $date; >>> 05/04/2015 23:00 echo Number::format(524.23); >>> 524.23 Numbers & Dates
  • 14.
    Locale::setDefault(‘fr-FR’); $date = newTime('2015-04-05 23:00:00'); echo $date; >>> 5 avril 2015 23:00:00 UTC echo Number::format(524.23); >>> 524,23 Numbers & Dates
  • 15.
    Use Alone Use thei18n libs anywhere with composer.
  • 16.
  • 17.
    Router::scope(‘/u‘, function ($routes){ $routes->connect(‘/name/:username’, [‘controller’ => ‘Users’, ’action’ => ‘show’]); }); // Use namespace prefixed controllers. Router::prefix(‘admin’, function ($routes) { $routes->connect(‘/articles/:action’, [‘controller’ => ‘Articles’]); }); Routing Scopes
  • 18.
    // Classic arrayformat. echo $this->Url->build([ ‘controller’ => ‘Users’, ‘action’ => ‘show’, ‘username’ => ‘thewoz’ ]); >>> /u/name/thewoz echo $this->Url->build([ ‘prefix’ => ‘Admin’, ‘controller’ => ‘Articles’, ‘action’ => ‘index’ ]); >>> /admin/articles/index Reverse Routing
  • 19.
    Router::scope(‘/u‘, function ($routes){ // Explicit name $routes->connect(‘/friends’, [‘controller’ => ‘Friends’], [‘_name’ => ‘u:friends’]); }); echo $this->Url->build([‘_name’ => ‘u:friends’]); >>> /u/friends Named Routes
  • 20.
    Router::scope('/', function ($routes){ $routes->extensions(['json']); $routes->resources('Articles'); }); >>> /articles and /articles/:id are now connected. // Generate nested resources Router::scope('/', function ($routes) { $routes->extensions([‘json’]); $routes->resources('Articles', function ($routes) { $routes->resources('Comments'); }); }); >>> /articles/:article_id/comments is now connected. Resource Routing
  • 21.
  • 22.
  • 23.
  • 24.
    $items = ['a'=> 1, 'b' => 2, 'c' => 3]; $collection = new Collection($items); // Create a new collection containing elements // with a value greater than one. $big = $collection->filter(function ($value, $key, $iterator) { return $value > 1; }); // Search data in memory. match() makes a new iterator $collection = new Collection($comments); $commentsFromMark = $collection->match(['user.name' => 'Mark']); Improved Arrays
  • 25.
    $people = newCollection($peopleData); // Find all the non-blondes $notBlond = $people->reject(function ($p) { return $p->hair_colour === ‘blond’; }); // Get all the people named jose $joses = $notBlond->filter(function ($p) { return strtolower($p->first_name) === ‘jose’; }); // Count by their hair colour $counts = $joses->countBy(function ($p) { return $p->hair_colour; }); Pipeline Example
  • 26.
    class JoseFinder { publicfunction __invoke($person) { return strtolower($person->first_name) === ‘jose’; } } $joses = $people->filter(new JoseFinder()); $notBlond = $people->reject(new NotBlondFilter()); Pipeline ++
  • 27.
    Use Alone Collections canbe used in any project.
  • 28.
  • 29.
    It is not2005 anymore
  • 30.
  • 31.
    // Get atable gateway/mapper. $connection = ConnectionManager::get(‘default’); $articles = new ArticlesTable([‘connection’ => $connection]); // Basic query building $query = $articles->find() ->where([‘Articles.author_id’ => $userid]) ->order([‘Articles.created’ => ‘DESC’]); // Find some published, promoted articles $query = $articles->find(‘promoted’) ->find(‘published’); Finding Records
  • 32.
    // Find articlesand eager load relations (1 query) $query = $articles->find() ->contain([‘Authors’, ‘Categories’]); // Load deeply nested relations (2 queries) $query = $articles->find() ->contain([‘Authors.RecentActivities’]); Eager Loading
  • 33.
    // Find allthe articles tagged with ‘Cat’ $query = $articles->find()->matching(‘Tags’, function ($q) { return $q->where([‘Tags.name’ => ‘Cat’]); }); // Find all the articles without the tag ‘Cat’ $query = $articles->find()->notMatching(‘Tags’, function ($q) { return $q->where([‘Tags.name’ => ‘Cat’]); }); Matching
  • 34.
    // Do extractionand transformations $result = $articles->find() ->all() ->extract(‘title’) ->map(function ($item) { return strtoupper($item); }); // Extract and reduce $query = $articles->find()->contain([‘Tags’]); $uniqueTags = $articles->all() ->extract(‘tags.{*}.name’) ->reduce(function ($out, $tag) { if (!in_array($tag, $out) { $out[] = $tag; } return $out; }, []); Collections+
  • 35.
    Entities Just vanilla PHPobjects for the most part.
  • 36.
    namespace AppModelEntity; use CakeORMEntity; classArticle extends Entity { protected $_accessible = [‘title’, ‘body’, ‘author_id’]; } Article Entity
  • 37.
    namespace AppModelEntity; use CakeORMEntity; classUser extends Entity { protected function _getFullName() { return $this->_properties['first_name'] . ' ' . $this->_properties['last_name']; } } echo $user->full_name; Virtual Fields
  • 38.
    Inspired By SQLAlchemy The bestORM I’ve ever used.
  • 39.
    No Proxies, No Annotations, NoIdentity Map, No Runtime Reflection
  • 40.
  • 41.
    Use alone Use theORM anywhere with composer.
  • 42.
  • 43.
    What’s Next • NewDateTime library, replacing Carbon • Polymorphic Associations • PSR7 Support • Value Objects
  • 44.
    Thank You. https://joind.in/14774 Twitter -mark_story Github - markstory