goncin@wordpress.com:~$ _

Linux, programação e toda sorte de nerdices

Arquivos da Categoria: php

Integrando WordPress e Yii Framework: uma nova abordagem

Artigo publicado originalmente em inglês no wiki do Yii
Framework
, em 1º de julho de 2011.

Parece que muitas pessoas andam tentando fazer com que o WordPress e o Yii Framework trabalhem em conjunto. Eu me deparei com o mesmo problema, mas agora creio que o resolvi, após muito quebrar a cuca e gastar inúmeras horas de trabalho.

Meu ponto de partida foi a leitura dos artigos (em inglês) do imasia e do isekream. O princípio de ambas as pesquisas é chamar a aplicação Yii de dentro do WordPress. A solução que proponho coloca-se na mão contrária: utilizar o WordPress como modelo de página para a aplicação Yii, de modo que o usuário final nem perceberá que saiu do primeiro e foi parar na segunda.

Vamos em frente.

No WordPress

Minha instalação do WordPress usa um tema-filho do Twentyten (o padrão do WordPress 3.x). Para os efeitos deste tutorial, assumamos que nossa instalação do WordPress está em http://seuservidor.com.br/wp. Ao aplicá-lo, altere o caminho de acordo com sua situação.

O primeiro passo é criar um arquivo na pasta do seu tema do WP, e chamá-lo yii-template.php.

Arquivo: [raiz-wp]/wp-content/themes/[seutema]/yii-template.php

<?php
/**
 * Template Name: Yii Template
 *
 * Template for Yii-powered pages
 *
 * The "Template Name:" bit above allows this to be selectable
 * from a dropdown menu on the edit page screen.
 *
 * @package WordPress
 * @subpackage Twenty_Ten
 * @since Twenty Ten 1.0
 */
get_header();
?>
 
<div id="container">
  <div id="content" role="main">
 
    <?php
    /*
     * O marcador de lugar abaixo será substituído mais tarde pelo conteúdo gerado pelo Yii.
     */
    ?>
    <!-- ###yii-content-placeholder### -->
 
  </div><!-- #content -->
</div><!-- #container -->
 
<?php get_sidebar(); ?>
<?php get_footer(); ?>

Acabamos de criar um novo modelo para páginas do WordPress.

O passo seguinte é criar uma página no WordPress que use o modelo recém-criado. Acesse o painel administrativo do seu WP, crie uma página e selecione “Yii Template” (deve estar listado) como modelo da página. Informe yiipage no título e deixe o conteúdo da página em branco. Após salvar, você deverá ser capaz de ver a página usando o endereço http://seuservidor.com.br/wp/yiipage.

Isso é tudo o que tínhamos que fazer no WordPress.

No Yii

Crie uma aplicação Yii (usando yiic) sob a raiz da sua instalação do WP, numa pasta chamada yii. Você deverá ver a conhecida página inicial do Yii ao acessar http://seuservidor.com.br/wp/yii.

We’ll need a custom ClientScript class. Let’s create it under [yii-root]/protected/components.

Teremos que criar nossa própria classe ClientScript. Vamos fazê-lo sob  [raiz-yii]/protected/components.

Arquivo: [raiz-yii]/protected/components/ClientScript.php

<?php
 
class ClientScript extends CClientScript {
 
  public function renderHead(&$output) {
    $html = '';
    foreach ($this->metaTags as $meta) $html.=CHtml::metaTag($meta['content'], null, null, $meta) . "\n";
    foreach ($this->linkTags as $link) $html.=CHtml::linkTag(null, null, null, null, $link) . "\n";    
    foreach ($this->cssFiles as $url => $media) $html.=CHtml::cssFile($url, $media) . "\n";
    foreach ($this->css as $css) $html.=CHtml::css($css[0], $css[1]) . "\n";
    if ($this->enableJavaScript) {
      if (isset($this->scriptFiles[self::POS_HEAD])) {
        foreach ($this->scriptFiles[self::POS_HEAD] as $scriptFile) $html.=CHtml::scriptFile($scriptFile) . "\n";
      }

      if (isset($this->scripts[self::POS_HEAD])) $html.=CHtml::script(implode("\n", $this->scripts[self::POS_HEAD])) . "\n";
    }

    if ($html !== '') {
      $count = 0;
      /*
       * A linha abaixo garante que tudo o que for registrado pelo Yii no POS_HEAD irá imediatamente
       * antes do final do cabeçalho (). Dessa forma, os estilos e scripts do Yii serão
       * renderizados *ABAIXO* e *DEPOIS* daqueles do WordPress.
       *
       * A linha original na classe ancestral era assim:
       * $output = preg_replace('/(]*>|)/is', '$1', $output, 1, $count);
       *
       */
      $output = preg_replace('/()/is', '$1', $output, 1, $count);
      if ($count) $output = str_replace('', $html, $output);
      else $output=$html . $output;
    }
  }
 }
?>

Será necessário também sobrepor o método CController.beforeRender(). Isso pode ser feito no arquivo Controller.php, que já existe em [raiz-yii]/protected/components.

Arquivo: [raiz-yii]/protected/components/Controller.php

<?php
/**
 * Controller is the customized base controller class.
 * All controller classes for this application should extend from this base class.
 */
class Controller extends CController
{
    /**
     * @var string the default layout for the controller view. Defaults to '//layouts/column1',
     * meaning using a single column layout. See 'protected/views/layouts/column1.php'.
     */
    public $layout='//layouts/column1';
    /**
     * @var array context menu items. This property will be assigned to {@link CMenu::items}.
     */
    public $menu=array();
    /**
     * @var array the breadcrumbs of the current page. The value of this property will
     * be assigned to {@link CBreadcrumbs::links}. Please refer to {@link CBreadcrumbs::links}
     * for more details on how to specify this property.
     */
    public $breadcrumbs=array();
 
