Symfony & Javascript. Combining the best of two worlds
-
Upload
nacho-martin -
Category
Technology
-
view
108 -
download
2
description
Transcript of Symfony & Javascript. Combining the best of two worlds
Symfony & JavaScript
Combining the best of two worlds
Nacho Martín@nacmartin
Symfony & JavaScript
Combining the best of two worlds
Nacho Martín@nacmartin
A bit of history
Client
Server
Client
Server
Client
Server
What’s that??
What’s that??
It’s just a JavaScript
Client
Server
Client
Server
Client
Server
Client
Server
Client
Server
Why should I care?
Users like it
Users like it
You want to do it
Users it
You want to do it
expect
Users it
You to do itneed
expect
It’s still just a JavaScript
But, but...
JavaScript is HARD
Sequential
Sequential
Sequential
Sequential
Sequential
Sequential
Sequential
Asynchronous
Asynchronous
Asynchronous
AsynchronousCall me back
Asynchronous
Asynchronous
Asynchronous
Done !
Asynchronous
for(var i = 1; i <= 5; i++) { console.log(i);}
for(var i = 1; i <= 5; i++) { console.log(i);}
12345
for(var i = 1; i <= 5; i++) { setTimeout(function() { console.log(i); }, 100);}
for(var i = 1; i <= 5; i++) { setTimeout(function() { console.log(i); }, 100);}
66666
for(var i = 1; i <= 5; i++) { (function() { var j = i; setTimeout( function() { console.log(j); }, 100); })();}
for(var i = 1; i <= 5; i++) { (function() { var j = i; setTimeout( function() { console.log(j); }, 100); })();}
12345
Callback nesting
Callback nesting
• Events
Callback nesting
• Events• Async.js
“this” gotchavar o = {};o.prop = {};
var o.f1 = function(){ var that = this;
this.prop.active = false;
var activate = function(){ that.prop.active = true;
};
activate();
};
“this” gotchavar o = {};o.prop = {};
var o.f1 = function(){ var that = this;
this.prop.active = false;
var activate = function(){ that.prop.active = true;
};
activate();
};
http://www.flickr.com/photos/bensonkua/3161323177/in/photostream/
Douglas Crockford
But, but...
But, but...
•Can be ugly
But, but...
•Can be ugly
•Tons of crappy code
But, but...
•Can be ugly
•Tons of crappy code
•Inconsistencies
But, but...
•Can be ugly
•Tons of crappy code
•Inconsistencies
•Weird stuff inside
But, but...
•Can be ugly
•Tons of crappy code
•Inconsistencies
•Weird stuff inside
•Huge community
But, but...
•Can be ugly
•Tons of crappy code
•Inconsistencies
•Weird stuff inside
•Huge community
•Easy to get help
But, but...
•Can be ugly
•Tons of crappy code
•Inconsistencies
•Weird stuff inside
•Huge community
•Easy to get help
•Low entry barrier
But, but...
•Can be ugly
•Tons of crappy code
•Inconsistencies
•Weird stuff inside
•Huge community
•Easy to get help
•Low entry barrier
•Is everywhere
http://www.flickr.com/photos/73935252@N00/181308667
http://www.flickr.com/photos/73935252@N00/181308667http://www.flickr.com/photos/39865537@N03/4395203300
The team needs discipline
compromise readablity
http://www.flickr.com/photos/43322231@N07/5589147122
Pick your battles
is the perfect complement
is the perfect complement
Client side JS
Text
Level I
http://www.flickr.com/photos/lecates/307250887/
Assetic
FOSJsRouterBundle
/** * @Route ("/foo/{id}/bar", name="my_route_to_expose", options={"expose"=true}) */public function exposedAction($foo)
Routing.generate('my_route_to_expose', { id: 10 });// /foo/10/bar
PHP
JS
Text
Level II
http://www.flickr.com/photos/49766155@N07/4945673508
Client
Server
Client
Server
Client
Server
Then Symfony...?
Then Symfony...?
Still does almost everything
•Small library
•Stable for JS world
•Active
•Open Source
•Popular
•Models
•Collections
•Views
•Templates
•Routing
•Models
•Repositories
•Controllers
•Views
•Routing
ModelModel
View
ModelModel
View
Books.fetch()
Books=new Backbone.collection();
Books.url = ‘/books’;
ModelModel
View
GET /books
Books.fetch()
Books=new Backbone.collection();
Books.url = ‘/books’;
ModelModel
View
GET /books
Books.fetch()
Books=new Backbone.collection();
Books.url = ‘/books’;
ModelModel
View
GET /books
Books.fetch()
Books=new Backbone.collection();
Books.url = ‘/books’;
Books.on(‘reset’, this.render);
ModelModel
View
GET /books
Books.fetch()
Books=new Backbone.collection();
Books.url = ‘/books’;
Books.on(‘reset’, this.render);
ModelModel
View
GET /books
Books.fetch()
Books=new Backbone.collection();
Books.url = ‘/books’;
Books.on(‘reset’, this.render);
ModelModel
View
ModelModel
Viewevents: { ‘click .mybutton’: ‘doStuffAndSave’}
ModelModel
Viewevents: { ‘click .mybutton’: ‘doStuffAndSave’}
ModelModel
Viewevents: { ‘click .mybutton’: ‘doStuffAndSave’}
doStuffAndSave: function() { var book = Books.get(3); book.stuff(); Books.get(3).save();}
ModelModel
Viewevents: { ‘click .mybutton’: ‘doStuffAndSave’}
doStuffAndSave: function() { var book = Books.get(3); book.stuff(); Books.get(3).save();}
ModelModel
View
PUT /books/3
events: { ‘click .mybutton’: ‘doStuffAndSave’}
doStuffAndSave: function() { var book = Books.get(3); book.stuff(); Books.get(3).save();}
http://www.flickr.com/photos/kaptainkobold/3203311346/
Build an API
FOSRestBundle
/** * @View() * GET /users */ public function getUsersAction() { return $this->getDoctrine()->getRepository('myBundle:User')->findAll(); }
Response[ {“id”:1, “name”:”nacho”, “password”: “X$$%$X”, “email”:”[email protected]”, “profile”: { “id”:3, “phone”: “666666666”} } }, {...},]
JMSSerializerMyBundle\User: exclusion_policy: ALL properties: id: expose: true name: expose: true email: expose: true
MyBundle\User: exclusion_policy: ALL properties: id: expose: true name: expose: true email: expose: true callback_methods: pre_serialize: serializeProfile
JMSSerializer
JMSSerializer
public function serializeProfile(){ $this->phone = $this->profile->getPhone(); $this->profile = null;}
Response
[ {“id”:1, “name”:”nacho”, “email”:”[email protected]”, “phone”: “666666666” }, {...},]
Deserialize forms
•SimpleThingsFormSerializeBundle
•Symfony-cmf/CreateBundle
•http://williamdurand.fr/2012/08/02/rest-apis-with-symfony2-the-right-way/
NelmioApiDocBundle
Twig.js
Twig
Twig.js
TwigBackbone
Twig.js
{% javascripts "@MyBundle/Resources/views/tmpl.html.twig" filter="twig_js, ?yui_js" %} <script language="javascript" src="{{ asset_url }}"> </script>{% endjavascripts %}
Server side JS
Client
Server
Client
Server
Client
Server
Client
Server
What for
•Streaming data
What for
•Streaming data
•Soft realtime
•Chats
•Notifications
What for
Challenges to face
•Organization of a big code base
Challenges to face
•Organization of a big code base
•General lower level of abstraction
Challenges to face
•Organization of a big code base
•General lower level of abstraction
•Deployment
•Serving static files
Challenges to face
•Organization of a big code base
•General lower level of abstraction
•Deployment
•Serving static files
Challenges to face
Use case:Notifications
♥
♥
♥
♥
Websockets
io.sockets.on('connection', function (socket) { socket.join('user1'); socket.broadcast.to('user1').emit('Hi user 1');});
http://www.flickr.com/photos/45940879@N04/6277724736
Dealing with secrets
http
MQ
The pusher way
secret secret
The pusher way
socket id
secret secret
The pusher way
socket id
chan
nel n
ame &
sock
et id
secret secret
The pusher way
socket id
chan
nel n
ame &
sock
et id
key:s
ignatu
re
secret secret
The pusher way
socket id
chan
nel n
ame &
sock
et id
key:s
ignatu
rechannel name &
key:signature
secret secret
Deploy
Deploy
Deploy
It’s just a JavaScript
Thanks
http://www.flickr.com/photos/95572727@N00/2380543038
Nacho Martín@nacmartin