Brincando com YQL - Yahoo Query Language

A tempos ouvi falar da YQL - ou Yahoo Query Language -, uma linguagem SQL criada pelo Yahoo, que nos permite consultar, filtrar e juntar dados através de web services.

Você pode por exemplo, filtrar dados de uma página html ou de um xml conforme sua necessidade, usando a já conhecida por nós, SQL, e outros recursos, como XPath.

A YQL nos permite também consultar bases de dados públicas, de serviços já conhecidos por todos nós, como o próprio Yahoo, Twitter, Flickr, YouTube entre outros.  

Assim, você pode reunir todos os serviços que sua aplicação irá consumir, em um único local, utilizando uma única API.

Eu procurei por aí, e não achei muita coisa interessante sendo desenvolvida, infelizmente. Acredito que por não ser tão conhecida da comunidade, ninguém parou para pensar nas inúmeras possibilidades que esse serviço pode oferecer.

Mas, falando tanto assim, vamos a parte prática ;)

SPara mostrar um exemplo rodando, vamos executar este YQL, onde listo todos os links da página inicial do Globo.com:

> select * from html where url="http://www.globo.com" and xpath='//a'

Agora selecione abaixo da box de edição, o tipo de retorno que deseja e pronto, super maneiro não é? Tá, mas agora você deve estar se perguntando, como utilizar isso de forma prática, vou colar um exemplo utilizando jQuery:

    $.ajax({
    type:'GET',
    url: "http://y.ahoo.it/jydbv",
    dataType: 'jsonp',
    crossDomain: true,
    beforeSend: function(){
        console.log('enviando requisição');
    },
    success:function(feed){
        if (feed.query.count > 0) {
            var results = feed.query.results.a;

            results.each(function(indice, objeto) {
                console.log(objeto);
            });
        } else {
            console.log('sem resultados.);
        }
    }
});

Explicando: o jQuery nos permite chamar um JSON “paralelo”, ou seja, em outro host, e é isso que o retorno do Yahoo nos envia, por isso que definimos ali na chamada, o dataType como ‘jsonp’, isso é muito importante. Depois disso, é só navegar no retorno, bem simples ;)

Em tempo, a url ali informada, ela pode ser obtida pelo console, no campo ao rodapé, intitulado “The Rest Query”, ou o topo, em um link bem discreto situado sobre a caixa de edição de Query, intitulado ‘permalink’, onde você pode recuperar o link inteiro, ou de forma diminuta, como a que eu utilizei. Se você colar este link no seu navegador, irá obter o retorno que configurou (XLM/JSON) no console, ou no parâmetro ‘format’ da URL.

Divirta-se ;)

Daemons em PHP

Quem nunca precisou criar um script que tivesse que rodar de tempos em tempos para efetuar alguma tarefa não é mesmo? Geralmente usamos a Cron para rodarmos os scripts, mas e quando o script já não roda mais no mesmo tempo esperado, e quando olhamos, temos várias instancias do mesmo script rodando no servidor, bem chato isso.

Eu sei que você vai falar: ‘sim, mas podemos tratar isso via não sei que’, sim eu sei., mas porque não, deixarmos um script rodando “eternamente” e executando a tarefa exatamente no momento exato em que um upload for finalizado por exemplo?, processando tudo em paralelo, de forma transparente ao usuário?  Ou mesmo um script para checar a cada N segundos, se determinada aplicação ainda está viva.

É para isso que servem os daemons, ou serviços. Daemons são escritos geralmente em C, Python e outras linguagens, mas porque não utilizamos nosso já conhecido PHP? A principal vantagem disso, é que aproveitamos para criar um ambiente único para a aplicação. Onde todas as peças, rodam sob uma mesma linguagem, facilitando assim a manutenção e aproveitando os profissionais já existentes na equipe, sem contar a reutilização de código ;)

Então, vamos montar um daemon exemplo, utilizando a classe System_Daemon, existente tanto no PEAR quanto no GitHub.

Primeiro, temos que clonar o projeto System_Daemon, de autoria do Kevin van Zonneveld (kvz) no GitHub.

** IMPORTANTE: em meus testes, tive que editar a classe System/Daemon.php, no método ‘isInBackground()’ e removi o ‘self::$_processIsChild &&’ do return, deixando somente o ‘self::isRunning()’. **

Agora vamos ao exemplo de código para rodarmos o daemon. No exemplo abaixo, colo uma estrutura básica de script, que utilizo em meus projetos com Zend, que é meu framework padrão.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH', __DIR__  . '/../application');

defined('APPLICATION_ENV')
    || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));<

set_include_path(
    implode(
        PATH_SEPARATOR,
        array(
            realpath(APPLICATION_PATH . '/../library'),
            realpath(APPLICATION_PATH . '/modules'),
            get_include_path(),
        )
    )
);

/** Zend_Application */
require_once 'Zend/Application.php';

