Categorias
CakePHP Desenvolvimento Web

Dica Rápida: usando tipos “complexos” com Migrations no Phinx

Essa é uma dica bem curta e realmente rápida pra registrar algo que precisei pesquisar algumas vezes nos últimos anos e sempre me esqueço.

Cena: você define uma tabela no seu projeto e gostaria de usar uma coluna com o tipo tsvector (como citei em posts recentes) ou então uuid. Você quer usar as funções do banco de dados para gerar o valor default para a coluna. Como fazer isso usando Migrations baseada no Phinx sem recorrer a SQL cru?

Resposta: utilize a classe Phinx\Util\Literal.

$this->table('posts')
    ->addColumn('id', 'uuid', [
        'default' => \Phinx\Util\Literal::from('gen_random_uuid()'),
        'null' => false
    ])
    ->save();

Literal pode ser utilizado tanto para definir valor default baseado em funções quanto para conversão entre tipos para uma mesma coluna (fazer CAST do antigo formato para o novo).

Categorias
CakePHP Desenvolvimento Web PHP Projetos

Fulltext Search – Busca Textual com Postgres – Parte 3 (Final)

Encerramos aqui essa breve introdução sobre busca textual (fulltext search) com Postgres apresentando um plugin que pode te auxiliar (se você utiliza CakePHP + Postgres) na implementação da busca – caso não use, talvez sirva de inspiração para um fork.

A história desse plugin vem lá de 2015 quando precisei incluir em uma busca que desconsidera-se pequenos erros de grafia e permitia o uso de sinônimos. Tínhamos restrições de hardware para implementar a busca – era uma aplicação nova, com orçamento pequeno e dispunha de um servidor com apenas 2 GB de RAM. Usar Elasticsearch seria inviável.

Na época o CakePHP tinha recém chego a versão 3.0, com um ORM todo remodelado, muito mais flexível e extensível do que nas versões anteriores. Pensei: fácil, vou estender ele e adicionar suporte aos novos tipos de dados e índices (tsvector, GIN e GIST, como vimos anteriormente). Bom, na prática não era tão fácil, a extensibilidade ainda era pequena, havia muitas dependências acopladas. A solução foi criar um shell que era invocado a cada X minutos e regerava a tabela de buscas com os tipos e índices apropriados usando SQL puro. Funcionou e foi o suficiente porque o sistema era novo e não tinha milhões de registros – já prevíamos que escalando o banco de dados, precisaríamos de mais hardware para extrair a rotina de busca.

Mais de 6 anos se passaram, agora estamos com o CakePHP 4.2 e seu ORM muito mais flexível e desacoplado. E mais uma vez me foi dado o desafio de puxar uma busca que utilizava o Elasticsearch para dentro do banco de dados principal (Postgres). Assim nasceu o autopage/pg-search.

Considerando que você tenha uma instalação do CakePHP > 4.2.2, a instalação começa com composer:

$ composer require autopage/pg-search

Em seguida, carregue o plugin na sua aplicação:

$ bin/cake plugin load Autopage/PgSearch

Por último, precisamos configurar sua aplicação para utilizar o driver Postgres fornecido. Para isso, edite seu arquivo de configuração (ou variável de ambiente, se utilizar) config/app.php ou config/app_local.php:

// No ínicio do arquivo
use Autopage\PgSearch\Database\Driver\Postgres;
...