  protected function beforeRender($view) {
 
    /* 
     * Let's prevent Yii from registering jQuery library. We'll stick with
     * the jQuery registered by WordPress.
    */
    Yii::app()->clientScript->scriptMap=array(
      'jquery.js'=>false,
      'jquery.min.js'=>false,
    );
    /*
     * O WordPress trabalha com a jQuery no modo "sem-conflito", i. e., ele não define o apelido $
     * para o objeto jQuery. No entanto, muitos scripts e plugin do Yii supõem que $ aponta para a
     * jQuery, de modo que precisamos fazer essa associação nós mesmos.
     */
    if(! Yii::app()->clientScript->isScriptRegistered('jquery-alias', CClientScript::POS_HEAD)) {
      Yii::app()->clientScript->registerScript('jquery-alias', 'var $ = jQuery', CClientScript::POS_HEAD);
    }

    /*
     * Para manter a coerência visual entre as páginas comuns do WordPress e aquelas turbinadas
     * pelo Yii, devemos utilizar o CSS fornecido pelo tema do WordPress. Contudo, o Yii usa
     * algumas classes CSS específicas para formulários, então é uma boa ideia registrar o
     * arquivo que as contém.
     */
    Yii::app()->clientScript->registerCssFile(Yii::app()->request->baseUrl . '/css/form.css');

    return parent::beforeRender($view);
  }

}
?>

Agora, a pedra fundamental da ideia toda. Vamos alterar o arquivo principal do layout do Yii, para buscar a página do WordPress que preparamos previamente, e substituir o marcador de lugar pelo conteúdo gerado pelo framework.

Arquivo: [raiz-yii]/protected/views/layouts/main.php

<?php
  /*
   * Aqui reside o cerne da mágica. Ao invés de usar o HTML do arquivo principal de
   * layout fornecido pelo Yii, buscamos a página especial do WordPress (como uma string)
   * e substituímos o marcador de lugar pelo conteúdo real.
   */

  echo str_replace('<!-- ###yii-content-placeholder### -->',
    $content, file_get_contents('http://seuservidor.com.br/wp/yiipage'));

  /* NÃO SE ESQUÇA DE APAGAR O CONTEÚDO DA PÁGINA ORIGINAL 😉 */

?>

Por fim, vamos dizer ao Yii para usar nossa classe ClientScript personalizada.

Arquivo: [raiz-yii]/protected/config/main.php

<?php   
    (...)   'components'=-->array(
    /*
     * Vamos usar nosso próprio ClientScript (application.components.ClientScript).
     */
    'clientScript' => array(
      'class' => 'ClientScript'
    ),
  (...)
?>

E isso é tudo. Você deverá conseguir ver sua aplicação Yii com tema WordPress acessando http://seuservidor.com.br/wp/yii, e até mesmo fazer login mediante http://seuservidor.com.br/wp/yii/index.php?r=site/login. Adicionalmente, você pode ajustar sua configuração do Yii para usar URLs de caminho e ocultar o nome do script (assim, seus URLs se parecerão com http://seuservidor.com.br/wp/yii/controller/action). E sim, o AJAX funciona! *__*

De volta ao WordPress, a tarefa final é criar itens de menu (como links) apontando para as páginas turbinadas pelo Yii.

Espero que isto seja tão útil para você quanto foi para mim. Saudações!

Anúncios

Meu ambiente de trabalho em 7 itens

Não sei direito onde a coisa começou. Recebi do Alexandre Gaigalas (@alganet) e, num segundo momento, também do Bruno Roberto Gomes (@brgomes) a incumbência de compartilhar 7 itens do meu ambiente de trabalho. Tanto um quanto o outro já escreveu sobre o mesmo tema, tendo recebido a tarefa de outras pessoas. Pesquisei um pouco a respeito, e descobri no blog do Duodraco que a ideia é fazer disso um meme. Então vamos lá. 🙂

Meu ambiente de trabalho. Não reparem a bagunça :P

Meu ambiente de trabalho. Não reparem a bagunça 😛

1) Um Ubuntu altamente personalizado

Há cerca de um ano, encarei o desafio de abandonar o Windows como plataforma de desenvolvimento e usar Linux para esse propósito. Escolhi a distribuição Ubuntu, que já usava nos meus computadores pessoais e com a qual já estava familiarizado.

Como gosto de deixar as coisas bem do meu jeito, meu Ubuntu, ao menos visualmente, em nada se parece com uma instalação recém-feita desse sistema operacional. Entre as personalizações que costumo fazer na interface, estão:

  • a troca do tema padrão (atualmente, uso o tema Orta com os ícones Faenza);
  • a redução para apenas um painel, o inferior, e o utilização do Docky na parte superior da tela para lançamento de aplicativos;
  • o applet Cardápio no lugar do tradicional menu do GNOME; e
  • o applet Dockbarx em substituição à lista de janelas/tarefas.

Minha instalação corrente começou na versão Karmic Koala (9.10), foi atualizada para a Lucid Lynx (10.04 LTS) e, no momento, corresponde à versão mais atual do SO, Maverick Meerkat (10.10). Tudo isso sem precisar formatar, comprovando a estabilidade do ambiente. Um ano, três versões e tudo rodando redondo. Exceto, é claro, quando eu tento fazer alguma atualização bleeding edge e ferro alguma coisa – a maior vítima é o driver da placa de vídeo. Mas #SouDev e não desisto nunca, daqui a pouco ponho o sistema de volta pra funcionar.

2) Netbeans para desenvolvimento PHP

Sempre estive em busca do IDE perfeito e open source (ou, pelo menos, freeware) para desenvolver em PHP (havia até um post meu sobre isso numa rede do Ning, mas todo mundo sabe o que aconteceu…). A meu ver, o estado da arte em termos de ambiente integrada para essa linguagem ainda não foi atingido. Contudo, o Netbeans evoluiu rapidamente e é, nos dias atuais, o que mais se aproxima do Olimpo. Tem, como vantagens, o fato de ser open source, multiplataforma (ainda que “multiplataforma”, aqui, seja sinônimo de Java) e relativamente leve, consideradas as circunstâncias. Por outro lado, ser baseado em Java, após a aquisição da Sun pela Oracle, é algo no mínimo temerário. Não por acaso, aguardo ansiosamente que o KDevelop com suporte a PHP amadureça e se torne logo utilizável. Pelo que já vi deste último, vem coisa boa por aí.

Netbeans IDE 7.0 Beta

Netbeans IDE 7.0 Beta

Quem estiver interessado no meu esquema (escuro) de cores para o Netbeans, pode baixá-lo aqui e importá-lo em Ferramentas > Opções > Importar (no canto inferior esquerdo do diálogo).

3) Wine, PlayOnLinux e Winetricks

Esta tríade de utilitários permite executar no Linux muitos programas da plataforma Windows. Se o Wine é uma camada de tradução das bibliotecas de runtime do Windows, o PlayOnLinux é um front-end que, por intermédio de scripts, automatiza a instalação de vários aplicativos comuns (algumas versões do Microsoft Office e do Photoshop, por exemplo), embora seu foco seja a instalação de jogos. Por seu turno, o Winetricks é um script que localiza, baixa e instala muitas das dependências mais recorrentes de programas Windows, como as fontes TrueType da Microsoft, os MDAC, os runtimes do Visual Basic e do Visual C++, etc.

