Do Clipper e Delphi ao Ruby e PHP: Antes e depois dos frameworks

1.330 visualizações

Publicada em

Nesta apresentação é demonstrada a evolução na maneira de programar entre as linguagens Clipper (procedural, modo texto), Delphi (Orientada a Objetos, focada em componentes, Desktop), até as linguagens Ruby e PHP, com exemplos que demonstram o uso de frameworks MVC.

Publicada em: Software
0 comentários
4 gostaram
Estatísticas
Notas
  • Seja o primeiro a comentar

Sem downloads
Visualizações
Visualizações totais
1.330
No SlideShare
0
A partir de incorporações
0
Número de incorporações
472
Ações
Compartilhamentos
0
Downloads
0
Comentários
0
Gostaram
4
Incorporações 0
Nenhuma incorporação

Nenhuma nota no slide

Do Clipper e Delphi ao Ruby e PHP: Antes e depois dos frameworks

  1. 1. Do Clipper e Delphi ao Ruby e PHP Antes e depois dos frameworks Pablo Dall'Oglio @pablodalloglio fb/pablodalloglio
  2. 2. Adianti Solutions Ltda © Pablo Dall'Oglio #2 1994 Inicia no Brasil a execução do Plano Real
  3. 3. Adianti Solutions Ltda © Pablo Dall'Oglio #3 1994 Raimundos lança seu primeiro disco
  4. 4. Adianti Solutions Ltda © Pablo Dall'Oglio #4 1994 Século em que o Wolf ainda tinha cabelo
  5. 5. Adianti Solutions Ltda © Pablo Dall'Oglio #5 CA-Clipper Sobre o Clipper ● Compilador criado em 1985 para linguagem xBase; ● Ideia surgiu no restaurante (Nantucket), quadro (Clipper); ● Dados armazenados em arquivos .DBF; ● Linguagem de execução procedural (v5.2 = 1,6Mb); ● Durou até a versão 5.3b (1997). Não há mais suporte; ● Existem iniciativas da comunidade (Flagship); ● Comandos (USE, SKIP, GOTOP, GO BOTTOM, e GO #); ● PC: 486 50 Mhz. Memória: 4Mb de RAM, HD: 512 Mb; ● Outras tecnologias da época:Turbo Pascal, C, Basic, DataFlex.
  6. 6. Adianti Solutions Ltda © Pablo Dall'Oglio #6 CA-Clipper Telas desenhadas artisticamente by hand
  7. 7. Adianti Solutions Ltda © Pablo Dall'Oglio #7 Procedural CAD_CLI.PRG @ 2,5,19,70 window "Cadastro de Clientes" cCOD_CLI := cad_cli->COD_CLI cNOME := cad_cli->NOME cENDERECO := cad_cli->ENDERECO @ 0,1 say "Codigo_____________ " + cad_cli->COD_CLI @ 1,1 say "Nome________________" get cNOME pict "@!" @ 2,1 say "Endereço____________" get cENDERECO if CONFIRMA("Confirma Alteração ?",20,44) if cad_cli->(RECLOCK()) cad_cli->COD_CLI := cCOD_CLI cad_cli->NOME := cNOME cad_cli->ENDERECO := cENDERECO cad_cli->(dbunlockall()) endif endif Exibe e coleta Registro trabalhado como um objeto Sem SQL Persistência e concorrência
  8. 8. Adianti Solutions Ltda © Pablo Dall'Oglio #8 Procedural NOTA_FISCAL.PRG function PROCESSA_NF() ABRE("RES_NF") if CONFIRMA("Confirma Nota Fiscal") res_nf->(dbappend()) if CONFIRMA("Imprimir Nota Fiscal") PRINT_NF( cSERIE_NF, nNUM_NF, cFILE ) endif if CONFIRMA("Imprimir Duplicata") IMPR_DUPLICATA(nNUM_NF, cCOD_CLI) endif endif Funções do User Space
  9. 9. Adianti Solutions Ltda © Pablo Dall'Oglio #9 Procedural CUPOM_FISCAL.PRG function PROCESSA_CF() function REGISTRA_CF( nVLR_TOT_CF,... ) function SHOW_TOTAIS() function CANCELA_ITEM( nITEM, cDESCR ) function BAIXA_ESTOQUE() function ALTA_ESTOQUE() function ABRE_CUPOM() function FECHA_CUPOM( nVLR_TOT_CF, nVLR_PAGO, ... ) function CANCELA_CUPOM( lFICOUABERTO ) function VENDE_ITEM( cCODIGO, cDESCR, nQUANT, nPR_VENDA, cITEM ) function LEITURA_X() function REDUCAO_Z() Cadeia de dependências não muito clara
  10. 10. Adianti Solutions Ltda © Pablo Dall'Oglio #10 CA-Clipper Considerações: ● Muito rápido e enxuto (Ex: Controle de vendas 841 Kb); ● Não leva a organização modular, somente separação por funções; ● Não leva a organização de nomes: Fica a cargo de cada um; ● Programas geralmente organizados em torno de telas; ● Não facilita o reuso: Dificuldade identificar partes para reaproveitar; ● Suscetível à mudanças: Dificuldade em localizar dependências; ● Diferentes aspectos no mesmo programa: – Apresentação: @ 0,1 say "Codigo_____________ "; – Controle: if CONFIRMA("Confirma Nota Fiscal"); – Persistência: cad_cli->(dbunlockall()).
  11. 11. Adianti Solutions Ltda © Pablo Dall'Oglio #11 1998 Coisas muito estranhas aconteceram
  12. 12. Adianti Solutions Ltda © Pablo Dall'Oglio #12 1998 Coisas muito estranhas mesmo
  13. 13. Adianti Solutions Ltda © Pablo Dall'Oglio #13 Delphi Sobre o Delphi ● Lançado pela Borland em 1995, como substituto doTurbo Pascal; ● Assim como oTurbo Pascal, foi idealizado por Anders Hejlsberg (DN); ● Anders Hejlsberg em 1996 move para MS, onde idealizou o C#; ● Em 2001, foi lançado o Kylix, versão para Linux; ● Posteriormente, a comunidade criou o Lazarus; ● Características fortes: – Programação visual (drag and drop); – Programação orientada a eventos (OnClick, OnChange); – Utilização de componentes (TButton, TEdit, TSpinButton); ● Outras tecnologias da época:Visual Basic, Power Builder.
  14. 14. Adianti Solutions Ltda © Pablo Dall'Oglio #14 Delphi Data Sources, Tabelas usadas pelo formulário Mapeamento entre objeto visual e BD
  15. 15. Adianti Solutions Ltda © Pablo Dall'Oglio #15 Delphi unit untCadastro; uses Windows, Messages, SysUtils, Classes, Graphics, Controls, ... type TfrmCadastro = class(TForm) dtbEndereco: TDatabase; tabEndereco: TTable; dtsEndereco: TDataSource; tabEnderecoNome: TStringField; dgrEndereco: TDBGrid; Label1: TLabel; dedCodigo: TDBEdit; var frmCadastro: TfrmCadastro; implementation Formulário: Arquivo separado Data Sources, Tabelas usadas pelo formulário
  16. 16. Adianti Solutions Ltda © Pablo Dall'Oglio #16 Delphi procedure TfrmCadastro.FormCreate(Sender: TObject); begin dtbEndereco.Open; tabEndereco.Open; end; procedure TfrmCadastro.sbnEditarClick(Sender: TObject); begin tabEndereco.Edit; end; procedure TfrmCadastro.sbnGravarClick(Sender: TObject); begin tabEndereco.Post; end; Entra em edição Envia dados
  17. 17. Adianti Solutions Ltda © Pablo Dall'Oglio #17 Delphi Considerações: ● Fortaleceu o uso da Orientação a Objetos; ● Consolidou o conceito de componente de interface (cápsulas); ● Levou a uma separação entre Interface (.dfm) e Lógica (.pas); ● Formou uma geração de programadores, acostumada à: – Arrastar e soltar objetos na tela (drag and drop); – Programar a lógica orientada à eventos; – Vincular fortemente o modelo de dados à interface. ● Não promoveu a tempo uma separação da lógica e do modelo; ● Essa geração tem dificuldades naWeb, que é orientada à requests.
  18. 18. Adianti Solutions Ltda © Pablo Dall'Oglio #18 2000 No Brasil, KLB vendia mais de 1 milhão de discos...
  19. 19. Adianti Solutions Ltda © Pablo Dall'Oglio #19 2000 ZH 16/08/2000
  20. 20. Adianti Solutions Ltda © Pablo Dall'Oglio #20 2001
  21. 21. Adianti Solutions Ltda © Pablo Dall'Oglio #21 Início foi dureza... <?php // configuração $conn = pg_connect("..."); // query $query = 'SELECT id, nome, endereco FROM cliente WHERE id not in (...)'; // resultados $result = pg_query($conn, $query); if ($result) { // apresentação echo '<table border="1">'; while ($row = pg_fetch_assoc($result)) { echo '<tr>'; echo '<td>' . $row['id'] . '</td>'; echo '<td>' . $row['nome'] . '</td>'; echo '<td>' . $row['endereco'] . '</td>'; echo '</tr>'; } echo '</table>'; } pg_close($conn); Business rules Apresentação Configuração
  22. 22. Adianti Solutions Ltda © Pablo Dall'Oglio #22 Design Patterns Padrões de Projeto “Um Pattern descreve um problema que ocorre com frequência em nosso ambiente, e então explica a essência da solução para este problema, de forma que tal solução possa ser utilizada milhões de outras vezes...” Christopher Alexander (1936 arquiteto)
  23. 23. Adianti Solutions Ltda © Pablo Dall'Oglio #23 MVC MVC ● Model ● View ● Controller
  24. 24. Adianti Solutions Ltda © Pablo Dall'Oglio #24 MVC MVC ● Model ● View ● Controller
  25. 25. Adianti Solutions Ltda © Pablo Dall'Oglio #25 Frameworks Frameworks ● Implementam vários Design Patterns; ● Fornecem uma arquitetura (arcabouço) para novas aplicações; ● Conjunto de classes que formam um design abstrato; ● Genéricos para um domínio de problema; ● Estendidos para criar APPs específicas; ● Frozenspots: Partes fixas. – Serviços já implementados. ● Hotspots: Partes flexíveis; – São invocados pelo framework.
  26. 26. Adianti Solutions Ltda © Pablo Dall'Oglio #26 ROR Ruby on Rails (2004) ● Baseado em MVC (Model-View-Controller); ● Fornece estruturas pré-definidas para: – Persistência (Active Record); – Montagem de tela (ActionView); – Controle de ação (Action Controller). ● DRY (Don't RepeatYourself): – Coluna = propriedade; – Sem setters e getters. ● Convention over configuration – Class User = table Users
  27. 27. Adianti Solutions Ltda © Pablo Dall'Oglio #27 TCC O início do interesse: ● Em 2004: – Havia estudado Fowler (2002); ● Em 2005: – Precisava de uma arquitetura para oTCC; – Criei um framework MVC para sistemas; – Foi batizado de Core Framework; ● Em 2006: – Em conversas preliminares, a Univates mostra interesse; – Adota-o como plataforma para desenvolvimento.
  28. 28. Adianti Solutions Ltda © Pablo Dall'Oglio #28 Alfa (2008-)
  29. 29. Adianti Solutions Ltda © Pablo Dall'Oglio #29 Boom O boom dos Frameworks: ● PHP: Zend, CodeIgniter, Cake, Synfony, Laravel,Yii, Prado; ● Java: Spring, Hibernate, Castor, Swing, SWT, Struts, JSF,Vraptor; ● Pyton: Django,TurboGears; ● Ruby: ROR, Rack, Cuba, Padrino; ● Javascript: Angular, Backbone, Ember, React, GWT, Knockout; ● C#: .NET, Nhibernate, Castel.
  30. 30. Adianti Solutions Ltda © Pablo Dall'Oglio #30 Adianti Quando surgiu o Adianti Framework: ● Versão atual iniciou ~2008; ● Lançado oficialmente em 2012; ● Focado em Business apps.
  31. 31. Adianti Solutions Ltda © Pablo Dall'Oglio #3112ª Conferencia Latino-americana de Software Livre Estrutura
  32. 32. Persistência: Active Record, Repository
  33. 33. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #33 Active Record (AF) Armazenar um novo objeto (INSERT). class Pessoa extends TRecord { const TABLENAME = 'tab_pessoas'; const PRIMARYKEY= 'id'; const IDPOLICY = 'max'; // {max, serial} } TTransaction::open('samples'); $object = new Pessoa; $object->name = 'Maria da Silva'; $object->address = 'Rua da Conceicao'; $object->phone = '(51) 8111-2222'; $object->status = 'S'; $object->email = 'maria@email.com'; $object->store(); // armazena o objeto TTransaction::close(); // fecha a transação. Business Rules
  34. 34. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #34 Active Record (AF) Alterar um objeto já existente (UPDATE). TTransaction::open('samples'); // abre uma transação $customer = Customer::find(31); // carrega o cliente 31 if ($customer) // se existe { $customer->phone = '51 8111-3333'; // muda o fone $customer->store(); // armazena o objeto } new TMessage('info', 'Objeto atualizado'); TTransaction::close(); // fecha a transação. INSERT OR UPDATE
  35. 35. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #35 Atalhos (AF) Manipular um conjunto de objetos conforme um filtro. $product = Product::find(2); $products = Product::all(); $products = Product::where('name', 'like', '%Computer%')->load(); $count = User::where('age', '>', 18)->count(); $products = Product::where('name', 'like', '%tablet%')->orderBy('price'); User::where('age', '>', 100)->delete(); Product::where('name', 'LIKE', '%computer%')->take(3)->skip(3); $contacts = Customer::find(123)->hasMany('Contact'); SQL gerado com segurança
  36. 36. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #36 Active Record (ROR) Armazenar um novo objeto (INSERT). class User < ActiveRecord::Base self.primary_key = "id_user" end user = User.new user.name = "David" user.occupation = "Code Artist" user.save // ou user = User.create(name: "David", occupation: "Code Artist") NOT NECESSARY
  37. 37. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #37 Atalhos (ROR) Manipulando Objetos client = Client.find(10) users = User.all david = User.find_by(name: 'David') users = User.where(name: 'David', occupation: 'Code Artist') .order(created_at: :desc) clients = Client.where("orders_count = ?", params[:orders]) clients = Client.limit(5).offset(30) Articles = Article.where('id > 10').limit(20).order('id asc')
  38. 38. Hooks e Callbacks
  39. 39. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #39 Callbacks (ROR) Injetando comportamento no ciclo do objeto: class Account < ActiveRecord::Base before_save :setupdate, :setloggedin private def setupdate self.Account_Update = Time.now end def setloggedin self.Account_LoggedIn = Time.now end end Callbacks: before_save after_save before_update after_update before_destroy after_destroy Callbacks: before_save after_save before_update after_update before_destroy after_destroy Agrega no ciclo de vida Evita sobrescrita
  40. 40. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #40 Hook Methods (AF) Injetando comportamento no ciclo do objeto: app/model/SystemProgram.php class SystemProgram extends TRecord { const TABLENAME = 'system_program'; const PRIMARYKEY= 'id'; const IDPOLICY = 'max'; // {max, serial} public function onAfterStore( $object ) { // ... } public function onAfterDelete( $object ) { // ... } } Hook Methods: onBeforeLoad() onAfterLoad() onBeforeStore() onAfterStore() onBeforeDelete() onAfterDelete() Hook Methods: onBeforeLoad() onAfterLoad() onBeforeStore() onAfterStore() onBeforeDelete() onAfterDelete() Agrega no ciclo de vida Evita sobrescrita
  41. 41. Page Controllers
  42. 42. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #42 Controller (ROR) Executando ações: /clients/new app/controllers/clientes_controller.rb class ClientsController < ApplicationController def new end def edit end def delete end end
  43. 43. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #43 Controller (AF) Executando ações: index.php?class=ClienteController&method=onEdit app/control/ClienteController.php class ClienteController extends TPage { function onEdit() { // ... } function onDelete() { // ... } }
  44. 44. Templates
  45. 45. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #45 Action View (ROR) Apresentando templates: app/controllers/restaurantes_controller.rb class RestaurantesController < ApplicationController def index @restaurantes = Restaurante.all end def show @restaurante = Restaurante.find(params[:id]) end end Template: index.html.erb Como $this->restaurantes, Torna-a disponível para a view
  46. 46. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #46 Action View (ROR) Apresentando templates: app/views/restaurantes/index.html.erb <table> <% @restaurantes.each do |restaurante| %> <tr> <td><%= restaurante.nome %></td> <td><%= restaurante.endereco %></td> <td><%= restaurante.especialidade %></td> </tr> <% end %> </table>
  47. 47. Adianti Solutions Ltda © Pablo Dall'Oglio #47 Html Renderer (AF) app/control/TemplateController.php class TemplateController extends TPage { public function exibe() { $html = new THtmlRenderer('app/resources/customer.html'); TTransaction::open('samples'); $customer = Customer::find(1); $replace = ['code' => $customer->id, 'name' => $customer->name, 'address' => $customer->address]; $html->enableSection('main', $replace); $html->show(); TTransaction::close(); } }
  48. 48. Adianti Solutions Ltda © Pablo Dall'Oglio #48 Html Renderer (AF) <!--[main]--> <table class="tform" style="border:1px solid #B7B7B7"> <tr> <td colspan="2">Customer data</div></td> </tr> <tr> <td width="50%"> ID </td> <td width="50%"> {$id} </td> </tr> <tr> <td width="50%"> Name </td> <td width="50%"> {$name} </td> </tr> <tr> <td width="50%"> Address </td> <td width="50%"> {$address} </td> </tr> </table> <!--[/main]--> Replaces
  49. 49. Adianti Solutions Ltda © Pablo Dall'Oglio #49 Html Renderer (AF)
  50. 50. Componentes
  51. 51. Adianti Solutions Ltda © Pablo Dall'Oglio #51 Componentes Representa um elemento visual, como uma cápsula; Pode ser reaproveitado em diferentes interfaces. $this->datagrid = new TDataGrid; $code = new TDataGridColumn('code', ...); $name = new TDataGridColumn('name', ...); $this->datagrid->addColumn($code); $this->datagrid->addColumn($name); $act1 = new TDataGridAction(...); $act1->setLabel('View name'); $act1->setImage('bs:search blue'); $act_group = new TDataGridActionGroup('Actions'); $act_group->addHeader('Available Options'); $act_group->addAction($act1); $this->datagrid->addActionGroup($act_group);
  52. 52. Adianti Solutions Ltda © Pablo Dall'Oglio #52 Componentes Formulário simples class SimpleFormController extends TPage { private $form; function __construct() { parent::__construct(); $this->form = new TQuickForm; $this->form->setFormTitle('Quick form'); $id = new TEntry('id'); $text = new TText('text'); $this->form->addQuickField('Id', $id, 40); $this->form->addQuickField('Text', $text, 120); $this->form->addQuickAction('Save', new TAction(array($this, 'onSave')), 'ico_save.png'); parent::add($this->form); }
  53. 53. Adianti Solutions Ltda © Pablo Dall'Oglio #53 Componentes Formulário simples
  54. 54. Adianti Solutions Ltda © Pablo Dall'Oglio #54 Comparativo Componentes e templates: ● Templates permitem maior liberdade de criação; ● Templates oferecem maiores dificuldades de manutenção; ● É fácil criar templates; ● Use em: telas peculiares; ● Componentes são mais limitados no aspecto visual; ● É melhor de manter um sistema baseado em componentes; ● É mais complexo criar um componente; ● Use em: telas padronizadas.
  55. 55. Domain-Driven Design
  56. 56. Adianti Solutions Ltda © Pablo Dall'Oglio #56 Orientação a modelos Aplicação orientada à SQL (BAD) ● Inserir autor em livro INSERT INTO autor_livro (autor_id, livro_id) VALUES ('$autor_id', '$livro_id'); ● Retornar os itens da Nota Fiscal SELECT * FROM nf, itens WHERE nf.id = itens.nf_id AND nf.id = '$nf_id' ● Percorrer dados relacionados SELECT * FROM turma, matricula, aluno WHERE turma.id=matricula.turma_id AND matricula.id_aluno = aluno.id AND turma.id = '$turma_id' Cérebro orientado à relações simples chaves entre tabelas Ver 10 piores SQL
  57. 57. Adianti Solutions Ltda © Pablo Dall'Oglio #57 Orientação a modelos Aplicação orientada ao domínio (GOOD) Utilização de relações mais complexas. Modelo relacional é consequência XMI → {PHP, SQL}
  58. 58. Adianti Solutions Ltda © Pablo Dall'Oglio #58 Studio Pro <?php /** * Customer Active Record * @author <your-name-here> */ class Customer extends TRecord { public function get_city() public function addSkill(Skill $skill) public function getSkills() public function load($id) public function store() public function delete($id = NULL) } ?> XML SQL PHP Modelo Astah StarUML
  59. 59. Adianti Solutions Ltda © Pablo Dall'Oglio #59 Orientação a modelos Exemplo de utilização // carrega o filme $filme = new Filme(5); print $filme->distribuidor->nome; print $filme->genero->nome; // carrega o filme $filme = new Filme(5); foreach ($filme->getAtores() as $ator) { print $ator->nome; } // adiciona o ator $ator = new Ator(10); $filme->addAtor( $ator ); $filme->store(); LEGIBILIDADE MAIORLazy Load Agregação
  60. 60. Adianti Solutions Ltda © Pablo Dall'Oglio #60 Orientação a modelos Aplicação orientada ao domínio (GOOD) ● Inserir autor em livro $livro = new Livro( 10 ); $livro->addAutor( new Autor(8) ); $livro->store(); ● Retornar os itens da Nota Fiscal $nf = new NotaFiscal(10); foreach ($nf->getItems() as $item) { print $item->produto->descricao; } ● Percorrer dados relacionados $turma = new Turma(10); foreach ($turma->getMatriculas() as $matricula) { print $matricula->aluno->nome; } NAVEGABILIDADE entre relações
  61. 61. Cache
  62. 62. Adianti Solutions Ltda © Pablo Dall'Oglio #6212ª Conferencia Latino-americana de Software Livre Utilizado em: Carregar objeto, Salvar objeto, Excluir objeto. class Disciplina extends TRecord { const TABLENAME = 'disciplinas'; const PRIMARYKEY = 'id'; const IDPOLICY = 'max'; const CACHECONTROL = 'Cache-Control-Class'; } $turma = new Turma(10); print $turma->disciplina->nome; print $turma->disciplina->curso->nome; foreach ($turma->getMatriculas() as $matricula) { print $matricula->aluno->nome; print $matricula->aluno->cidade->nome; print $matricula->aluno->cidade->estado->nome; } Grandes ganhos de Performance 1/3 tempo na matrícula Deve indicar classe específica Cache de objetos
  63. 63. Adianti Solutions Ltda © Pablo Dall'Oglio #6312ª Conferencia Latino-americana de Software Livre Cache de objetos Store: Ele é gravado tanto no banco de dados (a), quanto no cache (d). Load: Tenta ler da RAM (c). Senão, carrega (b), e grava na RAM (d).
  64. 64. Adianti Solutions Ltda © Pablo Dall'Oglio #64 Tutor
  65. 65. Adianti Solutions Ltda © Pablo Dall'Oglio #65 Template
  66. 66. Adianti Solutions Ltda © Pablo Dall'Oglio #66 Studio Form Designer
  67. 67. Adianti Solutions Ltda © Pablo Dall'Oglio #67 Studio Form Designer class TestView extends TPage { private $form; function __construct() { parent::__construct(); $this->form = new TForm; try { $ui = new TUIBuilder(500,300); $ui->setController($this); $ui->setForm($this->form); $ui->parseFile('app/forms/sample.form.xml'); $this->form->add($ui); $this->form->setFields($ui->getFields()); } catch (Exception $e) { new TMessage('error', $e->getMessage()); } parent::add($this->form); Wrapper
  68. 68. Adianti Solutions Ltda © Pablo Dall'Oglio #68 Studio PDF Designer
  69. 69. Adianti Solutions Ltda © Pablo Dall'Oglio #69 Studio PDF Designer class PDFDesignNFEView extends TPage { function onGenerate() { try { $designer = new TPDFDesigner; $designer->fromXml('app/reports/nfe.pdf.xml'); $designer->generate(); $designer->SetFont('Arial', 'B', 8); $designer->setFontColorRGB( '#4C4491' ); $designer->writeAtAnchor('bairro', 'Centro'); $designer->writeAtAnchor('municipio', 'Cidade teste'); $designer->writeAtAnchor('fone', '(11) 1234-5678'); $designer->gotoAnchorXY('details'); $designer->SetFont('Arial', '', 8); $designer->Cell( 62, 10, '12121212', 1, 0, 'C'); $designer->Cell(140, 10, utf8_decode('Guaraná'), 1, 0, 'L'); } //... Wrapper
  70. 70. Adianti Solutions Ltda © Pablo Dall'Oglio #70 Obrigado ● Adianti Framework: – www.adianti.com.br/framework ● Contato: – www.dalloglio.net – www.adianti.com.br – @pablodalloglio – @adiantisolution ● Não esquecer de falar do Sorteio!

×