Rogério Lino

Web development and tips

PHP: JsonSerializable

Desde a versão 5.4 do PHP ficou mais fácil transformar entidades em JSON através da função json_encode(). Basta implementar a interface JsonSerializable, no qual o único método que precisa ser implementado pela subclasse é o jsonSerialize.

Session Keep Alive

Uma maneira fácil de manter a sessão ativa no lado do servidor sem sobrecarregá-lo com longos tempos de timeout, é usar um script que redireciona o usuário para a tela de login após um determinado período de inatividade (teclado e mouse ociosos), e fazer requisições assíncronas ao servidor para manter a sessão ativa durante a atividade.

Simple Javascript Support Detection

Partindo do princípio que o seu navegador não suporta javascript e depois contrariando via o próprio javascript, é possível fazer uma simples verificação se o navegador do usuário está com javascript habilitado ou não.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html class="no-js" lang="pt-BR">
<head>
    <title>JS detection</title>
    <script>document.documentElement.className = document.documentElement.className.replace("no-js","js");</script>

    <style>
        .js .alert-danger { display: none; }
        .no-js .alert-success { display: none; }
    </style>
</head>
<body>

    <div class="alert alert-danger">O seu navegador não possui suporte à <b>Javascript</b></div>

    <div class="alert alert-success">O suporte à <b>Javascript</b> está ativado</div>

</body>
</html>

Visualizar demo online.

PHP: Slim Framework Action Based

Há algum tempo utilizo o Slim Framework como base de meus projetos. E o motivo é sua simplicidade, velocidade e facilidade.

E para criar CRUD, eu utilizo um trecho de código para trabalhar rotas semelhante aos frameworks action based. Seguindo a convenção /controlador/método.

Exemplo:

Para a URI /clients/add terei uma classe controladora ClientsController com um método público (a ação) add. E o script tentará renderizar a página add.php dentro do diretório clients. E para a URI /clients/view/1 será necessário ter o método view que recebe um parâmetro (nesse caso “1”).

Abaixo segue o trecho semelhante ao que está disponível no meu repositório no Github (porém nesse repositório utilizo o Twig como template engine): rogeriolino/slimapp-skeleton.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$app->any('/:controller(/)(:action(/)(:params+))', function($controller, $action = 'index', $params = array()) use ($app) {
    // transforma o parâmetro :controller no nome da classe controladora (com namespace)
    $class = "MeuNamespace\\" . ucfirst($controller) . "Controller";
    try {
        if (!class_exists($class)) {
            throw new \Exception('Controlador não encontrado');
        }
        $ctrl = new $class($app);
        $methodName = preg_replace('/[^A-z0-9]/', '_', $action);
        $ref = new \ReflectionMethod($class, $methodName);
        if (!$ref->isPublic()) {
            throw new \Exception('O método do controlador não é público.');
        }
        $view = $methodName;
        $rs = $ref->invokeArgs($ctrl, $params);
        if ($rs) {
            $view = $rs;
        }
        $app->render("{$controller}/{$view}.php");
    } catch (\Exception $e) {
        $app->notFound();
    }
});

Para utilizar o slimapp-skeleton basta clonar o repositório e depois fazer a instalação das dependências via Composer.

Angular.js: Inplace Editing

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="container" ng-app="todo">
    <div ng-controller="todoCtrl">
        <form ng-submit="add()">
            <input type="text" class="form-control" placeholder="New task..." ng-model="newTodo">
            <button class="btn btn-primary">Add</button>
        </form>
        <ul>
            <li ng-repeat="todo in todos">
                <span ng-click="editing = true" ng-hide="editing"></span>
                <span ng-show="editing">
                    <input type="text" class="form-control" ng-model="todo.text" ng-blur="editing = false" ng-required>
                    <a data-ng-click="editing = false" class="glyphicon glyphicon-ok"></a>
                </span>
            </li>
        </ul>
    </div>
</div>

Javascript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var app = angular.module('todo', []);

