Gerando URLs absolutas para rotas do Symfony2

Nas classes que extendem, em algum nível, a classe Controller padrão do Symfony2 está disponível um método utilitário que é simplesmente um atalho para o gerador de rotas do serviço de roteamento (router). Esse método é o generateUrl($route, $parameters, $referenceType).

Na maioria dos casos de uso, como em redirects, passamos apenas um ou dois parâmetros para esse método, que são, respectivamente, o nome da rota e, opcionalmente, os parâmetros que devem ser aplicados a ela. O terceiro parâmetro, que acaba esquecido, traz algumas possibilidades que podem ser muito úteis. Um exemplo prático: precisei incluir na resposta de um webservice em JSON a URL para uma página da aplicação relacionada a objetos específicos, como esse serviço seria consumido por uma aplicativo mobile, precisava retornar a URL absoluta — incluindo o protocolo e domínio — e não apenas o caminho, que é o comportamento padrão do método. Para fazer isso, bastou passar a constante abaixo no terceiro parâmetro do método:

\Symfony\Component\Routing\Generator\UrlGeneratorInterface::ABSOLUTE_URL

Para dar mais legibilidade ao código, adicionei um use para a interface:

use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

// ...

class MainController extends Controller
{
  public function indexAction()
  {
    // ...
    $item['Url'] = $this->generateUrl('item_detail', array('id' => $item['Id']), UrlGeneratorInterface::ABSOLUTE_URL);
  }
}

Declarando arrays em shell script, no bash

Apenas uma referência básica de declaração de arrays em shell script, no bash. Em relação ao uso, existem várias formas e possibilidades.

Exemplo com strings:

nomes=( "Esse" "Aquele" "Outro" )

Exemplo com inteiros:

ids=( 1 2 3 4 5 6 7 )

Comunicação entre PHP e Arduino via USB

Fazem uns 6 meses desde que tive meu primeiro contato com o Arduino, desde então eu sempre tive curiosidade de como seria fazer ele “conversar” com um script em PHP. Hoje, finalmente, eu botei a mão na massa e, depois de algumas pesquisas no Google, fiz algumas experiências de comunicação básica. A seguir deixo os dois experimentos que fiz.

Detalhe para a variável $ttyPath usada nos dois exemplos que contém o caminho do dispositivo, no meu caso, no Mac. No Linux e outros Unixes(-like) esse caminho deve ser algo parecido, é o mesmo caminho que aparece na IDE do Arduino. Não cheguei a testar no Windows, mas acredito que não seja complicado encontrar algum exemplo no Google.

Não vou explicar todo o código porque acredito que o próprio código e os comentários já dão uma boa noção do funcionamento, mas caso tenha qualquer dúvida, fique a vontade para usar o espaço para comentários.

Do Arduino para o script PHP

O primeiro experimento consiste em ler o que o Arduino escreve na porta serial.

to_php.cpp

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  Serial.println('Hello!');
  delay(1000);
}

Esse script PHP basicamente escreve na saída padrão o conteúdo enviado pelo Arduino.

conn_a.php

<?php
$ttyPath = '/dev/tty.usbmodem1a21';
$ttyHandler = fopen($ttyPath, 'r'); // Abrindo a conexão serial
while (true) { // Loop infinto, para testarmos a leitura como acontece no Serial Monitor
  $bytes = fread($ttyHandler, 1024); // Lendo uma linha da conexão, até 1024 bytes
  if (strlen($bytes) > 0) { // Se o Arduino enviou algo ...
    echo $bytes; // Imprimimos
  }
}
fclose($ttyHandler); // Fechando a conexão. De fato, o script nunca vai chegar aqui

Do script PHP para o Arduino

O segundo experimento faz o caminho inverso, de comunicação, do primeiro: envia a quantidade de vezes que o LED deve piscar.

from_php.cpp

int ledPin = 13; // Porta do LED embutido no Arduino UNO
int times = 0; // Por padrão, não deve piscar nenhuma vez

void setup()
{
  Serial.begin(9600); // Iniciando a porta serial
  pinMode(ledPin, OUTPUT); // Iniciando a porta do LED
}

