SlideShare ist ein Scribd-Unternehmen logo
1 von 40
Bacharel em Informática com ênfase em Análise de
Sistemas pela Unisinos, cursou mestrado em Engenharia
Informática e de Computadores pelo Instituto Superior
Técnico da Universidade Técnica de Lisboa (Portugal),
perito judicial ad hoc especializado em TI (mantenedor do
site PERITO.inf.br), Zend Certified Engineer (PHP 5.3), Zend
Certified PHP Engineer (PHP 5.5) e Zend Framework 2
Certified Architect (ZFCA) #ZEND004019, Certified
ScrumMaster pela Scrum Alliance #203613, Microsoft
Certified Professional (MCP), idealizador do projeto
Certificamp, consultor web e PHP evangelist.
Ari Stopassola Junior
Dummy
≠
Dumb
Mapeamento Objeto Relacional (ORM)
• Persistir o objeto numa estrutura
de dados relacional
• Tradução para tabelas, campos,
linhas e relacionamentos
• Conversões de tipo
• ORM mascara detalhes obscuros
• Overhead
• Requer aprendizagem de outras
tencnologias. Ex.: DQL (Doctrine),
Propel, Eloquent etc.
http://www.edzynda.com/use-laravels-eloquent-orm-outside-of-laravel/
Fontes: https://en.wikipedia.org/wiki/Object-relational_impedance_mismatch
http://blogs.tedneward.com/post/the-vietnam-of-computer-science
impedance mismatch
Ferramentas de Object-relational mapping
https://github.com/guilhermeblanco
Doctrine
Vantagens
• Estabilidade
• Comunidade
• Integração com os
principais frameworks
Desvantagens
•Curva de aprendizado
•Performance
Roadmap
• Modelo de domínio
• Database Abstraction Layer (DBAL)
• Object Relational Mapping (ORM)
• Entities
• Entity manager
• Mapping
• Repositories
• Life cicle events
• Query Builder
• Caching
• Proxies
• Event subsystem
Passeios
Nome
Descrição
Preço
Distância
...
Objetos Base relacional
Nome Descrição Preço Distância
Classe Passeios Tabela Passeios
ORM
composer require doctrine/orm
Fonte: http://docs.doctrine-project.org/projects/doctrine1/en/latest/en/manual/introduction.html
PDO x DBAL
Data-access Layer
• Permite a troca de banco de
dados utlizando as mesmas
chamadas de métodos
• Não reescreve SQL
• Tão pouco emula
funcionalidades inexistentes
Database Abstraction Layer
• Agnóstico
• Manipulação por meio de uma
API Orientada à Objetos
• Traz maior consistência na
manipulação do BD
• Doctrine usa DBAL, mas você
pode usar DBAL sem Doctrine
• DBAL utiliza PDO internamente
ExemplodeDBAL
<?php
include __DIR__ . '/doctrine_autoloader.php';
use DoctrineDBALConfiguration;
use DoctrineDBALDriverManager;
//Obtém a conexão
$dbParams = include __DIR__ . '/database.params.php';
$conn = DriverManager::getConnection($dbParams, new Configuration());
$sql = "SELECT * FROM orcamentos WHERE sobrenome = ?";
$stmt = $conn->prepare($sql);
$stmt->execute(array('STOPASSOLA'));
//OU utilizando QueryBuilder
$qb = $conn->createQueryBuilder();
$qb->select('*')->from('orcamentos')->where('sobrenome = :name');
$data = array(':name' => 'STOPASSOLA');
while ($tupla = $stmt->fetch()) {
var_dump($tupla);
}
Mapeandos os tipos de dados
Tipos do Doctrine Tipos SQL Tipos PHP
string VARCHAR string
integer INT integer
smallint SMALLINT integer
bigint BIGINT string
boolean BOOLEAN boolean
decimal DECIMAL double
date DATETIME DateTime
time TIME DateTime
datetime DATETIME/TIMESTAMP DateTime
text CLOB string
Eloquent implementa Active Record
class Passeios extends Eloquent {
}
$passeio = Passeios::find(32);
$passeio->name = "Tour Uva e Vinho";
$passeio->save();
Fonte: http://www.martinfowler.com/eaaCatalog/activeRecord.html
Doctrine 2 implementa Data Mapper
Fonte: http://martinfowler.com/eaaCatalog/dataMapper.html
<?php
/**
* @Entity
* @Table(name="passeios")
*/
class Passeio
{
/**
* @Id
* @GeneratedValue(strategy="AUTO")
* @Column(type="integer")
*/
private $id;
/**
* @Column(type="string", length=255, nullable=true)
*/
private $nome;
}
Annotations
• Instruções declarativas dentro de blocos de documentação
• Doctrine usa anotações para definir o mapeamento objeto-
relacional
• Annotations são metadados que descrevem a entidade, como ela
deve ser armazenada, que tipo de colunas serão usadas etc.
• Inspirado no PHPDocumentor www.phpdoc.org
• Definida sempre acima do nome da classe e de cada atributo
• Entre /** xxx */ e começam com o simbolo @
/**
* Produto
*
* @Entity
* @Table(name="produtos")
*/
Anotações obrigatórias
"Learning Doctrine" by Doug Bierer (O'Reilly)
@ORMColumn(Type="xxxx")
• smallint, integer, bigint
• decimal, float
• string, text, guid
• binary, blob, boolean
• date, date time, datetimez, time
• array, simple_array, json_array, object
http://doctrine-
dbal.readthedocs.io/en/latest/reference/types.html
Schema
Laravel ➡ Migrations
public function up()
{
Schema::create('passeios', function(Blueprint $table)
{
$table->increments('id');
$table->string('nome');
$table->text('descricao');
$table->timestamps();
});
}
$ php artisan migrate
$ php artisan make:migration create_passeios_table --create="passeios"
Entity Manager
$passeio = new Passeio;
$passeio->setName("Tour Itaimbezinho");
EntityManager::persist($passeio);
EntityManager::flush();
Entity Manager
$passeio = new Passeio;
$passeio->setName("Tour Itaimbezinho");
EntityManager::persist($passeio);
EntityManager::flush();
Fotohttps://www.flickr.com/photos/pragdave/173640462
Unit of Work
Fonte: http://martinfowler.com/eaaCatalog/unitOfWork.html
• Estratégia transactional write-behind
• Retarda a execução de cláusulas
SQL para executá-las
posteriormente de forma mais
eficiente
• Executa numa ordem tal de modo a
liberar o mais rápido possível as
tabelas em questão (write locks), ao
fim da transação
Doctrine Query Language – DQL
$query = EntityManager::createQuery("select p from
VendaBalcaoEntitiesPasseios p where p.preco >= 90
AND p.preco <= 150");
$passeios = $query->getResult();
Lab: https://github.com/stopassola/doctrine_lab
Herança: estratégia Single Table
/**
* @Entity
* @InheritanceType("SINGLE_TABLE")
* @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({"person"="Usuario","employee"="Colaborador"})
*/
Revistaphp|architect,ediçãomarço/2016.
Herança: estratégia Class Table
/**
* @Entity
* @InheritanceType("TABLE_PER_CLASS")
* @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({"person"="Usuario","employee"="Colaborador"})
*/
Revistaphp|architect,ediçãomarço/2016.
Hidratação
$produto = $entityManager->find('Produto', 5);
Possível workflow
1) Crie as entidades com suas respectivas annotations
2) Verifique incoerências das classes mediante o BD:
$ vendor/bin/doctrine orm:validate-schema
3) Realize a varredura nas annotations e crie as respectivas tabelas:
$ vendor/bin/doctrine orm:schema-tool:update --force
Relação 1:1 (lê-se um-para-um)
“cada colaborador trabalha para uma empresa parceira”
Colaborador
$id
$parceiro
Parceiro
$id
Owning side Inverse side
/**
* @OneToOne(targetEntity="Parceiro")
* @JoinColumn(name="parceiro", referencedColumnName="id")
*/
protected $parceiro;
Hóspede
$id
$nome
Hóspede
$id
$nome
Hotel
$id
$hospedes[]
Hóspede
$id
$hotel
Owning side Inverse side
/**
* @var DoctrineCommonCollectionsCollection
* @OneToMany(targetEntity="Hospede", mappedBy="hotel")
*/
protected $hospedes;
Relação 1:N (um-para-ene)
“Um hotel hospeda vários hóspedes”
id nome preco duracao
1 Tour Uva e Vinho 99 12
2 Noite Gaúcha 110 4
3 Alpen Park 30 3
4 Canyon Itaimbezinho 99 10
5 Parques de Gramado 35 5
pacotes_id passeios_id
1 1
1 2
2 3
2 4
3 3
4 1
4 5
Passeios
Relação N:M (ene-para-eme)
“Pacotes têm passeios e o mesmo passeio compõe vários pacotes”
id nome
1 Serra Gaúcha Tradicional
2 Aventura
3 Serra com as Crianças
4 Italiana e Alemã
Pacotes
Pacote
$id
$passeios[]
Pacote
$id
$passeios[]
Hóspede
$id
$nome
Hóspede
$id
$nome
Pacote
$id
$passeios[]
Passeio
$id
$pacotes[]
Owning side Inverse side
/**
* @ManyToMany(targetEntity="Passeio", mappedBy="pacotes")
* @JoinTable(name="pacotes_has_passeios",
* joinColumns={@JoinColumn(name="pacotes_id", "id")},
* inverseJoinColumns={@JoinColumn(name="passeios_id", "id")})
*/
protected $passeios;
Relação N:M (ene-para-eme)
“Pacotes têm passeios e o mesmo passeio compõe vários pacotes”
Referências
E-mail:
arijunior@gmail.com
Twitter: @stopassola
Skype: stopassola
LinkedIn:
http://pt.linkedin.com/in/stopassola
Facebook:
http://www.facebook.com/arijunior
Sites:
http://slideshare.net/arijunior
http://www.perito.inf.br
http://www.certificamp.com
http://www.rumoacertificacaophp.com
Contatos