require_once 'system_daemon/System/Daemon.php';

// Create application, bootstrap, and run
$application = new Zend_Application(APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini');
$application->bootstrap();

// Configuro o daemon
System_Daemon::setOption('usePEAR', false);
System_Daemon::setOption("appName", "uploaddaemon");
System_Daemon::setOption("appDescription", "Trata os uploads do site.");
System_Daemon::setOption("appDir", dirname(__FILE__));
System_Daemon::setOption("appExecutable", basename(__FILE__));
#System_Daemon::setOption("appPidLocation", '/var/run/uploaddaemon.pid');
System_Daemon::setOption("logVerbosity", '7');
System_Daemon::setOption("logLocation", '/var/log/uploaddaemon.log');
System_Daemon::setOption("authorName", "Thiago Paes");
System_Daemon::setOption("authorEmail", "[email protected]");

/**
 * Setup the CLI Commands
 * 
 * upload.php --help
 * upload.php --start
 * upload.php --stop
 */
try {
    $opts = new \Zend_Console_Getopt(
        array(
            'help'  => 'Exibe esta ajuda.',
            'start' => 'Inicia o Daemon.',
            'stop'  => 'Encerra o Daemon',
        )
    );

    $opts->parse();
} catch (\Zend_Console_Getopt_Exception $e) {
    exit($e->getMessage() ."\n\n". $e->getUsageMessage());
}

if(isset($opts->help)) {
    echo $opts->getUsageMessage();
    exit;
}

/**
 * Action : start
 */
if(isset($opts->start)) {
    try {
        System_Daemon::start();

        while (true) {
            System_Daemon::log(System_Daemon::LOG_INFO, "rodando...");

            // aguardo um minuto antes de executar novamente a ação
            sleep(60);
        }
    } catch (System_Daemon_Exception $e) {
        System_Daemon::log(System_Daemon::LOG_ERR, $e->getMessage());
    }
}

/**
 * Action : stop
 */
if(isset($opts->stop)) {
    System_Daemon::stop();
}

Pronto, com isso, já temos um exemplo de daemon rodando.

E é isso, divirta-se agora criando seus daemons para melhorar ainda mais suas aplicações e o ambiente delas.

Utilizando PHP na linha de comando com Zend Framework

Quem me conhece sabe que sempre gostei muito de brincar com o Terminal/Prompt, então, tenho costume de criar e utilizar vários scripts para automatizar algumas tarefas repetitivas, nos meus projetos, tenho costume de criar uma pasta ‘bin’, onde coloco os scripts que deverão rodar via Cron ou como um Daemon.

Mas assim como já utilizamos nosso framework favorito para fazermos nossos sites e/ou aplicações, porque não utilizarmos também para fazer nossos scripts?

Meu framework favorito atualmente, é o Zend, principalmente por ser modular - mas isso já é assunto para outro post ou conversa de bar -, então, vou apresentar abaixo, a estrutura básica de um script cli, utilizando o Zend.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
    <?php
/**
 * Script PHP-CLI exemplo
 */
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH', __DIR__  . '/../application');

defined('APPLICATION_ENV')
    || define(
        'APPLICATION_ENV', (
            getenv('APPLICATION_ENV') ?
            getenv('APPLICATION_ENV') :
            'production'
        )
    );

set_include_path(
    implode(
        PATH_SEPARATOR,
        array(
            realpath(APPLICATION_PATH . '/../library'),
            get_include_path(),
        )
    )
);

// Zend_Application
require_once 'Zend/Application.php';

// E vamos lá, rodando a aplicação com suas configurações
$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/configs/application.ini'
);
$application->bootstrap();

/**
 * Aqui, configuro os parâmetros de entrada válidos
 * 
 * teste.php --help
 * teste.php --start
 * tsete.php --stop
 */
try {
    $opts = new \Zend_Console_Getopt(
        array(
            'help'  => 'Exibe esta ajuda.',
            'start' => 'Inicia.',
            'stop'  => 'Encerra.',
        )
    );

    $opts->parse();
} catch (\Zend_Console_Getopt_Exception $e) {
    exit($e->getMessage() ."\n\n". $e->getUsageMessage());
}

if(isset($opts->help)) {
    echo $opts->getUsageMessage();
    exit;
}

/**
 * Action : start
 */
if(isset($opts->start)) {
    // nosso código
}

/**
 * Action : stop
 */
if(isset($opts->stop)) {
    // nosso código
}

Bom, o código está bem simples de entender e auto explicativo. Basicamente, instanciamos o Zend_Application, normalmente, como fazemos em nosso index.php, para instanciarmos a app e tudo que for necessário para rodar. Em seguida, com o Zend_Console_Getopt, definimos os parâmetros válidos, a partir daí, é só criar as funções de chamadas para as respectivas ações.

Pronto, agora é só dar asas a imaginação e se divertir um bocado com Zend e PHP-CLI.