Criando Webservices
ultra rápidos
com PHP Phalcon e MongoDB
terça-feira, 16 de julho de 13
Luiz Gustavo
Gavinho
‣ Manaus - Amazonas
‣ +14 anos de experiência
‣ Gerente de Projetos (PMP)
‣ Desenvolvedor de
Software.
‣ Bacharel em Informática
(ULBRA) e MBA em
Administração de Empresas
e Negócios (FGV).
CTO na Ingresse,
ingressos sociais
BDM na FPF Tech,
Centro de Inovação
Tecnológica
terça-feira, 16 de julho de 13
terça-feira, 16 de julho de 13
terça-feira, 16 de julho de 13
Por quê?
1. Performance e escala (picos de acesso)
2. Multi-telas (Web, Mobile,TV, Redes Sociais)
3. Parceiros (publicidade, vendas, guias, blogs)
terça-feira, 16 de julho de 13
Solução
Web JS App
Webservice
Mobile App
MongoDB MySQL
Repositório de Dados
CDN
terça-feira, 16 de julho de 13
PHP Phalcon
terça-feira, 16 de julho de 13
• Phalcon é um framework PHP MVC
completo open-source.
• Implementado em C como uma extensão
no PHP.
PHP Phalcon
http://phalconphp.com/
terça-feira, 16 de julho de 13
• Full MVC Applications (Single-
Module, Multi-Module e Micro
Applications)
• ORM (Transactions,
Relations, Validations,
Sharding, Hydration, etc)
• ODM para Mongo
• Template Engine (Volt)
• DI
• Events Managements
• Encryption
• HTTP Request/Response,
Cookie
• Escaping/Filtering
• Forms Builder/Validation
• Flash Messagens
• Cache
• Pagination
• Annotations
• Security
• Translations
• Assets Managements
• Universal Auto-loader
• Logging
• CLI
PHP Phalcon
Componentes
terça-feira, 16 de julho de 13
• Muito bem documentado
http://docs.phalconphp.com/en/latest/index.html
• Forum ativo: http://forum.phalconphp.com/
• Github: https://github.com/phalcon/cphalcon
• Blog: http://blog.phalconphp.com/
• Twitter: @phalconphp
• Webcasts: http://vimeo.com/phalconphp
PHP Phalcon
Será?
terça-feira, 16 de julho de 13
PHP Phalcon
Github Pulse
terça-feira, 16 de julho de 13
Benchmark
terça-feira, 16 de julho de 13
Benchmark 1
http://docs.phalconphp.com/en/latest/reference/benchmark/hello-world.html
2.5x
mais requisições
que o 2o colocado
CodeIgniter
PHP Phalcon
terça-feira, 16 de julho de 13
Benchmark 2
http://docs.phalconphp.com/en/latest/reference/benchmark/micro.html
2.5x
mais requisições
que o 2o colocado
Slim
PHP Phalcon
terça-feira, 16 de julho de 13
Benchmark 3
http://systemsarchitect.net/performance-benchmark-of-popular-php-frameworks/
2x
mais requisições
que o 2o colocado
Slim
PHP Phalcon
terça-feira, 16 de julho de 13
Outro Benchmark
• Base de dados: mais 5.000 eventos
• Apache Benchmark (ab)
• Cenários:
1. Yii + MongoDB
2. Phalcon + MongoDB
3. Zend 1 + Doctrine 1 + MySQL
terça-feira, 16 de julho de 13
Benchmark 4
~2x
mais requisições
que o 2o colocado
PHP Phalcon
Phalcon
Yii
Zend*
0 1 2 3 4
Requisições por segundo
* Zend com MySQL
Yii
terça-feira, 16 de julho de 13
Peregrinusalfa
terça-feira, 16 de julho de 13
‣Arquitetura
‣Framework de Webservice
REST/JSON integrado para
Phalcon.
Bootstrap
Controller
Service
Dao
Model
MongoDB MySQL
Peregrinusalfa
terça-feira, 16 de julho de 13
Bootstrap (index.php)
• Inicia Micro Application
• Definição das Rotas
• Conexões com banco de dados
• Mapeamento de pastas dos Namespaces
• Demais inicializações
Peregrinusalfa
terça-feira, 16 de julho de 13
$loader = new PhalconLoader();
$loader->registerNamespaces(array(
'Peregrinus' => 'library/framework/',
'PeregrinusError' => 'library/framework/',
'IngresseModel' => 'app/model/',
'IngresseController' => 'app/controller/',
'IngresseLibrary' => 'app/library/',
'IngresseService' => 'app/service/',
'IngresseDao' => 'app/dao/'
));
$loader->register();
terça-feira, 16 de julho de 13
$di = new PhalconDIFactoryDefault();
$di->set(SQLCONNECTION,function(){
$conn = new PhalconDbAdapterPdoMysql(array(
"host" => "localhost",
"username" => "root",
"password" => "root",
"dbname" => DBNAME_SQL,
));
return $conn;
});
$di->set(NOSQLCONNECTION, function() {
$mongo = new Mongo();
return $mongo->selectDb(DBNAME_NOSQL);
}, true);
$di->set('collectionManager', function(){
return new PhalconMvcCollectionManager();
}, true);
terça-feira, 16 de julho de 13
$app->get('/event', function () use ($app) {
$eventController = new IngresseController
EventController($app);
echo $eventController->run();
});
terça-feira, 16 de julho de 13
Controller
• Coleta dos parâmetros do comando REST
• Chamada do Service(Dao)
Peregrinusalfa
terça-feira, 16 de julho de 13
class EventController extends PeregrinusBaseController {
public function run($action = '') {
parent::run($action);
$this->searchEvents();
return $this->getJSON();
}
terça-feira, 16 de julho de 13
public function searchEvents() {
//process params
$page = $this->getPage();
$pageSize = $this->getPageSize();
$state = $this->getState();
$fieldset = $this->getFields();
$location = $this->getLocation();
$dates = $this->getDates();
$eventDao = new IngresseDaoEventDao();
$eventService = new IngresseServiceEventService();
$eventService->setEventDao($eventDao);
$pack = $eventService->search($page,$pageSize,$fieldset,
$location,$state,$dates);
$this->_pack = array(
'status' => true,
'data' => $pack['data'],
'paginationInfo' => $pack['info']
);
}
terça-feira, 16 de julho de 13
Service
• Validação dos parâmetros
• Processamento dos dados
• Processamento de regras de negócio
Peregrinusalfa
terça-feira, 16 de julho de 13
public function search($page,$pageSize,$fieldset,$location,$state,
$dates) {
$eventDao = $this->_eventDao;
$pack = array();
if (isset($eventDao)) {
//validate params
$state = $this->validateStateParam($state);
$location = $this->validateLocationParam($location);
$dates = $this->validateDatesParam($dates);
$fieldset = $this->validateFieldsParam($fieldset);
//set params
$eventDao->setFieldset($fieldset);
$eventDao->setPageSize($pageSize);
$eventDao->addLocationFilter($location, $state);
$eventDao->addDatesFilter($dates);
//get data
$pack = $eventDao->getPage($page);
}
return $pack;
}
terça-feira, 16 de julho de 13
private function validateStateParam($plainParam) {
if ($plainParam != '') {
$pattern = '/^[a-z]{2}$/';
if (!preg_match($pattern, $plainParam)) {
throw new Peregrinus_Exception('Invalid [state]
parameter format. The parameter must be with two lowercase
letters. Examples: am, sp, rj.');
}
return strtoupper($plainParam);
}
else {
return null;
}
}
terça-feira, 16 de julho de 13
DAO
• Comunicação com o banco de dados
• Definição de parâmetros
• Construção das queries e comandos, seja
Mongo ou SQL.
• Cache*
Peregrinusalfa
terça-feira, 16 de julho de 13
public function getPage($page) {
$match = $this->_conditions;
$project = array();
$group = array();
...
if (count($match) > 0) {
$_options[] = array('$match' => $match);
}
$_options[] = array('$project' => $project);
$_options[] = array('$unwind' => $unw);
$_options[] = array('$group' => $group);
$_options[] = array('$sort' => $sort);
...
$agg = $this->_model->aggregate($_options);
$rows = $this-
>transformAggregationResultToSimpleArray($agg['result']);
$fieldset = $this->_fieldset;
$data = $this->processDataToSend($rows,
$fieldset);
...
terça-feira, 16 de julho de 13
Model
• Mapeamento do banco de dados
• Múltiplas conexões (MySQL e MongoDB)
• Uso de Namespaces
• Phalcon ODM:
• Mapeamento das coleções
• Regras de integridade e validação de dados
• Phalcon ORM:
• Mapeamento das tabelas e relacionamentos
Peregrinusalfa
terça-feira, 16 de julho de 13
namespace IngresseModel;
class Event extends PhalconMvcCollection {
public function getSource() {
return 'event'; //collection name
}
public function initialize()
{
$this->setConnectionService(NOSQLCONNECTION);
}
}
terça-feira, 16 de julho de 13
Padrão de Documentação
event:{
id,
title,
description,
type,
status,
saleEnabled,
link,
date{list of event dates},
planner{default set Planner},
addedBy{default set User},
category{list of Tags},
venue{full set Venue},
rsvp{list of, at maximum 5 Users in
Ingresse list},
aiddp,
formalName,
cnpj,
cpf,
cityNumber,
private,
totalTicketsSold,
totalTickets,
totalRevenue,
totalIngresseTax,
totalMoipTax,
totalProfit,
tax,
taxToCostumer,
creationDate,
modificationDate
}
Public information
Private - can only be requested by event
owner and admins
Entidades
Peregrinusalfa
terça-feira, 16 de julho de 13
Padrão de Documentação
Conjunto de conteúdos
Set Properties
Default
id, title, description (200
chars), date, type, link,
venue
Peregrinusalfa
terça-feira, 16 de julho de 13
Padrão de Documentação
Action
Particular Params
List all events ordered by date from past to
future
lat (none): requires long (higher priority than
the state*)
long(none): requires lat (higher priority than
the state*)
from(present date)
to(none)
state(none): valid state code. Ex.: am for
"Amazonas"
term(none): text to be used to search for
tags, titles, description, link encoded in URI
format - see RFC-3986.
venues names
Exemplo
/event/?term=Migration%20Party&state=sp
Brings all events who has term words in any context and are in São Paulo.
Comandos
Peregrinusalfa
terça-feira, 16 de julho de 13
Peregrinus
Phalcon
API2
terça-feira, 16 de julho de 13
@lgavinho
lg@gavinho.eti.br
crazydeploy.tumblr.com
linkedin.com/in/lgavinho
falcão peregrino: o animal mais rápido do mundo. A ave chega a atingir incríveis
360 quilômetros por hora durante um voo em queda livre.
www.gavinho.eti.br
terça-feira, 16 de julho de 13

TDC2013 SP - Criando Webservices ultra rápidos com PHP Phalcon e MongoDB

  • 1.
    Criando Webservices ultra rápidos comPHP Phalcon e MongoDB terça-feira, 16 de julho de 13
  • 2.
    Luiz Gustavo Gavinho ‣ Manaus- Amazonas ‣ +14 anos de experiência ‣ Gerente de Projetos (PMP) ‣ Desenvolvedor de Software. ‣ Bacharel em Informática (ULBRA) e MBA em Administração de Empresas e Negócios (FGV). CTO na Ingresse, ingressos sociais BDM na FPF Tech, Centro de Inovação Tecnológica terça-feira, 16 de julho de 13
  • 3.
  • 4.
  • 5.
    Por quê? 1. Performancee escala (picos de acesso) 2. Multi-telas (Web, Mobile,TV, Redes Sociais) 3. Parceiros (publicidade, vendas, guias, blogs) terça-feira, 16 de julho de 13
  • 6.
    Solução Web JS App Webservice MobileApp MongoDB MySQL Repositório de Dados CDN terça-feira, 16 de julho de 13
  • 7.
  • 8.
    • Phalcon éum framework PHP MVC completo open-source. • Implementado em C como uma extensão no PHP. PHP Phalcon http://phalconphp.com/ terça-feira, 16 de julho de 13
  • 9.
    • Full MVCApplications (Single- Module, Multi-Module e Micro Applications) • ORM (Transactions, Relations, Validations, Sharding, Hydration, etc) • ODM para Mongo • Template Engine (Volt) • DI • Events Managements • Encryption • HTTP Request/Response, Cookie • Escaping/Filtering • Forms Builder/Validation • Flash Messagens • Cache • Pagination • Annotations • Security • Translations • Assets Managements • Universal Auto-loader • Logging • CLI PHP Phalcon Componentes terça-feira, 16 de julho de 13
  • 10.
    • Muito bemdocumentado http://docs.phalconphp.com/en/latest/index.html • Forum ativo: http://forum.phalconphp.com/ • Github: https://github.com/phalcon/cphalcon • Blog: http://blog.phalconphp.com/ • Twitter: @phalconphp • Webcasts: http://vimeo.com/phalconphp PHP Phalcon Será? terça-feira, 16 de julho de 13
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
    Outro Benchmark • Basede dados: mais 5.000 eventos • Apache Benchmark (ab) • Cenários: 1. Yii + MongoDB 2. Phalcon + MongoDB 3. Zend 1 + Doctrine 1 + MySQL terça-feira, 16 de julho de 13
  • 17.
    Benchmark 4 ~2x mais requisições queo 2o colocado PHP Phalcon Phalcon Yii Zend* 0 1 2 3 4 Requisições por segundo * Zend com MySQL Yii terça-feira, 16 de julho de 13
  • 18.
  • 19.
    ‣Arquitetura ‣Framework de Webservice REST/JSONintegrado para Phalcon. Bootstrap Controller Service Dao Model MongoDB MySQL Peregrinusalfa terça-feira, 16 de julho de 13
  • 20.
    Bootstrap (index.php) • IniciaMicro Application • Definição das Rotas • Conexões com banco de dados • Mapeamento de pastas dos Namespaces • Demais inicializações Peregrinusalfa terça-feira, 16 de julho de 13
  • 21.
    $loader = newPhalconLoader(); $loader->registerNamespaces(array( 'Peregrinus' => 'library/framework/', 'PeregrinusError' => 'library/framework/', 'IngresseModel' => 'app/model/', 'IngresseController' => 'app/controller/', 'IngresseLibrary' => 'app/library/', 'IngresseService' => 'app/service/', 'IngresseDao' => 'app/dao/' )); $loader->register(); terça-feira, 16 de julho de 13
  • 22.
    $di = newPhalconDIFactoryDefault(); $di->set(SQLCONNECTION,function(){ $conn = new PhalconDbAdapterPdoMysql(array( "host" => "localhost", "username" => "root", "password" => "root", "dbname" => DBNAME_SQL, )); return $conn; }); $di->set(NOSQLCONNECTION, function() { $mongo = new Mongo(); return $mongo->selectDb(DBNAME_NOSQL); }, true); $di->set('collectionManager', function(){ return new PhalconMvcCollectionManager(); }, true); terça-feira, 16 de julho de 13
  • 23.
    $app->get('/event', function ()use ($app) { $eventController = new IngresseController EventController($app); echo $eventController->run(); }); terça-feira, 16 de julho de 13
  • 24.
    Controller • Coleta dosparâmetros do comando REST • Chamada do Service(Dao) Peregrinusalfa terça-feira, 16 de julho de 13
  • 25.
    class EventController extendsPeregrinusBaseController { public function run($action = '') { parent::run($action); $this->searchEvents(); return $this->getJSON(); } terça-feira, 16 de julho de 13
  • 26.
    public function searchEvents(){ //process params $page = $this->getPage(); $pageSize = $this->getPageSize(); $state = $this->getState(); $fieldset = $this->getFields(); $location = $this->getLocation(); $dates = $this->getDates(); $eventDao = new IngresseDaoEventDao(); $eventService = new IngresseServiceEventService(); $eventService->setEventDao($eventDao); $pack = $eventService->search($page,$pageSize,$fieldset, $location,$state,$dates); $this->_pack = array( 'status' => true, 'data' => $pack['data'], 'paginationInfo' => $pack['info'] ); } terça-feira, 16 de julho de 13
  • 27.
    Service • Validação dosparâmetros • Processamento dos dados • Processamento de regras de negócio Peregrinusalfa terça-feira, 16 de julho de 13
  • 28.
    public function search($page,$pageSize,$fieldset,$location,$state, $dates){ $eventDao = $this->_eventDao; $pack = array(); if (isset($eventDao)) { //validate params $state = $this->validateStateParam($state); $location = $this->validateLocationParam($location); $dates = $this->validateDatesParam($dates); $fieldset = $this->validateFieldsParam($fieldset); //set params $eventDao->setFieldset($fieldset); $eventDao->setPageSize($pageSize); $eventDao->addLocationFilter($location, $state); $eventDao->addDatesFilter($dates); //get data $pack = $eventDao->getPage($page); } return $pack; } terça-feira, 16 de julho de 13
  • 29.
    private function validateStateParam($plainParam){ if ($plainParam != '') { $pattern = '/^[a-z]{2}$/'; if (!preg_match($pattern, $plainParam)) { throw new Peregrinus_Exception('Invalid [state] parameter format. The parameter must be with two lowercase letters. Examples: am, sp, rj.'); } return strtoupper($plainParam); } else { return null; } } terça-feira, 16 de julho de 13
  • 30.
    DAO • Comunicação como banco de dados • Definição de parâmetros • Construção das queries e comandos, seja Mongo ou SQL. • Cache* Peregrinusalfa terça-feira, 16 de julho de 13
  • 31.
    public function getPage($page){ $match = $this->_conditions; $project = array(); $group = array(); ... if (count($match) > 0) { $_options[] = array('$match' => $match); } $_options[] = array('$project' => $project); $_options[] = array('$unwind' => $unw); $_options[] = array('$group' => $group); $_options[] = array('$sort' => $sort); ... $agg = $this->_model->aggregate($_options); $rows = $this- >transformAggregationResultToSimpleArray($agg['result']); $fieldset = $this->_fieldset; $data = $this->processDataToSend($rows, $fieldset); ... terça-feira, 16 de julho de 13
  • 32.
    Model • Mapeamento dobanco de dados • Múltiplas conexões (MySQL e MongoDB) • Uso de Namespaces • Phalcon ODM: • Mapeamento das coleções • Regras de integridade e validação de dados • Phalcon ORM: • Mapeamento das tabelas e relacionamentos Peregrinusalfa terça-feira, 16 de julho de 13
  • 33.
    namespace IngresseModel; class Eventextends PhalconMvcCollection { public function getSource() { return 'event'; //collection name } public function initialize() { $this->setConnectionService(NOSQLCONNECTION); } } terça-feira, 16 de julho de 13
  • 34.
    Padrão de Documentação event:{ id, title, description, type, status, saleEnabled, link, date{listof event dates}, planner{default set Planner}, addedBy{default set User}, category{list of Tags}, venue{full set Venue}, rsvp{list of, at maximum 5 Users in Ingresse list}, aiddp, formalName, cnpj, cpf, cityNumber, private, totalTicketsSold, totalTickets, totalRevenue, totalIngresseTax, totalMoipTax, totalProfit, tax, taxToCostumer, creationDate, modificationDate } Public information Private - can only be requested by event owner and admins Entidades Peregrinusalfa terça-feira, 16 de julho de 13
  • 35.
    Padrão de Documentação Conjuntode conteúdos Set Properties Default id, title, description (200 chars), date, type, link, venue Peregrinusalfa terça-feira, 16 de julho de 13
  • 36.
    Padrão de Documentação Action ParticularParams List all events ordered by date from past to future lat (none): requires long (higher priority than the state*) long(none): requires lat (higher priority than the state*) from(present date) to(none) state(none): valid state code. Ex.: am for "Amazonas" term(none): text to be used to search for tags, titles, description, link encoded in URI format - see RFC-3986. venues names Exemplo /event/?term=Migration%20Party&state=sp Brings all events who has term words in any context and are in São Paulo. Comandos Peregrinusalfa terça-feira, 16 de julho de 13
  • 37.
  • 38.
    @lgavinho lg@gavinho.eti.br crazydeploy.tumblr.com linkedin.com/in/lgavinho falcão peregrino: oanimal mais rápido do mundo. A ave chega a atingir incríveis 360 quilômetros por hora durante um voo em queda livre. www.gavinho.eti.br terça-feira, 16 de julho de 13