Como vimos neste artigo, é possível obter classes de entidades existentes em nosso banco de dados com o Doctrine. Neste artigo, vou explanar mais detalhadamente dois métodos de realizar isto elaborando um projeto simples, na prática. O primeiro é via cógido PHP; o outro é através de linha de comando.
Iremos utilizar a seguinte hierarquia de pasta:
Na hierarquia acima, criei a pasta src, que conterá nosso código de desenvolvimento com as classes do projeto organizadas em subpastas. A subpasta Entity terá, como o nome sugere, as entidades de fato. A pasta vendor conterá as bibliotecas PHP que vamos utilizar ao longo do desenvolvimento.
O Composer automaticamente cria esta pasta, porém criei para modos didático afim de organizar nosso código.
Agora, através do composer vamos obter as bibliotecas que precisamos. Crie o arquivo composer.json na raiz do nosso projeto, conforme abaixo:
Caso precise, veja detalhes da instalação do composer aqui:
{ "require": { "doctrine/orm": "2.4.*", "symfony/yaml": "2.*" }, "autoload": { "psr-4": { "App\": "src" } } }
O arquivo tem o doctrine/orm e o symfony/yaml como bibliotecas requeridas, e no autoloader utilizamos a especificação PSR-4, tendo em vista que este padrão nos dá flexibilidade de criar o namespace ‘App’ dentro da pasta ‘src’, algo que não seria possível com o PSR-0. Caso queira mais informações sobre especificação PSR-4, clique aqui.
Coloquei o Symfony/Yaml como dependência porque o Doctrine sugere tal biblioteca e precisaremos dela em nosso projeto para exportar as entidades no formato yml.
No terminal rodamos o composer:
E na pasta vendo estarão nossas bibliotecas e o autoloader:
Agora já temos nossa hierarquia de pasta, a definição de nosso autoloader e a biblioteca Doctrine devidamente configurada. Vamos ver nosso banco de dados.
Sistema de cadastro de atletas
Digamos que faremos um sistema de cadastro de atletas e eles podem estar em uma ou mais modalidades, ter um ou mais e-mails e telefones. Criei o banco de dados em MySQL e modelei utilizando o Workbench, que é open source e pode ser encontrado aqui.
Aqui é um dos passos de grande importância no desenvolvimento de software. Uma modelagem de banco de dado mal elaborada acarreta diversos problemas no decorrer do desenvolvimento e um reparo de erro de modelagem pode custar caro se não for identificado antes do desenvolvimento de fato.
Veja nossa modelagem feita:
Veja que do relacionamento entre atleta e modalidade surgiu uma tabela cuja a finalidade é apenas guardar o id de cada entidade, afim de definir um vínculo de uma com a outra. Qual o motivo pelo qual não fizemos o mesmo com o e-mail e com o telefone? Porque se trata de um relacionamento “N pra N”: um atleta pode ter muitas modalidades e uma modalidade pode ter muitos atletas. Com o telefone é diferente. Um atleta pode ter muitos telefones, mas um telefone pertence a apenas um atleta; a mesma coisa com o e-mail. O objetivo não é aprofundar na normalização de banco de dados mas fiz questão de ressaltar bem esse passo, pois o considero muito importante.
Segue o código de nosso modelo:
CREATE SCHEMA IF NOT EXISTS `imasters` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ; USE `imasters` ; CREATE TABLE IF NOT EXISTS `imasters`.`atleta` ( `id` INT NOT NULL AUTO_INCREMENT, `nome` VARCHAR(80) NOT NULL, `cpf` CHAR(11) NOT NULL, PRIMARY KEY (`id`)) ENGINE = InnoDB; CREATE TABLE IF NOT EXISTS `imasters`.`modalidade` ( `id` INT NOT NULL AUTO_INCREMENT, `nome` VARCHAR(60) NOT NULL, PRIMARY KEY (`id`)) ENGINE = InnoDB; CREATE TABLE IF NOT EXISTS `imasters`.`telefone` ( `id` INT NOT NULL AUTO_INCREMENT, `atleta_id` INT NOT NULL, `numero` INT(9) NOT NULL, `ddd` INT(3) NOT NULL, PRIMARY KEY (`id`), INDEX `fk_telefone_atleta1_idx` (`atleta_id` ASC), CONSTRAINT `fk_telefone_atleta1` FOREIGN KEY (`atleta_id`) REFERENCES `imasters`.`atleta` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB; CREATE TABLE IF NOT EXISTS `imasters`.`email` ( `id` INT NOT NULL AUTO_INCREMENT, `atleta_id` INT NOT NULL, `email` VARCHAR(50) NOT NULL, PRIMARY KEY (`id`), INDEX `fk_email_atleta1_idx` (`atleta_id` ASC), CONSTRAINT `fk_email_atleta1` FOREIGN KEY (`atleta_id`) REFERENCES `imasters`.`atleta` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB; CREATE TABLE IF NOT EXISTS `imasters`.`atleta_modalidade` ( `atleta_id` INT NOT NULL, `modalidade_id` INT NOT NULL, PRIMARY KEY (`atleta_id`, `modalidade_id`), INDEX `fk_atleta_has_modalidade_modalidade1_idx` (`modalidade_id` ASC), INDEX `fk_atleta_has_modalidade_atleta_idx` (`atleta_id` ASC), CONSTRAINT `fk_atleta_has_modalidade_atleta` FOREIGN KEY (`atleta_id`) REFERENCES `imasters`.`atleta` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT `fk_atleta_has_modalidade_modalidade1` FOREIGN KEY (`modalidade_id`) REFERENCES `imasters`.`modalidade` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB;
Engenharia reversa
Com o banco de dados feito, agora podemos criar nossas entidades. Vamos utilizar o Doctrine para exportar do banco de dados cada tabela (ou as mais importantes) e transformá-las em classes para que possamos trabalhar.
Vamos criar na raiz no nosso projeto o arquivo bootstrap.php. Ele é responsável em criar o uma instância EntityManager, que irá gerenciar as ações das entidades.
<?php require_once "vendor/autoload.php"; use DoctrineORMToolsSetup; use DoctrineORMEntityManager; $paths = array("/src"); $isDevMode = true; $dbParams = array( 'dbname' => 'imasters', 'user' => 'root', 'password' => 'root', 'host' => '127.0.0.1', 'driver' => 'pdo_mysql', ); $config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode); $entityManager = EntityManager::create($dbParams, $config);
Este é um arquivo padrão no Doctrine, onde eu basicamente informo em qual path está o código do meu projeto, qual os dados do banco que irei trabalhar e qual ambiente que estou desenvolvendo.
O Doctrine permite quatro tipo de exportações de mapeamento: XML, YML, PHP e Annotation. Todos com suas devidas características trazem o mapeamento do banco transcrevendo-o em arquivos para serem utilizados.
Há uma maneira de exportar com PHP, chamando o arquivo .php pelo browser ou pelo console, porém o Doctrine tem uma ferramenta que permite, através de linha de comando, realizar o mesmo procedimento, dentre outros.
Para tal ferramenta funcionar, é requerido o arquivo cli-config.php. Nele conterá o HelperSet, com informações que já configuramos no arquivo bootstrap.php.
Vejamos abaixo as duas formas:
O arquivo export.php (exportando via código)
<?php // Requerimos o arquivo bootstrap.php com as configurações de banco de dados e retornando o EntityManager require_once 'bootstrap.php'; /* * Estamos agora recuperando os metadados com o DatabaseDriver */ $entityManager->getConfiguration()->setMetadataDriverImpl( new DoctrineORMMappingDriverDatabaseDriver( $entityManager->getConnection()->getSchemaManager() ) ); $cmf = new DoctrineORMToolsDisconnectedClassMetadataFactory(); $cmf->setEntityManager($entityManager); $metadata = $cmf->getAllMetadata(); $cme = new DoctrineORMToolsExportClassMetadataExporter(); /* * Obtemos uma instancia Exporter e exportamos os arquivos a pasta determinada como segundo parâmetro. * */ $exporter = $cme->getExporter('xml', 'src/Entity'); //$exporter->setEntityGenerator(new DoctrineORMToolsEntityGenerator()); $exporter->setMetadata($metadata); $exporter->export();
Observações:
- No código $exporter = $cme->getExporter(‘yml’, ‘src/Entity’); onde está ‘yml’, você pode substituir pelo modo que desejar (php, xml ou annotation). O segundo parâmetro diz respeito à pasta onde você quer exportar as Entidades;
- Veja que deixei o código: $exporter->setEntityGenerator( newDoctrineORMToolsEntityGenerator() ); comentado, precismos deste código para exportar arquivos com Annotation do Doctrine. Eu, particularmente, sempre exporto para o modo Annotation. É uma escolha pessoal e talvez o costume de já haver trabalhado bastante com hibernate no Java.
Veja abaixo o resultado:
O arquivo cli-config.php (exportando via linha de comando)
<?php // Requerimos o arquivo bootstrap.php com as configurações de banco de dados e retornando o EntityManager require_once 'bootstrap.php'; /* * Aqui estamos setando o HelperSet, o Doctrine exige esta configuração. o DB que é a conexão e EM é o EntityManager. * No arquivo boostrap o configuramos. * */ $helperSet = new SymfonyComponentConsoleHelperHelperSet(array( 'db' => new DoctrineDBALToolsConsoleHelperConnectionHelper($entityManager->getConnection()), 'em' => new DoctrineORMToolsConsoleHelperEntityManagerHelper($entityManager) )); return $helperSet;
Em nosso console:
Note que coloquei a exportação do modo Annotation na pasta Entity, pois, caso eu colocasse na pasta src, o código iria reclamar que já existe os arquivos exportados e tentaria substituí-los.
No nosso projeto você verá algo como:
Agora é só se preocupar com a lógica de negócio.
Aqui se encerra nosso artigo, tudo de bom para todos. Até a próxima.
Sugestões e dúvidas? Podem comentar abaixo, que eu procurarei responder a todos.
Mensagem do anunciante:
Experimente a Umbler, startup de Cloud Hosting por demanda feita para agências e desenvolvedores e ganhe até R$ 100 em créditos!
Powered by WPeMatico