Weitere ähnliche Inhalte

Was ist angesagt?

Mapeamento Objeto Relacional em PHP com Outlet ORM
Mapeamento Objeto Relacional em PHP com Outlet ORMMapeamento Objeto Relacional em PHP com Outlet ORM
Mapeamento Objeto Relacional em PHP com Outlet ORM
Fábio Rehm
 
55 New Things in Java 7 - Brazil
55 New Things in Java 7 - Brazil55 New Things in Java 7 - Brazil
55 New Things in Java 7 - Brazil
Stephen Chin
 

Was ist angesagt? (20)

Introdução à MEAN Stack
Introdução à MEAN StackIntrodução à MEAN Stack
Introdução à MEAN Stack
 
PHP GERAL
PHP GERALPHP GERAL
PHP GERAL
 
Sapo Sessions PHP
Sapo Sessions PHPSapo Sessions PHP
Sapo Sessions PHP
 
Escrevendo modulos python com rust
Escrevendo modulos python com rustEscrevendo modulos python com rust
Escrevendo modulos python com rust
 
Mongo + php
Mongo + phpMongo + php
Mongo + php
 
Entre na fila. Processamento distribuído usando Gearman
Entre na fila. Processamento distribuído usando GearmanEntre na fila. Processamento distribuído usando Gearman
Entre na fila. Processamento distribuído usando Gearman
 
