Applicazioni distribuite con Symfony2

Post on 02-Jul-2015

192 views 0 download

description

La sezione Utilities di Facile.it ha recentemente riscritto il proprio applicativo interno utilizzando Ember.js con Ember Data che si appoggia a sua volta ad un WebService REST realizzato in PHP tramite Symfony2 full-stack e alcuni bundle messi a disposizione dall'ecosistema di Symfony per gestire Redis, ElasticSearch, ACL e quant'altro si è reso necessario. Durante la presentazione verranno discusse le motivazioni che hanno portato a scegliere ciascun componente, come è stato integrato all'interno dell'applicativo, in quali problematiche ci si è imbattuti e come sono state risolte.

Transcript of Applicazioni distribuite con Symfony2

10ottobre2014,SymfonyDay,Milano

MatteoGalliSoftwareEngineer@Facile.it(Utilities)...maanchefotografoeviaggiatore

matteo.galli@facile.ittwitter.com/thinkindieinstagram.com/thinkindie

Facile.itèuncomparatoreditariffe

assicurativeenergetiche(luceegas)telefoniche(ADSL,fissoemobile)mutui,contibancarieprestiti

InostriufficisonoaMilano,masoprattutto...

StackLAMP/LEMPSymfony/ZendElasticSearchNode.jsRabbitMQRedisEmber.js/AngularJS/Backbone.jsVagrant/Ansible/Puppet

SiamopresentianchesuGitHubgithub.com/facile-it

Bunny

SeparazionetrafrontendebackendMultibusinessRicercaglobaleACL,anchenellaricercaGestionediprocessiinbackground

WebService RESTful basatosull'esistenza di (ades. leentità

diDoctrine)dicuisihaaccessoalleloro tramite un

globale(URI).

GET/api/users/1HTTP/1.1Host:ws.bunny.facile.itAccept:application/vnd.api+json

HTTP/1.1200OKContent-Type:application/vnd.api+jsondate:Thu,19Oct201414:38:16GMT

{"id":1,"timestamp":"2014-06-10T15:42:37+02:00","lastUpdateTimestamp":"2014-06-10T15:42:37+02:00","username":"BunnyWs","nome":"Bunny","cognome":"WS","email":"bunnyws@facile.it","isActive":true}

FOSRestBundleFOSOAuthServerBundleFOSUserBundleJSONAPI(Ember.jsDriven)

Semplifica e velocizza lo sviluppodi unWebServiceRESTful

gestionedeicodiciHTTPdirispostadifferenti view handlers perdifferentivaloridiAcceptURLREST-friendly

/***@RouteResource("Compagnia")*/classCompagnieControllerextendsBunnyController{/***@View()*/publicfunctioncgetAction(){}/***@View()*/publicfunctiongetAction(Request$request){}/***@View()*/publicfunctionpostAction(Request$request){}/***@View()*/publicfunctionpatchAction(Request$request){}/***@View()*/publicfunctiondeleteAction(Request$request){}}

UnbundledibaseperilWS

Unbundleperognibusiness(ADSL,Luce&Gas,Mobile),

differenti alpiùperunnumero ristrettodi entitàodi

comandiinbackground

Un bundle per ciascuna altra attività cross-

business(es.:inviodiSMS)

Posso rapidamente ricercare unqualsiasi documento contenenteunqualsiasitermineFOSElasticaBundle: le entità diDoctrine vengono persisteanchesuElasticSearch

SmartReindexing: la modifica diunaentità richiede l'aggiornamentodi tutti i documenti in cui ècontenuta

$inheritanceTree=$this->getInheritanceTree($rootEntity);$entities=$this->em->getConfiguration()->getMetadataDriverImpl()->getAllClassNames();foreach($entitiesas$entity){$class=$this->cmf->getMetadataFor($entity);$associationMappings=$class->getAssociationMappings();if(empty($associationMappings)){continue;}else{foreach($associationMappingsas$nestedEntity){if(in_array($nestedEntity['targetEntity'],$inheritanceTree)){...}}}}