PSPad editor rodando via Wine

PSPad editor rodando via Wine

Dessa forma, consigo trabalhar, no Ubuntu, com alguns bons programas feitos para a plataforma do Tio Bill, tais como o PSPad, o EMS SQL Manager 2010 for MySQL e o EMS SQL Manager 2008 for SQL Server.

4) Firefox com WebDeveloper Toolbar e outras extensões

Como desenvolvedor web, tenho um bom número de navegadores instalados (o Infernet Explorer roda na VM, veja mais abaixo). Meu navegador principal continua sendo o Firefox, porque muitas de suas extensões ainda não encontram paralelos para o Google Chrome – apesar de todos os predicados deste. Dentre as extensões que mais utilizo, estão a WebDeveloper Toolbar e a DownThemAll!. Um recurso nativo particularmente interessante do navegador, para mim, é o Console de Erros Javascript – pego muitos erros por ele, sem sequer precisar acionar o Firebug.

Firefox com WebDeveloper Toolbar em ação

Firefox com WebDeveloper Toolbar em ação

5) VMWare Player

OK, esse não é open source, é só freeware. Trabalho uma Instituição de Ensino Superior com foco em Ciências Sociais Aplicadas, ou, traduzindo, o povo daqui adora uma planilha. E, para manter a compatibilidade, eu, o único linuxista dessas bandas, não posso viver só de OpenOffice.org. Necessito utilizar o Microsoft Office, versão 2010, adquirida pela Instituição e que (ainda) não consegui instalar via Wine. Há outras cositas também que me forçam a ter um ambiente Windows à disposição, como Photoshop, Delphi (para alguns sistemas legados) e Crystal Reports.

Durante muito tempo, deixei o VirtualBox , da Sun Oracle, encarregado das minhas máquinas virtuais. Sem embargo, dois fatores fizeram com que eu passasse a utilizar o VMWare Player: (1) este divide o disco virtual em vários arquivos, facilitando o processo de backup e (2) com ele, os efeitos visuais funcionam, ao contrário do que ocorria com o VirtualBox. Pode parecer frescura, mas, para mim, os efeitos visuais são fundamentais, principalmente quanto a testá-los em outras distros Linux e versões futuras do Ubuntu, coisa que faço com frequência. Além do mais, suspender e recuperar uma VM mostrou-se sensivelmente mais rápido no VMWare Player, relativamente ao VirtualBox.

VMWare Player rodando Windows 7

VMWare Player rodando Windows 7

6) Gnome-RDP Remmina

UPDATE: seguindo o conselho do visitante BlueHood, expresso em seu comentário mais abaixo, acabei por trocar o Gnome-RDP pelo Remmina, até então desconhecido para mim. Vale a pena conhecê-lo! =D

Há muitos servidores rodando Windows Server aqui. E a rede toda é baseada no Active Directory. Felizmente, o Ubuntu conta com ferramentas para acesso remoto a máquinas Windows utilizando o protocolo RDP (mais conhecido por “Terminal Services”). O Gnome-RDP Remmina é simples, objetivo, e cumpre muito bem o seu papel, e ademais suporta também os protocolos VNC, SFTP e SSH. Para quem utiliza KDE, o utilitário equivalente é o KRDC.

O Remmina acessando um servidor Windows via Terminal Services

O Remmina acessando um servidor Windows via Terminal Services

7) The Gimp

OK, OK, passo longe de ser um designer. Mas nem por isso estou livre de usar softwares de edição gráfica. Tenho o Photoshop instalado na VM, e <vergonha-propria mode="on"> desse programa sei utilizar menos de 1% do seu potencial </vergonha-propria>.

Quando a tarefa com imagens não é complexa o bastante para justificar a subida da VM à memória, faço uso do Gimp, sempre em Single-Window mode. Com ele, consigo fazer as coisas mais triviais, como redimensionamento e conversão de formatos, recortes e strokes. Enfim, no quesito “software gráfico” sou um mero principiante, em início de aprendizado, esperando absorver novas habilidades à medida que as necessidades surjam.

The Gimp e o meu papel de parede atual

The Gimp e o meu papel de parede atual

Bonus track: Terminal + Guake

Nenhum desenvolvedor que se preze deve temer a linha de comando. Algumas tarefas (como, por exemplo, atualizar o Ubuntu) são muito mais simples via terminal. E o Guake, uma quase-unanimidade, torna a praticidade do terminal ainda mais prática, se é que me entendem. Após instalado e carregado, basta um F12 para que uma janela de terminal se descortine com elegância à frente de seus olhos.

O Guake trabalhando

O Guake trabalhando

Passando a bola adiante

Para manter o espírito do meme, passo a bola para o Francisco Prado (@fr_prado), o Henrique Lobo Weissmann (@loboweissmann), o Bruno Bemfica (@CodeAddicted) e o Fábio Vedovelli (@vedovelli). Compartilhem sua forma de trabalho, pessoal! 🙂

Normalizando nomes próprios com PHP

Salve, pessoal! Para compensar minha relativa inatividade nos últimos tempos, volto hoje com um post mais denso, que acredito e espero que seja útil a toda a comunidade #SouDev.

Vou tratar sobre normalização de nomes próprios. Norma… o quê? 😕

O problema

Algo que sempre achei horroroso em bancos de dados é a falta de padrão na capitalização (uso de letras maiúsculas e minúsculas) em nomes próprios – sejam de pessoas, logradouros ou localidades. Sobrinhos, geralmente, gravam no BD esses dados como foram coletados ou digitados, e programadores preguiçosos, no mais das vezes, limitam-se a aplicar um strtoupper() ou equivalente e entopem o cadastro com LETRAS MAIÚSCULAS. Na sinceridade, não sei qual das duas situações deixa o banco mais feio. O uso indiscriminado de letras maiúsculas, vale lembrar, cansa os olhos e dificulta a leitura após um certo tempo.

Já vi um caso em que a “saída” foi o uso de ucfirst() puro e simples. Menos mau, mas tão indolente quanto.

Fazer uma normalização, transformando “JOSÉ DA SILVA PEREIRA E SOUZA” em “José da Silva Pereira e Souza” não é uma tarefa difícil, desde que o desenvolvedor esteja atento a alguns detalhes.

A solução

Criei uma classe com um método estático em PHP (para não fugir ao paradigma da orientação a objetos) para propor minha solução. Expliquei, tanto quanto pude, todas as etapas nos comentários do código. Trata-se, em última instância, da implementação de um algoritmo relativamente simples, que não deve oferecer dificuldades para ser portado para outras linguagens. Se você utiliza PHP, de agora em diante aplique GUtils::normalizarNome($nome) e tenha um cadastro mais bonitinho e legível! 😛 Se não, implemente a ideia em sua linguagem favorita. 😉

<?php
/**
 * Classe contêiner para métodos estáticos de utilidades variadas
 *
 * @author goncin (goncin ARROBA gmail PONTO com)
 */
class GUtils {

  /**
   * Constantes definidas para melhor legibilidade do código. O prefixo NN_ indica que
   * seu uso está relacionado ao método público e estático normalizarNome().
   */
  const NN_PONTO = '\.';
  const NN_PONTO_ESPACO = '. ';
  const NN_ESPACO = ' ';
  const NN_REGEX_MULTIPLOS_ESPACOS = '\s+';
  const NN_REGEX_NUMERO_ROMANO =
    '^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$';

   /**
   * Normaliza o nome próprio dado, aplicando a capitalização correta de acordo
   * com as regras e exceções definidas no código.
   * POR UMA DECISÃO DE PROJETO, FORAM UTILIZADAS FUNÇÕES MULTIBYTE (MB_) SEMPRE
   * QUE POSSÍVEL, PARA GARANTIR SUA USABILIDADE EM STRINGS UNICODE.
   * @param string $nome O nome a ser normalizado
   * @return string O nome devidamente normalizado
   */
  public static function normalizarNome($nome) {

    /*
     * A primeira tarefa da normalização é lidar com partes do nome que
     * porventura estejam abreviadas,considerando-se para tanto a existência de
     * pontos finais (p. ex. JOÃO A. DA SILVA, onde "A." é uma parte abreviada).
     * Dado que mais à frente dividiremos o nome em partes tomando em
     * consideração o caracter de espaço (" "), precisamos garantir que haja um
     * espaço após o ponto. Fazemos isso substituindo todas as ocorrências do
     * ponto por uma sequência de ponto e espaço.
     */
    $nome = mb_ereg_replace(self::NN_PONTO, self::NN_PONTO_ESPACO, $nome);

    /*
     * O procedimento anterior, ou mesmo a digitação errônea, podem ter
     * introduzido espaços múltiplos entre as partes do nome, o que é totalmente
     * indesejado. Para corrigir essa questão, utilizamos uma substituição
     * baseada em expressão regular, a qual trocará todas as ocorrências de
     * espaços múltiplos por espaços simples.
     */
    $nome = mb_ereg_replace(self::NN_REGEX_MULTIPLOS_ESPACOS, self::NN_ESPACO,
      $nome);

    /*
     * Isso feito, podemos fazer a capitalização "bruta", deixando cada parte do
     * nome com a primeira letra maiúscula e as demais minúsculas. Assim,
     * JOÃO DA SILVA => João Da Silva.
     */
    $nome = mb_convert_case($nome, MB_CASE_TITLE, mb_detect_encoding($nome));

    /*
     * Nesse ponto, dividimos o nome em partes, para trabalhar com cada uma
     * delas separadamente.
     */
    $partesNome = mb_split(self::NN_ESPACO, $nome);

    /*
     * A seguir, são definidas as exceções à regra de capitalização. Como
     * sabemos, alguns conectivos e preposições da língua portuguesa e de outras
     * línguas jamais são utilizadas com a primeira letra maiúscula.
     * Essa lista de exceções baseia-se na minha experiência pessoal, e pode ser
     * adaptada, expandida ou mesmo reduzida conforme as necessidades de cada
     * caso.
     */
    $excecoes = array(
      'de', 'di', 'do', 'da', 'dos', 'das', 'dello', 'della',
      'dalla', 'dal', 'del', 'e', 'em', 'na', 'no', 'nas', 'nos', 'van', 'von',
      'y'
    );

    for($i = 0; $i < count($partesNome); ++$i) {

      /*
       * Verificamos cada parte do nome contra a lista de exceções. Caso haja
       * correspondência, a parte do nome em questão é convertida para letras
       * minúsculas.
       */
      foreach($excecoes as $excecao)
        if(mb_strtolower($partesNome[$i]) == mb_strtolower($excecao))
          $partesNome[$i] = $excecao;

      /*
       * Uma situação rara em nomes de pessoas, mas bastante comum em nomes de
       * logradouros, é a presença de numerais romanos, os quais, como é sabido,
       * são utilizados em letras MAIÚSCULAS.
       * No site
       * http://htmlcoderhelper.com/how-do-you-match-only-valid-roman-numerals-with-a-regular-expression/,
       * encontrei uma expressão regular para a identificação dos ditos
       * numerais. Com isso, basta testar se há uma correspondência e, em caso
       * positivo, passar a parte do nome para MAIÚSCULAS. Assim, o que antes
       * era "Av. Papa João Xxiii" passa para "Av. Papa João XXIII".
       */
      if(mb_ereg_match(self::NN_REGEX_NUMERO_ROMANO,
        mb_strtoupper($partesNome[$i])))
        $partesNome[$i] = mb_strtoupper($partesNome[$i]);
    }

    /*
     * Finalmente, basta juntar novamente todas as partes do nome, colocando um
     * espaço entre elas.
     */
    return implode(self::NN_ESPACO, $partesNome);

  }

}
const NN_PONTO = ‘\.’;
const NN_PONTO_ESPACO = ‘. ‘;
const NN_ESPACO = ‘ ‘;
const NN_REGEX_MULTIPLOS_ESPACOS = ‘\s+’;
const NN_REGEX_NUMERO_ROMANO =
‘^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$’;

Aproveitando “layouts” implementados em ASP em aplicações PHP

Hoje, quase sem querer, descobri uma solução inusitada que me poupou muito tempo e esforço. Senta que lá vem história…

O caso

Estava eu trabalhando num hotsite para um congresso internacional. Uma outra pessoa fez todo o layout e as páginas informativas, tendo ficado por minha conta desenvolver o processo de inscrição dos participantes.

O problema

O layout e as páginas informativas foram feitas em ASP (clássico), e eu vou desenvolver o procedimento de inscrição em PHP. As páginas da inscrição devem seguir o look and feel das demais páginas, aproveitando cabeçalho, rodapé e menus.

A solução

No código-fonte ASP, havia três includes:

<!--#include file="cabecalho.asp"-->
(...)
<!--#include file="menu.asp"-->
(...)
<!--#include file="rodape.asp"-->

Para não ter de refazer em PHP esses três arquivos, que, aliás, estavam alocados em outro servidor, achei por bem pegar o conteúdo deles, já devidamente processados, e injetá-los no layout para ser usado com PHP. Assim, esses três includes transformaram-se em:

<?php echo file_get_contents('http://servidor/caminho/cabecalho.asp'); ?>
(...)
<?php echo file_get_contents('http://servidor/caminho/menu.asp'); ?>
(...)
<?php echo file_get_contents('http://servidor/caminho/rodape.asp'); ?>

Funcionou, foi uma boa sacada, mas isso resolvia apenas parte do problema. Como os arquivos incluídos estavam em outro servidor em relação ao meu script PHP, os hiperlinks e os caminhos para as imagens ficaram quebrados. Foi necessário incluir o caminho para o servidor nas tags a e image. Nada que um str_replace não dê jeito.

<?php
  $include = file_get_contents('http://servidor/caminho/cabecalho.asp');
  $include = str_replace(array('src="', 'href="'),
    array('src="http://servidor/caminho/', 'href="http://servidor/caminho/') , $include);
  echo $include;
?>
(...)
<?php
  $include = file_get_contents('http://servidor/caminho/menu.asp');
  $include = str_replace(array('src="', 'href="'),
    array('src="http://servidor/caminho/', 'href="http://servidor/caminho/') , $include);
  echo $include;
?>
(...)
<?php
  $include = file_get_contents('http://servidor/caminho/rodape.asp');
  $include = str_replace(array('src="', 'href="'),
    array('src="http://servidor/caminho/', 'href="http://servidor/caminho/') , $include);
  echo $include;
?>

E voilà! Tudo funcionando, sem precisar reimplementar do zero o layout em PHP. 🙂 Agora posso me concentrar apenas em gerar o conteúdo.

Gerador da letra da musiquinha do elefante em PHP

Divirtam-se! 😛

<?php

echo "1 elefante incomoda muita gente\n";

for($i = 2; $i <= PHP_INT_MAX; ++$i) {

	echo "$i elefantes ";

	for($j = 0; $j < $i; ++$j)
		echo 'incomodam ';

	echo "muito mais\n";

	++$i;

	echo "$i elefantes incomodam muita gente\n";

}

O novo Registro de Identidade Civil (RIC), e as implicações para quem é desenvolvedor

Salve, pessoal!

Após um loooongo hiato, volto a blogar. E a inspiração deste post surgiu a partir de um tweet do glorioso @miguelmolina78.

Como deve ser do conhecimento de todos, o Governo Federal tomou a iniciativa de criar o Registro de Identidade Civil (RIC), instituído pela Lei nº 9.454, de 7 de abril de 1997, e regulamentado pelo Decreto nº 7.166, de 5 de maio de 2010. O lapso de mais de três anos entre a lei e o decreto é algo relativamente normal, pois, enquanto a primeira apenas estatuiu que o RIC existisse, o segundo é que especifica como seu funcionamento no mundo real, a partir de estudos técnicos. Sua emissão já começou. Ainda assim, muitas questões ainda estão por ser respondidas.

O principal objetivo do RIC é acabar, paulatinamente, com a confusão gerada pela emissão das Carteira de Identidade (RG) pelos Estados e pelo Distrito Federal. O atual sistema permite que, em tese, uma pessoa possa ter até 27 (!!) RGs com números distintos, cada qual emitido por uma Unidade da Federação diferente. E, como se sabe, cada uma dessas UFs é plenamente autônoma para adotar o sistema de numeração que quiser nos RGs que emite, tornando ingrata, para nós desenvolvedores, a tarefa de validá-los. Quantos de nós não usam o velho e bom CPF (que deveria ser utilizado apenas por instituições financeiras) para identificar unicamente uma pessoa num cadastro, exatamente por falta de padronização dos RGs?

Pois bem, se o RIC cumprir seu propósito, a vida dos #SouDev será bastante facilitada. Todavia, como já disse, alguns pontos ainda estão pendentes. Do nosso ponto de vista, o mais importante talvez seja o cálculo do dígito verificador (DV) do número do RIC.

RIC de exemplo (divulgação)

RIC de exemplo (divulgação)

A partir das imagens de divulgação disponibilizadas pelo Governo Federal (ainda não tive o privilégio de “ver com a mão” um RIC de verdade), o que se pode inferir é que o número RIC é composto por 10 (dez) dígitos numéricos, seguidos por um hífen e pelo DV. Se o cálculo do DV seguir o padrão Módulo 11, calculá-lo e validá-lo não deve ser diferente do que já fazemos em relação aos números de CPF e RG.

<?php
function ricCalcularDigito($numRic) {

  // Retira o hífen do número RIC, caso haja
  $numRic = str_replace('-', '', $numRic);

  if(strlen($numRic) < 10 || strlen($numRic) > 11)
    throw new Exception ('[ricCalcularDigito] O número RIC deve conter 10 dígitos (sem o DV) ou 11 dígitos (com o DV), ignorado o hífen');

  // Sequência de multiplicação
  $seqMult = array (8, 9, 2, 3, 4, 5, 6, 7, 8, 9);

  $soma = 0;

  for($i = 0; $i < 10; ++$i) {

    $caracterPos = substr($numRic, $i, 1);

    if(! is_numeric($caracterPos))
      throw new Exception("[ricCalcularDigito] Encontrado caracter não-numérico na posição $i");

    // Multiplica-se o carater da posição pelonúmero correspondente da sequência de
    // multiplicação, somando-se o resultado aos anteriores
    $soma += ((int) $caracterPos) * $seqMult[$i];

  }

  // O dígitoé, normalmente, o resto da soma dividido por 11...
  $dv = $soma % 11;

  // ... ou 0 (zero), se o resto for igual a 10.
  return $dv == 10 ? 0 : $dv;

}

function ricVerificarDigito($numRic) {

  // Retira o hífen do número RIC, caso haja
  $numRic = str_replace('-', '', $numRic);

  if(strlen($numRic) != 11)
    throw new Exception ('[ricVerificarDigito] O número RIC deve conter 11 dígitos (com o DV), ignorado o hífen');

  $dv = strlen($numRic, 10, 1);

  if(! is_numeric($dv))
    throw new Exception('[ricVerificarDigito] Encontrado caracter não-numérico na posição 11 (DV)');

  return ((int) $dv) == ricCalcularDigito($numRic);

}