app.controller('todoCtrl', function($scope) {

    $scope.todos = [
        {text: "First task"}
    ];

    $scope.add = function() {
        if ($scope.newTodo && $scope.newTodo != '') {
            $scope.todos.push({
                text: $scope.newTodo
            });
            $scope.newTodo = '';
        }
    }

});

JSFiddle demo

PHP: 5.5 New Features

A versão 5.5 do PHP foi lançada no mês passado, e trouxe algumas funcionalidades relevantes. Entre elas, seguem abaixo as mais interessantes (pelo menos para mim):

Generators

Com o Generators você pode iterar com um dado dentro de uma função sem a necessidade de criar um array para ser retornado.

1
2
3
4
5
6
7
8
9
10
function numerosInteiros($minimo, $maximo) {
    for ($i = $minimo; $i <= $maximo; $i++) {
        // a keyword yield "libera" a variável $i para a iteração (sem sair/retornar da/a função)
        yield $i;
    }
}

for (numerosInteiros(1, 10) as $numero) {
    echo "$numero ";
}

Ou um exemplo do próprio site php.net

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
function xrange($start, $limit, $step = 1) {
    if ($start < $limit) {
        if ($step <= 0) {
            throw new LogicException('Step must be +ve');
        }

        for ($i = $start; $i <= $limit; $i += $step) {
            yield $i;
        }
    } else {
        if ($step >= 0) {
            throw new LogicException('Step must be -ve');
        }

        for ($i = $start; $i >= $limit; $i += $step) {
            yield $i;
        }
    }
}

/*
 * Note that both range() and xrange() result in the same
 * output below.
 */

echo 'Single digit odd numbers from range():  ';
foreach (range(1, 9, 2) as $number) {
    echo "$number ";
}

Repare que não há necessidade de criar um array, populá-lo, retorná-lo, e só depois iterá-lo para imprimir os valores.

Finally

Mesmo já possuindo a bastante tempo o bloco try/catch, só agora a partir da versão 5.5 foi introduzida a keyword finally. No qual você define um bloco para ser executado de qualquer maneira (mesmo que caia no catch).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function divide($a, $b) {
    if ($b === 0) {
        throw new Exception('Divisão por zero');
    }
    return $a / $b;
}

try {
    echo '10 / 2 = ' . divide(10, 2);
    echo '2 / 0 = ' . divide(2, 0);
} catch (Exception $e) {
    echo $e->getMessage();
} finally {
    echo 'Término das operações';
}

::class

Agora é possível resolver o nome da classe apenas através de MinhaClass::class.

1
2
3
4
5
6
7
<?php
namespace NS {
    class ClassName {
    }
    echo ClassName::class;
}
?>

empty()

Agora é possível passar expressões para a função empty() e não mais apenas variáveis.

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
function always_false() {
    return false;
}

if (empty(always_false())) {
    echo "This will be printed.\n";
}

if (empty(true)) {
    echo "This will not be printed.\n";
}
?>

Veja mais

Para saber mais sobre a nova versão acesse os links abaixo:

http://www.php.net/releases/5_5_0.php http://br2.php.net/manual/en/migration55.php

E o php.net também lançou sua versão nova (ainda em beta). Clique aqui para abrir a versão beta.

UTF-8 Icons

Com a adoção dos navegadores mais modernos, muitos projetos estão adotando os ícones UTF-8 em botões. Assim diminui a dependência de imagens tornando o carregamento mais rápido. Exemplo: http://dev.rogeriolino.com/exemplos/css/utf8_icons/index.html

Prós

  • Não há necessidade de imagens como dependência;

  • Pode usar a cor que desejar;

  • São escaláveis, muito fáceis de alterar o tamanho;

  • Pode usar transformações CSS (transparência, sombra, rotação, etc);

  • Reuso de ícones através de seletores CSS;

Contras

  • Os ícones das fonts padrões não são tão legais;

  • Embora não haja dependência de imagem, pode ter de font (web font);

  • Dependendo da font escolhida, um iconset pode ser mais leve;

Veja mais sobre ícones UTF-8