symfony & javascript. combining the best of two worlds

Post on 27-Jan-2015

114 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

 

TRANSCRIPT

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/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”:”nacho@limenius.com”, “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”:”nacho@limenius.com”, “phone”: “666666666” }, {...},]

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

nacho@limenius.com

top related