Nada obstante, segundo o código acima, o dígito para o número RIC de exemplo é “0” (zero), e não “2”, como sugere a imagem de divulgação. Fica a pergunta: a imagem contém um número com dígito também fictício, ou o cálculo do DV utiliza outro método? Já que nem o Grande Oráculo sabe, o jeito é aguardar os próximos capítulos.

JetBrains PhpStorm: o novo garoto no quarteirão dos IDEs para PHP

Desde o ano passado (pelo menos), o pessoal da JetBrains vinha trabalhando num novo IDE para PHP. Cheguei a baixá-lo durante a fase de desenvolvimento, quando então o novo produto sequer tinha um nome definitivo ainda (era chamado simplesmente de “JetBrains Web IDE”), e se apresentava bastante promissor. A empresa parecia estar buscando o feedback dos desenvolvedores PHP para construir um produto específico para eles. Pois bem, o tempo se passou e finalmente foi lançada a primeira versão do IDE, agora batizado oficialmente como JetBrains PhpStorm.

Antes que me questionem: o JetBrains PhpStorm não é open source 😦 , mas tem um esquema de licenciamento bastante generoso, e sai na faixa para estudantes e desenvolvedores de projetos open source (!). E, mesmo que não se enquadre nas duas situações anteriores, adquirir uma licença dele sai mais barato que outras IDEs comerciais, como o Zend Studio, por exemplo. Seja como for, qualquer um tem 45 dias para testá-lo na condição de trial.

A pergunta, portanto, é outra: o que ele oferece em troca do preço da licença? É o que eu vou tentar desvendar de agora em diante.

Baixei a versão para Linux (uso o Ubuntu 10.04 LTS) e descompactei numa pasta sob a minha /home. Para iniciá-lo, há o script webide.sh sob  <pasta do JetBrains PhpStorm>/bin.

O JetBrains PhpStorm, assim como o Netbeans e o Eclipse, também roda sobre a plataforma Java, mas, ao contrário de seus “colegas”, pareceu-me muito mais leve para carregar. Afora o carregamento, confesso que primeira impressão não foi das melhores. O PhpStorm não assumiu o look and feel padrão do GNOME, e sua aparência padrão é horrível, para dizer o mínimo. Mas é bem fácil modificar isso: basta ir em File > Settings (aliás, um local um tanto quanto não-usual para as configurações; precisei consultar a Ajuda do produto para localizá-las), e, na guia IDE Settings > Appearance, alterar o Look and Feel para GTK+.

Resolvido o problema da aparência, criei um projeto, utilizando fontes já existentes. Eis o que obtive:

JetBrains PhpStorm com projeto carregado

JetBrains PhpStorm com projeto carregado

Isso feito, fui procurar como configurar o servidor remoto para o upload (deployment) da aplicação. Esperava eu encontrar essas configurações clicando com o botão secundário do mouse sobre o nome do projeto na árvore à esquerda, mas nada. Descobri que as configurações do projeto ficam também em File > Settings, e concluí em definitivo que, para se trabalhar com o PhpStorm, é necessário mudar o conceito de “onde ficam as coisas”. Deixando esses entraves conceituais à parte, pode-se configurar o deployment em File > Settings > Project Settings > Deployment > Options. E, aqui, uma ótima surpresa: além dos métodos FTP e SFTP, que são praxe, o PhpStorm permite também a criação de destinos em pastas montadas ou locais (!), para o caso de se ter acesso ao servidor Web pela rede local, o que é o meu caso. Esse tipo de configuração eu só havia visto antes no Adobe Dreamweaver.
Opções de destinos de "deployment" no PhpStorm

Opções de destinos de "deployment" no PhpStorm

Após o destino configurado, é possível enviar o arquivo para o servidor remoto clicando sobre o arquivo desejado na árvore do projeto e selecionando Upload to <nome do projeto>. Faltou, porém, uma opção de download a partir do servidor remoto, e a função Synchronize parece não ter sido ainda implementada: ao ser acionada, informa que o processo foi concluído com sucesso, mas nada acontece efetivamente.

A função de Code Completion é muito boa, retornando as sugestões quase que instantaneamente.

"Code completion": nem dá tempo de pensar

"Code completion": nem dá tempo de pensar

A impressão geral e inicial passada pelo JetBrains PhpStorm é a de um produto que está no caminho certo, mas que, apesar de estampar 1.0.2 como número de versão, demonstra ter ainda muito o que melhorar e evoluir. Nos próximos dias, continuarei explorando-o. Pelo que já vi de suas capacidades de depuração, a configuração parece ser a mais fácil dentre todos os IDEs que já analisei. Espero voltar em breve com um post específico sobre este tópico :).

Enquanto isso, se você desenvolve em PHP e puder fazê-lo, baixe também o JetBrains PhpStorm e dê um pouco de atenção a ele. Tudo leva a crer que valerá bastante a pena.

O Yii Framework e os “models” (modelos)

Dando seguimento à série de artigos sobre o Yii Framework, desejo compartilhar algumas reflexões acerca dos modelos (models) do padrão de desenvolvimento MVC e de como o Yii Framework implementa o conceito.

Para deixar as coisas mais claras, tomei a liberdade de traduzir a definição de modelo constante deste artigo da Wikipédia de língua inglesa (quase sempre mais completa que a versão lusófona):

O modelo é utilizado para gerenciar informações e notificar os observadores quando a informação é alterada. O modelo é a representação dos dados específica de um negócio, sobre os quais a aplicação trabalha. A lógica de negócio dá significado aos dados brutos (como, por exemplo, determinar se hoje é o dia do aniversário do usuário, ou os totais, impostos e valores de frete para itens de um carrinho de compras). Quando o estado do modelo se altera, este notifica suas visões [views] associadas, de forma que elas possam ser atualizadas.

Várias aplicações usam um mecanismo de armazenamento persistente, como um banco de dados, para guardar os dados. O padrão MVC não menciona especificamente a camada de acesso aos dados, porque se supõe que ela esteja sob o modelo ou encapsulada por este. Modelos não são objetos de acesso a dados; contudo, em aplicações muito simples, com pouca lógica de negócio, não há nenhuma distinção efetiva a se fazer. O Active Record é um padrão de desenvolvimento bem aceito e que une o código da lógica de negócios e o de acesso aos dados – um modelo que sabe como persistir a si mesmo.

Do que foi abordado acima, aprofundemos dois tópicos.

1. O modelo nem sempre está relacionado a um objeto de banco de dados

