SlideShare a Scribd company logo
Building SPA with Symfony2 and 
AngularJS 
Antonio Perić-Mažar 
02.10.2014, ZgPHP Conference 2014 
https://joind.in/12007
About me 
• Antonio Perić-Mažar, 
mag. ing. comp. 
• CEO @ locastic 
• Software developer, Symfony2 
• Sylius Awesome Contributor :) 
• www.locastic.com 
• antonio@locastic.com 
• twitter: @antonioperic
Who we are? 
• locastic (www.locastic.com) 
• Web and mobile development 
• UI/UX design 
• Located in Split, Croatia
Our works?
Building Single Page Application (SPA) with Symfony2 and AngularJS
Symfony2 AngularJS 
Usage, language Backend, PHP Frontend, Javascript 
Dependency Injection Yes Yes 
Templating Twig HTML 
Form component Yes Yes 
Routing component Yes Yes 
MVC Yes Yes 
Testable Yes Yes 
Services Yes Yes 
Events Yes Yes 
i18n Yes Yes 
Dependency management Yes Yes 
Deteatciled comparison: http://vsch.a..rt.com/compare/a..n. gularjs/vs/symfony
SPA 
 Aka SPI (Single Page interface) 
 desktop apps UX 
 HTML / JS / CSS / etc in single page load 
 fast 
 AJAX and XHR