Proxy, Man-In-The-Middle e testes
Proxy, Man-In-The-Middle e testesProxy, Man-In-The-Middle e testes
Proxy, Man-In-The-Middle e testes
 
Postgresql + Python = Power!
Postgresql + Python = Power!Postgresql + Python = Power!
Postgresql + Python = Power!
 
Mapeamento Objeto Relacional em PHP com Outlet ORM
Mapeamento Objeto Relacional em PHP com Outlet ORMMapeamento Objeto Relacional em PHP com Outlet ORM
Mapeamento Objeto Relacional em PHP com Outlet ORM
 
Php FrameWARks - sem CakePHP
Php FrameWARks - sem CakePHPPhp FrameWARks - sem CakePHP
Php FrameWARks - sem CakePHP
 
Escreva aplicações web assíncronas com python3 + tornado
Escreva aplicações web assíncronas com python3 + tornadoEscreva aplicações web assíncronas com python3 + tornado
Escreva aplicações web assíncronas com python3 + tornado
 
Golang para desenvolvedores pragmáticos parte 2
Golang para desenvolvedores pragmáticos  parte 2Golang para desenvolvedores pragmáticos  parte 2
Golang para desenvolvedores pragmáticos parte 2
 
Python 08
Python 08Python 08
Python 08
 
Postgresql +python
Postgresql +pythonPostgresql +python
Postgresql +python
 