Isso pode soar estranho, mas basta pensar um pouco para dar razão à assertiva. O ciclo de vida de uma aplicação MVC é, basicamente, coletar dados por intermédio de um formulário (visão, view), filtrá-los segundo as regras de negócio (o que é feito no controlador – controller) e armazená-los para posterior consulta, usando os modelos (models) para tanto.

Há ocasiões, no entanto, em que os dados coletados não precisam ou não devem ser armazenados – eles são necessários apenas em uma etapa intermediária do processamento. Talvez o exemplo mais típico dessa situação sejam os formulários de login, nos quais coletamos um nome de usuário e uma senha, que servem à autenticação/autorização. Depois disso, o nome do usuário (ou seu código, dependendo da lógica implementada) é, no máximo, armazenado num cookie ou num objeto de sessão. Armazenar a senha seria um total contrassenso, por questões de segurança.

O que nos impede, então, de representar os dados de um formulário de login como um modelo? É exatamente isso que o Yii Framework faz. Em todo projeto iniciado com o auxílio da ferramenta de linha de comando yiic, é gerado um modelo chamado LoginForm (na pasta protected/models), cujo conteúdo é o seguinte:

class LoginForm extends CFormModel
{
	public $username;
	public $password;
	public $rememberMe;

	private $_identity;

	/**
	 * Declares the validation rules.
	 * The rules state that username and password are required,
	 * and password needs to be authenticated.
	 */
	public function rules()
	{
		return array(
			// username and password are required
			array('username, password', 'required'),
			// rememberMe needs to be a boolean
			array('rememberMe', 'boolean'),
			// password needs to be authenticated
			array('password', 'authenticate', 'skipOnError'=>true),
		);
	}

	/**
	 * Declares attribute labels.
	 */
	public function attributeLabels()
	{
		return array(
			'rememberMe'=>'Remember me next time',
		);
	}

	/**
	 * Authenticates the password.
	 * This is the 'authenticate' validator as declared in rules().
	 */
	public function authenticate($attribute,$params)
	{
		$this->_identity=new UserIdentity($this->username,$this->password);
		if(!$this->_identity->authenticate())
			$this->addError('password','Incorrect username or password.');
	}

	/**
	 * Logs in the user using the given username and password in the model.
	 * @return boolean whether login is successful
	 */
	public function login()
	{
		if($this->_identity===null)
		{
			$this->_identity=new UserIdentity($this->username,$this->password);
			$this->_identity->authenticate();
		}
		if($this->_identity->errorCode===UserIdentity::ERROR_NONE)
		{
			$duration=$this->rememberMe ? 3600*24*30 : 0; // 30 days
			Yii::app()->user->login($this->_identity,$duration);
			return true;
		}
		else
			return false;
	}
}

A classe CFormModel, na hierarquia do Yii Framework, descende de CModel. Estão ali alguns métodos que costumamos ver nos posts anteriores, como o rules(), que estabelece as regras de validação para os dados, e o attributeLabels(), no qual podemos definir os nomes dos campos na linguagem natural do usuário.

Os dados de login são colhidos e processados, mas nunca armazenados em banco de dados – mesmo porque nem a classe CFormModel, nem sua ancestral, CModel, implementam um método save(). Pelo “jeitão de ser” do Yii Framework, CFormModel deve ser usado toda vez que os dados do formulário não serão armazenados (ao menos diretamente) num banco de dados. Para o trabalho com banco de dados, utilizamos o CActiveRecord.

2. O Active Record reúne em si regras de negócio e código de acesso a dados

O quão chocante lhe parece esta afirmação? Trata-se, é verdade, de uma quebra do paradigma MVC, que preconiza que as regras de negócio devem residir unicamente no controlador (controller). Ponderemos, porém: validação de dados é, em última análise, regra de negócio NOTA MENTAL: escrever um post sobre validação de dados no Yii Framework. E, se esses dados foram ou serão armazenados em banco de dados, a validação precisa obedecer, necessariamente, a definição da estrutura do BD, bem como as características e limitações do SGBD correspondente.

Logo, faz todo o sentido deixar que o próprio modelo verifique se a informação a ser armazenada num campo definido como VARCHAR(100) não ultrapassa esse comprimento. Podemos chamar isso, grosso modo, de forma. O controlador poderia ter-se encarregado de checar essa mesma informação quanto ao aspecto do conteúdo: é um endereço existente? É um nome de pessoa válido? É um município dentro da área de representação da empresa?

Por isso, e para poupar o precioso tempo do desenvolvedor, é que o Yii Framework mantém as regras de validação de dados, quanto à sua forma, no modelo (clique aqui para ver o exemplo de um código de modelo gerado a partir de um objeto de banco de dados), refletindo, sempre que possível, as regras já definidas no BD (tais quais campos requeridos, comprimento máximo, tipo de valor – numérico, alfanumérico, etc.). Tudo isso é implementado estendendo-se a classe CActiveRecord que, por seu turno, também estende CModel.

Concluindo…

O Yii Framework nos leva a repensar o conceito de modelo, desprendendo-o da correlação, julgada muitas vezes  necessária, com um objeto de banco de dados. Com isso, as possibilidades de uso dos modelos ampliam-se, como é o caso do formulário de login anteriormente citado.

O framework também implementa de forma elegante o padrão de desenvolvimento Active Record, encarregando os modelos gerados a partir de estruturas de bancos de dados da validação formal das informações, poupando o desenvolvedor de escrever código para isso 8) .

Para saber mais

  • The Definitive Guide to Yii (em português)

Grandes canções da (des)humanidade (em PHP, é lógico!)

Se analisarmos as letras de algumas das canções mais famosas que já surgiram, seja em solo nacional ou no resto do mundo, verificaremos que um estranho (porém constante) fenômeno assola os compositores: a falta de criatividade (em alguns casos, o excesso dela). Na maior parte das vezes, esse problema se traduz na repetição de versos, palavras, sílabas ou – na pior das hipóteses – vogais por toda a letra da música “afetada”.

Sabedor de que os computadores são ótimos com repetições, por que não implementar algum código para poupar os pobres compositores do trabalho entediante de escrever partes repetidas? Pensando nisso, e atendendo à sugestão do companheiro #SouDev Francisco Prado, achei por bem rascunhar algumas linhas de exemplo no velho e bom PHP, referentes a algumas músicas que me ocorreram. Divirtam-se, com moderação 8) .