Building Single Page Application (SPA) with Symfony2 and AngularJS
UI == APP
SPA Arhitecture 
Backend (rest api) with Symfony2 
Frontend with AngularJs 
Separation or combination?
SPA Arhitecture 
Backend (rest api) with Symfony2 
Frontend with AngularJs 
Separation or combination?
RESTful ws 
Simpler than SOAP & WSDL 
Resource-oriented (URI) 
Principles: 
HTTP methods (idempotent & not) 
stateless 
directory structure-like URIs 
XML or JSON (or XHTML) 
GET (vs HEAD), POST, PUT (vs PATCH), DELETE, OPTIONS
Building Rest API with SF2 
There is bundle for everything in Sf2. Right? 
So lets use some of them!
Building Rest API with SF2 
What we need? 
JMSSerializerBundle 
FOSRestBundle 
NelmioApiDocBundle
Building Rest API with SF2 
JMSSerializerBundle 
(de)serialization 
via annotations / YAML / XML / PHP 
integration with the Doctrine ORM 
handling of other complex cases (e.g. circular references)
Building Rest API with SF2 
LocasticBundleTodoBundleEntityTodo: 
# exclusion_policy: ALL 
exclusion_policy: NONE 
properties: 
# description: 
# expose: true 
createdAt: 
# expose: true 
exclude: true 
deadline: 
type: DateTime<'d.m.Y. H:i:s'> 
# expose: true 
done: 
# expose: true 
serialized_name: status
Building Rest API with SF2 
fos_rest: 
disable_csrf_role: ROLE_API 
param_fetcher_listener: true 
view: 
view_response_listener: 'force' 
formats: 
xml: true 
json: true 
templating_formats: 
html: true 
format_listener: 
rules: 
- { path: ^/, priorities: [ html, json, xml ], fallback_format: ~, prefer_extension: true } 
exception: 
codes: 
'SymfonyComponentRoutingExceptionResourceNotFoundException': 404 
'DoctrineORMOptimisticLockException': HTTP_CONFLICT 
messages: 
'SymfonyComponentRoutingExceptionResourceNotFoundException': true 
allowed_methods_listener: true 
access_denied_listener: 
json: true 
body_listener: true
Building Rest API with SF2 
/** 
* @ApiDoc( 
* resource = true, 
* description = "Get stories from users that you follow (newsfeed)", 
* section = "Feed", 
* output={ 
* "class" = "LocasticBundleFeedBundleEntityStory" 
* }, 
* statusCodes = { 
* 200 = "Returned when successful", 
* 400 = "Returned when bad parameters given" 
* } 
* ) 
* 
* @RestView( 
* serializerGroups = {"feed"} 
* ) 
*/ 
public function getFeedAction() 
{ 
$this->get('locastic_auth.auth.handler')->validateRequest($this->get('request')); 
return $this->getDoctrine()->getRepository('locastic.repository.story')->getStories($this- 
>get('request')->get('me')); 
}
Building Rest API with SF2
Templating 
TWIG <3
Templating 
<!DOCTYPE html> 
<html> 
<head> 
<meta charset="UTF-8" /> 
<title>{% block title %}Welcome!{% endblock %}</title> 
{% block stylesheets %} 
<!-- Place favicon.ico and apple-touch-icon.png in the root directory --> 
{#<link rel="stylesheet" href="{{ asset('css/normalize.css') }}">#} 
<link rel="stylesheet" href="{{ asset('css/main.css') }}"> 
<!-- load bootstrap and fontawesome via CDN --> 
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" /> 
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.0/css/font-awesome.css" /> 
<script src="{{ asset('js/vendor/modernizr-2.6.2.min.js') }}"></script> 
{% endblock %} 
<link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" /> 
</head> 
<body> 
{% block body %}{% endblock %} 
{% block javascripts %} 
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script> 
<script src="https://code.angularjs.org/1.2.16/angular-route.min.js"></script> 
<script src="{{ asset('js/main.js') }}"></script> 
{% endblock %} 
</body> 
</html>
Templating 
Problem: 
{{ interpolation tags }} - used both by twig and AngularJS
Templating 
{% verbatim %} 
{{ message }} 
{% endverbatim %}
Templating 
var phpDayDemoApp = angular.module('phpDayDemoApp', [], 
function($interpolateProvider) { 
$interpolateProvider.startSymbol('[['); 
$interpolateProvider.endSymbol(']]'); 
}); 
Now we can use 
{% block content %} 
[[ message ]] {# rendered by AngularJS #} 
{% end block %} 
Tweak Twig lexer delimiters? Bad idea.
Templating 
Using assetic for minimize 
{% javascripts 
"js/angular-modules/mod1.js" 
"#s/angular-modules/mod2.js" 
"@AngBundle/Resources/public/js/controller/*.js" 
output="compiled/js/app.js" 
%} 
<script type="text/javascript" src="{{ asset_url }}"></script> 
{% endjavascripts %}
Templating 
Using assetic for minimize 
Since Angular infers the controller's dependencies from the names of 
arguments to the controller's constructor function, if you were to minify the 
JavaScript code for PhoneListCtrl controller, all of its function arguments 
would be minified as well, and the dependency injector would not be able 
to identify services correctly. 
Use an inline annotation where, instead of just providing the function, you 
provide an array. This array contains a list of the service names, followed by 
the function itself. 
function PhoneListCtrl($scope, $http) {...} 
phonecatApp.controller('phpDayCtrl', ['$scope', '$http', PhoneListCtrl]);
Templating 
Frontend developers still can use their tools like: 
Bower 
Grunt 
Etc.
Managing routes 
Client side: 
ngRoute 
independent since Angular 1.1.6 
hashbang #! & HTML5 mode 
<base href="/"> 
$locationProvider 
.html5Mode(true) 
.hashPrefix('!'); 
Also good for SEO!
Managing routes 
http://localhost/todos 
http://localhost/#todos 
Resolving conflicts 
Fallback, managing 404 
angular: 
path: '/{route}' 
defaults: { _controller: LocasticAngularBundle:Default:index} 
requirements: 
route: ".+"
Managing routes – client side 
// module configuration...$routeProvider.when('/todos/show/:id', { 
templateUrl : 'todo/show', 
controller : 'todoController' 
}) 
// receive paramssfugDemoApp.controller('todoController', function($scope, $http, $routeParams){ 
$scope.todo = {}; 
$http 
.get('/api/todo/show/' + $routeParams.id) 
.success(function(data){ 
$scope.todo = data['todo']; 
}); 
});
Managing routes 
Think of using FOSJsRoutingBundle for Frontend route 
managament 
<script 
src="{{ asset('bundles/fosjsrouting/js/router.js') }}"></script> 
<script src="{{ path('fos_js_routing_js', {"callback": 
"fos.Router.setData"}) }}"></script> 
my_route_to_expose_with_defaults: 
pattern: /blog/{page} 
defaults: { _controller: AcmeBlogBundle:Blog:index, page: 1 
}
Managing routes – server side 
locastic_rest_todo_getall: 
pattern: /api/get-all 
defaults: 
_controller: LocasticRestBundle:Todo:getAll 
locastic_rest_todo_create: 
pattern: /api/create 
defaults: 
_controller: LocasticRestBundle:Todo:create 
locastic_rest_todo_show: 
pattern: /api/show/{id} 
defaults: 
_controller: LocasticRestBundle:Todo:show
Translations 
AngularJS has its own translation system 
I18N/L10N . But it might be interesting to monitor 
and centralize translations from your backend 
Symfony. 
JMSTranslationBundle
Forms 
Symfony Forms <3 
We don't want to throw them away 
Build custom directive
Forms 
sfugDemoApp.directive('ngToDoForm', function() { 
return { 
restrict: 'E', 
template: '<div class="todoForm">Form will be!</div>' 
} 
}); 
'A' - <span ng-sparkline></span> 
'E' - <ng-sparkline></ng-sparkline> 
'C' - <span class="ng-sparkline"></span> 
'M' - <!-- directive: ng-sparkline → 
Usage of directive in HTML: 
<ng-to-do-form></ng-to-do-form>
Forms 
sfugDemoApp.directive('ngToDoForm', function() { 
return { 
restrict: 'E', 
templateUrl: '/api/form/show.html' 
} 
});
Forms 
sfugDemoApp.directive('ngToDoForm', function() { 
return { 
restrict: 'E', 
templateUrl: '/api/form/show.html' 
} 
}); 
locastic_show_form: 
pattern: /form/show.html 
defaults: 
_controller: LocasticWebBundle:Default:renderForm 
public function renderFormAction() 
{ 
$form = $this->createForm(new TodoType()); 
return $this->render('LocasticWebBundle::render_form.html.twig', array( 
'form' => $form->createView() 
)); 
}
Forms 
Suprise!!!
Forms 
Template behind directive 
<form class="form-inline" role="form" style="margin-bottom: 30px;"> 
Create new todo: 
<div class="form-group"> 
{{ form_label(form.description) }} 
{{ form_widget(form.description, {'attr': {'ng-model': 'newTodo.description', 'placeholder': 
'description', 'class': 'form-control'}}) }} 
</div> 
<div class="form-group"> 
<label class="sr-only" for="deadline">Deadline</label> 
<input type="text" class="form-control" id="deadline" placeholder="deadline (angular-ui)" ng-model=" 
newTodo.deadline"> 
</div> 
<input type="button" class="btn btn-default" ng-click="addNew()" value="add"/> 
</form>
Submitting forms? 
When the AngularJS $http service POSTs data the header application/x-www-form-urlencoded 
is never set (unlike jQuery’s $.ajax()). Also, the $http data is not serialized 
when sent. Both of these facts mean that the $_POST variable is never set properly by 
php. Without the $_POST variable Symfony’s built in form handling cannot be used. 
The fix is actually pretty simple: 
 angular needs to forced into setting a header 
 the data needs to be serialized 
 and the data needs to be normalized into a multidimensional array.