Conhecendo o Zend Framework
Conhecendo o Zend FrameworkConhecendo o Zend Framework
Conhecendo o Zend Framework
 
Palestra Desenvolvimento Ágil para Web com ROR UVA
Palestra Desenvolvimento Ágil para Web com ROR UVAPalestra Desenvolvimento Ágil para Web com ROR UVA
Palestra Desenvolvimento Ágil para Web com ROR UVA
 
Zabbix Conference LatAm 2019 - Automação: Ganhando produtividade
Zabbix Conference LatAm 2019 - Automação: Ganhando produtividadeZabbix Conference LatAm 2019 - Automação: Ganhando produtividade
Zabbix Conference LatAm 2019 - Automação: Ganhando produtividade
 
Go Lang para desenvolvedores pragmáticos (parte 1)
Go Lang para desenvolvedores pragmáticos (parte 1)Go Lang para desenvolvedores pragmáticos (parte 1)
Go Lang para desenvolvedores pragmáticos (parte 1)
 
Zephir
ZephirZephir
Zephir
 
55 New Things in Java 7 - Brazil
55 New Things in Java 7 - Brazil55 New Things in Java 7 - Brazil
55 New Things in Java 7 - Brazil
 

Andere mochten auch

Integração contínua em PHP com Jenkins
Integração contínua em PHP com JenkinsIntegração contínua em PHP com Jenkins
Integração contínua em PHP com Jenkins
Gilmar Pupo
 

Andere mochten auch (20)

Rumo à Certificação PHP
Rumo à Certificação PHPRumo à Certificação PHP
Rumo à Certificação PHP
 
DevOps: desenvolvedores e sysadmins cooperando na prática
DevOps: desenvolvedores e sysadmins cooperando na práticaDevOps: desenvolvedores e sysadmins cooperando na prática
DevOps: desenvolvedores e sysadmins cooperando na prática
 
Integração contínua em PHP com Jenkins
Integração contínua em PHP com JenkinsIntegração contínua em PHP com Jenkins
Integração contínua em PHP com Jenkins
 
Treinamento PHP: Strings & Patterns
Treinamento PHP: Strings & PatternsTreinamento PHP: Strings & Patterns
Treinamento PHP: Strings & Patterns
 
Aplicação de automação residencial: RaspberryPI com PHP
Aplicação de automação residencial: RaspberryPI com PHPAplicação de automação residencial: RaspberryPI com PHP
Aplicação de automação residencial: RaspberryPI com PHP
 
Ambiente de desenvolvimento com docker
Ambiente de desenvolvimento com docker Ambiente de desenvolvimento com docker
Ambiente de desenvolvimento com docker
 
Symfony2 e Elasticsearch com FosElasticaBundle
Symfony2 e Elasticsearch com FosElasticaBundleSymfony2 e Elasticsearch com FosElasticaBundle
Symfony2 e Elasticsearch com FosElasticaBundle
 
Code smells in PHP
Code smells in PHPCode smells in PHP
Code smells in PHP
 
Mecanismo de busca PHP + MongoDB
Mecanismo de busca PHP + MongoDBMecanismo de busca PHP + MongoDB
Mecanismo de busca PHP + MongoDB
 
Zend Framework 3 - porque só o que existe pode ser aprimorado
Zend Framework 3 - porque só o que existe pode ser aprimoradoZend Framework 3 - porque só o que existe pode ser aprimorado
Zend Framework 3 - porque só o que existe pode ser aprimorado
 
Workshop Magento
Workshop MagentoWorkshop Magento
Workshop Magento
 
Preparando-se para a prova da Certificação Zend PHP 5.3
Preparando-se para a prova da Certificação Zend PHP 5.3Preparando-se para a prova da Certificação Zend PHP 5.3
Preparando-se para a prova da Certificação Zend PHP 5.3
 
Impacto dos frameworks PHP
Impacto dos frameworks PHPImpacto dos frameworks PHP
Impacto dos frameworks PHP
 
Depurando aplicações PHP like a BOSS
Depurando aplicações PHP like a BOSSDepurando aplicações PHP like a BOSS
Depurando aplicações PHP like a BOSS
 
Construção e provisionamento de ambientes de desenvolvimento virtualizados
Construção e provisionamento de ambientes  de desenvolvimento virtualizadosConstrução e provisionamento de ambientes  de desenvolvimento virtualizados
Construção e provisionamento de ambientes de desenvolvimento virtualizados
 