<?php

  class GeradorLetraMusica {

    /********************************************************************************
     * Música: Era um Garoto que Como Eu Amava os Beatles e os Rolling Stones
     * Banda: Engenheiros do Hawaii
     */
    static public function refraoEraUmGarotoQueComoEu() {
      // Aqui tive de cortar um pouco o nome do método. Apesar de o PHP não ter um
      // erro do tipo "identifier too long", isso aqui não é Java, p*rra!
      for($i = 0; $i < 7; ++$i)
        echo 'Ratatata ';
    }

    /********************************************************************************
     * Música: Patience
     * Banda: Guns N' Roses
     */
    static public function introPatience() {
      global $boca;

      while(! $boca->lingua->estaDormente())
        $boca->assobiar();
    }

    /********************************************************************************
     * Música: Mmm Mmm Mmm Mmm
     * Banda: Crash Test Dummies
     */
    static public function refraoMmmMmmMmmMmm() {
      // Nem compensa fazer loop...
      echo 1 1 1 1 1 1 1 1;
    }

    /********************************************************************************
     * Música: Rebolation
     * Banda (?!): Parangolé
     */
    static public function refraoRebolation() {
      global $sujeito;
      do {
        echo 'Rebolation, tion, tion ';
      } while ($sujeito->consegueEsquecer());
    }

    /********************************************************************************
     * Música: Galopeira
     * Intérprete: Donizete
     */
    static public function refraoGalopeira($folego = 60 /* Você aguenta? */) {
      echo 'Galop';
      for($i = $folego - 2; $i >=0; --$i)
        echo 'e';

      // O laço "for" acima não acaba com o fôlego
      // porque tem de sobrar um pouquinho para o final
      echo 'ira, nunca mais te esquecereeeei';
    }

    /********************************************************************************
     * Música: Trolololo
     * Intérprete: Homem do Trolololo
     */
    static public function refraoTrolololo() {
      setlocale(LC_ALL, 'ru');
      while(true) {
        echo 'Трололололололололололо ';
      }
    }

  }

Vídeos no Youtube para quem quiser conferir as canções:

Entendendo as “relations” (relações) do Yii Framework

No post em que apresentei o Yii Framework, demonstrei a capacidade que este possui de gerar o código dos modelos para o padrão de desenvolvimento MVC a partir da estrutura do banco de dados. Hoje vou um passo além, para mostrar que o código gerado reflete não apenas os atributos, mas também as relações (foreign keys) existentes entre as tabelas do BD.

Consideremos, pois, uma estrutura de dados bem simples:

A tabela 'aluno' possui uma chave estrangeira N para 1 em 'escola'

A tabela 'aluno' possui uma chave estrangeira N para 1 em 'escola'

Nessa estrutura hipotética, cada aluno está vinculado a uma escola; por óbvio, uma escola pode possuir zero ou mais alunos. Na UML, esse tipo de relação é denominado dependência, como nos ensina o companheiro #SouDev Edgard Davidson. A partir dessas informações, o Gii (scaffolder do Yii Framework – veja aqui como habilitá-lo no seu projeto) pode gerar o código para os modelos. Desde a versão 1.0.1 do framework, não é mais necessário que as relações provenham das chaves estrangeiras previamente definidas no banco de dados; é possível defini-las em código, editando o corpo do método relations().

Do código gerado para ambos os modelos (Aluno e Escola, que se encontram na árvore do projeto sob protected/models), destaco os seguintes trechos:

<?php
class Aluno extends CActiveRecord
{

  (...)

	/**
	 * @return array relational rules.
	 */
	public function relations()
	{
		// NOTE: you may need to adjust the relation name and the related
		// class name for the relations automatically generated below.
		return array(
			'escola' => array(self::BELONGS_TO, 'Escola', 'cod_escola'),
		);
	}

  (...)

}
<?php
class Escola extends CActiveRecord
{

  (...)

	/**
	 * @return array relational rules.
	 */
	public function relations()
	{
		// NOTE: you may need to adjust the relation name and the related
		// class name for the relations automatically generated below.
		return array(
			'alunos' => array(self::HAS_MANY, 'Aluno', 'cod_escola'),
		);
	}

  (...)

}

O Gii capturou as definições de chaves estrangeiras e estabeleceu as relações entre as tabelas de acordo com aquelas. No caso, um aluno pertence a (self::BELONGS_TO) uma escola, que, por seu turno, tem vários (self::HAS_MANY) alunos.

A partir disso, abre-se uma miríade de possibilidades. Neste cenário, seria comum ter de apresentar, junto com as informações do aluno, o nome da escola no qual este estuda. Poderíamos escrever o seguinte:

<?php
  // Recupera os dados do aluno cujo código é 1000
  $aluno = Aluno::model()->findByPk(1000);

  echo 'Código: ' . $aluno->cod_aluno . '<br />';
  echo 'Nome do aluno: ' . $aluno->nome_aluno . '<br />';
  echo 'Nome da escola: ' . $aluno->escola->nome_escola . '<br />';

Notem (linha 7) que, para obter o nome da escola, não foi preciso instanciar um objeto da classe Escola apenas para que obtivéssemos o nome da escola. Ao invés disso, beneficiamo-nos de uma relação definida no modelo Aluno.

De forma semelhante, a partir de uma instância da classe Escola, seremos capazes de listar todos os alunos vinculados a ela, escrevendo algo como:

<?php
  // Recupera os dados da escola cujo código é 50
  $escola = Escola::model()->findByPk(50);

  // Recupera uma lista de alunos vinculados à escola
  $alunos = $escola->alunos;

  foreach($alunos as $aluno) {
    echo 'Código: ' . $aluno->cod_aluno . '<br />';
    echo 'Nome do aluno: ' . $aluno->nome_aluno . '<br />';
    echo '<hr />';
  }

O código da linha 6 é o bastante para se obter uma lista de alunos vinculados à escola, graças à relação definida na classe Escola.

Em ambos os exemplos, utilizei a técnica chamada lazy loading para recuperar dados relacionados. Há ainda outras formas de se fazer isso, bem como outros tipos de relações além de self::BELONGS_TO e self::HAS_MANY, sobre as quais você pode obter mais informações consultado o Guia Definitivo do Yii Framework.

Um aspecto final a ser salientado é que estivemos utilizando, durante todo o tempo, um outro padrão de desenvolvimento, denominado Active Record. Ele nos permitiu trabalhar com as informações do banco de dados sem lançar mão, em momento algum, da linguagem SQL. O Active Record, por sua vez, é uma das implementações possíveis de ORM (Object-relational mapping) 8) .

%d blogueiros gostam disto: