THE FUTURE
OF PLUGIN DEV
Brandon Kelly
Craft 3 Dev Preview
coming in May
Powered by Yii 2
Totally refactored
Faster
Requests/second
(bigger is better)
EE Joomla Drupal 7 Craft 2 Craft 3
17.52
9.79
9.05
4.784.17
Response Times
(in milliseconds - smaller is better)
EE Joomla Drupal 7 Craft 2 Craft 3
57
102110
209
240
buildwithcraft.com/3
What has changed for
Craft has also changed
for plugins
• What’s changed in PHP
• What’s changed in Yii
• What’s changed in Craft
• Port a plugin
Game plan
PHP
Yii 2 and Craft 3 both

require PHP 5.4
(Yii 1 required 5.1; Craft 2 required 5.3)
• JSON extension
• ZIP extension
• Upload progress-tracking hooks
• DateTime/DateTimeZone
PHP 5.2 features
• Namespaces
• Late static bindings
• Closures
PHP 5.3 features
Namespaces
namespace craftpluginsfoo;
class Plugin {
public function getClassName() {
return get_class($this);
}
}
$plugin = new Plugin();
echo $plugin->getClassName();
// => "craftpluginsfooPlugin"
Late static bindings
class Object {
public static function className() {
return get_called_class();
}
}
class Foo extends Object {
}
echo Foo::className();
// => "Foo"
Closures
$obj->on('thing', function($event) {
// ...
});
• Traits
• Short array syntax
• Function array dereferencing
• Class member access on
instantiation
PHP 5.4 Features
Traits
trait FooTrait {
public $bar = 'bar';
}
class Foo {
use FooTrait;
}
$foo = new Foo();
echo $foo->bar;
// => "bar"
Short array syntax
$myIndexedArray = [
'key1' => 1,
'key2' => 2
];
$myBoringArray = [1, 2, 3];
Function array dereferencing
function foo() {
return ['one', 'two', 'three'];
}
echo foo()[0];
// => "one"
Class member access on instantiation
class Foo {
public function bar() {
// ...
}
}
(new Foo())
->bar();
Yii
Class Names
and Namespaces
• No more “C” class name prefix
• Namespaces resemble the folder
structure (PSR-4)
• No more Yii::import()
• Path aliases define the root
namespaces for the autoloader
Class name/namespace changes
Path alias example
Yii::setAlias('@foo', '/path/to/foo');
echo Yii::getAlias('@foo/subpath');
// => "/path/to/foo/subpath"
Important path aliases to be aware of
Path Alias Server Path Root Namespace
@yii …/app/vendor/yiisoft/yii2 yii
@craft/app …/app craftapp
@craft/plugins/foo …/plugins/foo craftpluginsfoo
Objects and Components
• Base class for everything
• Property getters/setters
• Event handling
• Behaviors
CComponent in Yii 1
• yiibaseObject
• yiibaseComponent
Split into two classes in Yii 2
• The new base class for
everything
• Only does property

getters/setters
Object
• Extends Object
• Event handling
• Behaviors
Component
• Extend Object for classes that
don’t do anything besides
represent data (glorified arrays)
• Extend Component for
everything else
When to use which?
• yiibaseEvent
• yiidbTableSchema
• yiimailBaseMessage
• yiiwebCookieCollection
• yiiwebUrlRule
Object examples
• yiibaseModel
• yiidbConnection
• yiii18nI18N
• yiimailBaseMailer
• yiiwebRequest
Component examples
Objects are configurable
• Define object config settings as
public properties
• Pass configuration arrays into the
object constructor
Configuring objects
Object configuration examples
class User extends Object {
public $age;
}
$user = new User(['age' => 21]);
Object configuration examples
class User extends Object {
public function setAge($age) {
// ...
}
public function getAge() {
// ...
}
}
$user = new User(['age' => 21]);
Object configuration examples
$user = Yii::createObject('fooUser');
$user = Yii::createObject([
'class' => 'fooUser',
'age' => 21
]);
Service Locators
• Base: yiidiServiceLocator
• They have sub-components
• Components accessed via magic
getters and get()
• Subcomponents are created the
first time they’re requested
Service locators
Modules
• Base: yiibaseModule
• They are service locators, so they
have sub-components
• They also have controllers, views,
and sub-modules
Modules
Applications
• Base: yiibaseApplication
• They are modules
• They handle the request
• Only one application per request
Applications
• Web requests:

yiiwebApplication

• Console requests:

yiiconsoleApplication
Two application classes
Controllers
• Web and console applications
have controllers (no more
“console command” classes)
• Controller action routing works
the same either way
• They return the response
Controllers
Request vs. Response
• Request classes define the incoming
web/console request
• Response classes define the outgoing
web/console response
• The response is automatically sent at
the end of the application processing
Request vs. response
• Describes the HTTP request
• Method (GET, POST, etc.)
• Ajax/Pjax/Flash?
• Headers, body, parameters
• Acceptable content types/languages
• HTTP authentication
• URL, host name, URI, port, SSL
• Referrer, user agent, client IP
yiiwebRequest
• Describes the console command
• Requested route
• Requested parameters
yiiconsoleRequest
• Defines the HTTP response
• Status code (200, 404, etc.)
• Headers
• Cookies
• Body
yiiwebResponse
• HTML
• XML
• JSON
• JSONP
Web response formats
Formatted response examples
$response = Yii::$app->getResponse();
$response->data = $user;
$response->format = 'json';
$response->send();
{
"id": 5,
"username": "admin",
"age": 21
}
Formatted response examples
$response = Yii::$app->getResponse();
$response->data = $user;
$response->format = 'xml';
$response->send();
<response>
<id>5</id>
<username>admin</username>
<age>21</age>
</response>
Events
• Defined by “onEventName()”
methods on component classes
• Attached by setting a magic
“onEventName” property
• Raised by calling raiseEvent()
within the event method
Events in Yii 1
Yii 1 event example
class User extends CComponent {
public function wake() {
$this->onWake(new CEvent());
}
public function onWake($ev) {
$this->raiseEvent('onWake', $ev);
}
}
$user = new User();
$user->onWake = function($ev){/*...*/};
• Not explicitly predefined
• Attached by calling on()
• Raised by calling trigger()
Events in Yii 2
Yii 2 event example
class User extends Component {
public function wake() {
$this->trigger('afterWake');
}
}
$user = new User();
$user->on('afterWake', function($ev){
// ...
});
Class-level Event Handlers
Class-level event handler example
Event::on('fooUser', 'afterWake',
function($ev) {
// ...
}
);
Asset Bundles
• For JS and CSS resources
• They can have dependencies
• They can publish their files into
the web root when registered
• They can compile LESS, Sass,
Stylus, and CoffeeScript
Asset bundles
Defining an asset bundle
class AppAsset extends AssetBundle
{
public $sourcePath = '@app/assets';
public $basePath = '@web/assets';
public $depends = [
'yiiwebJqueryAsset'
];
public $css = [
'css/app.scss'
];
}
Registering an asset bundle
Yii::$app->view->registerAssetBundle(
'fooAppAsset'
);
DB Queries
• All SELECT queries are defined
by yiidbQuery objects
• All other queries are defined by
yiidbCommand objects
• Schema-specific SQL is always
built with QueryBuilder
DB Queries
Query methodsQuery Definition Query Execution
select()
distinct()
from()
where()
innerJoin()
leftJoin()
rightJoin()
groupBy()
having()
union()
orderBy()
limit()
offset()
batch()
each()
all()
one()
scalar()
column()
count()
sum()
average()
min()
max()
exists()
createCommand()
SELECT query examples
$user = (new Query())
->from('{{%users}}')
->where(['id' => 5])
->one();
SELECT query examples
$users = (new Query())
->from('{{%users}}')
->where('age >= :min', [
':min' => 21
])
->all();
Command methodsQuery Definition Query Management Query Execution
insert()
batchInsert()
update()
delete()
createTable()
renameTable()
dropTable()
truncateTable()
addColumn()
dropColumn()
renameColumn()
alterColumn()
addPrimaryKey()
dropPrimaryKey()
addForeignKey()
dropForeignKey()
createIndex()
dropIndex()
cache()
noCache()
getSql()
setSql()
getRawSql()
prepare()
cancel()
bindParam()
bindPendingParams()
bindValue()
bindValues()
query()
queryAll()
queryOne()
queryScalar()
queryColumn()
execute()
More query examples
Yii::$app->db->createCommand()
->insert('users', [
'username' => 'brandon'
'age' => 29
])
->execute();
More query examples
Yii::$app->db->createCommand()
->update('users',
['age' => 30],
['id' => 5]
)
->execute();
How they map together
Query Execution Method Command Execution Method
all() queryAll()
one() queryOne()
count()
sum()
average()
min()
max()
exists()
scalar()
queryScalar()
column() queryColumn()
Active Record
• Base: yiidbActiveRecord
• Records’ ::find() methods
return ActiveQuery objects
• ActiveQuery handles the query
definition and active record
object population
Active Record
Active record query example
$users = User::find()
->where('age => :min', [
':min' => 21
])
->all();
Internationalization
(I18n)
• Yii 2 uses PHP’s Intl extension to
format dates, numbers, etc.
• Only very basic single-language
fallbacks built-in.
• Only 30% of servers have Intl
• What could go wrong?
Internationalization
Craft
• No more Craft namespace
• Namespaces reflect the folder
structure now
• Root namespace is craftapp
• Plugins’ root namespaces follow
the pattern craftpluginsfoo
Namespaces
• Craft 2: craft() returns the
CraftWebApp instance
• Craft 3: Craft::$app returns the

craftappwebApplication
instance
Accessing the Application instance
• Magic property names are still
available:

Craft::$app->entries
• We’ve also added getter methods
for all services:

Craft::$app->getEntries()
Accessing the Application components
• userSession is now user /
getUser()
• httpSession is now session /
getSession()
Application component name changes
Routes and Controllers
• In Craft 2, routes pointed to
templates by default, and could
point to a controller action with a
special syntax
• That’s reversed in Craft 2: by
default routes point to actions
Routes and controllers
Craft 2 route example
return array(
// Template route:
'foo' => 'path/to/template',
// Controller action route:
'bar' => array(
'action' => 'foo/bar'
)
);
Craft 3 route example
return [
// Template route:
'foo' => [
'template' => 'template/path',
],
// Controller action route:
'bar' => 'foo/bar'
];
• Params captured by URL rules
are now passed directly to the
action’s arguments
• URL Manager’s
setRouteVariables() is now
setRouteParams()
Routes and controllers
Models
• No more defineAttributes()
• Attributes must be defined as
public properties on the model
• Validation rules must be defined
in the rules() method
Model changes in Craft 3
Craft 2 model example
class User extends BaseModel {
protected function defineAttributes()
{
return array(
'id' => AttributeType::Number,
'age' => AttributeType::Number
);
}
}
Craft 3 model example
class User extends Model {
public $id;
public $age;
public function rules() {
return [
['id,age', 'number']
];
}
}
Records
• No more defineAttributes()
• Column names are determined
by analyzing the table
• Validation rules must be defined
in the rules() method
• Records no longer create tables
Record changes in Craft 3
Templates
• TemplatesService is now
craftappwebView
• include*()→register*()
• render()→renderTemplate()
• register[Css|Js]Resource()
register asset bundles
Templates
• “beginPage”, “endPage”,
“beginBody”, and “endBody”
events are triggered when
rendering templates
Templates
‘Types
• No more separation of
component models and their
“type” classes
‘Types
Field type architectureCraft 2 Craft 3
Field Model
Field Type
Field Model
Widget type architectureCraft 2 Craft 3
Widget Model
Widget Type
Widget Model
Task type architectureCraft 2 Craft 3
Task Model
Task Type
Task Model
Element type architectureCraft 2 Craft 3
Element Model
Element Type
Element Model
‘Type Settings
• No more defineSettings()
• Settings are now defined directly
on the component classes as
public properties
‘Type settings
Craft 2 field type example
class XFieldType extends BaseFieldType
{
protected function defineSettings() {
return array(
'maxlen' => AttributeType::Number
);
}
// ...
}
Craft 3 field type example
class X extends Field
{
public $maxlen;
// ...
}
Element Queries
• ElementCriteriaModel ,
modifyElementsQuery(), and
defineCriteriaAttributes()
are dead!
• Replaced with Element Query
classes
Element Queries
• Elements’ ::find() methods
return ElementQuery objects
• ElementQuery handles the query
definition and element object
population
Element Queries
• Element types that need custom
query parameters can extend
ElementQuery and override their
element class’ ::find() method
to return their custom element
query class
Element Queries
• Element queries have protected
beforePrepare() and
afterPrepare() methods that
can be overridden to support
custom parameters
Element Queries
Element query example
class User extends Element {
public static function find() {
return new UserQuery(
get_called_class()
);
}
// ...
}
Element query example
class UserQuery extends ElementQuery {
public $age;
protected function beforePrepare() {
if ($this->age) {
$this->subQuery->andWhere(
['age' => $this->age]
);
}
return parent::beforePrepare();
}
}
Plugins
• Primary plugin class is no longer
necessary
• Plugins are modules
• General plugin info now defined
by config.json
Plugins
config.json example
{
"name": "Foo",
"version": "1.0",
"developer": "Pixel & Tonic",
"developerUrl": "http://foo.com"
}
• Plugins are modules
• Primary plugin class is optional
• General plugin info now defined
in config.json
• No more strict class name/folder
requirements
Plugins
Installing Plugins
• Craft 2 would automatically
create/drop tables based on your
records on install/uninstall
• Craft 3 leaves it up to the plugin,
calling its install() and
uninstall() methods
Installing Plugins
• By default, install() and
uninstall() will check for an
“Install” migration within the
plugin, and call its safeUp() and
safeDown() methods
Installing Plugins
• Craft has an InstallMigration
class that can be extended
• All you have to do is override its
defineSchema() function,
defining your plugin’s default
table schema.
Installing Plugins
Install migration example
class Install extends InstallMigration
{
protected function defineSchema() {
'{{%foo_users}}' => [
'columns' => [
'username' => 'string(36)',
'age' => 'integer'
]
]
}
}
• Craft has its own Install migration
that the installer runs:

craft/app/migrations/Install.php
• Also shows how to add default
content to the tables
Installing Plugins
Let’s port a plugin
Thank you!
Try the Craft 3 Dev Preview today at
buildwithcraft.com/3

The Future of Plugin Dev

  • 1.
    THE FUTURE OF PLUGINDEV Brandon Kelly
  • 2.
    Craft 3 DevPreview coming in May
  • 3.
  • 4.
  • 5.
  • 6.
    Requests/second (bigger is better) EEJoomla Drupal 7 Craft 2 Craft 3 17.52 9.79 9.05 4.784.17
  • 7.
    Response Times (in milliseconds- smaller is better) EE Joomla Drupal 7 Craft 2 Craft 3 57 102110 209 240
  • 8.
  • 9.
    What has changedfor Craft has also changed for plugins
  • 10.
    • What’s changedin PHP • What’s changed in Yii • What’s changed in Craft • Port a plugin Game plan
  • 11.
  • 12.
    Yii 2 andCraft 3 both
 require PHP 5.4 (Yii 1 required 5.1; Craft 2 required 5.3)
  • 13.
    • JSON extension •ZIP extension • Upload progress-tracking hooks • DateTime/DateTimeZone PHP 5.2 features
  • 14.
    • Namespaces • Latestatic bindings • Closures PHP 5.3 features
  • 15.
    Namespaces namespace craftpluginsfoo; class Plugin{ public function getClassName() { return get_class($this); } } $plugin = new Plugin(); echo $plugin->getClassName(); // => "craftpluginsfooPlugin"
  • 16.
    Late static bindings classObject { public static function className() { return get_called_class(); } } class Foo extends Object { } echo Foo::className(); // => "Foo"
  • 17.
  • 18.
    • Traits • Shortarray syntax • Function array dereferencing • Class member access on instantiation PHP 5.4 Features
  • 19.
    Traits trait FooTrait { public$bar = 'bar'; } class Foo { use FooTrait; } $foo = new Foo(); echo $foo->bar; // => "bar"
  • 20.
    Short array syntax $myIndexedArray= [ 'key1' => 1, 'key2' => 2 ]; $myBoringArray = [1, 2, 3];
  • 21.
    Function array dereferencing functionfoo() { return ['one', 'two', 'three']; } echo foo()[0]; // => "one"
  • 22.
    Class member accesson instantiation class Foo { public function bar() { // ... } } (new Foo()) ->bar();
  • 23.
  • 24.
  • 25.
    • No more“C” class name prefix • Namespaces resemble the folder structure (PSR-4) • No more Yii::import() • Path aliases define the root namespaces for the autoloader Class name/namespace changes
  • 26.
    Path alias example Yii::setAlias('@foo','/path/to/foo'); echo Yii::getAlias('@foo/subpath'); // => "/path/to/foo/subpath"
  • 27.
    Important path aliasesto be aware of Path Alias Server Path Root Namespace @yii …/app/vendor/yiisoft/yii2 yii @craft/app …/app craftapp @craft/plugins/foo …/plugins/foo craftpluginsfoo
  • 28.
  • 29.
    • Base classfor everything • Property getters/setters • Event handling • Behaviors CComponent in Yii 1
  • 30.
  • 31.
    • The newbase class for everything • Only does property
 getters/setters Object
  • 32.
    • Extends Object •Event handling • Behaviors Component
  • 33.
    • Extend Objectfor classes that don’t do anything besides represent data (glorified arrays) • Extend Component for everything else When to use which?
  • 34.
    • yiibaseEvent • yiidbTableSchema •yiimailBaseMessage • yiiwebCookieCollection • yiiwebUrlRule Object examples
  • 35.
    • yiibaseModel • yiidbConnection •yiii18nI18N • yiimailBaseMailer • yiiwebRequest Component examples
  • 36.
  • 37.
    • Define objectconfig settings as public properties • Pass configuration arrays into the object constructor Configuring objects
  • 38.
    Object configuration examples classUser extends Object { public $age; } $user = new User(['age' => 21]);
  • 39.
    Object configuration examples classUser extends Object { public function setAge($age) { // ... } public function getAge() { // ... } } $user = new User(['age' => 21]);
  • 40.
    Object configuration examples $user= Yii::createObject('fooUser'); $user = Yii::createObject([ 'class' => 'fooUser', 'age' => 21 ]);
  • 41.
  • 42.
    • Base: yiidiServiceLocator •They have sub-components • Components accessed via magic getters and get() • Subcomponents are created the first time they’re requested Service locators
  • 43.
  • 44.
    • Base: yiibaseModule •They are service locators, so they have sub-components • They also have controllers, views, and sub-modules Modules
  • 45.
  • 46.
    • Base: yiibaseApplication •They are modules • They handle the request • Only one application per request Applications
  • 47.
    • Web requests:
 yiiwebApplication
 •Console requests:
 yiiconsoleApplication Two application classes
  • 48.
  • 49.
    • Web andconsole applications have controllers (no more “console command” classes) • Controller action routing works the same either way • They return the response Controllers
  • 50.
  • 51.
    • Request classesdefine the incoming web/console request • Response classes define the outgoing web/console response • The response is automatically sent at the end of the application processing Request vs. response
  • 52.
    • Describes theHTTP request • Method (GET, POST, etc.) • Ajax/Pjax/Flash? • Headers, body, parameters • Acceptable content types/languages • HTTP authentication • URL, host name, URI, port, SSL • Referrer, user agent, client IP yiiwebRequest
  • 53.
    • Describes theconsole command • Requested route • Requested parameters yiiconsoleRequest
  • 54.
    • Defines theHTTP response • Status code (200, 404, etc.) • Headers • Cookies • Body yiiwebResponse
  • 55.
    • HTML • XML •JSON • JSONP Web response formats
  • 56.
    Formatted response examples $response= Yii::$app->getResponse(); $response->data = $user; $response->format = 'json'; $response->send(); { "id": 5, "username": "admin", "age": 21 }
  • 57.
    Formatted response examples $response= Yii::$app->getResponse(); $response->data = $user; $response->format = 'xml'; $response->send(); <response> <id>5</id> <username>admin</username> <age>21</age> </response>
  • 58.
  • 59.
    • Defined by“onEventName()” methods on component classes • Attached by setting a magic “onEventName” property • Raised by calling raiseEvent() within the event method Events in Yii 1
  • 60.
    Yii 1 eventexample class User extends CComponent { public function wake() { $this->onWake(new CEvent()); } public function onWake($ev) { $this->raiseEvent('onWake', $ev); } } $user = new User(); $user->onWake = function($ev){/*...*/};
  • 61.
    • Not explicitlypredefined • Attached by calling on() • Raised by calling trigger() Events in Yii 2
  • 62.
    Yii 2 eventexample class User extends Component { public function wake() { $this->trigger('afterWake'); } } $user = new User(); $user->on('afterWake', function($ev){ // ... });
  • 63.
  • 64.
    Class-level event handlerexample Event::on('fooUser', 'afterWake', function($ev) { // ... } );
  • 65.
  • 66.
    • For JSand CSS resources • They can have dependencies • They can publish their files into the web root when registered • They can compile LESS, Sass, Stylus, and CoffeeScript Asset bundles
  • 67.
    Defining an assetbundle class AppAsset extends AssetBundle { public $sourcePath = '@app/assets'; public $basePath = '@web/assets'; public $depends = [ 'yiiwebJqueryAsset' ]; public $css = [ 'css/app.scss' ]; }
  • 68.
    Registering an assetbundle Yii::$app->view->registerAssetBundle( 'fooAppAsset' );
  • 69.
  • 70.
    • All SELECTqueries are defined by yiidbQuery objects • All other queries are defined by yiidbCommand objects • Schema-specific SQL is always built with QueryBuilder DB Queries
  • 71.
    Query methodsQuery DefinitionQuery Execution select() distinct() from() where() innerJoin() leftJoin() rightJoin() groupBy() having() union() orderBy() limit() offset() batch() each() all() one() scalar() column() count() sum() average() min() max() exists() createCommand()
  • 72.
    SELECT query examples $user= (new Query()) ->from('{{%users}}') ->where(['id' => 5]) ->one();
  • 73.
    SELECT query examples $users= (new Query()) ->from('{{%users}}') ->where('age >= :min', [ ':min' => 21 ]) ->all();
  • 74.
    Command methodsQuery DefinitionQuery Management Query Execution insert() batchInsert() update() delete() createTable() renameTable() dropTable() truncateTable() addColumn() dropColumn() renameColumn() alterColumn() addPrimaryKey() dropPrimaryKey() addForeignKey() dropForeignKey() createIndex() dropIndex() cache() noCache() getSql() setSql() getRawSql() prepare() cancel() bindParam() bindPendingParams() bindValue() bindValues() query() queryAll() queryOne() queryScalar() queryColumn() execute()
  • 75.
    More query examples Yii::$app->db->createCommand() ->insert('users',[ 'username' => 'brandon' 'age' => 29 ]) ->execute();
  • 76.
  • 77.
    How they maptogether Query Execution Method Command Execution Method all() queryAll() one() queryOne() count() sum() average() min() max() exists() scalar() queryScalar() column() queryColumn()
  • 78.
  • 79.
    • Base: yiidbActiveRecord •Records’ ::find() methods return ActiveQuery objects • ActiveQuery handles the query definition and active record object population Active Record
  • 80.
    Active record queryexample $users = User::find() ->where('age => :min', [ ':min' => 21 ]) ->all();
  • 81.
  • 82.
    • Yii 2uses PHP’s Intl extension to format dates, numbers, etc. • Only very basic single-language fallbacks built-in. • Only 30% of servers have Intl • What could go wrong? Internationalization
  • 83.
  • 84.
    • No moreCraft namespace • Namespaces reflect the folder structure now • Root namespace is craftapp • Plugins’ root namespaces follow the pattern craftpluginsfoo Namespaces
  • 85.
    • Craft 2:craft() returns the CraftWebApp instance • Craft 3: Craft::$app returns the
 craftappwebApplication instance Accessing the Application instance
  • 86.
    • Magic propertynames are still available:
 Craft::$app->entries • We’ve also added getter methods for all services:
 Craft::$app->getEntries() Accessing the Application components
  • 87.
    • userSession isnow user / getUser() • httpSession is now session / getSession() Application component name changes
  • 88.
  • 89.
    • In Craft2, routes pointed to templates by default, and could point to a controller action with a special syntax • That’s reversed in Craft 2: by default routes point to actions Routes and controllers
  • 90.
    Craft 2 routeexample return array( // Template route: 'foo' => 'path/to/template', // Controller action route: 'bar' => array( 'action' => 'foo/bar' ) );
  • 91.
    Craft 3 routeexample return [ // Template route: 'foo' => [ 'template' => 'template/path', ], // Controller action route: 'bar' => 'foo/bar' ];
  • 92.
    • Params capturedby URL rules are now passed directly to the action’s arguments • URL Manager’s setRouteVariables() is now setRouteParams() Routes and controllers
  • 93.
  • 94.
    • No moredefineAttributes() • Attributes must be defined as public properties on the model • Validation rules must be defined in the rules() method Model changes in Craft 3
  • 95.
    Craft 2 modelexample class User extends BaseModel { protected function defineAttributes() { return array( 'id' => AttributeType::Number, 'age' => AttributeType::Number ); } }
  • 96.
    Craft 3 modelexample class User extends Model { public $id; public $age; public function rules() { return [ ['id,age', 'number'] ]; } }
  • 97.
  • 98.
    • No moredefineAttributes() • Column names are determined by analyzing the table • Validation rules must be defined in the rules() method • Records no longer create tables Record changes in Craft 3
  • 99.
  • 100.
    • TemplatesService isnow craftappwebView • include*()→register*() • render()→renderTemplate() • register[Css|Js]Resource() register asset bundles Templates
  • 101.
    • “beginPage”, “endPage”, “beginBody”,and “endBody” events are triggered when rendering templates Templates
  • 102.
  • 103.
    • No moreseparation of component models and their “type” classes ‘Types
  • 104.
    Field type architectureCraft2 Craft 3 Field Model Field Type Field Model
  • 105.
    Widget type architectureCraft2 Craft 3 Widget Model Widget Type Widget Model
  • 106.
    Task type architectureCraft2 Craft 3 Task Model Task Type Task Model
  • 107.
    Element type architectureCraft2 Craft 3 Element Model Element Type Element Model
  • 108.
  • 109.
    • No moredefineSettings() • Settings are now defined directly on the component classes as public properties ‘Type settings
  • 110.
    Craft 2 fieldtype example class XFieldType extends BaseFieldType { protected function defineSettings() { return array( 'maxlen' => AttributeType::Number ); } // ... }
  • 111.
    Craft 3 fieldtype example class X extends Field { public $maxlen; // ... }
  • 112.
  • 113.
    • ElementCriteriaModel , modifyElementsQuery(),and defineCriteriaAttributes() are dead! • Replaced with Element Query classes Element Queries
  • 114.
    • Elements’ ::find()methods return ElementQuery objects • ElementQuery handles the query definition and element object population Element Queries
  • 115.
    • Element typesthat need custom query parameters can extend ElementQuery and override their element class’ ::find() method to return their custom element query class Element Queries
  • 116.
    • Element querieshave protected beforePrepare() and afterPrepare() methods that can be overridden to support custom parameters Element Queries
  • 117.
    Element query example classUser extends Element { public static function find() { return new UserQuery( get_called_class() ); } // ... }
  • 118.
    Element query example classUserQuery extends ElementQuery { public $age; protected function beforePrepare() { if ($this->age) { $this->subQuery->andWhere( ['age' => $this->age] ); } return parent::beforePrepare(); } }
  • 119.
  • 120.
    • Primary pluginclass is no longer necessary • Plugins are modules • General plugin info now defined by config.json Plugins
  • 121.
    config.json example { "name": "Foo", "version":"1.0", "developer": "Pixel & Tonic", "developerUrl": "http://foo.com" }
  • 122.
    • Plugins aremodules • Primary plugin class is optional • General plugin info now defined in config.json • No more strict class name/folder requirements Plugins
  • 123.
  • 124.
    • Craft 2would automatically create/drop tables based on your records on install/uninstall • Craft 3 leaves it up to the plugin, calling its install() and uninstall() methods Installing Plugins
  • 125.
    • By default,install() and uninstall() will check for an “Install” migration within the plugin, and call its safeUp() and safeDown() methods Installing Plugins
  • 126.
    • Craft hasan InstallMigration class that can be extended • All you have to do is override its defineSchema() function, defining your plugin’s default table schema. Installing Plugins
  • 127.
    Install migration example classInstall extends InstallMigration { protected function defineSchema() { '{{%foo_users}}' => [ 'columns' => [ 'username' => 'string(36)', 'age' => 'integer' ] ] } }
  • 128.
    • Craft hasits own Install migration that the installer runs:
 craft/app/migrations/Install.php • Also shows how to add default content to the tables Installing Plugins
  • 129.
  • 130.
    Thank you! Try theCraft 3 Dev Preview today at buildwithcraft.com/3