void loop()
{
  if (Serial.available() > 0) { // Se a porta estiver disponível ...
    times = Serial.read() - '0'; // Lemos o conteúdo recebido como inteiro
    if (times < 0 || times > 9) { // Validando o valor lido
      times = 0;
    }
  }
  while (times > 0) { // Piscando até que o número de "piscadas" faltantes seja zerado
    digitalWrite(ledPin, HIGH); // Acende ...
    delay(500); // Espera 1/2 segundo
    digitalWrite(ledPin, LOW); // Apaga ...
    delay(500); // Espera 1/2 segundo
    times--; // Diminui uma "piscada"
  }
}

Nesse script PHP vamos passar o número de “piscadas” do LED como parâmetro. Por padrão, sempre que um script PHP é executado diretamente pelo cliente o primeiro argumento ($argv[0]) é o nome do próprio script ('conn_b.php', por exemplo), sendo assim precisamos capturar o segundo argumento para identificar o número de “piscadas”.

conn_b.php

<?php
$ttyPath = '/dev/tty.usbmodem1a21';
if (count($argv) < 2) { // Esperamos que o número de "piscadas" seja passado como parâmetro
  exit(1);
}
$blinkTimes = (int) $argv[1]; // Lendo o parâmetro com a quantidade de "piscadas"
$ttyHandler = fopen($ttyPath, 'r+'); // Abrindo a conexão serial
fwrite($ttyHandler, (string) $blinkTimes); // Escrevendo a quantidade na conexão
fclose($ttyHandler); // Fechando a conexão

Exemplo de execução (com o Arduino conectado à porta USB):

$ php conn_b.php 5

UPDATE: Infelizmente, notei que esse modelo de comunicação, funciona apenas se o Serial Monitor da IDE do Arduino estiver aberta. Isso acontece porque é necessário abrir a conexão COM e na velocidade correta – normalmente 9600 baud. Assim que conseguir uma solução independente da IDE, atualizo os scripts.

UPDATE 2: O Paulo Trentin colocou um link nos comentários para um artigo que ele escreveu. Eu ainda não tive oportunidade de testar, mas a princípio ele teria resolvido essa questão da comunicação com o hardware exigir a IDE do Arduino aberta durante a execução: http://www.paulotrentin.com.br/eletronica/controlando-arduino-com-php-via-serial/

Referências:

Livro: Código Limpo

Li esse livro faz mais de 1 ano. Havia emprestado para um colega da Gazeta do Povo e, como ele me devolveu essa semana, decidi retornar ao texto por curiosidade — o caminho para casa, de ônibus, é quase sempre dedicado à leitura. Me deparei com um capítulo (17) incrível que eu havia esquecido. Basicamente um resumo de muitos tópicos que o livro trata, com exemplos de código e o que (e não) fazer em cada situação.

Listo abaixo os tópicos relacionados à funções desse capítulo:

Parâmetros em excesso

As funções devem ter um número pequeno de parâmetros. Ter nenhum é melhor. Depois vem um, dois e três. Mais do que isso é questionável e deve-se evitar com preconceito.

Parâmetros de saída

Os parâmetros de saída são inesperados. Os leitores esperam que parâmetros sejam de entrada e não de saída. Se sua função deve alterar o estado de algo, faça-a mudar o do objeto no qual ela é chamada.

Parâmetros lógicos

Parâmetros booleanos explicitamente declaram que a função faz mais de uma coisa. Eles são confusos e devem ser eliminados.

Função morta

Devem-se descartar os métodos que nunca são chamados. Manter pedaços de código mortos é devastador. Não tenha receio de excluir a função. Lembre-se de que o seu sistema de código fonte ainda se lembrará dela.

Caso esse trecho tenha despertado o seu interesse pelo livro, fica uma dica: leia-o no original, em inglês, se você puder. Ou se prepare para uma tradução muito falha e que em alguns pontos requer muito tempo de interpretação e dedução.

cleancode-W800

Martin, Robert C. – Código Limpo: Habilidades Práticas do Agile Software. AltaBooks, 2009.

