Neste artigo trataremos sobre um tema que em algumas situações nos traz algumas dores de cabeça como, por exemplo, na hora de gerarmos gráficos e depois exportarmos eles em formatos diferentes. Mas esta é uma causa diferenciada já que podemos contar com a ajuda da biblioteca Highcharts e do nosso framework de trabalho, CakePHP.

Muitas vezes no decorrer de um projeto, surgem solicitações de visualização das informações contidas na base de dados devido a pesquisas realizadas em gráficos. Como bem sabemos o desenvolvimento de gráficos muitas vezes se torna árdua dependendo das informações solicitadas e também do formato de apresentação desses gráficos. No entanto, temos a nossa disposição várias bibliotecas excelentes em js que facilitam este trabalho pra nós. Trataremos então de uma biblioteca em específico, devido a ela ser simplesmente completa e de fácil utilização para nossos projetos, além de ser compatível com jQuery ou prototype ou mootools que é o caso da biblioteca Highcharts.js. Nosso foco nesse artigo será o desenvolvimento de gráficos com base em informações produzidas através de um formulário no CakePHP.

Nota: O CakePHP é um framework baseado na linguagem PHP, é extremamente importante ter pelo menos um conhecimento básico em PHP.

Porque utilizarmos o HighCharts.js?

Como citado anteriormente, há uma grande variedade de bibliotecas JavaScript para a construção de gráficos disponíveis no mercado, e uma que chama bastante a atenção é a Highcharts.js que é compatível tanto com jQuery quanto com Mootools. Para iniciarmos com a apresentação. Podemos ver e fazer o download da bibliotecaonde podemos baixar alguns exemplos. Ele possui algumas variações como é o caso do HighMaps que é utilizado para a criação de mapas interativos para apresentar resultados de vendas, resultados eleitorais ou qualquer outra informação relacionada com geografia. Ele é perfeito para o uso autônomo ou em painéis, combinado com o Highcharts, além dessa variação, temos também o HighStock que Inclui opções mais sofisticadas de navegação como uma pequena série de navegações, intervalos entre datas pré-definidas, selecionadores de data, de deslocamento, etc., ele é muito utilizado quando se trata de sistemas para bolsa de valores. A configuração para um gráfico, como demonstrado é simples e usa o tipo de dados JSON, há também vários tipos de gráficos que podemos utilizar, a partir dos gráficos de linha, de áreas, de colunas, barras, pizza e também gráfico de dispersão, dentre outros.

Sem mais demora, vamos por a mão na massa, começando com a criação de nosso pequeno formulário nos moldes MVC desenvolvido em nosso framework CakePHP, que a muito tempo não escrevemos sobre as suas maravilhas.

MiniMundo do exemplo

Uma pesquisa será realizada numa comunidade para que se saiba com relação aos casais se são casados, se tem filhos, idade dos entrevistados, dentre outras informações que possam compor o nosso cenário e se torne prática a criação de gráficos demonstrativos.

Estaremos criando dois tipos de gráficos nesse exemplo que são os de pizza e o de colunas, mas sintam-se a vontade de utilizar outras formas de gráficos que o highcharts oferece. Com base nas informações já passadas comecemos então a criação de nossas classes.

Criação da base de dados

Primeiramente, criaremos a tabela que será utilizada para o nosso exemplo, de acordo com a Listagem 1 apresentada a seguir, para isso, é necessário que vocês já tenham o ambiente preparado.


CREATE TABLE `pesquisas` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `sexo` VARCHAR(50) NOT NULL,
  `faixa_etaria` VARCHAR(50) NOT NULL,
  `localidade` VARCHAR(50) NOT NULL,
  `se_casado` VARCHAR(50) NOT NULL,
  `tem_filho` VARCHAR(50) NOT NULL,
  `se_trabalha` VARCHAR(50) NOT NULL,
  `ocupacao` VARCHAR(50) NOT NULL,
PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=0;
Listagem 1. Criando a tabela de pesquisas

Após a criação da base de dados, é hora de trabalharmos com a estrutura MVC do projeto, onde começaremos pelo Model que é a camada responsável pela validação dos dados.

Criando o model de Pesquisa

Como bem sabemos, os models são as classes que formam a camada de negócios de nossas aplicações. Eles são responsáveis ​​pela gestão de praticamente com relação a nossos dados, a validação, e também suas interações, bem como a evolução do fluxo de trabalho de informações em seu domínio. Normalmente, as classes do model representam dados e são usados ​​em aplicações CakePHP para acesso a dados. Eles geralmente representam uma tabela de banco de dados, mas podem ser usados para acessar qualquer coisa que possa manipular dados, como arquivos, serviços externos ou mesmo eventos.