return [
...
// Dentro da configuração dos datasources
...
    'Datasources' => [
        'default' => [
            'driver' => Postgres::class,
...

Pronto, você já pode criar migrations (não depende disso), fixtures, Tables e querys com o CakePHP.

Uma migration poderia ser:

<?php
declare(strict_types=1);

use Migrations\AbstractMigration;
use Phinx\Util\Literal;

class CriaTabelaBuscas extends AbstractMigration
{
    /**
     * More information on this method is available here:
     * https://book.cakephp.org/phinx/0/en/migrations.html#the-change-method
     * @return void
     */
    public function change()
    {
        $tabela = $this->table('buscas');
        $tabela
            ->addColumn('original_id', 'integer', ['null' => false, 'default' => null])
            ->addColumn('nome', 'string', ['limit' => 255, 'null' => false, 'default' => null])
            ->addColumn('data', 'date', ['null' => false, 'default' => null])
            ->addColumn('conteudo', 'text', ['null' => false, 'default' => null])
            ->addColumn('conteudo_fts', Literal::from('tsvector'), ['null' => false, 'default' => null])
            ->addTimestamps('criado', 'modificado')
            ->create();
    }
}

Para salvar registros, basta popular a entidade. Repare que criei duas colunas conteudo, uma text e outra tsvector. A ideia é que a primeira contenha a forma original que exibiremos ao usuário, enquanto a tsvector é preparada para execução da busca. Na hora de popular a entidade, atribua o mesmo valor em conteudo e conteudo_fts, o driver cuidará da conversão necessária na hora de persistir.

Já uma consulta ao banco poderia ser feita com:

// Não esqueça de sanitizar antes de passar na query abaixo
$termo = $this->request->getQuery('q');
$resultados = $this->Buscas->find()
    ->where(["conteudo_fts @@ phraseto_tsquery('{$termo}')"])
    ->order(['data' => 'desc'])
    ->all();

Ainda tem um behavior que adiciona um finder especial para busca, você deve vincular ele a tabela associada com a tabela de buscas – nesse exemplo da migration, o behavior seria ligado na tabela OriginalsTable. Veja as configurações disponíveis na documentação do projeto.

É isso, com essa sequência de artigos espero ter mostrado que é possível oferecer uma busca boa o suficiente para a maioria das aplicações sem precisar estourar orçamento com hardware ou serviços externos. E claro, que essa implementação não precisa ser nenhum bicho de sete cabeças.

Se tiver alguma dúvida ou encontrar algum problema, pode usar tanto a caixa de comentários abaixo quanto o github.

Categorias
CakePHP Desenvolvimento Web Programação

CakePHP 3.0 – O Fim do Locale

 

A nova versão do meu framework favorito está em estágio avançado e trás uma infinidade de coisas legais.

Dentre as novidades, quero deixar uma dica rápida para um problema comum a qualquer um que não use data/decimais em formato dos EUA: até hoje, para o Cake 1.3 e 2.x eu utilizo o plugin Locale, que já falei a respeito aqui antes.

Com o CakePHP 3.0, o plugin é completamente desnecessário: o novo ORM é capaz de interpretar os dados enviados em formato local para o formato nativo da máquina, de forma transparente.

Você só precisa registrar que os tipos do ORM deve utilizar localização…

Diga ao seu ambiente qual seu locale (pode fazer isso no bootstrap.php):

ini_set('intl.default_locale', 'pt_BR');

Inclua as linhas abaixo no início do seu AppController:

use Cake\Database\Type;
// Habilita o parseamento de datas localizadas
Type::build('date')
 ->useLocaleParser()
 ->setLocaleFormat('dd/MM/yyyy');
Type::build('datetime')
 ->useLocaleParser()
 ->setLocaleFormat('dd/MM/yyyy HH:mm:ss');
Type::build('timestamp')
 ->useLocaleParser()
 ->setLocaleFormat('dd/MM/yyyy HH:mm:ss');

// Habilita o parseamento de decimal localizaddos
Type::build('decimal')
 ->useLocaleParser();
Type::build('float')
 ->useLocaleParser();

Pronto, os dados do seu formulário serão interpretados e convertidos antes de serem salvos.

Para alterar a validação de data, você deve usar algo assim:

$validator->add('birthday', 'valid', [
 'rule' => ['date', 'dmy'], // esse é o importante, onde você avisa que a data estará localizada
 'message' => __('Informe uma data válida')
 ]);

E em substituição ao LocaleHelper, você pode formatar suas datas com o método format disponível (já que o registro agora é um objeto), e no caso de float/decimal, você usa a lib Number.

use Cake\I18n\Number;
$data = $user->birthday->format('d/m/Y');
$salary = Number::format($user->salary);

E é isso, sem nenhum plugin, sua aplicação estará falando português (ou qualquer outra linguagem/localização que você deseje utilizar).

Categorias
CakePHP Desenvolvimento Web PHP

[CakePHP] Acl: Problema com Acos “duplicados”

Quando falamos em Acl e CakePHP muitos tem a lembrança de horas lutando contra um monte de código para tentar fazer funcionar a autenticação e permissionamento. Bastam algumas dezenas de projetos e você fica craque em configura-lo.

Porém vez ou outra aparece uma dúvida que te faz perder várias horas debugando e as vezes termina isso sem uma solução razoável.

Trabalhamos muito com Plugins na Radig e um problema que enfrentávamos de vez em quando era o de ter um plugin com o mesmo nome de uma ação de controller. Nestes, quando você verifica a permissão para a ação usando uma sintaxe de caminho parcial, isto é, algo como:

$this->Acl->check('acao', 'Fulano');
$this->Acl->check('Controller/acao', 'Fulano');
$this->Acl->check('Plugin/Controller/acao', 'Fulano');

Um erro é retornado, dizendo que o Aco não pode ser verificado (lembrando que para o exemplo, Plugin teria o mesmo nome de acao).

Isso foi até assunto de um bug reportado para o CakePHP, afirmando que a falha estava no fato das comparações no banco de dados serem, na maioria das vezes, case-insensitive. De fato, como respondeu o Mark Story, uma forma de resolver este “problema” é utilizar no banco de dados um COLLATION que seja de fato case-sensitive. O problema nisso é que a maioria dos conjuntos de caracteres, ao menos no MySQL, são case-insensitive, então você teria de mudar todos os seus banco de dados para corrigir isso.

Porém o usuário nlcO postou uma dica interessante: basta usar o caminho completo do Aco que não haverá conflito, mesmo quando controllers, plugins ou actions tiverem os mesmos nomes. Mas como usar o caminho completo? Basta ver qual é seu Aco raiz (que possuí o parent_id = NULL) e ir incluindo após ele todos os subsequêntes – plugins, controllers e actions, até formar o caminho completo.

No meu exemplo ficaria:

$this->Acl->check('aplicacao/Plugin/Controller/acao', 'Fulano');
Categorias
CakePHP PHP Projetos

[Comitiva] Como utilizar controle de permissão no sistema

Como escrevi anteriormente, o PHPMS mantém um sistema para gerenciar eventos – desde a divulgação de informações, cadastro de eventos, inscrições, pagamentos, envio de mensagens para inscritos e check-in.

Mas o objetivo deste post não é dizer o que já foi dito, quero iniciar uma série de posts onde vou explicar o funcionamento de alguns recursos dentro do Comitiva, convidando todos os desenvolvedores a opinar sobre implementação e contribuir com o projeto.

O assunto de hoje é controle de acesso, então vamos ao que interessa.

Como funciona o controle de acesso no Comitiva?

Utilizamos o componente Auth do CakePHP para cuidar da autenticação (efetuar login, verificar se o usuário está logado e efetuar logout).
Mas precisávamos ir um pouco além da configuração básica, definindo diferentes opções para diferentes tipos de usuários. Para isso, consideramos duas opções iniciais: usar também o Acl Behavior ou ficar apenas com o AuthComponent e criar diferentes actions para diferentes tipos de usuários.

Como possuímos apenas dois tipos de usuários (admin e participant) decidimos pela que seria mais simples inicialmente – mesmo sabendo que a manutenção no futuro poderia ser mais complicada – que foi criar diferentes actions para os tipos de usuários.

Para criar essa funcionalidade, definimos inicialmente um prefixo para cada tipo de usuário (prefixos ‘admin‘ e ‘participant‘). Em seguida configuramos o AuthComponent desta maneira (código extraído do AppController):

//Configure AuthComponent
$this->Auth->authorize = 'controller';

if( !isset($this->params['prefix']) || !( in_array($this->params['prefix'], Configure::read('Routing.prefixes')) ) )
{
	// all non-prefixed actions are allowed
	$this->Auth->allow('*');
}

Ou seja, toda ação que não tiver prefixo ou o prefixo não estiver definido nas configurações de rota serão públicas (assim é possível, por exemplo, deixar uma página com instruções acessível à qualquer usuário).

Mas como fica essa verificação de tipos no controlador? Como definimos o método de autorização do Auth como ‘controller’, precisamos definir em todos os controladores o método isAuthorized que deve retornar true quando o acesso é aprovado e false caso contrário.
Seguindo a ideia de que cada tipo de usuário possui um prefixo próprio nas ações, nosso método isAuthorized fica desta forma:

if($this->userLogged == TRUE && $this->params['prefix'] == User::get('type'))
{
	return true;
}

return false;

Onde o atributo $this->userLogged pertence a classe AppController e sua função é reduzir chamada ao método $Auth->login() e na segunda parte da condição temos uma comparação entre o prefixo da url acessada e o tipo do usuário – se ambos forem iguais, então o acesso está liberado.

Por fim, devemos criar nossas ações para cada tipo de usuário, onde o prefixo será usado para validar o acesso à aquela ação, veja o exemplo da ação “listar pagamentos”:

// ação exclusiva para admin - tem acesso aos pagamentos de todos os outros usuários
public function admin_index($event_id = null)
{
	$this->Subscription->recursive = 0;
		
	if(is_numeric($event_id))
	{
		$this->paginate = array(
			'conditions' => array(
				'event_id' => $event_id
			)
		);
	}
		
	$this->set(compact('event_id'));
	$this->set('subscriptions', $this->paginate());
}

// ação exclusiva para participant - tem acesso somente aos próprios pagamentos
public function participant_index()
{
	$this->Subscription->recursive = 0;
	$this->set('subscriptions', $this->paginate(array('user_id' => User::get('id'))));
}

Como podem ver, isso permite a criação de diferentes regras de negócio para os diferentes tipos de usuários e embora aumente a quantidade de código “redundante” por repetir alguns procedimentos para todos os tipos de usuários, a leitura e entendimento do código é facilitada – basta ver o prefixo do método (ação) para saber quem terá acesso a ele.

Categorias
CakePHP PHP

Dica Rápida – Otimizando código

Há um bom tempo atrás rolou uma discussão na lista do PHPMS sobre um comparativo de performance entre PHP x Python x Ruby x Perl.

Bom, a conclusão que tirei do comparativo foi de que a velocidade de execução é importante, mas mais do que isso, o programador é essencial. No exemplo da thread supracitada, o PHP perdia feio para as outras linguagens, mas olhando para o código escrito em PHP, dava para notar  vários erros de uso da linguagem e suas funções (ponto para o Begnini que viu o código antes de todos).

Então a dica de hoje é: estude bem a linguagem. Procure a saber o funcionamento das funções e construções da linguagem, isso é essencial para se tornar um bom programador.

Exemplos de código

//uso comum
for($i = 0; count($var) < 0; $i++)
  ...

//forma mais adequada
for($i = 0, $c = count($var); $c < 0; ++$i)
 ...

//outro caso, ao invés de forçar várias verificações
if( $a > 100 )
 ...
if( $a < 100 )
 ...
if( $a == 100 )

//use a estrutura adequada
if( $a > 100 )
 ...
else if( $a < 100 )
 ...
else //não precisa fazer o último teste
 ...

// esse último caso que me inspirou a fazer o post

// a pessoa só queria saber se o array $var tava vazio, e para isso contou todos os seus elementos
if ( count($var) > 0 )
 ...

// enquanto ela poderia ter usado uma verificação direta como
if ( !empty($var) )

Este último caso, que motivou o post foi visto no changelog da versão 1.2.6 do CakePHP. Neste caso o “erro” foi encontrado e corrigido pelo brasileiro Juan Basso neste commit.

O intuito do post não é meter o dedo na cara de ninguém, apenas alertar para situações onde culpamos uma determinada linguagem pelo desempenho de nossa aplicação quando o problema na verdade é o mal uso que estamos fazendo.

Categorias
CakePHP PHP

CakePHP 1.3 quase assado

Pouco mais de um ano após o lançamento da versão 1.2.0 do CakePHP, está para ser lançado, dia 13 de fevereiro, a versão 1.3 deste poderoso framework.

Tenho feito alguns testes em cima dele, estou inclusive reescrevendo um pequeno CMS que possuímos na empresa em cima desta versão (árvore 1.3-dev do repositório do projeto) e apesar de alguns pequenos bugs (ainda é uma versão de desenvolvimento, né?) esta versão possui muitas melhorias na sintaxe – que agora está mais concisa –  e novas funcionalidades.

Para a migração de nossa aplicação, não foi preciso alterar muita coisa, porém para grandes aplicações, deve-se considerar a necessidade do upgrade.

Abaixo segue uma lista de links para algumas páginas com informações sobre esta nova versão do CakePHP (todas em inglês):

Caso tenha interesse em ajudar os desenvolvedores, baixe a versão em desenvolvimento e faça alguns testes. Só não esqueça de reportar eventuais problemas ou patchs que você venha a produzir. Não se preocupem com o tempo de resposta da equipe de desenvolvimento, eles realmente estão empenhados em fazer um bom trabalho, é possível que tenha feedback de seu ticket/patch em menos de 1 hora – experiência própria.

Logo que concluir algumas tarefas e tiver feito mais testes colocarei aqui meu “parecer” sobre a nova versão, enquanto isso acompanhe a página de desenvolvimento para ficar por dentro das atualizações.

Categorias
CakePHP opensuse PHP Tutoriais

Trabalhando com PHP 5.2 no OpenSUSE 11.2 (Downgrade do PHP 5.3 para 5.2)

No final de 2009 foi lançado a versão 11.2 do OpenSUSE, e como de costume para esta distro, todos os seus pacotes foram atualizados para a última (ou uma das últimas) versão estável. Isso aconteceu como PHP (que no lançamento estava na versão 5.3) como o MySQL (versão 5.1) dentre vários outros.

Acontece que quem trabalha com Drupal, Joomla! ou CakePHP (última  versão estável é a 1.2) deve aguardar ainda para poder utilizar a versão 5.3 do PHP, que incluí várias mudanças, caso contrário eles podem não funcionar ou apresentar vários avisos.

Pesquisando sobre o problema descobri que não há no repositório do OpenSUSE (os oficiais nem nos mais conhecidos) o PHP 5.2 disponível, então como fazer? Baixar o fonte e compila-lo? É uma saída, mas queria algo “OpenSUSU-like” (mais fácil).

Dando uma vasculhada no oráculo encontrei openSUSE 11.2: Downgrade PHP 5.3 to 5.2

Resolvi adaptar algumas coisas e funcionou perfeitamente, vamos lá aos passos com minhas modificações:

  1. Abra o Gerenciador de Software;
  2. Vá no menu “Configuração” -> “Repositórios”;
  3. Procure o repositório “Atualizações Para o OpenSUSE 11.2-0”, clique sobre ele e depois no botão editar, na parte inferior da janela;
  4. No campo “Diretório do Servidor” altere o “11.2” para “11.1” e então clique em OK; Na versão 11.1 o PHP está na versão 5.2
  5. Procure o repositório “OpenSUSE 11.2 OSS”, clique sobre ele e depois no botão editar; Este e o próximo passo são necessário caso você deseje fazer o downgrade do MySQL para versão 5.0 (eu recomendo isso para deixar tudo compatível, como era no OpenSUSE 11.1)
  6. No campo “Diretório do Servidor” altere o “11.2” para “11.1” e então clique em OK;
  7. Novamente clique em OK na listagem de repositórios;
  8. De volta a janela de gerenciamento de software, pesquise por PHP5, caso você já tenha instalado o PHP 5.3 aproveite agora para remover tudo relativo a ele, caso contrário selecione os pacotes que precisar e tenha certeza de marcar a versão correta (para mim foi 5.2.11). Verifique a versão de cada pacote clicando sobre ele e em seguida na aba “Versões” da janela, se houver mais de uma, marque a relativa ao PHP 5.2.x (onde x for o maior disponível);
  9. Agora, pesquise os pacotes relativos ao MySQL (utilize o termo “mysql” na caixa de busca);
  10. Você deve marcar as opções “libmysqlclient15”, “mysql” e “mysqlclient” conferindo se todos estão com a versão selecionada para 5.0.x (onde x é o maior número disponível);
  11. Clique agora em OK para instalar os pacotes, uma janela irá abrir informando a necessidade de instalar alguma dependência. Dê uma olhada se não há conflitos e clique em OK; Agora é só aguardar.
  12. Abra agora o “Repositórios de Software” e volte os repositórios para sua configuração original (trocando o 11.1 para 11.2), caso contrário não receberá as últimas atualizações dos outros softwares. Recomendo também que vá ao “Gerenciador de Software” e bloqueie os pacotes que instalou, para que o OpenSUSE não tente atualiza-los (os pacotes do PHP e MySQL);
  13. Depois de instalar os pacotes, reinicie seu Apache logando-se como root no terminal e executando o comando “rcapache2 restart”; Verifique se o PHP está funcionando corretamente. Deve estar;
  14. No OpenSUSE 11.2 o socket do MySQL mudou de endereço, mas como instalamos a versão antiga do MySQL não teremos essa alteração, porém alguns aplicativos (além do PHP) usam o MySQL (como o meu Amarok), então vamos criar um link simbólico onde deveria ser o endereço novo apontando para o antigo para que não haja problema, faremos isso como root;
  15. Crie o diretório que é padrão para o socket na versão 11.2 do OpenSUSE: mkdir /var/run/mysql
  16. Entre no diretório criado e crie o link simbólico para o socket: ln -s mysql.sock /var/lib/mysql/mysql.sock
  17. Reinicie seu OpenSUSE e bom proveito.

Caso tenha alguma dúvida deixe-a nos comentários. Se necessário tiro alguns screenshots para ilustrar melhor.

Categorias
CakePHP Desenvolvimento Web eventos PHP

Latinoware 2009 – COLAPHP – Evento fantástico

Eae pessoal, tudo tranquilo?

Tenho andado bem corrido ultimamente e não tenho conseguido dar a atenção que queria ao blog. De agora em diante as coisas não devem melhorar muito, mas farei o possível para trazer coisas interessantes pra cá.

Desde o dia 21/10/2009 estou em Foz do Iguaçu – PR, para participar do Latinoware 2009, um dos maiores eventos de software livre das Américas.
Estou tendo a oportunidade de ministrar um minicurso e apresentar uma palestra no “subevento” COLAPHP – Congresso Latinoamericano de PHP, que possui uma trilha dedicada a linguagem dentro do  Latinoware.

A experiência não poderia estar sendo melhor. Pude conhecer excelentes profissionais e fazer muitas amizades.

—————– fim do rascunho 1 ——————-

Nos dias 23 e 24 de outubro tive a oportunidade de ministrar um minicurso e uma palestra dentro da trilha COLAPHP do Latinoware.

Ambos tratavam do CakePHP, no caso do minicurso fizemos uma introdução no framework, falando um pouco de seu funcionamento, suas convenções e criamos rapidamente uma aplicação simples utilizando o terminal com o Bake.

O slides utilizado no minicurso foi este:

No caso da palestra, falei novamente sobre a integração de aplicações escritas em CakePHP e Flex, dando uma revisada na apresentação. Ela ficou assim:

Aproveito o espaço (e a disponibilidade de tempo) para agradecer todos que participaram do evento como um todo, seja na organização, apoio ou assistindo, perguntando, corrigindo e ajudando a gente durante as apresentações. Obrigado a todos.

—————- fim do rascunho 2 ——————-

O texto do rascunho 1 foi escrito em 23/10/2009, o do rascunho 2 logo após o evento, hoje é 16/01/2010 e o textos ainda estevam como rascunho para ser publicado no blog. Pois é, esse final de ano foi realmente muito corrido, mas valeu a pena.

Agora é hora de se organizar para poder ter um 2010 ainda mais proveitoso (de começo ele já está sendo muito melhor).

Até breve.

Categorias
CakePHP eventos PHP

1º Workshop PHPMS – PHP Extremo, SUCESSO

É com grande alegria que informo a todos o sucesso que atingimos com a realização de nosso primeiro Workshop. Tudo no evento saiu melhor do que esperado (menos um pedacinho da minha apresentação, mas isso é detalhe,hehehe).

Tivemos público maior do que o esperado, e todos muito participativos, a quantidade de empresas apoiando também foi grande – principalmente se pegarmos como referência outros eventos de Campo Grande. O nível das apresentações também estavam muito bem definido. Enfim, se melhorasse era perigoso estragar.

Passei a última semana inteira preparando minha apresentação no workshop, inclusive quase não durmi essa noite (3 horas exatas), mas no final tudo aconteceu dentro dos conformes. A participação dos presentes foi outro ponto que me chamou a atenção, serviu para provar que quem estava ali realmente sabia o que estava fazendo ali.

Quero aproveeitar mais uma vez para agradecer a todos que ajudaram de alguma forma no evento: organizadores e amigos (porkaria, zehzinho, Leonardo), o sempre disposto palestrante e amigo Raphael (raphox), aos apoiadores, aos patrocinadores e claro, a todos os presentes que acreditaram no evento e compareceram mesmo com o tempo ruim.

Para quem foi ao evento e gostaria de ver a apresentação de slides que utilizei, ela está acessível pelo endereço: http://www.slideshare.net/cauancabral/php-flex
Na apresentação falei sobre a utilização de Flex para construção de RIA’s juntamente com PHP (mais especificamente utilizando o framework  CakePHP), o exemplo da palestra pode ser encontrado no repositório svn: http://svn.radig.com.br/pagode – na data da  palestra a versão utilizada foi a #3, o sistema será complementado até que se torne realmente um sistema de controle financeiro pessoal. Portanto se tiver interesse no mesmo, acompanhe aqui no blog as novidades do projeto.

———-

O Raphox e o Porkaria também liberaram os slides das palestras, veja aqui e aqui respectivamente.