Submitting forms? 
var postData = { 
formtype_name: { 
id: some_id, 
name: some_name 
} 
}; 
$http({ 
method: "POST", 
url: url, 
headers: { 
'Content-Type': 'application/x-www-form-urlencoded' 
}, 
data: $.param(postData) 
});
Same-origin policy 
For security reasons, web browsers prevent JavaScript to Ajax requests (XMLHttpRequest) 
to other areas ( Same-origin policy ). 
An example of exception thrown by the browser: 
XMLHttpRequest cannot load http://api.mondomaine.com/v1/maressource.json. 
Invalid HTTP status code 405 
 Using JSOP (Json with Padding) – easy with FOSRestApi 
 Configure server (simple and stupid) 
<VirtualHost *:80> ServerName mon-appli-angular.com DocumentRoot 
/var/www/some-ng-app/ Alias /api /var/www/some-ng-app/ <Directory xxxx> 
</Directory> </VirtualHost> </VirtualHost> 
 Use Cors 
CORS (Cross-origin resource sharing) is an elegant and standardized response to allow 
Cross-domain requests. 
Be careful though, the CORS mechanism is not supported by all browsers (guess 
which ) …
Testing 
Symfony and AngularJS are designed to test. So write test 
Behat 
PHPUnit 
PHPSpec 
Jasmine 
… 
Or whatever you want just write tests
Summary 
The cleanest way is to separate backend and frontend. But there is some 
advantages to use both together. 
Twig + HTML works well. 
Assetic Bundle is very useful to minify bunches of Javascript files used by 
AngularJs 
Translation in the template. the data in the API payload does not need 
translation in most cases. Using Symfony I18N support for the template 
makes perfect sense. 
Loading of Option lists. Say you have a country list with 200+ options. You 
can build an API to populate a dynamic dropdown in angularjs, but as 
these options are static, you can simply build that list in twig. Forms in
And remember 
Keep controllers small and stupid, master Dependency 
injection, delegate to services and events.
Thank you!
QA 
Please rate my talk 
https://joind.in/12007 
follow me on twitter: @antonioperic

More Related Content

