Olá pessoal. Neste artigo veremos como criar um gráfico do tipo pizza, o famoso Pie Chart, no Flex Builder, com uso do PHP obtendo os dados de um servidor de banco de dados MySQL.

Inicialmente iremos criar, como de costume, um arquivo PHP que, nada mais nada menos, irá trazer os dados que precisamos do nosso banco de dados MySQL.

O banco que será usado como exemplo possui uma tabela de cargos, uma tabela de setor (entende-se por departamento) e uma tabela email. Cada departamento possui no mínimo um email cadastrado. Não se atente a tabela de emails, pois isto faz parte de uma regra de negócio específica e que não influenciará em nada na construção do gráfico, apenas para fins de esclarecimento sobre as relações entre as tabelas. O script para construção das tabelas segue abaixo.


DROP TABLE IF EXISTS `comercial`.`email`;
CREATE TABLE  `comercial`.`email` (
  `idemail` int(11) NOT NULL AUTO_INCREMENT,
  `descricao` varchar(200) COLLATE latin1_general_ci NOT NULL DEFAULT '''',
  PRIMARY KEY (`idemail`)
) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci 
COMMENT=''emails da empresa'';
Listagem 1. Tabela email

DROP TABLE IF EXISTS `comercial`.`setor`;
CREATE TABLE  `comercial`.`setor` (
  `idsetor` int(11) NOT NULL AUTO_INCREMENT,
  `descricao` varchar(200) COLLATE latin1_general_ci NOT NULL DEFAULT '''',
  `idemail` int(11) NOT NULL DEFAULT ''0'',
  `idemail2` int(11) DEFAULT NULL,
  PRIMARY KEY (`idsetor`),
  KEY `FK_setor_1` (`idemail`),
  CONSTRAINT `FK_setor_1` FOREIGN KEY (`idemail`) REFERENCES `email` (`idemail`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
Listagem 2. Tabela Setor

DROP TABLE IF EXISTS `comercial`.`cargos`;
CREATE TABLE  `comercialesper`.`cargos` (
  `idcargo` int(11) NOT NULL AUTO_INCREMENT,
  `idsetor` int(11) NOT NULL DEFAULT ''0'',
  `descricao` varchar(250) COLLATE latin1_general_ci NOT NULL DEFAULT '''',
  PRIMARY KEY (`idcargo`),
  KEY `FK_cargos_1` (`idsetor`),
  CONSTRAINT `FK_cargos_1` FOREIGN KEY (`idsetor`) REFERENCES `setor` (`idsetor`)
) ENGINE=InnoDB AUTO_INCREMENT=77 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
Listagem 3. Tabela cargos

Após a criação das tabelas, iremos povoá-las com dados. Para exemplo, foram inseridos: Administrativo, Compras, Vendas , TI, Fiscal , Logística e Lojas. Idem para os cargos onde foi atribuído um idsetor a cada cargo. Como são diversos cargos, não é necessário mencioná-los aqui, pois o objetivo didático é explicar o procedimento. O leitor pode povoar as tabelas como preferir.

O passo seguinte é criar um arquivo PHP que carrega as informações que iremos exibir no gráfico pizza. Aqui iremos demonstrar a relação de cargos cadastrados por setor específico. Para isso, criaremos o arquivo PHP que segue abaixo. Não será exibido aqui o arquivo de conexão com o banco de dados MySQL, apenas será citado no código, como conn.php. Há diversos exemplos sobre como conectar o PHP ao banco de dados MySQL, como não faz parte do escopo, também iremos pular esta parte.


<?php
  include "conn.php";
  $link = getConnDB();
   $sql =	''select
			se.descricao as setor,
			count(*) as total from cargos ca
			inner join setor se
			on ca.idsetor = se.idsetor
			group by setor'';
	 // Perform Query
  $result = mysql_query($sql, $link);

  if ($result)
  {
     /* xml result */
     $xml = XMLHeader() . "<all>";

     while ($row = mysql_fetch_assoc($result))
     {
       
	   $v_setor						=    $row[''setor''];
	   $v_total						=    $row[''total''];  
                $node = "<row" .
         				 " setor           = ".   QuotedStr( $v_setor      ).
				 " total           = ".   QuotedStr( $v_total      ).
	 	 "/>" ;
       $xml = $xml . $node;
     }
    $xml = $xml . "</all>" ;
    /* close statement */
    mysql_free_result($result);
    /* return result */
    echo $xml ;
  }?>
Listagem 4. Consultando os dados

Comentando o código do arquivo PHP , na primeira linha incluímos o arquivo de conexão que traz as configurações de conexão com banco de dados MySL. A variável $link = getConnDB() captura a conexão com o banco de dados, enquanto $sql armazena a query que vai trazer o total de cargos agrupados por departamento e o nome do departamento. Na sequência, a query é executada e se existir resultado, o XML é montado, respeitando os nós setor e total que possuem os valores retornados pela query. No final, o XML é exibido pelo comando echo que é executado com a variável que o armazena ($xml).

Ao executarmos essa página, que foi chamada de load_totalcargo.php, retornamos o seguinte XML para o banco de dados utilizado neste exemplo:


<?xml version="1.0" encoding="ISO-8859-1"?>
<all>
<row total="15" setor="ADMINISTRATIVO"/>
<row total="3" setor="COZINHA"/>
<row total="8" setor="LOGISTICA"/>
<row total="11" setor="LOJA"/>
<row total="1" setor="TI"/>
</all>
Listagem 5. XML retornado

Com o retorno do XML podemos confirmar que nosso script PHP está correto e funcionado. Iremos ao Flex Builder e criaremos um novo projeto.

Este projeto de exemplo foi chamado de comercial, sua estrutura será um arquivo principal chamado comercial.mxml. Iremos criar uma classe chamada Total, onde iremos colocar as informações, atributos desta classe, que são setor e total. Segue o código da classe:


package classes.Total
{
import flash.xml.XMLNode;
public class TotalData
{
	public var setor:String;
	public var total:String;
	
	public function TotalData()
	{
	}
	public function doLoadFromXML(loNode:XMLNode):void
	{
		this.setor	= loNode.attributes.setor;
		this.total	= loNode.attributes.total;
	}
	public function doLoadFormGrid(loItem:Object):void
	{
		this.setor		= loItem["setor"];
		this.total		= loItem["total"];
	}
  }
}
Listagem 6. Classe Total

A classe Total possui o método doLoadFromXML(), que recebe os valores dos campos que retornam do arquivo PHP.

Com a classe criada, iremos construir um componente que será o responsável pela execução do arquivo PHP no servidor web. Para isso, iremos clicar com o botão direito do mouse na pasta src->New->Folder e nomearemos como ws. Por conseguinte, repetimos o processo na pasta ws->New->MXML Component para criarmos um novo componente que terá o código a seguir:


<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="10" height="10">
	<mx:Metadata>
		[Event(name="OnExecute")]
	</mx:Metadata>		
	<mx:HTTPService id="srvTotalRead"
		result="OnResultTotalRead(event)"
		fault="OnFaultEvent(event)"
		resultFormat="xml">
	</mx:HTTPService>	
	<mx:Script>
		<![CDATA[
			import classes.Util;
			import classes.Total.TotalData;
			import mx.rpc.events.FaultEvent;
			import mx.collections.ArrayCollection;
			import mx.rpc.events.ResultEvent;			
			
			[Bindable]
		    public var FoList:ArrayCollection = new ArrayCollection();
		    
		    private function OnFaultEvent(event:FaultEvent): void
			{
				Util.ShowMessage("Erro! " + event.message);
			}
			
			// função que define a leitura do xml ,como um evento que gera um 
			xml como resultado na grid
		private function OnResultTotalRead(event:ResultEvent):void
		{
			var lcXML:String = event.result.toString();
			
			/* pede o arquivo xml */
			var loXML:XMLDocument = new XMLDocument(lcXML);
			
			/* colecao */
			var loData:classes.Total.TotalData = null;
			
			/* remove os dados anteriores */
			this.FoList.removeAll();
			
			/* carregar o xml */
			for each (var loNode:XMLNode in loXML.childNodes)
			{
				if (loNode.nodeName == "all")
				{
					for each (var loItem:XMLNode in loNode.childNodes)
					{
						loData = new TotalData(); 
						loData.doLoadFromXML(loItem);
						this.FoList.addItem(loData);
					}
				}
			}
			
			var loEvent:Event = new Event("OnExecute");
			this.dispatchEvent(loEvent);
		} 
			
		public function doLoadTotalCargo():void
		{
			var params:Object = {};
			
			this.srvTotalRead.method="POST";
		  	this.srvTotalRead.url=Util.GetBasePath()+ "load_totalcargo.php" ;
		  	this.srvTotalRead.send(params);
			
		}	
			  
		]]>
	</mx:Script>
</mx:Canvas>
Listagem 7. Componente para execução do arquivo PHP

Esse componente criado foi nomeado como wsTotal e ele possui uma altura e largura de apenas 10 pixels, o suficiente para manipularmos e arrastá-lo com o mouse pela nossa aplicação. Para usarmos os dados em XML em runtime, criamos o componente como HTTPService que dá acesso a URLs e retorna dados visualizados na URL especificada, no caso todo o path(caminho) até o nosso arquivo PHP (laod_totalcargo.php). Quando criamos o objeto HTTPService, devemos informar também o evento result. O evento result é transmitido quando os dados são retornados sucessivamente pelo objeto HTTPService, o trecho do código que demonstra a criação do objeto HTTPService é:


<mx:HTTPService id="srvTotalRead"
	result="OnResultTotalRead(event)"
	fault="OnFaultEvent(event)"
	resultFormat="xml">
</mx:HTTPService>	
Listagem 8. Objeto HTTPService

Nesse objeto que foi nomeado de srvTotalRead está o evento result. O fault que mostra algum erro e o resultFormat, que é o tipo retornado do serviço, no caso XML, se fosse texto, usaríamos TEXT. Criar o objeto HTTPService não faz os dados serem retornados automaticamente, para isso temos que evocar o método send do serviço em resposta a algum evento, neste caso será acionado no evento creationcomplete(), que é o inicio da aplicação.

Vamos nos ater a função a seguir que irá realizar toda a tarefa de recuperar os dados XML:


public function doLoadTotalCargo():void
{
	var params:Object = {};
	
	this.srvTotalRead.method="POST";
  	this.srvTotalRead.url=Util.GetBasePath()+ "load_totalcargo.php" ;
  	this.srvTotalRead.send(params);
	
}
Listagem 9. Recuperando os dados do XML

Na função doLoadTotalCargo() , usamos o method POST, a URL e enviamos pelo método send a solicitação. Com isso nosso componente se comunica com a URL informada e também retorna os dados que precisamos.

Já que possuímos a classe Total e o componente wsTotal, agora precisamos criar o gráfico propriamente dito que será alimentado pelos dados retonados do wsTotal.

No modo Design, vá até a aba Components e escolha dentro da pasta Charts o gráfico de pizza, denominando de PieeChart. Arraste-o até sua aplicação e posicione conforme sua conveniência. Sua aparência ficará como a Figura 1 se você também adicionar um panel.

Gráfico PieeChart
Figura 1. Gráfico PieeChart

Neste exemplo o gráfico foi exibido como uma janela modal, mas para facilitar o entendimento não será incluído aqui o código para esse comportamento e consequentemente será desnecessário o código para o botão fechar. Segue o código do gráfico:


<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="800" height="532" 
backgroundColor="#FFFFFF" xmlns:ns1="ws.*" creationComplete="doComplete()">
<mx:Script>
<![CDATA[
	
	import classes.Util;		
	
private function doSair():void
	{
		Util.CloseWindow(this);
	}
	
	public function doComplete():void
	{
		webTotal.doLoadTotalCargo();
	}
	//<mx:PieSeries displayName="total" nameField="setor"  field="total" 
	labelPosition="insideWithCallout"  />
	
]]>
</mx:Script>
<ns1:wsTotal x="652" y="22" id="webTotal">
</ns1:wsTotal>
<mx:Panel x="0" y="0" width="100%" height="531" layout="absolute" title="Gráfico de Totais 
de Cargos por Departamento" borderColor="#076900">
	<mx:PieChart x="0" y="0" id="chTotalCargos" width="100%" dataProvider="{webTotal.FoList}" 
	showDataTips="true" height="419">
		<mx:series>
			<mx:PieSeries displayName="setor"  nameField="setor"  field="total" 
			labelPosition="insideWithCallout" />
			
		</mx:series>
	</mx:PieChart>
	<mx:Legend dataProvider="{chTotalCargos}"    height="64" x="0" width="780" bottom="0"/>
	<mx:Button x="687" y="10" label="Fechar" click="doSair()" icon="@Embed(
	source=''../imagens/11292_16x16.png'')" height="33"/>
</mx:Panel>	
</mx:Canvas>
Listagem 10. Código do gráfico

Arrastamos no modo Design de nossa aplicação, de dentro da pasta custom, o componente wsTotal e nomeamos de webTotal. Sua presença é exibida no código: .

Criamos a função doComplete(), que chama o método doLoadTotalCargo() e a colocamos no início da aplicação no evento creationcomplete: creationComplete="doComplete()".

Agora vamos no nosso gráfico e setaremos algumas propriedades:


<mx:PieChart x="0" y="0" id="chTotalCargos" width="100%" 
dataProvider="{webTotal.FoList}" showDataTips="true" height="419">
	<mx:series>
		<mx:PieSeries displayName="setor"  nameField="setor"  field="total" 
		labelPosition="insideWithCallout" />
		
	</mx:series>
</mx:PieChart>
<mx:Legend dataProvider="{chTotalCargos}"    
height="64" x="0" width="780" bottom="0"/>
Listagem 11. Definindo propriedades do gráfico

Nosso gráfico recebeu o nome de chTotalCargos e seu dataProvider é o nosso wsTotal(webTotal), acessando os dados pela variável FoList que é um arrayCollection, que é atualizada dinamicamente com o uso do Bindable []. Informamos que a propriedade showDataTips é true para exibirmos os dados. Em MS:Series setamos para o gráfico o displayName como setor, o nameField como setor e o Field como total. O displayName permitirá exibir como se fosse um tooltip ao posicionar o ponteiro do mouse sobre uma área do gráfico qualquer. Outrossim, iremos setar a propriedade labelPosition como “insideWithCallout”, para exibir os dados posicionados no corpo do gráfico.

Para a legenda dos gráfico, usaremos como dataprovider o nosso gráfico, que já recebe esses dados vindos do displayName.

A execução nos exibe a imagem a seguir com o mouse na área maior:

 Gráfico retornado com os dados recuperados de nosso banco de dados
Figura 2. Gráfico retornado com os dados recuperados de nosso banco de dados

Com isso concluímos a criação do nosso gráfico. Espero ter ajudado a quem necessita mostrar gráficos com dados dinâmicos.