Rogério Lino

Web development and tips

PHP: Template Engines

Todo mundo que programa em PHP sente falta de uma boa alternativa para separar o código PHP do visual (HTML). Nessas horas vale a pena estudar algumas template engines para PHP disponíveis para saber qual que melhor se adapta à suas necessidades e projeto. Alguns frameworks MVC possuem sua própria engine, outros tentam.

Smarty

O mais famoso e usado como inspiração por muitos outros projetos. Robusto (possuindo blocos condicionais/loops e várias funções próprias) e rápido (“compilando” suas páginas para arquivos PHP).

1
2
3
4
5
<ul>
{foreach from=$myArray item=foo}
    <li>{$foo}</li>
{/foreach}
</ul>
1
2
3
4
$smarty = new Smarty;
$arr = array(1000, 1001, 1002);
$smarty->assign ('myArray', $arr);
$smarty->display ('HelloWorld.tpl');

vlibtemplate

Com esta engine saímos de um problema e entramos em outro, é necessário aprender (lembrar) algumas palavras reservadas para sinalizar variáveis, além do uso dos limitadores das expressões.

1
2
3
4
5
6
7
8
9
<html>
    <head>
        <title>{tmpl_var name='title_text'}</title>
        <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
    </head>
    <body>
        <p>{tmpl_var name='body_text'}</p>
    </body>
</html>
1
2
3
4
$tmpl = new vlibTemplate('tmpl/basic.htm');
$tmpl->setvar('title_text', 'TITLE: This is the vLIB basic example ...');
$tmpl->setvar('body_text', 'BODY: This is the message set using setvar()');
$tmpl->pparse();

FXL Template

Muito pouco usual, o FXL faz uso dos blocos de comentário HTML para definir os loops. Outros semelhantes e nada melhores são: QuickSkin e XTemplate.

1
2
3
4
5
6
7
8
9
 <table>
     <!-- START row -->
         <tr>
             <!-- START cell -->
             <td >{td_value} </td>
             <!-- END cell -->
         </tr>
     <!-- END row -->
 </table>
1
2
3
4
5
6
7
8
9
10
11
12
13
$fxlt = new fxl_template('example.tpl');
$fxlt_row = $fxlt->get_block('row');
$fxlt_cell = $fxlt_row->get_block('cell');
for ($tr = 1; $tr <= 3; $tr++) {
    for ($td = 1; $td <= 3; $td++) {
        $fxlt_cell->assign('td_value', $tr.':'.$td);
        $fxlt_row->assign('cell', $fxlt_cell);
        $fxlt_cell->clear();
    }
    $fxlt->assign('row', $fxlt_row);
    $fxlt_row->clear();
}
$fxlt->display();

Vemplator

Mais do mesmo, mas com alterações de sintaxe.

1
2
3
4
5
6
7
8
<h1>{if:logged} Welcome {username} {else:} User not logged {end:} </h1>
<ul>
    {foreach:rows,row}
        <li>
        {row['name']}
        </li>
    {end:}
</ul>
1
2
3
4
5
6
7
8
9
10
11
$t = new vemplator();
// if/else
$t->assign('logged', true);
$t->assign('username', 'Rogerio');
// loop
$items = array(
  array('name' => 'Laptop'),
  array('name' => 'Memory Stick')
);
$t->assign('rows', $rows);
echo $t->output('example.template.html');

TinyButStrong

Uma alternativa ao estilo Smarty de muitos, porém é mais confuso e segue um padrão de nomenclatura bem particular.

1
2
3
<table>
    <tr><td>[blk.val;block=tr]</td></tr>
</table>
1
2
3
4
5
$TBS =& new clsTinyButStrong ;
$TBS->LoadTemplate('template.htm') ;
$list = array('X','Y','Z') ;
$TBS->MergeBlock('blk',$list) ;
$TBS->Show();

Dwoo

Possui como diferencial um Template Inheritance, o que facilita muito a vida na construção de templates.

1
2
3
4
5
6
7
8
9
10
11
12
13
<html>
    <head>
        <title>{block "title"}My site name{/block} </title>
    </head>
    <body>
        <h1>{block "page-title"}Default page title{/block} </h1>
        <div id="content">
        {block "content"}
            Welcome to my amazing homepage
        {/block}
        </div>
    </body>