DoctrineMetadata:hogiàunamappa(ricorsiva)dellerelazionitraentità

ACL= ccess ontrol istPermettono di definire regole ( )capillariperaccederearisorse.Es.: permessi dei files supiattaformeUnix,regoledelfirewall.

La gestione base delle ACL vieneaffidata al provider di default diSymfony e vengono persistite suMySQL

Le ACE vengono definite in ciascunaentitàtramitecustomannotationsnamespaceFacile\Ws\BunnyBundle\Entity;useFacile\Ws\BunnyBundle\Annotation\EntityAceasACE;/***@ACE("ROLE",name="ROLE_ADMIN",mask="MASK_MASTER");*@ACE("ROLE",name="ROLE_USER",mask="MASK_VIEW");*/classCompagnia{/***@ACE("ROLE",name="ROLE_USER",mask="MASK_VIEW")*@ACE("ROLE",name="ROLE_ADMIN",mask="MASK_MASTER")*/protected$nome;}

Utilizzare il provider di default diSymfony per filtrare una collezione dientità non è nésoddisfacente.

Youknow,forsearch!

QuandounaentitàvienesalvatasuElasticSearchildocumentovienedivisoindueparti

:contenenteleACL"espanse":l'entitàveraepropria

{"data":{"lastUpdateTimestamp":"2014-10-08T09:28:45+02:00","id":5,"timestamp":"2014-06-10T15:42:33+02:00","venduto":true,"nome":"Facile.it","type":"energia"},"meta":{"acl":[{"mask":1,"name":"role_user","type":"role"},{"name":"role_admin","mask":64,"type":"role"}]}}

Laricercadidocumentivieneeseguitacon\Elastica\Queryefiltrataconiruoliricopertidall'utenteattivo$elasticaFilterOr=new\Elastica\Filter\BoolOr();foreach($this->getUserExpandedRoles()as$role){$elasticaFilterRolesName=new\Elastica\Filter\Term();$elasticaFilterRolesName->setTerm('meta.acl.name',strtolower($role));$elasticaFilterRolesType=new\Elastica\Filter\Term();$elasticaFilterRolesType->setTerm('meta.acl.type','role');

$elasticaFilterAndRole=new\Elastica\Filter\BoolAnd();$elasticaFilterAndRole->addFilter($elasticaFilterRolesName);$elasticaFilterAndRole->addFilter($elasticaFilterRolesType);

$elasticaFilterOr->addFilter($elasticaFilterAndRole);}

$elasticaQuery=new\Elastica\Query(new\Elastica\Query\MatchAll());$elasticaQuery->setFilter($elasticaFilterOr);

Utilizzandoifiltri(dalladocumentazionediES):

nonvienecalcolatolo_scoreperognidocumento,ma

vieneapplicataunalogicabooleana

irisultatidimoltifiltripossonoesseresalvatiincache

restringo la query sui documenti effettivamente

ricercabili,ottimizzandolaquerystessa

Redis è un database di tipo chiave-valore,dovelachiave,comeilvalore,possono essere una qualsiasisequenzadibytes.

http://redis.io

Redisèutilizzabileper:

CachingavanzatoRankingsintemporealeContatoriPub/SubCode

BunnyutilizzaRedisperlacachedi

MetadatidiDoctrineQuery(DQL SQL)RisultatidellequeryEntità

doctrine:orm:entity_managers:bunny:metadata_cache_driver:type:redishost:localhostport:6380query_cache_driver:type:redishost:localhostport:6380result_cache_driver:type:redishost:localhostport:6380

Redis viene utilizzato anche per lagestionedi codeconResque tramitephp-resque.Qualsiasi operazione cheparticolarmente complessa vienedemandata quindi ad un processoasincronooprogrammato.

Esempidiprocessiasincroni:

SmartReindexingGenerazionediReportCaricamento su account FTPesterniCaricamentibatchsugestionaliditerzi

https://joind.in/talk/view/12215