PPT
Workshop: Symfony2 Intruduction: (Controller, Routing, Model)
PPT
Symfony2 and AngularJS
PDF
Symfony2, Backbone.js &amp; socket.io - SfLive Paris 2k13 - Wisembly
PDF
Symfony3 w duecie z Vue.js
PDF
Symfony tips and tricks
PDF
Bootstrat REST APIs with Laravel 5
PDF
Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...
PDF
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more
Workshop: Symfony2 Intruduction: (Controller, Routing, Model)
Symfony2 and AngularJS
Symfony2, Backbone.js &amp; socket.io - SfLive Paris 2k13 - Wisembly
Symfony3 w duecie z Vue.js
Symfony tips and tricks
Bootstrat REST APIs with Laravel 5
Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more

What's hot (20)

PPTX
REST APIs in Laravel 101
PDF
Keeping the frontend under control with Symfony and Webpack
PDF
Bullet: The Functional PHP Micro-Framework
ODP
Creating REST Applications with the Slim Micro-Framework by Vikram Vaswani
PDF
Creating a modern web application using Symfony API Platform, ReactJS and Red...
ODP
Javascript laravel's friend
PDF
WebGUI Developers Workshop
PPTX
Laravel 5
PDF
RESTful API development in Laravel 4 - Christopher Pecoraro
PDF
Hello World on Slim Framework 3.x
PPTX
How to Build SPA with Vue Router 2.0
PDF
OSCON Google App Engine Codelab - July 2010
PDF
Silex: From nothing to an API
PDF
RESTful API Design & Implementation with CodeIgniter PHP Framework
PDF
A Little Backbone For Your App
PDF
ACL in CodeIgniter
KEY
Silex, the microframework
PDF
Kyiv.py #17 Flask talk
PDF
AngularJS with Slim PHP Micro Framework
KEY
LvivPy - Flask in details
REST APIs in Laravel 101
Keeping the frontend under control with Symfony and Webpack
Bullet: The Functional PHP Micro-Framework
Creating REST Applications with the Slim Micro-Framework by Vikram Vaswani
Creating a modern web application using Symfony API Platform, ReactJS and Red...
Javascript laravel's friend
WebGUI Developers Workshop
Laravel 5
RESTful API development in Laravel 4 - Christopher Pecoraro
Hello World on Slim Framework 3.x
How to Build SPA with Vue Router 2.0
OSCON Google App Engine Codelab - July 2010
Silex: From nothing to an API
RESTful API Design & Implementation with CodeIgniter PHP Framework
A Little Backbone For Your App
ACL in CodeIgniter
Silex, the microframework
Kyiv.py #17 Flask talk
AngularJS with Slim PHP Micro Framework
LvivPy - Flask in details
Ad

Viewers also liked (20)

PDF
Symfony and Angularjs
PDF
Symfony + AngularJS | Mladen Plavsic @DaFED26
PPTX
Symfony with angular.pptx
ODP
Desarrollo Web Ágil con Symfony, Bootstrap y Angular
PDF
deSymfony 2013 - Creando aplicaciones web desde otro ángulo con Symfony y A...
PPT
Symfony 2 : chapitre 4 - Les services et les formulaires
PPTX
Introduction au business modèle des applications mobile
PDF
Building real time applications with Symfony2
PDF
برنامج جمعية بسمة أمل بوجدة لسنة 2013
PDF
Dependency Injection Smells
PDF
Symfony2 & l'architecture Rest
PDF
Etude des Frameworks PHP
PPTX
Créer une API GraphQL avec Symfony
PDF
Drupal8 for Symfony Developers
PDF
Applications secure by default
PDF
LVIV IT Arena - SmartHome using low cost components
PDF
Building Multi-Tenant and SaaS products in PHP - CloudConf 2015
ODP
SPI server centric SEO compatible stateless web sites... ALLELUIA!
PDF
How to choose a web framework and be surprised
PDF
Design patterns avec Symfony
Symfony and Angularjs
Symfony + AngularJS | Mladen Plavsic @DaFED26
Symfony with angular.pptx
Desarrollo Web Ágil con Symfony, Bootstrap y Angular
deSymfony 2013 - Creando aplicaciones web desde otro ángulo con Symfony y A...
Symfony 2 : chapitre 4 - Les services et les formulaires
Introduction au business modèle des applications mobile
Building real time applications with Symfony2
برنامج جمعية بسمة أمل بوجدة لسنة 2013
Dependency Injection Smells
Symfony2 & l'architecture Rest
Etude des Frameworks PHP
Créer une API GraphQL avec Symfony
Drupal8 for Symfony Developers
Applications secure by default
LVIV IT Arena - SmartHome using low cost components
Building Multi-Tenant and SaaS products in PHP - CloudConf 2015
SPI server centric SEO compatible stateless web sites... ALLELUIA!
How to choose a web framework and be surprised
Design patterns avec Symfony
Ad

Similar to Building Single Page Application (SPA) with Symfony2 and AngularJS (20)

PDF
Building APIs in an easy way using API Platform
PPTX
AngularJS 1.x - your first application (problems and solutions)
PDF
Lone StarPHP 2013 - Building Web Apps from a New Angle
PDF
Crash Course in AngularJS + Ionic (Deep dive)
PDF
AngularJS for Web and Mobile
PDF
Tek 2013 - Building Web Apps from a New Angle with AngularJS
PPTX
Angular js for enteprise application
PPTX
Angular js 1.0-fundamentals
PPTX
Angular training - Day 3 - custom directives, $http, $resource, setup with ye...
PDF
Angular mobile angular_u
PPT
AngularJS and SPA
PDF
AngularJS in Production (CTO Forum)
PDF
Max Voloshin - "Organization of frontend development for products with micros...
PPTX
Angular js workshop
PDF
API Platform 2.1: when Symfony meets ReactJS (Symfony Live 2017)
PPTX
AngularJS with TypeScript and Windows Azure Mobile Services
PDF
Hands-on with the Symfony2 Framework
PDF
The Angular road from 1.x to 2.0
PPTX
Angular jS Introduction by Google
 
PDF
ITB2015 - Crash Course in Ionic + AngularJS
Building APIs in an easy way using API Platform
AngularJS 1.x - your first application (problems and solutions)
Lone StarPHP 2013 - Building Web Apps from a New Angle
Crash Course in AngularJS + Ionic (Deep dive)
AngularJS for Web and Mobile
Tek 2013 - Building Web Apps from a New Angle with AngularJS
Angular js for enteprise application
Angular js 1.0-fundamentals
Angular training - Day 3 - custom directives, $http, $resource, setup with ye...
Angular mobile angular_u
AngularJS and SPA
AngularJS in Production (CTO Forum)
Max Voloshin - "Organization of frontend development for products with micros...
Angular js workshop
API Platform 2.1: when Symfony meets ReactJS (Symfony Live 2017)
AngularJS with TypeScript and Windows Azure Mobile Services
Hands-on with the Symfony2 Framework
The Angular road from 1.x to 2.0
Angular jS Introduction by Google
 
ITB2015 - Crash Course in Ionic + AngularJS

More from Antonio Peric-Mazar (20)

PDF
You call yourself a Senior Developer?
PDF
Using API Platform to build ticketing system #symfonycon
PDF
Using API platform to build ticketing system (translations, time zones, ...) ...
PDF
Are you failing at being agile? #digitallabin
PDF
Symfony 4: A new way to develop applications #ipc19
PDF
A year with progressive web apps! #webinale
PDF
The UI is the THE application #dpc19
PDF
Symfony 4: A new way to develop applications #phpsrb
PDF
REST easy with API Platform
PDF
A year with progressive web apps! #DevConMU
PDF
Service workers are your best friends
PDF
Progressive Web Apps are here!
PDF
Symfony4 - A new way of developing web applications
PDF
Build your business on top of Open Source
PDF
Building APIs in an easy way using API Platform
PDF
Lessons learned while developing with Sylius
PDF
Drupal8 for Symfony developers - Dutch PHP
PDF
Drupal8 for Symfony Developers (PHP Day Verona 2017)
PDF
Maintainable + Extensible = Clean ... yes, Code!
PDF
A recipe for effective leadership
You call yourself a Senior Developer?
Using API Platform to build ticketing system #symfonycon
Using API platform to build ticketing system (translations, time zones, ...) ...
Are you failing at being agile? #digitallabin
Symfony 4: A new way to develop applications #ipc19
A year with progressive web apps! #webinale
The UI is the THE application #dpc19
Symfony 4: A new way to develop applications #phpsrb
REST easy with API Platform
A year with progressive web apps! #DevConMU
Service workers are your best friends
Progressive Web Apps are here!
Symfony4 - A new way of developing web applications
Build your business on top of Open Source
Building APIs in an easy way using API Platform
Lessons learned while developing with Sylius
Drupal8 for Symfony developers - Dutch PHP
Drupal8 for Symfony Developers (PHP Day Verona 2017)
Maintainable + Extensible = Clean ... yes, Code!
A recipe for effective leadership