</html>
1
2
3
4
5
6
7
8
9
{extends "base.html"}

{block "title"}
    Gallery
{/block}

{foreach $images img}
    <img src="{$img.url}" alt="{$img.description}"></img>
{/foreach}
1
2
3
4
5
6
7
8
$dwoo = Dwoo();
$images = array(
    array('url' => 'img1.jpg', 'description' => 'Ferrari'),
    array('url' => 'img2.jpg', 'description' => 'BMW')
);
$params = array();
$params['images'] = $images;
echo $dwoo->get("gallery.tpl", $params);

h2o

Baseado no Smarty, Django Templates e Jinja (os dois últimos para Python).

1
2
3
4
5
6
7
8
<html>
    <head>
        <title>PHP: Template Engines</title>
    </head>
    <body>
        Todo mundo que programa em PHP sente falta de uma boa alternativa para separar o código PHP do visual (HTML). Nessas horas vale a pena estudar algumas template engines para PHP disponíveis para saber qual que melhor se adapta à suas necessidades e projeto. Alguns frameworks MVC possuem sua própria engine, outros tentam.

[Smarty](http://www.smarty.net/)

O mais famoso e usado como inspiração por muitos outros projetos. Robusto (possuindo blocos condicionais/loops e várias funções próprias) e rápido ("compilando" suas páginas para arquivos PHP).

    
```html
    
    {foreach from=$myArray item=foo}
  • {$foo}
  • {/foreach}
``` ```php $smarty = new Smarty; $arr = array(1000, 1001, 1002); $smarty->assign ('myArray', $arr); $smarty->display ('HelloWorld.tpl'); ``` [vlibtemplate](http://vlib.clausvb.de/vlibtemplate.php) Com esta engine saímos de um problema e entramos em outro, é necessário aprender (lembrar) algumas palavras reservadas para sinalizar variáveis, além do uso dos limitadores das expressões. ```html {tmpl_var name='title_text'}

{tmpl_var name='body_text'}

``` ```php $tmpl = new vlibTemplate('tmpl/basic.htm'); $tmpl->setvar('title_text', 'TITLE: This is the vLIB basic example ...'); $tmpl->setvar('body_text', 'BODY: This is the message set using setvar()'); $tmpl->pparse(); ``` [FXL Template](http://www.feverxl.org/template/) Muito pouco usual, o FXL faz uso dos blocos de comentário HTML para definir os loops. Outros semelhantes e nada melhores são: [QuickSkin](http://quickskin.worxware.com/) e [XTemplate](http://xtemplate.sourceforge.net/). ```html
{td_value}
``` ```php $fxlt = new fxl_template('example.tpl'); $fxlt_row = $fxlt->get_block('row'); $fxlt_cell = $fxlt_row->get_block('cell'); for ($tr = 1; $tr <= 3; $tr++) { for ($td = 1; $td <= 3; $td++) { $fxlt_cell->assign('td_value', $tr.':'.$td); $fxlt_row->assign('cell', $fxlt_cell); $fxlt_cell->clear(); } $fxlt->assign('row', $fxlt_row); $fxlt_row->clear(); } $fxlt->display(); ``` [Vemplator](http://www.greaterscope.net/projects/Vemplator) Mais do mesmo, mas com alterações de sintaxe. ```html

{if:logged} Welcome {username} {else:} User not logged {end:}

    {foreach:rows,row}
  • {row['name']}
  • {end:}
``` ```php $t = new vemplator(); // if/else $t->assign('logged', true); $t->assign('username', 'Rogerio'); // loop $items = array( array('name' => 'Laptop'), array('name' => 'Memory Stick') ); $t->assign('rows', $rows); echo $t->output('example.template.html'); ``` [TinyButStrong](http://www.tinybutstrong.com/) Uma alternativa ao estilo Smarty de muitos, porém é mais confuso e segue um padrão de nomenclatura bem particular. ```html
[blk.val;block=tr]
``` ```php $TBS =& new clsTinyButStrong ; $TBS->LoadTemplate('template.htm') ; $list = array('X','Y','Z') ; $TBS->MergeBlock('blk',$list) ; $TBS->Show(); ``` [Dwoo](http://dwoo.org/) Possui como diferencial um [Template Inheritance](http://wiki.dwoo.org/index.php/TemplateInheritance), o que facilita muito a vida na construção de templates. ```html {block "title"}My site name{/block}

{block "page-title"}Default page title{/block}

{block "content"} Welcome to my amazing homepage {/block}
``` ```html {extends "base.html"} {block "title"} Gallery {/block} {foreach $images img} {$img.description} {/foreach} ``` ```php $dwoo = Dwoo(); $images = array( array('url' => 'img1.jpg', 'description' => 'Ferrari'), array('url' => 'img2.jpg', 'description' => 'BMW') ); $params = array(); $params['images'] = $images; echo $dwoo->get("gallery.tpl", $params); ``` [h2o](http://www.h2o-template.org/) Baseado no Smarty, [Django Templates](http://www.djangoproject.com/) e [Jinja](http://jinja.pocoo.org/) (os dois últimos para Python). ```html {{ page.title }} {{ page.content }} ``` ```php $h2o = new h2o('index.html'); $page = array( 'title' => 'title of a page', 'body' => 'Hello world' ); echo $h2o->render(compact('page')); ``` [PEAR Flexy](http://pear.php.net/package/HTML_Template_Flexy/) Entre os projetos disponíveis no PEAR ([PHPLIB](http://pear.php.net/package/HTML_Template_PHPLIB/), [Sigma](http://pear.php.net/package/HTML_Template_Sigma/) e [IT](http://pear.php.net/package/HTML_Template_IT/)) esse é o melhor. Tem como desvantagem o fato de ter que definir as propriedades da sua classe como public (pelo menos dá para trabalhar com classes), linhas de includes e configurações exageradas (não presentes no exemplo abaixo), e algumas automações que precisam ser bem explicadas senão o programador (usuário) fica doido. Além de ter que codificar muito mais linhas se compararmos com os demais exemplos. ```html {title} Input Box: {someMethod()} ``` ```php class controller_test { var $title; var $numbers = array(); var $elements = array(); function controller_test() { $this->start(); $this->output(); } function start() { $this->title = "Hello World"; // create an HTML Element for the form element. $this->elements['input'] = new HTML_Template_Flexy_Element; $this->elements['input']->setValue('Hello'); for ($i = 1;$i< 5;$i++) { $this->numbers[$i] = "Number $i"; } } function output() { $output = new HTML_Template_Flexy(); $output->compile("home.html"); $output->outputObject($this,$this->elements); } function someMethod() { return "Hello From A Method"; } } new controller_test(); ``` _Todos os exemplos a cima foram retirados dos próprios sites dos projetos, sofrendo alterações afim de minimizar as linhas e focar em suas caracterísicas, vantagens e desvantagens._ Em meados do ano passado comecei escrever uma engine baseada no [JSF](https://javaserverfaces.dev.java.net/)+[Facelets](https://facelets.dev.java.net/) (Java) e nesse mês voltei a trabalhar nela e espero que no próximo ano (2011) já tenha uma versão liberada (farei um post sobre).
</body> </html>
1
2
3
4
5
6
$h2o = new h2o('index.html');
$page = array(
  'title' => 'title of a page',
  'body' => 'Hello world'
);
echo $h2o->render(compact('page'));

PEAR Flexy

Entre os projetos disponíveis no PEAR (PHPLIB, Sigma e IT) esse é o melhor.

Tem como desvantagem o fato de ter que definir as propriedades da sua classe como public (pelo menos dá para trabalhar com classes), linhas de includes e configurações exageradas (não presentes no exemplo abaixo), e algumas automações que precisam ser bem explicadas senão o programador (usuário) fica doido. Além de ter que codificar muito mais linhas se compararmos com os demais exemplos.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<html>
    <head>
        <title>{title}</title>
    </head>
    <body>
        <!-- o valor do input será adicionado em $element['input'] -->
        Input Box: <input name="input" />
        <ul>
            <!-- isso é o mesmo que foreach ($numbers as $number => $string) -->
            <li flexy:foreach="numbers,number,string" >
                <a href="mypage.html?id={number}">{string}</a>
            </li>
        </ul>
        <!-- chamando o método da classe -->
        {someMethod()}
    </body>
</html>
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
class controller_test  {

    var $title;
    var $numbers = array();
    var $elements = array();

    function controller_test() {
        $this->start();
        $this->output();
    }

    function start() {
        $this->title = "Hello World";
        // create an HTML Element for the form element.
        $this->elements['input'] = new HTML_Template_Flexy_Element;
        $this->elements['input']->setValue('Hello');

        for ($i = 1;$i< 5;$i++) {
            $this->numbers[$i] = "Number $i";
        }
    }

    function output() {
        $output = new HTML_Template_Flexy();
        $output->compile("home.html");
        $output->outputObject($this,$this->elements);
    }

    function someMethod() {
        return "Hello From A Method";
    }

}
new controller_test();

Todos os exemplos a cima foram retirados dos próprios sites dos projetos, sofrendo alterações afim de minimizar as linhas e focar em suas caracterísicas, vantagens e desvantagens.

Em meados do ano passado comecei escrever uma engine baseada no JSF+Facelets (Java) e nesse mês voltei a trabalhar nela e espero que no próximo ano (2011) já tenha uma versão liberada (farei um post sobre).

CSS: Footer Always in Bottom

É muito comum vermos pessoas procurando saber como deixar um elemento HTML sempre no final da página, mas caso a página seja redimensionada criando rolagem, esse elemento continue no final dela. Ou seja, não apenas colocar o elemento com position fixed.

Para tal exemplo vamos precisar de um HTML simples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<html>
    <head>
    </head>
    <body>
        <div id="page">
            <div id="content">
                <h1>Footer always in bottom</h1>
                <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla aliquet imperdiet justo, quis congue velit egestas quis. Suspendisse ac tellus vitae est ultrices imperdiet eget at dolor. Donec sit amet viverra arcu. Aenean pulvinar vehicula justo, tincidunt congue nisi pharetra eu. Suspendisse potenti. Sed libero quam, lacinia at facilisis eu, egestas sodales dolor. Duis gravida, diam interdum cursus dictum, ligula libero pellentesque lacus, vitae viverra nulla metus id erat. Suspendisse fermentum aliquam hendrerit. Sed vulputate massa ut felis sagittis molestie. Suspendisse facilisis condimentum diam, a hendrerit urna venenatis sit amet. Cras orci diam, aliquam quis fringilla ac, euismod vel orci. Quisque ac pharetra nisi. Quisque et orci ligula. Praesent lacus felis, bibendum ac varius ac, eleifend in nulla. Aliquam sodales porttitor iaculis. Aliquam pretium risus ac neque egestas convallis. Sed dignissim massa ut odio vestibulum gravida ut vel nulla.</p>
                <p>Sed non lacus in nibh lobortis imperdiet. Aliquam auctor tellus quis elit adipiscing consequat. Ut in elit at orci dapibus gravida interdum eget sapien. Sed lobortis, massa nec aliquet aliquet, nulla mi tincidunt quam, id iaculis turpis nibh interdum leo. Curabitur in lorem et risus ultrices pharetra. Mauris adipiscing eros vitae diam sodales et rutrum velit consequat. Fusce adipiscing congue ultrices. Nullam fermentum ullamcorper urna a malesuada. Sed sit amet congue tortor. Nulla accumsan blandit diam sed feugiat. Morbi lobortis fermentum metus, ac pulvinar dui commodo ut.</p>
            </div>
            <div id="footer">
                <p>footer here</p>
            </div>
        </div>
    </body>
</html>

E o CSS abaixo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
* {
padding: 0px;
margin: 0px;
}

html, body {
height: 100%;
}

#page {
min-height: 100%;
position: relative;
}

#footer {
width: 100%;
bottom: 0;
position: absolute;
}

O exemplo funcionando você confere aqui.

Javascript Game Engine for HTML5 Canvas

Comecei escrever um pequeno projeto para facilitar a criação de jogos em Javascript utilizando HTML5 Canvas para isso. Baseado em scenegraph podendo criar nós dependentes, relativos ao nó pai. Por enquanto a estrutura da engine é composta por:

Canvas: para encapsular a tag canvas, pegando automaticamente o context e fornecendo algumas funções a mais.

Game: o jogo em sí, possui uma ou muitas cenas (Scene). Contém o loop principal para atualizações do canvas. Necessita de uma instância do Canvas.

Scene: deve ser estendida para criar cenas customizadas, deve implementar o método update(interval).

CanvasNode: um nó do grafo, possui as coordenadas e ângulo de rotação do elemento no canvas.

CanvasNodeGroup: um grupo de nós. Estende CanvasNode.

Graphics: um nó “printável”, quem for estendê-lo deve implementar o método draw(). Possui como subclasses: Rectangle, Triangle, Circle, Text, Image2d e Line.

GraphicsGroup: estende CanvasNodeGroup, possui um grupo de graphics. Scene é um GraphicsGroup.

Os próximos passos serão a implementação de TileMap, Scene Intro, Menu e botões. Agora é só aguardar até o próximo exemplo.

[update 2010-05-06] Added mouse and button support. See example above. [/update]

[update 2010-05-06] Examples in http://mangame.rogeriolino.com/ [/update]

[update 2011-11-11] Source now available in GitHub! [/update]

PHP: Socket Class

[UPDATE 16-05-2012]

Criei um projeto no Github e também adicionei suporte ao Websocket. Clique aqui para ver o post novo

[/UPDATE]

Muitas linguagens oferecem suporte a Sockets, e com PHP não é diferente, porém a falta de orientação a objetos nas funções do PHP pode ser um inconveniente para algumas pessoas. E como eu me incluo entre essas pessoas, quando precisei utilizar sockets em PHP acabei criando um classe para englobar essas funções soltas e fornecer tratamento a erros.

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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
/**
 * Copyright 2010 http://rogeriolino.com
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Socket
 *
 * @author rogeriolino
 */
class Socket {

    private $port     = 3000;
    private $address  = "localhost";
    private $blocking = true;

    private $buffer   = 2048;
    private $backlog  = 5;

    private $type     = SOCK_STREAM;
    private $family   = AF_INET;
    private $protocol = SOL_TCP;

    private $resource;

    /**
     * Socket constructor
     * @param  $resource
     */
    public function  __construct($resource = null) {
        if ($resource == null) {
            $this->resource = socket_create($this->family, $this->type, $this->protocol);
        } else {
            $this->resource = $resource;
        }
    }

    /**
     * Returns the socket port
     * @return int
     */
    public function getPort() {
        return $this->port;
    }

    /**
     * Define the socket port
     * @param int $port
     */
    public function setPort($port) {
        $this->port = $port;
    }

    /**
     *
     * @return string
     */
    public function getAddress() {
        return $this->address;
    }

    public function setAddress($address) {
        $this->address = $address;
    }

    /**
     * Returns if the socket is blocking mode
     * @return boolean
     */
    public function isBlocking() {
        return $this->blocking;
    }

    /**
     * Defines whether the socket is blocking or nonblocking mode
     * @param boolean $block
     */
    public function setBlocking($blocking) {
        $this->blocking = ($blocking == true);
        $this->updateBlockingMode();
    }

    /**
     * Returns the socket communication type
     * @return int
     */
    public function getType() {
        return $this->type;
    }

    /**
     * Define the socket communication type
     * @param int $type
     */
    public function setType($type) {
        if ($type == SOCK_STREAM || $type == SOCK_DGRAM || $type == SOCK_SEQPACKET || $type == SOCK_RAW || $type == SOCK_RDM) {
            $this->type = $type;
        } else {
            throw new SocketException("Invalid socket communication type");
        }
    }

    /**
     * Returns the socket protocol family
     * @return int
     */
    public function getFamily() {
        return $this->family;
    }

    /**
     * Define the socket protocol family
     * @param int $family
     */
    public function setFamily($family) {
        if ($family == AF_INET || $family == AF_INET6 || $family == AF_UNIX) {
            $this->family = $family;
        } else {
            throw new SocketException("Invalid socket protocol family");
        }
    }

    /**
     * Returns the socket protocol
     * @return int
     */
    public function getProtocol() {
        return $this->protocol;
    }

    /**
     * Define the socket protocol, must be compatible whit the protocol family
     * @param int $protocol
     */
    public function setProtocol($protocol) {
        if ($protocol == SOL_TCP || $protocol == SOL_UDP || $protocol == SOL_SOCKET) {
            $this->protocol = $protocol;
        } else {
            throw new SocketException("Invalid socket protocol");
        }
    }

    /**
     * Binds to a socket
     * @throws SocketException
     */
    public function bind() {
        if (socket_bind($this->resource, $this->address, $this->port) === false) {
            throw new SocketException("Socket bind failed: " . $this->error());
        }
    }

    /**
     * Listens for a connection on a socket
     * @throws SocketException
     */
    public function listen() {
        if (socket_listen($this->resource, $this->backlog) === false) {
            throw new SocketException("Socket listen failed: " . $this->error());
        }
    }

    /**
     * Accepts a connection
     * @throws SocketException
     * @return Socket
     */
    public function accept() {
        $sock = socket_accept($this->resource);
        if ($sock === false) {
            throw new SocketException("Socket accept failed: " . $this->error());
        }
        return new Socket($sock);
    }

    /**
     * Reads data from the connected socket
     * @return string
     */
    public function read() {
        $data = "";
        while (($m = socket_read($this->resource, $this->buffer)) != "") {
            $data .= $m;
        }
        return $data;
    }

    /**
     * Write the data to connected socket
     * @param string $message
     */
    public function write($data) {
        socket_write($this->resource, $data, strlen($data));
    }

    /**
     * Initiates a connection on a socket
     * @throws SocketException
     * @return boolean
     */
    public function connect() {
        try {
            return socket_connect($this->resource, $this->address, $this->port);
        } catch (SocketException $e) {
            return false;
        }
    }

    /**
     * Close the socket connection
     */
    public function close() {
        socket_close($this->resource);
    }

    private function updateBlockingMode() {
        if ($this->blocking) {
            socket_set_block($this->resource);
        } else {
            socket_set_nonblock($this->resource);
        }
    }

    private function error() {
        return socket_strerror(socket_last_error($this->resource));
    }

}

Classe para as exceções:

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
/**
 * Copyright 2010 http://rogeriolino.com
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * SocketException
 *
 * @author rogeriolino
 */
class SocketException extends Exception {

    public function  __construct($message, $code = 0, $previous = null) {
        $this->message = $message;
        $this->code = $code;
        $this->message = $previous;
    }

}

Espero que seja de bom aproveito.

Twitter: Resumo #2

Twitter

Flash: SWFAddress + ReWrite = SEO

SWFAddress é uma pequena mas poderosa biblioteca que provê deep linking para Flash e Ajax. É uma ferramenta de desenvolvimento, permitindo a criação de URLs unicas e virtuais que podem apontar para uma seção do site ou aplicação. SWFAddress habilita algumas de importantes capacidades que faltam hoje em dia nas tecnologias RIA, incluindo:

  • Adicionar ao Favoritos de um navegador ou site social

  • Enviar links via email ou mensageiros instantâneos

  • Procurar por um conteúdo específico através dos sites de buscas

  • Utilizar o histórico do navegador e o botão de recarregar

O Flash está para o SEO assim como o Coringa está para o Batman. Mas nem tudo está perdido quando se trata de otimizar a indexação do site em SWF nos mecanismos de busca. Com SWFAddress você pode interagir com a página via javascript alterando a URL e o próprio conteúdo do filme, possibilidade do o uso dos botões voltar e avançar do browser, adicionar ao Favoritos e alterar a animação do seu filme de acordo com a URL que está sendo requisitada.

Caso sua página seja acessada através da URL **http://siteemflash.com/#contato**, você poderá pular na timeline indo direto para o frame do contato. Para evitar o reload da página toda interação é feita através de âncoras html (#). E as alterações da URL utilizando âncoras são desprezadas pelos buscadores, uma vez que a âncora só serve para movimentar o foco na mesma página, logo o seu conteúdo permanece inalterado.

É aí que entra o módulo ReWrite do Apache, com o mod_rewrite podemos escrever condições para tratar as requisições, redirecionando-as ou não. Então voltando ao exemplo anterior, teríamos uma condição que quando for requisitada a página **http://siteemflash.com/contato** (ou qualquer outra URL) redireciona para a página inicial (index) adicionando a âncora para contato (#contato) e imprime na página o conteúdo referente à mesma. Esse conteúdo impresso não será visível, apenas para indexação. O sitemap ou a estrutura básica do site, também deve estar contido no bloco de código html invisível, juntamente com todas outras informações relevantes.

Resumindo, você acaba tendo um trabalho dobrado ao desenvolver o site, mas evita transtornos de indexação. É muito útil para quem não abre mão do site feito com o uso da ferramenta da Adobe.

No próprio site da Asual tem um exemplo de uso do SWFAddress para SEO (o exemplo pode ser baixado pelo site). Abaixo segue alguns sites que fizeram uso da biblioteca, no qual o primeiro eu participei do desenvolvimento:

PHP: Annotations

É indiscutível a agilidade e facilidade de configuração que as annotations provêm no Java, e com o objetivo de trazer tal comodidade ao PHP surgiu o projeto Addendum - escrito por Jan Suchal - que permite via Reflection) acessar as annotations das classes.

As annotations devem ser escritas em blocos de comentários, uma vez que o @ (caracter que inicia uma annotation) é um caractere reservado no PHP. Elas podem ser mono ou multi valoradas de acordo com os exemplos abaixo.

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
// Custom annotation
class Persistent extends Annotation {}

// Custom annotation
class Table extends Annotation {}

// Multi valued annotation
class Secured extends Annotation {
   public $role;
   public $level;
}

/** 
 * @Persistent 
 * @Table("people")
 * @Secured(role = "admin", level = 2)
 */
class Person {
   // some code
}

// getting the annotation by class name
$reflection = new ReflectionAnnotatedClass('Person');

// getting the annotation by instance
$person = new Person();
$reflection = new ReflectionAnnotatedClass($person);

// true
$reflection->hasAnnotation('Persistent');

// contains string "people"
$reflection->getAnnotation('Table')->value;

E seguindo na mesma onda da JPA, a versão 2.0 do projeto Doctrine implementou também a mesma funcionalidade e agora possui suas próprias annotations facilitando a configuração das classes de persistência e seus relacionamentos.

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
/**
 * @DoctrineEntity(tableName="cms_articles")
 */
class CmsArticle {

  /**
  * @DoctrineId
  * @DoctrineColumn(type="integer")
  * @DoctrineIdGenerator("auto")
  */
  public $id;

  /**
  * @DoctrineColumn(type="varchar", length=255)
  */
  public $topic;

  /**
  * @DoctrineColumn(type="varchar")
  */
  public $text;

  /**
  * @DoctrineManyToOne(targetEntity="CmsUser", joinColumns={"user_id" = "id"})
  */
  public $user;

  /**
  * @DoctrineOneToMany(targetEntity="CmsComment", mappedBy="article")
  */
  public $comments;
}

SGA Livre

ATENÇÃO: Se você está pensando em utilizar um sistema para gerenciar a fila de atendimento da sua organização, conheça o Novo SGA.

**SGA LIVRE** significa Sistema de Gerenciamento do Atendimento, versão Livre. É desenvolvido pela DATAPREV, totalmente baseado em tecnologias de software livre e de código aberto.

Através do SGA é possível gerenciar filas e fluxo de atendimento em quaisquer tipos de empresas ou organizações que prestam serviço de atendimento presencial à pessoas.

O SGA oferece o controle de filas de atendimento através de emissão de senhas e chamada das mesmas através de painéis. As filas de atendimento podem conter um único serviço ou um grupo de serviços. Os painéis podem chamar um, vários ou todos os serviços. Uma unidade de atendimento pode ter vários painéis.

O SGA é mais do que um sistema de controle de filas. Ao gerenciar o fluxo de atendimento, o sistema apresenta uma série de recursos que auxiliam na gerência e administração das unidades de atendimento.

Fornece uma diversidade de informações gerenciais preciosas, através de relatórios, estatísticas e gráficos avançados sobre atendimentos de uma unidade, de um grupo de unidades ou de todas elas. É possível obter estatísticas e tempos médios de atendimento por atendente, por período e por unidade, entre outras. Pode-se obter dados detalhados ou agregados.

As informações gerenciais fornecidas pelo SGA possibilitam aos gestores planejar, acompanhar, monitorar, otimizar e agilizar o atendimento aos clientes.

fonte: [http://www.softwarepublico.gov.br/ver-comunidade?community_id=15719494](http://www.softwarepublico.gov.br/ver-comunidade?community_id=15719494)

Não é novidade o lançamento da versão livre do SGA, porém é com muito orgulho que hoje vejo este software ganhando força no cenário nacional, e também por ter participado do seu desenvolvimento. O software foi desenvolvido em PHP fornecendo uma camada para abstração do RDMS, utilizando como interface de acesso o PDO (suporte padrão ao PostgreSQL). Tal contribuição foi desde definir a estrutura do sistema, passando por diagramação, HTML, CSS, até a programação PHP e Javascript.

Tela de instalação do SGA

Dividido em módulos é fácil customizar a ferramenta para atender as necessidades específicas de qualquer centro de atendimento. Para facilitar o uso de requisições assíncronas no sistema foi utilizada o código Ajax) da lib escrita por mim e já comentada nesse blog (libjsx, Ajax.js).

Tela de atendimento do SGA

Quem quiser utilizar ou contribuir com o projeto basta se cadastrar no site http://www.softwarepublico.gov.br/ e acessar a página da comunidade.

HTML5: Database

Uma das funcionalidades mais robustas presentes nessa nova versão do HTML é exatamente o suporte ao armazenamento local, sem ser por Cookie mas sim pelo banco de dados presente no browser. Tal funcionalidade já está presente no Webkit que fornece uma aplicação de exemplo: http://webkit.org/demos/sticky-notes/.

No Webkit as informações são armazenadas utilizando SQLite, e acredito que o Firefox irá pelo mesmo caminho, já que ele também utiliza o SQLite para armazenar os “Favoritos”.

Para abrir a conexão com a banco de dados (openDatabase) deve-se informar o nome do banco (database name), a versão (database version), o nome de exibição (display name) e o tamanho estimado em bytes (estimated size) que será armazenado.

var db;
try {
    if (window.openDatabase) {
        db = openDatabase("MyDB", "1.0", "HTML5 Database Example", 200000);
        if (!db) {
            alert("Failed to open the database.");
        }
    } else {
        alert("Couldn't open the database.");
    }
} catch(err) { }

Uma vez estabelecida a conexão a interação passa ser efetuada através de comandos SQL.

db.transaction(function(tx) {
tx.executeSql("CREATE TABLE myTable (id REAL UNIQUE, name TEXT, description TEXT, timestamp REAL");
});

db.transaction(function (tx) {
tx.executeSql("INSERT INTO myTable (id, name, description, timestamp) VALUES (?, ?, ?, ?)", [id, name, description, timestamp]);
});

db.transaction(function(tx) {
tx.executeSql("DELETE FROM myTable WHERE id = ?", [id]);
});

db.transaction(function(tx) {
    tx.executeSql(
        "SELECT * FROM myTable WHERE id = ?", 
         [id], 
         function(tx, result) {
             // success
             if (result.rows.length > 0) {
                   alert("My name is: " + result.rows.item(0)['name']);
             } else {
                  alert("Sorry, no result for this id");
              }
         }, 
         function(tx, error) {
             // error
             alert("Error when try retrieve data: " + error.message);
         }
    );
});

O método executeSql pode receber 4 parâmetros, sendo eles:

  • O SQL a ser executado

  • Os valores parametrizados para serem utilizados na consulta (array)

  • Função callback para ser executada caso haja sucesso (onSuccess)

  • Função callback para ser executada caso haja falha (onError)

Sinceramente eu achei muito legal conceder mais esse poder ao Javascript no HTML5, porém “com grandes poderes vêm grandes responsabilidades”.