Split string no MySQL

O MySQL não tem uma função para quebrar strings separadas por um determinado caractere (vírgula, por exemplo). A maioria das soluções que encontrei na web são baseadas em procedures. Não satisfeito com essa opção, fiz alguns estudos e cheguei à seguinte query:

SELECT DISTINCT 
SUBSTRING_INDEX(SUBSTRING_INDEX('1,2,3,4,5', ',', `i`), ',', -1) AS `val` 
FROM (
  SELECT @n := @n + 1 AS `i` 
  FROM `huge_table`, (SELECT @n := 0) `a` LIMIT 999
) `b`

Explicando:

  1. Geramos uma lista com valores de 1 até 999 (SELECT @n := @n + 1 AS `i` FROM `huge_table`, (SELECT @n := 0) `n` LIMIT 999). Aqui `huge_table` deve ser substituído pelo nome de uma tabela que tenha o número de registros (linhas) no mínimo igual ao valor especificado na cláusula LIMIT.
  2. Em seguida usamos esses valores no sequência de funções SUBSTRING_INDEX para extrair os valores da string.

Obs.: Você pode usar um valor menor (ou maior) no LIMIT se souber que a sua lista tem sempre menos (ou mais) valores.

Solução : WordPress e imagens com acentuação no Safari

Já vi esse problema acontecer mais de uma vez e acredito que não tenha encontrado uma solução — ou até mesmo algum relato parecido — porque no inglês (idioma largamente usado com o WordPress) não existe acentuação. Mas nos países que falam Português (ou qualquer outro idioma que possua acentos), um usuário ou outro acaba usando acentuação em nomes de arquivo. Ao fazer o upload de um arquivo desses e usar uma função como a wp_get_attachment_image para exibir a imagem, ela não é carregada no Safari (ao menos no Mac OS X). Ainda não consegui descobrir o motivo exato, pois em outros navegadores funciona como esperado.

Enfim, a solução é bem simples e baseia-se em um filtro.

add_filter('wp_get_attachment_image_attributes', 'ck_image_attrs');

function ck_image_attrs($attrs)
{
  foreach ($attrs as $name => $value)
  {
    if ('src' != $name)
    {
      break;
    }
    $attrs[$name] = ck_fix_image_url($value);
  }
  return $attrs;
}

function ck_fix_image_url($url)
{
  $parts = parse_url($url);
  $path = explode('/', $parts['path']);
  $path = array_map('rawurlencode', $path);
  $path = implode('/', $path);
  return str_replace($parts['path'], $path, $url);
}

Separei a lógica na função ck_fix_image_url para que possa ser usada em conjunto com a wp_get_attachment_image_src, por exemplo.

Funções úteis em JS para extrair dados de URLs

Existem bibliotecas bem legais para extrair dados da URL, mas às vezes você não precisa de todas aquelas informações. Para evitar que seu código fique inchado ou a importação de bibliotecas completas, pode ser interessante usar funções específicas que retornam apenas o dados que você precisa. Tem duas delas que uso com bastante frequencia:

Hash

function getHash(url)
{
  if (typeof url != 'string')
  {
    return null;
  }
  return url.replace(/^.*(#.*)$/, '$1');
}

Parâmetro (GET)

function getParam(url, param)
{
  if (typeof url != 'string' || typeof param != 'string')
  {
    return;
  }
  var regex = new RegExp('[\\?&]' + param + '=' + '(.+?)([&#]|$)', 'i');
  return (value = (regex.exec(window.location.href)||[,null])[1]) 
      ? decodeURIComponent(value) 
      : null;
}

Deixando o inglês de lado

O tempo anda cada vez mais curto e hoje fazem aproximadamente uns 18 meses que não escrevo nada por aqui. Um dos objetivos iniciais desse blog era treinar a minha escrita em inglês, mas como não tenho praticado muito, toda vez que penso em escrever acabo procrastinando. Porém a partir de hoje estou deixando o inglês de lado e tomando o português como idioma principal dos textos publicados por aqui. Aos poucos também vou traduzir os textos antigos — que não são muitos mesmo.

Até logo!