TDC2016SP - Trilha Microservices
TDC2016SP - Trilha MicroservicesTDC2016SP - Trilha Microservices
TDC2016SP - Trilha Microservices
 
DevOps
DevOpsDevOps
DevOps
 
TDC2016SP - Trilha Node.Js
TDC2016SP - Trilha Node.JsTDC2016SP - Trilha Node.Js
TDC2016SP - Trilha Node.Js
 
Apostila uml
Apostila umlApostila uml
Apostila uml
 
PHP, non lo stesso vecchio linguaggio
PHP, non lo stesso vecchio linguaggioPHP, non lo stesso vecchio linguaggio
PHP, non lo stesso vecchio linguaggio
 

Ähnlich wie Doctrine for Dummies

pgBouncer: um aglomerador de conexões para PostgreSQL
pgBouncer: um aglomerador de conexões para PostgreSQLpgBouncer: um aglomerador de conexões para PostgreSQL
pgBouncer: um aglomerador de conexões para PostgreSQL
elliando dias
 
LabMM4 (T22 - 12/13) - segurança
LabMM4 (T22 - 12/13) - segurançaLabMM4 (T22 - 12/13) - segurança
LabMM4 (T22 - 12/13) - segurança
Carlos Santos
 

Ähnlich wie Doctrine for Dummies (20)

Doctrine for dummies
Doctrine for dummiesDoctrine for dummies
Doctrine for dummies
 
Migrando para o PHP 5
Migrando para o PHP 5Migrando para o PHP 5
Migrando para o PHP 5
 
Pdo do PHP Palestra
Pdo do PHP PalestraPdo do PHP Palestra
Pdo do PHP Palestra
 
pgBouncer: um aglomerador de conexões para PostgreSQL
pgBouncer: um aglomerador de conexões para PostgreSQLpgBouncer: um aglomerador de conexões para PostgreSQL
pgBouncer: um aglomerador de conexões para PostgreSQL
 
Desenvolvimento de aplicações PHP com MongoDB
Desenvolvimento de aplicações PHP com MongoDBDesenvolvimento de aplicações PHP com MongoDB
Desenvolvimento de aplicações PHP com MongoDB
 
PHP fora da Web
PHP fora da WebPHP fora da Web
PHP fora da Web
 
PHP e PostgreSQL: Um é pouco, dois é bom, três é demais
PHP e PostgreSQL: Um é pouco, dois é bom, três é demaisPHP e PostgreSQL: Um é pouco, dois é bom, três é demais
PHP e PostgreSQL: Um é pouco, dois é bom, três é demais
 
Desenvolvimento ágil com Kohana framework
Desenvolvimento ágil com Kohana frameworkDesenvolvimento ágil com Kohana framework
Desenvolvimento ágil com Kohana framework
 
PHP like a super hero
PHP like a super heroPHP like a super hero
PHP like a super hero
 
JavaScript - A Linguagem
JavaScript - A LinguagemJavaScript - A Linguagem
JavaScript - A Linguagem
 
Escrevendo códigos php seguros
Escrevendo códigos php segurosEscrevendo códigos php seguros
Escrevendo códigos php seguros
 
Documentacao automatica
Documentacao automaticaDocumentacao automatica
Documentacao automatica
 
LabMM4 (T22 - 12/13) - segurança
LabMM4 (T22 - 12/13) - segurançaLabMM4 (T22 - 12/13) - segurança
LabMM4 (T22 - 12/13) - segurança
 
Web App Flaws - SQL Injection
Web App Flaws - SQL InjectionWeb App Flaws - SQL Injection
Web App Flaws - SQL Injection
 
Arquitetando Soluções de Dados com PostgreSQL
Arquitetando Soluções de Dados com PostgreSQLArquitetando Soluções de Dados com PostgreSQL
Arquitetando Soluções de Dados com PostgreSQL
 
PHP FrameWARks - FISL
PHP FrameWARks - FISLPHP FrameWARks - FISL
PHP FrameWARks - FISL
 
Terraform.pptx
Terraform.pptxTerraform.pptx
Terraform.pptx
 