Recently uploaded (20)

PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
NewMind AI Monthly Chronicles - July 2025
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PPTX
Big Data Technologies - Introduction.pptx
PDF
Machine learning based COVID-19 study performance prediction
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PDF
CIFDAQ's Market Insight: SEC Turns Pro Crypto
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
Electronic commerce courselecture one. Pdf
PPTX
Cloud computing and distributed systems.
PDF
Spectral efficient network and resource selection model in 5G networks
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PDF
Modernizing your data center with Dell and AMD
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
Review of recent advances in non-invasive hemoglobin estimation
PDF
Network Security Unit 5.pdf for BCA BBA.
Agricultural_Statistics_at_a_Glance_2022_0.pdf
NewMind AI Monthly Chronicles - July 2025
Understanding_Digital_Forensics_Presentation.pptx
Big Data Technologies - Introduction.pptx
Machine learning based COVID-19 study performance prediction
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Digital-Transformation-Roadmap-for-Companies.pptx
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
CIFDAQ's Market Insight: SEC Turns Pro Crypto
Per capita expenditure prediction using model stacking based on satellite ima...
Electronic commerce courselecture one. Pdf
Cloud computing and distributed systems.
Spectral efficient network and resource selection model in 5G networks
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Modernizing your data center with Dell and AMD
Reach Out and Touch Someone: Haptics and Empathic Computing
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Review of recent advances in non-invasive hemoglobin estimation
Network Security Unit 5.pdf for BCA BBA.