De acordo com a Listagem 2 apresentada a seguir, estamos criando o model de pesquisas onde iremos fazer a validação das informações necessárias para gerar o nosso gráfico, além de criar funções necessárias que serão utilizadas no PesquisasController.


<?php
class Pesquisa extends AppModel
{
    public $sexo = array("Masculino" => "Masculino", "Feminino" => "Feminino");
    public $faixa_etaria = array("Abaixo dos 16 anos" => "Abaixo dos 16 anos", "17 a 20" =
    > "17 a 20", "21 a 30" => "21 a 30", "31 a 40" => "31 a 40", "Acima dos 50 anos" =
    > "Acima dos 50 anos");
    public $onde_mora = array("Recife" => "Recife", "Cabo" => "Cabo", "Caetés" =
    > "Caetés", "Outros" => "Outros");
public $trabalha = array("Sim" => "Sim", "Não" => "Não");
public $filhos = array("Sim" => "Sim", "Não" => "Não");
public $seCasado = array("Sim" => "Sim", "Não" => "Não");
public $ocupacao = array("Desempregado" => " Desempregado ", "Professor" =
> " Professor", “Engenheiro” => “Engenheiro”, “Estudante” => “Estudante”, “Outros” =
> “Outros”);
    public function sexoEntrevistado()
    {
        $genero = $this->find('all', array('fields' =
        > array('count(Pesquisa.sexo) as quantidade', 'sexo'), 'group' => 'sexo'));
        $dados = array();
        foreach ($genero as $value) {
            $dados[$value['Pesquisa']['sexo']] = $value[0]['quantidade'];
        }
 
        return $dados;
    }
 
    public function idadeEntrevistado()
    {
        $idade = $this->find('all', array('fields' =
        > array('count(Pesquisa.faixa_etaria) as quantidade', 'faixa_etaria'), 'group' =
        > 'faixa_etaria'));
        $dados = array();
        foreach ($idade as $value) {
            $dados[$value['Pesquisa']['faixa_etaria']] = $value[0]['quantidade'];
        }
        return $dados;
    }
 
    public function localidadeEntrevistado()
    {
        $localidade = $this->find('all', array('fields' =
        > array('count(Pesquisa.localidade) as quantidade', 'localidade'), 'group' =
        > 'localidade'));
        $dados = array();
        foreach ($localidade as $value) {
            $dados[$value['Pesquisa']['localidade']] = $value[0]['quantidade'];
        }
        return $dados;
    }
 
public function seCasadoEntrevistado()
    {
        $casado = $this->find('all', array('fields' =
        > array('count(Pesquisa.se_casado) as quantidade', ' se_casado'), 'group' =
        > ' se_casado'));
        $dados = array();
        foreach ($casado as $value) {
            $dados[$value['Pesquisa']['se_casado']] = $value[0]['quantidade'];
        }
        return $dados;
    }
public function seTemFilhosEntrevistado()
    {
        $filhos = $this->find('all', array('fields' =
        > array('count(Pesquisa.tem_filho) as quantidade', ' tem_filho'), 'group' =
        > 'tem_filho'));
        $dados = array();
        foreach ($filhos as $value) {
            $dados[$value['Pesquisa']['tem_filho']] = $value[0]['quantidade'];
        }
        return $dados;
    }
public function ocupacaoEntrevistado()
    {
        $ocupacao = $this->find('all', array('fields' =
        > array('count(Pesquisa.ocupacao) as quantidade', 'ocupacao'), 'group' =
        > 'ocupacao'));
        $dados = array();
        foreach ($ocupacao as $value) {
            $dados[$value['Pesquisa']['ocupacao']] = $value[0]['quantidade'];
        }
        return $dados;
    }
 
    function beforeSave($options = array())
    {
        $this->data['Pesquisa']['localidade'] = utf8_decode($this-
        >data['Pesquisa']['localidade']);
    }
}
Listagem 2. Criando o model Pesquisa

Criando o controlador PesquisasController

Nossos controladores devem lidar com a interpretação dos dados da solicitação, certificando-se que os models corretos estão sendo chamados, e que a resposta certa ou a exibição é processada corretamente. A camada controller é a camada considerada intermediária entre o model e a view. Os controladores são utilizados normalmente para gerenciar a lógica em torno de um único model.

Agora que temos o nosso model criado e com algumas validações definidas em nossa função básica do CakePhp que é a beforeSave que tem a finalidade de realizar uma validação antes de que os dados sejam inseridos no banco de dados, onde utilizamos a função utf8_decode, para que as informações que fossem salvas na base de dados incluísse os caracteres especiais sem problemas. Vamos então definir o nosso controller agora que será chamado então de PesquisasController, o código segue de acordo com o apresentado pela Listagem 3.


<?php
class PesquisasController extends AppController
{
    public $helpers = array("Html", "Form");
    // Recuperação das informações trazidas da base de dados pelo model e fazendo a 
    transação para exibição na index.
    public function index()
    {
        $genero_sexual = $this->Pesquisa->sexoEntrevistado();
        $this->set('genero', $genero_sexual);
 
        $faixaEtaria = $this->Pesquisa->idadeEntrevistado();
        $this->set('faixa_etaria', $faixaEtaria);
 
        $localidade = $this->Pesquisa->localidadeEntrevistado();
        $this->set('localidade', $localidade);
    }
 
    // Função responsável pela inserção dos dados na base de dados.
    public function inserir()
    {
        $sexo_entrevistado = $this->Pesquisa->sexo;
        $this->set("sexo", $sexo_entrevistado);
 
        $faixa_etaria = $this->Pesquisa->faixa_etaria;
        $this->set("faixa_etaria", $faixa_etaria);
 
        $onde_mora = $this->Pesquisa->onde_mora;
        $this->set("localidade", $onde_mora);
     
       $filho = $this->Pesquisa->filho;
        $this->set("filho", $filho);
 
       $casado = $this->Pesquisa->casado;
        $this->set("casado", $casado);
 
       $ocupacao = $this->Pesquisa->ocupacao;
        $this->set("ocupacao", 
        nbsp;ocupacao);

        if($this->request->is("post")){
         $this->Pesquisa->create();
        if($this->Pesquisa->save($this->request->data)){
         $this->Session->setFlash(__('Pesquisainseridacomsucesso'));
         $this->redirect(array("action"=>"/index"));
        }else{
          $this->Session->setFlash(__("Não foi possível inserir esta pesquisa"));
        }
      }
    }
}
Listagem 3. Criação do Controlador PesquisasController

Criando as views do projeto

As views são responsáveis ​​por gerarem as saídas específicas que são necessárias para o que foi solicitado. Muitas vezes isto pode ser, na forma de HTML, XML, ou mesmo JSON, além de outras utilizações.

Seguindo com nosso projeto, criaremos agora as views de inserção dos dados e também a de visualização dos gráficos (que é nosso intuito aqui). Estas serão representadas pelas Listagens 4 e 5.


<?php
echo $this->Form->create();
echo $this->Form->input("sexo", array("type" => "select", "label" =
> "Qual o seu sexo?", "empty" => "Selecione uma opção", "options" => $sexo));
echo $this->Form->input("faixa_etaria", array("type" => "select", "label" =
> "Qual a sua idade?", "empty" => "Selecione uma opção", "options" => $faixa_etaria));
echo $this->Form->input("localidade", array("type" => "select", "label" =
> "Onde mora?", "empty" => "Selecione uma opção", "options" => $localidade));
echo $this->Form->input("ocupacao", array("type" => "select", "label" =
> "Qual a sua ocupação?", "empty" => "Selecione uma opção", "options" => $ocupacao));
echo $this->Form->end('Salvar');
Listagem 4. Criação da view inserir.ctp

