[Alexandre Magno] SWFUpload – Server-side

Neste post irei demonstrar a regra de negócio por trás do SWFUpload, uma biblioteca javascript usada para controle de upload de arquivos no Browser utilizando o Flash. Ela controla o lado cliente enquanto o desenvolvedor a utiliza de uma forma extensível com a interface com o usuário. Em posts anteriores eu mostrei como esta interação pode ser feita com o jQuery, e muitas dúvidas surgiram de como receber os arquivos no lado servidor. Irei demonstrar utilizando o PHP com a framework CakePHP em como manipular os arquivos.

Foi utilizada o componente do cakePHP para este propósito.

Primeiramente, para acessar os arquivos no server-side utilizando PHP, temos basicamente o seguinte código:


$_FILE['Filedata'];

Sim, é a mesma forma como é recebido arquivos no server utilizando o input do tipo file. Esta biblioteca é totalmente não-obstrusiva. Você trata da mesma forma como trataria se o Javascript não estivesse habilitado. A diferença aqui é que ele faz a chamada para o script server-side a cada interação de upload, permitindo que seja feito múltiplos e com controles que não são possíveis com o upload padrão do formulário, como barra de progresso e tamanho do arquivo.

Para realizar regras mais elaboradas, utilizei um componente do SWFUploade para CakePHP. Ele possui métodos que facilitam a manipulação dos arquivos enviados para o server. Irei aproveitar para explicar um pouco da arquitetura MVC (Model, View, Controller) e do funcionamento do cakePHP.

O código do back-end segue abaixo:


function addFoto($id) {

$this->Portfolio->id = $id;
$this->set('portfolioId', $this->Portfolio->read());
$cliente = $this->Portfolio->field('cliente',"where id='$id'");
if (isset($this->params['form']['Filedata'])) {

$minuscula = strtolower($cliente);
$cliente_filtrado = strtr($minuscula,'áéíóúêçã ','aeioueca_');

// upload the file
// use these to configure the upload path, web path, and overwrite settings if necessary
$this->SwfUpload->uploadpath = 'img' . DS . 'upload'. DS. $cliente_filtrado . DS;
$this->SwfUpload->webpath = '/img/upload/'.$cliente_filtrado.'/';
chmod('/img/upload/'.$cliente_filtrado,777);
$caminho_db = explode("/",$this->SwfUpload->webpath);
$this->SwfUpload->overwrite = true;

//by default, SwfUploadComponent does NOT overwrite files

if ($this->SwfUpload->upload()) {

// save the file to the db, or do whateve ryou want to do with the data
$this->params['form']['Filedata']['name'] = $this->SwfUpload->filename;
$this->params['form']['Filedata']['path'] = $this->SwfUpload->webpath;
$this->params['form']['Filedata']['fspath'] = $this->SwfUpload->uploadpath.$this->SwfUpload->filename;
$this->data['Foto']['url'] = '/'.$caminho_db[2].'/'.$caminho_db[3].'/'.$this->SwfUpload->filename;
$this->data['Foto']['descricao'] = "";
$this->data['Foto']['status'] = 0;
$this->data['Foto']['portfolio_id'] = $id;

if (!$this->Foto->save($this->data)){
$this->Session->setFlash('Database save failed');

} else {
$this->Session->setFlash('File Uploaded: ' . $this->SwfUpload->filename . '; Database id is ' . $this->Foto->getLastInsertId() . '.');

}
} else {
$this->Session->setFlash($this->SwfUpload->errorMessage);

}
}

}//fim addFoto

Inicialmente, toda a implementação fica dentro de uma função addFoto, pois neste caso o SWFUpload foi usado para este propósito. Esta função fica dentro de uma classe, o controller, que estende a classe App Controller. Para quem não tem familiaridade, parece meio estranho, mas a arquitetura MVC é bastante intuitiva.

O método addFoto fica no controller Admin, pois neste caso o upload de fotos foi usado para um CMS. Neste gerenciador o cliente pode enviar fotos e assim elas podem ser visualizadas e descritas em uma outra página. Cada controller pode ter vários actions, que seria os métodos da classe. Essa estrutura também é aplicada a url, sendo assim, o action do form onde o upload é feito pode facilmente ser http://www.dominio.com/admin/addFoto.

Por trás do controller e actions, existe a abstração com o banco de dados, em que é feito nesta framework e em muitas outras MVC o mapeamento automático do Banco de dados em objeto. Assim, existe um model Portfolio que representa uma tabela no banco em que pode ser acessado seus campos correspondentes(linha 3).

Para completar o trio MVC, falta somente a View. Na linha 4 o controller atribuiu uma variável para ser acessada pela view. A view é simplesmente o template HTML, que no MVC é estritamente usado somente para exibição de dados para o usuário. Neste caso, não realizamos regra de negócio na view, deixando esta tarefa com o controller. Assim a view poderá acessar normalmente a variável passada, que pode ser string, array ou até um objeto.

O Componente é uma classe usada para realizar tarefas no controller com intuito de reaproveitar regra de negócios. Para a view, existe os Helpers, que executam lógicas como por exemplo gerar formulários.

Na linha 13 a 17 atribui algumas propriedades do componente SWFUpload para escolher o caminho a ser enviado o arquivo. Na linha 21, o método de envio foi chamado em uma estrutura condicional, pois este método retorna booleano com o status do upload realizado.

O $this->params do CakePHP simplesmente é um atributo do Controller principal onde fica guardado todos os POST’s enviados pelo form, assim ele pode ler os dados do arquivo.

$this->data é um array que fica no formato do [Model][campo] para ser preenchido para que em uma única chamada do método Save as informações no banco são corretamente salvos.

O restante da implementação prepara a formatação do arquivo para ser inserido no banco de dados com as referências corretas. Na linha 32 então os dados são salvos no banco de dados.

Infelizmente não posso postar este exemplo devido a ética profissional (por este lado retiro o infelizmente, ele foi posto pensando na facilidade para os leitores, pois um exemplo vale mais que mil palavras). Mas espero que tenha servido de referência e um caminho para os que estão utilizando esta ferramenta ou que não conheciam os poderes que a arquitetura MVC pode oferecer.

Algumas referências: