Internetnutzer sind es heutzutage gewohnt, dass Webseiten unmittelbar auf Interaktion reagieren und ohne häufiges Nachladen funktionieren. Techniken, die solche Webseiten ermöglichen, sollten durch die Zuhilfenahme zuverlässiger Frameworks umgesetzt werden. Serverseitig ist für viele Entwickler Symfony das Mittel der Wahl, im Browser kann es Ember.js sein, das vor allem im Bereich der Single-Page-Applikationen glänzt. Mit beiden zusammen kann also nichts mehr schief gehen, oder?
Dieser Vortrag zeigt Symfony und Ember.js in Kombination und wie man umdenken muss, wenn man gewohnt ist, klassische Webseiten zu entwickeln. Speziell geht er auf die dabei auftretenden Herausforderungen im Templating, Routing und bei der Model-Synchronisierung ein.
25. var Post = DS.Model.extend({
title: DS.attr(),
body: DS.attr(),
date: DS.attr(),
slug: DS.attr(),
comments: DS.hasMany('comment', { async: true }),
teaser: function () {
return this.get('body').substr(0, 100);
}.property('body')
});
m o d e l s / p o s t . j s
26. S T O R E
A D A P T E R
J S A P P L I K AT I O N
R E S T F U L A P I
30. ro u t e r. j s
var BlogPostRoute = Ember.Route.extend({
model: function (params) {
return this.store.find('post', { slug: params.slug });
},
serialize: function(model) {
return { slug: model.get('slug') };
}
});
ro u t e s / b l o g / p o s t . j s
Router.map(function() {
this.resource('blog', { path: '/' }, function () {
this.route('post', { path: '/:slug' });
});
});
31. DS.RESTAdapter.extend({
namespace: ‘app_dev.php/api’
});
a d a p t e r s / a p p l i c a t i o n . j s
this.store.find('post')
GET /app_dev.php/api/posts
this.store.find(‘post’, { slug: ‘first-post’ })
GET /app_dev.php/api/posts?slug=first-post
this.store.find(‘post’, 1)
GET /app_dev.php/api/posts/1
32. R E S T F U L A P I
C O N T R O L L E R
R E P O S I T O RY
D ATA B A S E
33. R E S T F U L A P I
jms/serializer
willdurand/negotiation
symfony/symfony
willdurand/hateoas
http://www.slideshare.net/seiffertp
composer require
40. <div class="blog-post">
<h1>{{#link-to 'blog.post' slug}}{{title}}{{/link-to}}</h1>
<div class="blog-post-content">
{{body}}
</div>
<div class="blog-post-comments">
{{#each comments}}
{{partial 'blog/comment'}}
{{/each}}
</div>
</div>
{{#link-to 'blog.index'}}Zurück zur Liste{{/link-to}}
b l o g / p o s t . h b s
41. var Post = DS.Model.extend({
title: DS.attr(),
body: DS.attr(),
date: DS.attr(),
slug: DS.attr(),
comments: DS.hasMany('comment', { async: true }),
teaser: function () {
return this.get('body').substr(0, 100);
}.property('body')
});
m o d e l s / p o s t . j s
42. <div class="blog-post">
<h1>{{#link-to 'blog.post' slug}}{{title}}{{/link-to}}</h1>
<div class="blog-post-content">
{{body}}
</div>
<div class="blog-post-comments">
{{#each comments}}
{{partial 'blog/comment'}}
{{/each}}
</div>
</div>
{{#link-to 'blog.index'}}Zurück zur Liste{{/link-to}}
b l o g / p o s t . h b s
45. $ ember serve —-proxy=http://symfony-api:80
version: 0.0.43
Proxying to http://symfony-api:80
Livereload server on port 35729
Serving on http://0.0.0.0:4200
$ npm install -g ember-cli
46.
47.
48. B R O W S E R
HTTP + Socket
N G I N X
S Y M F O N Y A P P
GET /app_dev.php/api/…
P H P - F P M
D e v e l o p m e n t
Lokal
Vagrant
VM
49. B R O W S E R
N G I N X
S Y M F O N Y A P P
GET /api/…
P H P - F P M
P ro d u c t i o n
GET /