<script type="text/javascript" src="../js/highcharts.js"></script>
<script type="text/javascript" src="../js/exporting.js"></script>
<script>
$(function () {
    $('#genero').highcharts({
        chart: {
            plotBackgroundColor: null,
            plotBorderWidth: 1,//null,
            plotShadow: false
        },
        title: {
            text: 'Gênero sexual dos entrevistados'
        },
        tooltip: {
            pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
        },
        plotOptions: {
            pie: {
                allowPointSelect: true,
                cursor: 'pointer',
                dataLabels: {
                    enabled: true,
                    format: '<b>{point.name}</b>: {point.percentage:.1f} %',
                    style: {
                        color: (Highcharts.theme && 
                        Highcharts.theme.contrastTextColor) || 'black'
                    }
                }
            }
        },
        series: [
            {
                type: 'pie',
                name: 'Sexo',
                data: [
                    <?php
                      foreach ($genero AS $key => $value) {
                        echo "['" . $key . "'," . $value . "],";
                      }
                    ?>
                ]
            }
        ]
    });
    $('#faixa_etaria').highcharts({
        chart: {
            type: 'column'
        },
        title: {
            text: 'Faixa etária dos entrevistados'
        },
        xAxis: {
            categories: [
                <?php
                foreach ($faixa_etaria AS $key => $value) {
                    echo "'" . $key . "',";
                }
                ?>
            ]},
        yAxis: {
            min: 0,
            title: {
                text: 'Total de pessoas'
            }
        },
        plotOptions: {
            column: {
                pointPadding: 0.2,
                borderWidth: 0
            }
        },
        series: [
            {
                name: 'Faixa etária dos entrevistados',
                data: [<?php
                        foreach ($faixa_etaria AS $key => $value) {
                            echo "['" . $key . "'," . $value . "],";
                        }
                    ?>],
                dataLabels: {
                    enabled: false,
                    rotation: -90,
                    color: '#333',
                    align: 'right',
                    x: 4,
                    y: 10,
                    style: {
                        fontSize: '13px',
                        fontFamily: 'Verdana, sans-serif'
                    }
                }
            }
        ]
    });
    $('#localidade').highcharts({
        chart: {
            type: 'column'
        },
        title: {
            text: 'Local de origem dos entrevistados'
        },
        xAxis: {
            categories: [
                <?php
                foreach ($localidade AS $key => $value) {
                   $value = utf8_encode($value);
                   $key = utf8_encode($key);
                   echo "'" . $key . "',";
                }
                ?>
            ]},
        yAxis: {
            min: 0,
            title: {
                text: 'Total de pessoas'
            }
        },
        plotOptions: {
            column: {
                pointPadding: 0.2,
                borderWidth: 0
            }
        },
        series: [
            {
                name: 'Localidade',
                data: [<?php
                        foreach ($localidade AS $key => $value) {
                        $key = utf8_encode($key);
                        $value = utf8_encode($value);
                            echo "['" . $key . "'," . $value . "],";
                        }
                      ?>],
                dataLabels: {
                    enabled: false,
                    rotation: -90,
                    color: '#333',
                    align: 'right',
                    x: 4,
                    y: 10,
                    style: {
                        fontSize: '13px',
                        fontFamily: 'Verdana, sans-serif'
                    }
                }
            }
        ]
    });
});
</script>
<div>
<?php
echo $this->Html->link('Inserir novo formulário', array('controller' =
> 'pesquisas',  'action' => 'inserir',  'full_base' => true));
?>
</div>
<div id="genero" style="min-width: 310px; height: 400px; margin: 0"></div>
<div id="faixa_etaria" style="min-width: 310px; height: 400px; margin: 0 auto"></div>
<div id="localidade" style="min-width: 310px; height: 400px; margin: 0 auto"></div>
Listagem 5. Criação da view index, responsável pela visualização dos Gráficos

Na nossa view inserir.ctp não temos muitos segredos, já que estamos utilizando o padrão do cakePHP, como apresentado na Listagem 4, mas já na view index, basicamente iremos trabalhar com javascript, sem muitas confusões. Aqui precisaremos primeiro seguir alguns passos antes de fazermos as modificações necessárias para o nosso projeto que são:

  • Baixar os arquivos js para a pasta webroot
  • Chamá-los na view em que iremos utilizar, no caso, a nossa index.

Então vejamos como ficará a nossa classe de acordo com a Listagem 5. Ao copiarmos o arquivo js do exemplo apresentado pelo Highcharts, podemos perceber que ele possui várias configurações que dependendo do caso podem nos ser úteis, apenas por exemplo, deixamos todas ativas de forma padrão, mas vocês podem treinar um pouco fazendo as modificações e vendo como irá ficar o exemplo de vocês. Outra informação importante com relação ao Highcharts é que além de visualizarmos nossos gráficos na tela, também temos a possibilidade de exportá-los num dos formatos disponíveis pela própria biblioteca, podendo ser como pdf, jpg, dentre outros tipos. Basta clicar no botão representado pela Figura 1 que serão apresentadas as opções.

Gráfico gerado pelo Highcharts com CakePHP
Figura 1. Gráfico gerado pelo Highcharts com CakePHP

Percebam que basicamente o que temos aqui é apenas código JavaScript, que é o mesmo código exemplo utilizado nos exemplos do highcharts com a diferença que aqui estamos fazendo a recuperação dos dados de uma base real e não estaticamente adicionados.

Como devem ter percebido também, cada uma das funções precisava de um id para que o gráfico fosse apresentado. Neste nosso projeto, estão sendo visualizados apenas três dos gráficos que podem ser gerados, alguns trechos de código foram retirados propositalmente para que haja o treinamento realizado por vocês.

Então é isso pessoal, nesse artigo apresentamos a forma simples de criarmos gráficos utilizando o CakePHP framework, o que acreditamos que possa ajudar bastante nos seus projetos. Outros exemplos de utilização do highcharts vocês podem encontrar através desse endereço. Nos vemos na próxima, até mais!

Links úteis:

Bibliotecas highcharts utilizadas no exemplo:

Biblioteca necessária do jQuery