Zabbix monitorando o zimbra collaboration 8.8 (1)
Zabbix   monitorando o zimbra collaboration 8.8 (1)Zabbix   monitorando o zimbra collaboration 8.8 (1)
Zabbix monitorando o zimbra collaboration 8.8 (1)
 
Crawling - Coleta de dados na Web com PHP
Crawling - Coleta de dados na Web com PHP Crawling - Coleta de dados na Web com PHP
Crawling - Coleta de dados na Web com PHP
 
Evolução e futuro do uso de paradigmas no JavaScript
Evolução e futuro do uso de paradigmas no JavaScriptEvolução e futuro do uso de paradigmas no JavaScript
Evolução e futuro do uso de paradigmas no JavaScript
 

Doctrine for Dummies

Hinweis der Redaktion

  1. Reduzir a impedância. Experimente fazer um left outer join num ORM, ou uma função de agregação como média. Alguns falharam ao executar transações, passando a responsabilidade para a aplicação. Não há necessidade de cache, pois o mongoDB já fica em memório – o quanto houver de RAM disponível. Usar monboDB simplifica o desenvolvimento da aplicação pois não requer tratar de atualizações de registros, cache expirado etc.
  2. Hibernate do Java e ao ActiveRecord do Rails. Mapeamento em arquivos .ini ou XML Propel e Doctrine usam o design pattern ActiveRecord, enquanto que o Zend_Db_Table usa Table Data Gateway pattern e Row Data Gateway pattern. Livro "Patterns of Enterprise Application Architecture" do Martin Fowler de 2003. CakePHP Doctrine é a mais popular.
  3. Top 5 contributors do projeto: https://github.com/doctrine/doctrine2/graphs/contributors
  4. Inspirado no Hibernate do Java
  5. E como ficam as agregações, composições de objetos?
  6. O Doctrine é uma coleção de sub-projetos como, por exemplo, DBAL, cache, Annotations etc.
  7. Instala também o Doctrine Commons.
  8. Evita utilizar um ”dialeto” SQL específico de cada banco. Não que necessariamente o BD será trocado o tempo todo, mas traz maior consistência. Esconde detalhes de cada banco. Ex.: PostreSQL CREATE SEQUENCE serial; SELECT nextval('serial'); JSON em BD também é um recurso interessantíssimo do PostgreSQL Padroniza o acesso via OO. Conexão via DBAL é semelhante ao que seria feito através de PDO. Inclusive os nomes dos métodos são semelhantes, para diminuir a curva de aprendizado. Usa interface fluente. Ex.: $obj->metodoA()->metodoB()->metodoC();
  9. Herda toda a lógica de persistência do ORM, gerando overhead.
  10. Pode-se utilizar YAML, XML e o próprio PHP.
  11. Annotations são metadados que descrevem a entidade, como ela deve ser armazenada, tipo de colunas serão usadas etc.
  12. @Entity identifica a classe como uma entidade para o EntityManager @Table informa o nome da tabela, embora seja dispensável caso a tabela tenha o mesmo nome da classe. @Column identifica uma propriedade do objeto como um campo da tabela. Podem haver outras propriedades que não sejam mapeadas. Se o nome for diferente, usa-se o atributo ”name”. Caso o nome do campo mude na tabela, basta apontar na annotation da respectiva classe É um componente muito utilizado em outros projetos, além do Doctrine.
  13. Mecanismo que lida com a persistência dos objetos. Registrar uma entidade.
  14. Mecanismo que lida com a persistência dos objetos.
  15. Executa quando ocorre o flush. Útil para quem utiliza Testes unitários, onde os testes são feitos encapsulados em uma transação e depois desfeitos no fim – de modo a não alterar o BD. Cada insert, se único, será encapsulado numa transação.
  16. Inspirado do Hibernate do Java (HQL), é um ”dialeto” de SQL orientado à objetos. Mais controle sobre as querys. Pensar nas consultas sob o ponto de vista de objetos ao invés de relacionamentos. Ver Expression. As consultas trazem objetos.
  17. Mapped Superclasses TABLE_PER_CLASS
  18. orm:schema-tool:update --dump-sql mostra a query que deverá ser executada no BD para alinhar com as classes registradas (entidades) [Database] FAIL - The database schema is not in sync with the current mapping file.
  19. Uma e somente uma…
  20. Uma e somente uma…
  21. Uma e somente uma…
  22. entregar adesivos!