Building Single Page Application (SPA) with Symfony2 and AngularJS

  • 1. Building SPA with Symfony2 and AngularJS Antonio Perić-Mažar 02.10.2014, ZgPHP Conference 2014 https://joind.in/12007
  • 2. About me • Antonio Perić-Mažar, mag. ing. comp. • CEO @ locastic • Software developer, Symfony2 • Sylius Awesome Contributor :) • www.locastic.com • antonio@locastic.com • twitter: @antonioperic
  • 3. Who we are? • locastic (www.locastic.com) • Web and mobile development • UI/UX design • Located in Split, Croatia
  • 6. Symfony2 AngularJS Usage, language Backend, PHP Frontend, Javascript Dependency Injection Yes Yes Templating Twig HTML Form component Yes Yes Routing component Yes Yes MVC Yes Yes Testable Yes Yes Services Yes Yes Events Yes Yes i18n Yes Yes Dependency management Yes Yes Deteatciled comparison: http://vsch.a..rt.com/compare/a..n. gularjs/vs/symfony
  • 7. SPA  Aka SPI (Single Page interface)  desktop apps UX  HTML / JS / CSS / etc in single page load  fast  AJAX and XHR
  • 10. SPA Arhitecture Backend (rest api) with Symfony2 Frontend with AngularJs Separation or combination?
  • 11. SPA Arhitecture Backend (rest api) with Symfony2 Frontend with AngularJs Separation or combination?
  • 12. RESTful ws Simpler than SOAP & WSDL Resource-oriented (URI) Principles: HTTP methods (idempotent & not) stateless directory structure-like URIs XML or JSON (or XHTML) GET (vs HEAD), POST, PUT (vs PATCH), DELETE, OPTIONS
  • 13. Building Rest API with SF2 There is bundle for everything in Sf2. Right? So lets use some of them!
  • 14. Building Rest API with SF2 What we need? JMSSerializerBundle FOSRestBundle NelmioApiDocBundle
  • 15. Building Rest API with SF2 JMSSerializerBundle (de)serialization via annotations / YAML / XML / PHP integration with the Doctrine ORM handling of other complex cases (e.g. circular references)
  • 16. Building Rest API with SF2 LocasticBundleTodoBundleEntityTodo: # exclusion_policy: ALL exclusion_policy: NONE properties: # description: # expose: true createdAt: # expose: true exclude: true deadline: type: DateTime<'d.m.Y. H:i:s'> # expose: true done: # expose: true serialized_name: status
  • 17. Building Rest API with SF2 fos_rest: disable_csrf_role: ROLE_API param_fetcher_listener: true view: view_response_listener: 'force' formats: xml: true json: true templating_formats: html: true format_listener: rules: - { path: ^/, priorities: [ html, json, xml ], fallback_format: ~, prefer_extension: true } exception: codes: 'SymfonyComponentRoutingExceptionResourceNotFoundException': 404 'DoctrineORMOptimisticLockException': HTTP_CONFLICT messages: 'SymfonyComponentRoutingExceptionResourceNotFoundException': true allowed_methods_listener: true access_denied_listener: json: true body_listener: true
  • 18. Building Rest API with SF2 /** * @ApiDoc( * resource = true, * description = "Get stories from users that you follow (newsfeed)", * section = "Feed", * output={ * "class" = "LocasticBundleFeedBundleEntityStory" * }, * statusCodes = { * 200 = "Returned when successful", * 400 = "Returned when bad parameters given" * } * ) * * @RestView( * serializerGroups = {"feed"} * ) */ public function getFeedAction() { $this->get('locastic_auth.auth.handler')->validateRequest($this->get('request')); return $this->getDoctrine()->getRepository('locastic.repository.story')->getStories($this- >get('request')->get('me')); }
  • 19. Building Rest API with SF2
  • 21. Templating <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>{% block title %}Welcome!{% endblock %}</title> {% block stylesheets %} <!-- Place favicon.ico and apple-touch-icon.png in the root directory --> {#<link rel="stylesheet" href="{{ asset('css/normalize.css') }}">#} <link rel="stylesheet" href="{{ asset('css/main.css') }}"> <!-- load bootstrap and fontawesome via CDN --> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" /> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.0/css/font-awesome.css" /> <script src="{{ asset('js/vendor/modernizr-2.6.2.min.js') }}"></script> {% endblock %} <link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" /> </head> <body> {% block body %}{% endblock %} {% block javascripts %} <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script> <script src="https://code.angularjs.org/1.2.16/angular-route.min.js"></script> <script src="{{ asset('js/main.js') }}"></script> {% endblock %} </body> </html>
  • 22. Templating Problem: {{ interpolation tags }} - used both by twig and AngularJS
  • 23. Templating {% verbatim %} {{ message }} {% endverbatim %}
  • 24. Templating var phpDayDemoApp = angular.module('phpDayDemoApp', [], function($interpolateProvider) { $interpolateProvider.startSymbol('[['); $interpolateProvider.endSymbol(']]'); }); Now we can use {% block content %} [[ message ]] {# rendered by AngularJS #} {% end block %} Tweak Twig lexer delimiters? Bad idea.
  • 25. Templating Using assetic for minimize {% javascripts "js/angular-modules/mod1.js" "#s/angular-modules/mod2.js" "@AngBundle/Resources/public/js/controller/*.js" output="compiled/js/app.js" %} <script type="text/javascript" src="{{ asset_url }}"></script> {% endjavascripts %}
  • 26. Templating Using assetic for minimize Since Angular infers the controller's dependencies from the names of arguments to the controller's constructor function, if you were to minify the JavaScript code for PhoneListCtrl controller, all of its function arguments would be minified as well, and the dependency injector would not be able to identify services correctly. Use an inline annotation where, instead of just providing the function, you provide an array. This array contains a list of the service names, followed by the function itself. function PhoneListCtrl($scope, $http) {...} phonecatApp.controller('phpDayCtrl', ['$scope', '$http', PhoneListCtrl]);
  • 27. Templating Frontend developers still can use their tools like: Bower Grunt Etc.
  • 28. Managing routes Client side: ngRoute independent since Angular 1.1.6 hashbang #! & HTML5 mode <base href="/"> $locationProvider .html5Mode(true) .hashPrefix('!'); Also good for SEO!
  • 29. Managing routes http://localhost/todos http://localhost/#todos Resolving conflicts Fallback, managing 404 angular: path: '/{route}' defaults: { _controller: LocasticAngularBundle:Default:index} requirements: route: ".+"
  • 30. Managing routes – client side // module configuration...$routeProvider.when('/todos/show/:id', { templateUrl : 'todo/show', controller : 'todoController' }) // receive paramssfugDemoApp.controller('todoController', function($scope, $http, $routeParams){ $scope.todo = {}; $http .get('/api/todo/show/' + $routeParams.id) .success(function(data){ $scope.todo = data['todo']; }); });
  • 31. Managing routes Think of using FOSJsRoutingBundle for Frontend route managament <script src="{{ asset('bundles/fosjsrouting/js/router.js') }}"></script> <script src="{{ path('fos_js_routing_js', {"callback": "fos.Router.setData"}) }}"></script> my_route_to_expose_with_defaults: pattern: /blog/{page} defaults: { _controller: AcmeBlogBundle:Blog:index, page: 1 }
  • 32. Managing routes – server side locastic_rest_todo_getall: pattern: /api/get-all defaults: _controller: LocasticRestBundle:Todo:getAll locastic_rest_todo_create: pattern: /api/create defaults: _controller: LocasticRestBundle:Todo:create locastic_rest_todo_show: pattern: /api/show/{id} defaults: _controller: LocasticRestBundle:Todo:show
  • 33. Translations AngularJS has its own translation system I18N/L10N . But it might be interesting to monitor and centralize translations from your backend Symfony. JMSTranslationBundle
  • 34. Forms Symfony Forms <3 We don't want to throw them away Build custom directive
  • 35. Forms sfugDemoApp.directive('ngToDoForm', function() { return { restrict: 'E', template: '<div class="todoForm">Form will be!</div>' } }); 'A' - <span ng-sparkline></span> 'E' - <ng-sparkline></ng-sparkline> 'C' - <span class="ng-sparkline"></span> 'M' - <!-- directive: ng-sparkline → Usage of directive in HTML: <ng-to-do-form></ng-to-do-form>
  • 36. Forms sfugDemoApp.directive('ngToDoForm', function() { return { restrict: 'E', templateUrl: '/api/form/show.html' } });
  • 37. Forms sfugDemoApp.directive('ngToDoForm', function() { return { restrict: 'E', templateUrl: '/api/form/show.html' } }); locastic_show_form: pattern: /form/show.html defaults: _controller: LocasticWebBundle:Default:renderForm public function renderFormAction() { $form = $this->createForm(new TodoType()); return $this->render('LocasticWebBundle::render_form.html.twig', array( 'form' => $form->createView() )); }
  • 39. Forms Template behind directive <form class="form-inline" role="form" style="margin-bottom: 30px;"> Create new todo: <div class="form-group"> {{ form_label(form.description) }} {{ form_widget(form.description, {'attr': {'ng-model': 'newTodo.description', 'placeholder': 'description', 'class': 'form-control'}}) }} </div> <div class="form-group"> <label class="sr-only" for="deadline">Deadline</label> <input type="text" class="form-control" id="deadline" placeholder="deadline (angular-ui)" ng-model=" newTodo.deadline"> </div> <input type="button" class="btn btn-default" ng-click="addNew()" value="add"/> </form>
  • 40. Submitting forms? When the AngularJS $http service POSTs data the header application/x-www-form-urlencoded is never set (unlike jQuery’s $.ajax()). Also, the $http data is not serialized when sent. Both of these facts mean that the $_POST variable is never set properly by php. Without the $_POST variable Symfony’s built in form handling cannot be used. The fix is actually pretty simple:  angular needs to forced into setting a header  the data needs to be serialized  and the data needs to be normalized into a multidimensional array.
  • 41. Submitting forms? var postData = { formtype_name: { id: some_id, name: some_name } }; $http({ method: "POST", url: url, headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, data: $.param(postData) });
  • 42. Same-origin policy For security reasons, web browsers prevent JavaScript to Ajax requests (XMLHttpRequest) to other areas ( Same-origin policy ). An example of exception thrown by the browser: XMLHttpRequest cannot load http://api.mondomaine.com/v1/maressource.json. Invalid HTTP status code 405  Using JSOP (Json with Padding) – easy with FOSRestApi  Configure server (simple and stupid) <VirtualHost *:80> ServerName mon-appli-angular.com DocumentRoot /var/www/some-ng-app/ Alias /api /var/www/some-ng-app/ <Directory xxxx> </Directory> </VirtualHost> </VirtualHost>  Use Cors CORS (Cross-origin resource sharing) is an elegant and standardized response to allow Cross-domain requests. Be careful though, the CORS mechanism is not supported by all browsers (guess which ) …
  • 43. Testing Symfony and AngularJS are designed to test. So write test Behat PHPUnit PHPSpec Jasmine … Or whatever you want just write tests
  • 44. Summary The cleanest way is to separate backend and frontend. But there is some advantages to use both together. Twig + HTML works well. Assetic Bundle is very useful to minify bunches of Javascript files used by AngularJs Translation in the template. the data in the API payload does not need translation in most cases. Using Symfony I18N support for the template makes perfect sense. Loading of Option lists. Say you have a country list with 200+ options. You can build an API to populate a dynamic dropdown in angularjs, but as these options are static, you can simply build that list in twig. Forms in
  • 45. And remember Keep controllers small and stupid, master Dependency injection, delegate to services and events.
  • 47. QA Please rate my talk https://joind.in/12007 follow me on twitter: @antonioperic