TypeScript: uma solução mais simples e organizada de escrever e compilar Javascript

Se você é desenvolvedor, assim como eu, você provavelmente já teve que utilizar JavaScript em suas aplicações, sendo elas em dot.net, php, java ou qualquer outra linguagem server-side que dependa desta interação maravilhosa no ambiente web.

Obviamente, deve ter sofrido um pouco para escrever códigos utilizando esta linguagem client-side. Para poupar esforços, acredito que também chegou a tomar conhecimento ou mesmo familiaridade com a biblioteca jQuery – e gostou dos efeitos que ela oferece – Afinal, são muitas as facilidades e a simplicidade como ela resolve as coisas para você. Mal precisamos nos aprofundar dentro de sua estrutura complexa de código escrito nativamente para entender como funciona, e chegar no nosso objetivo de interação com o usuário final. Alguns desenvolvedores fazem oposição ao seu uso, já que o JavaScript nativo atende bem e sem muita complicação os mesmos recursos com uma velocidade e desempenho até melhor, daria para discutir isso o dia inteiro, mas não vim aqui para criar contrariedades…

Acredito também que em algum momento você já teve que esbarrar em algo um pouco mais complexo (porém de raciocínio simplicista) como o AngularJS, e deve ter sofrido um pouco também até se adaptar a esta arquitetura brilhante que este Framework maravilhoso oferece. Daí deve ter aprendido um monte de lance legal que facilitou muito a sua vida, ou não. Gostou do Framework?! Não? É isso aí mesmo, tem gente que detesta, e tem gente que ama. Mas de certo modo, quem odiava o AngurarJS, pode talvez gostar do Angular 2. Alguns que adoram o AngularJS, vão detestar essa nova versão.

Mas espera um pouquinho… talvez não detestar a arquitetura do Angular 2 em si (ou talvez sim?), mas tem uma coisa que acredito que a maioria irá detestar é a dificuldade de migração entre as duas versões. Pois é justamente esse o dilema, e a queixa da maioria dois desenvolvedores de AngularJS. A ideia é ter a mente aberta…, afinal o cérebro não vai cair por aí. Abandonar o AngularJS e mudar completamente para Angular 2, tem benefícios, a começar por sofrer menos com códigos nativos do JavaScript.

Daí você vai me perguntar: Como assim parar e sofrer menos com JavaScript se eu adoro??? De fato, se você ama javascript, fique tranquilo… não é exatamente parar de escrever JavasScript, mas deixar de sofrer com a linguagem rebuscada. Isso mesmo… melhorou agora?

Para quem não entendeu bulhufas de JavaScript até agora, sinta-se agraciado e feliz de começar do zero aprendendo esta nova linguagem: TypeScript, que está sendo utilizada no Angular 2. Você não vai mais precisar trabalhar e sofrer tanto com JavaScript.
Necessariamente, você precisa aprender TypeScript para trabalhar com Angular 2, mas não precisa saber Angular 2 para trabalhar com TypeScript.

Legal, mas afinal para que serve o TypScript? Bom, ele serve para uma infinidade de coisas, uma delas é para compilar JavaScript. O que o TypeScript faz basicamente é compilar um código maduro, orientado e organizado para o código de máquina, complicado e rebuscado chamado JavaScript, através de uma estrutura muito mais amigável ao desenvolvedor que está acostumado com a linguagem server-side e orientação a objetos.

E afinal, o que é o TypeScript?
É uma linguagem para desenvolvimento JavaScript em larga escala. Com TypeScript podemos escrever código utilizando uma estrutura fortemente tipada e ter este código compilado para JavaScript puro, que rode em qualquer navegador e em qualquer host.

Veja abaixo um exemplo de código escrito em TypeScript:

Arquivo: galeria.ts

[code]
module Galeria {

export interface Album {
id:number;
imagem:string;
titulo:string;
descricao?:string;
}

export class MyAlbum implements Album {

id:number;
imagem:string;
titulo:string;
descricao:string;

constructor(
id:number,
imagem:string,
titulo:string,
descricao?:string
){
this.id = id;
this.imagem = imagem;
this.titulo = titulo;
this.descricao = (descricao) ? descricao : null;

}

public getAlbum() {
let data = {
id: this.id,
titulo: this.titulo,
imagem: this.imagem,
descricao: this.descricao
};
return data;
}

}
}

var galeria = new Galeria.MyAlbum(10, "album01.jpg", "Meu Album", "Este album é somente um teste");
var obj = galeria.getAlbum();

window.onload = () => {
document.body.innerHTML = `<p>
ID: ${obj.id}<br>
Álbum: ${obj.titulo}<br>
Descrição: ${obj.descricao}<br>
<img src="imagens/${obj.imagem}" border="0">
</p>`;
}
[/code]

Agora a saída do arquivo galeria.js compilado:

[code]
var Galeria;
(function (Galeria) {
var MyAlbum = (function () {
function MyAlbum(id, imagem, titulo, descricao) {
this.id = id;
this.imagem = imagem;
this.titulo = titulo;
this.descricao = (descricao) ? descricao : null;
}
MyAlbum.prototype.getAlbum = function () {
var data = {
id: this.id,
titulo: this.titulo,
imagem: this.imagem,
descricao: this.descricao
};
return data;
};
return MyAlbum;
}());
Galeria.MyAlbum = MyAlbum;
})(Galeria || (Galeria = {}));
var galeria = new Galeria.MyAlbum(10, "album01.jpg", "Meu Album", "Este album é somente um teste");
var obj = galeria.getAlbum();
window.load() = function () {
document.body.innerHTML = "<p>\n ID: " + obj.id + "<br>\n \u00C1lbum: " + obj.titulo + "<br>\n Descri\u00E7\u00E3o: " + obj.descricao + "<br>\n <img src=\"imagens/" + obj.imagem + "\" border=\"0\">\n </p>";
};[/code]

E um arquivo de mapeamento, galeria.js.map:

[code]
{"version":3,"file":"main.js","sourceRoot":"","sources":["main.ts"],"names":[],"mappings":"AAAA,IAAO,OAAO,CAwCb;AAxCD,WAAO,OAAO,EAAC,CAAC;IASZ;QAOI,iBACI,EAAS,EACT,MAAa,EACb,MAAa,EACb,SAAiB;YAEjB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;YACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;YACrB,IAAI,CAAC,SAAS,GAAG,CAAC,SAAS,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC;QAEpD,CAAC;QAEM,0BAAQ,GAAf;YACI,IAAI,IAAI,GAAG;gBACP,EAAE,EAAE,IAAI,CAAC,EAAE;gBACX,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,SAAS,EAAE,IAAI,CAAC,SAAS;aAC5B,CAAC;YACF,MAAM,CAAC,IAAI,CAAC;QAChB,CAAC;QAEL,cAAC;IAAD,CAAC,AA9BD,IA8BC;IA9BY,eAAO,UA8BnB,CAAA;AACL,CAAC,EAxCM,OAAO,KAAP,OAAO,QAwCb;AAED,IAAI,OAAO,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,aAAa,EAAE,WAAW,EAAE,+BAA+B,CAAC,CAAC;AACnG,IAAI,GAAG,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;AAC7B,MAAM,CAAC,IAAI,EAAE,GAAG;IACZ,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG,4CACM,GAAG,CAAC,EAAE,wDACH,GAAG,CAAC,MAAM,iEACN,GAAG,CAAC,SAAS,+DACN,GAAG,CAAC,MAAM,yDACzB,CAAC;AACpC,CAAC,CAAA"}
[/code]

No exemplo que eu coloquei acima, o arquivo ts, é um exemplo simples de utilização modular, que contém um interface, ou seja, uma maneira de criar um contrato da arquitetura e desenvolvimento.

Mas você poderia fazer algum muito mais simples como por exemplo:

[code]
class Usuario {
private nome:string;
private email:string;

public setNome(nome:string):void {
this.nome = nome;
}

public setEmail(email:string):void {
this.email = email;
}

public getEmail():string {
return this.email
}

public getNome():string {
return this.nome;
}
}

var usuario = new Usuario();
usuario.setNome("Luiz Fernando");
usuario.setEmail("luizf@servidor.com");
console.log(usuario.getNome, usuario.getEmail);
[/code]

Para saber mais acesse o site: https://www.typescriptlang.org

Módulo de Contagem Regressiva (Cronômetro) para AngularJS

Código do módulo de contagem regressiva:

[code]
angular.module("iCountdown",[]).directive("iCountdown",function(){return{restrict:"EAC",scope:{setDate:"@",expireMessage:"@",formatView:"@"},replace:!0,template:"<div><div></div></div>",link:function(e,t){e.insertDate=function(){e.setMessageExpired(e.expireMessage),e.setDateFinal(e.setDate),e.start()},e.$watch("setDate",function(){e.insertDate()},!0);var n=new Date,a=1e3,i=60*a,r=60*i,o=24*r,s={second:a,minute:i,hour:r,day:o,interval:null,messageFinal:"expired!",format:"Y-m-d H:i:s",dateEnd:null};e.setMessageExpired=function(e){s.messageFinal=e},e.setId=function(t){s.id=t,e.viewElement.setAttribute("id",t)},e.setDateFinal=function(e){s.dateEnd=e};var d=function(e){var t=/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/,n=t.exec(e);return new Date(+n[1],+n[2]-1,+n[3],+n[4],+n[5],+n[6])};e.remaining=function(){var a=new Date;n=d(s.dateEnd);var i=n-a;if(0>i)return clearInterval(s.interval),void(t[0].innerHTML=s.messageFinal);var r=Math.floor(i/s.day),o=Math.floor(i%s.day/s.hour),l=Math.floor(i%s.hour/s.minute),u=Math.floor(i%s.minute/s.second),c=[];c[0]=(10>r?"0":"")+r,c[1]=(10>o?"0":"")+o,c[2]=(10>l?"0":"")+l,c[3]=(10>u?"0":"")+u,t[0].innerHTML=e.setFormatViewTime(c)},e.setFormatViewTime=function(t){return e.formatView.replace(/%d/gi,t[0]).replace(/%h/gi,t[1]).replace(/%i/gi,t[2]).replace(/%s/gi,t[3])},e.setFormatDate=function(e){s.format=e},e.start=function(){return n instanceof Date&&!isNaN(n.valueOf())?void(s.interval=setInterval(this.remaining,s.second)):(console.log("A data final não foi definida, adicione uma data conforme o exemplo: yyyy-mm-dd hh:mm:ss!"),!1)}}}});
[/code]

Basta definir uma data futura no “set-date”, que ele irá contar a partir do relógio do servidor até chegar ao final, em “format-view”, %d será a entrada dos dias que faltam, %h são as horas, %i os minutos, e %s os segundos, e “expire-message”, e a mensagem final quando expirar o tempo do cronômetro.

Esta é tag da diretiva para inserir uma instância na sua HTML do seu cronômetro:

[code]<i-countdown set-date="2015-08-21 10:10:10" format-view="%d dias %h hrs %i min %s seg" expire-message="Acabou o tempo"></i-countdown>[/code]

Classe simples de conexão em PDO utilizando Orientação a Objeto

Para conectar no banco, crie este arquivo:

ConexaoDatabase.php

[code lang=”php”]

<?php

class ConexaoDatabase {

private static $servidor = ‘localhost’; // Servidor, no caso poderia ser também localhost
private static $usuario = ‘root’; // usuário do banco de dados
private static $senha = ”; // senha do banco de dados
private static $banco = ‘noticias’; // nome do banco de dados
private static $instance = null;
public static function getConnection() {
if (!self::$instance instanceof PDO) {
try {
self::$instance = new PDO(‘mysql:host=’ . self::$servidor . ‘;dbname=’ . self::$banco, self::$usuario, self::$senha, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
} catch (PDOException $exc) {
echo "Erro ao conectar :: {$exc->getMessage()}";
}
}
return self::$instance;
}
public function fetchAll($query) {
$con = self::getConnection();

$stmt = $con->prepare($query);

$this->execute($stmt);

if ($stmt->rowCount()) {
return $stmt->fetchAll(PDO::FETCH_OBJ);
} else {
return false;
}
}

public function fetch($query) {
$con = self::getConnection();

$stmt = $con->prepare($query);

$this->execute($stmt);

if ($stmt->rowCount()) {
return $stmt->fetch(PDO::FETCH_OBJ);
} else {
return false;
}
}

public function execute(PDOStatement $stmt, array $data = null) {
try {
if (isset($data)) {
$stmt->execute($data);
} else {
$stmt->execute();
}
} catch (PDOException $exc) {
echo $exc->getTraceAsString();
var_dump($exc->getMessage());
}
}
/** UPDATE OR INSERT DATA

**/
public function save($sql, array $data) {

$con = self::getConnection();

$stmt = $con->prepare($sql);

$this->execute($stmt, $data);

if($stmt->rowCount()) {
return true;
}else{
return false;
}
}

}

?>

[/code]

Agora vamos criar uma tabela simples de notícias, para isso execute a seguinte query no seu mysql:

[code]
/** cria o banco **/
CREATE DATABASE noticias;
/** cria a tabela **/
CREATE TABLE `tab_noticias` (
`id_noticia` int(11) NOT NULL AUTO_INCREMENT,
`permissao` tinyint(2) NOT NULL,
`titulo` varchar(300) DEFAULT NULL,
`texto` longtext,
`data_publicacao` datetime DEFAULT NULL,
PRIMARY KEY (`id_noticia`))
ENGINE=InnoDB DEFAULT CHARSET=utf8;

/** inserindo dados na tabela **/

INSERT INTO `tab_noticias` VALUES(null,1,’Notícia exemplo 1′,'<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sapien nisl, elementum rutrum ex sit amet, facilisis luctus felis. Proin lobortis odio non facilisis blandit. Vivamus mollis facilisis quam sed eleifend. Sed quis nunc elit. Ut accumsan sit amet lorem nec gravida. Sed non cursus dui. Sed feugiat ultricies luctus. Quisque vitae mi cursus, convallis orci quis, aliquam purus. Nullam non massa id ex pretium dapibus non vitae erat. Sed aliquam ex dignissim, aliquet leo quis, tincidunt libero. In ac euismod massa. Nam quis sem eget libero interdum ultricies at a lacus.</p><p>Proin est tortor, feugiat at magna ac, tempus faucibus nunc. Aliquam quis orci a metus ultricies fringilla id vitae nunc. Curabitur nunc urna, suscipit et odio a, rhoncus rutrum nibh. Vestibulum ipsum erat, tempus nec semper non, feugiat eget sem. Ut vestibulum libero ipsum, a accumsan leo tristique et. Vestibulum nulla nisi, tincidunt vitae nisl sed, vulputate molestie urna. Pellentesque facilisis risus at pharetra elementum. Nullam elementum erat nulla, id commodo nisi euismod sed. Aenean quis ipsum vestibulum, vestibulum lectus eu, sagittis sapien. Vestibulum vel semper enim, nec malesuada lectus. Fusce feugiat nisl ac lacus convallis commodo. Donec sit amet turpis turpis. Ut rhoncus elit leo, in pharetra est molestie non. Donec semper, felis vitae luctus pretium, lectus erat venenatis elit, eget condimentum est mauris eu quam. Vivamus sit amet odio ut dui vulputate euismod in vel sapien.</p><p>Sed mattis lacus lacus, sed egestas ex condimentum eu. Aliquam id mollis magna. Duis accumsan ligula in enim semper suscipit. Vestibulum at mauris eu orci ultrices porttitor id quis nunc. Etiam id nisl porta, suscipit diam sed, rutrum augue. Nunc consectetur augue quis arcu euismod volutpat. Nulla convallis mi dui, in sollicitudin augue tincidunt id. Nulla erat justo, congue sit amet lectus eget, blandit elementum mauris. Nullam euismod non metus non consequat. Aenean non purus mollis, molestie felis id, ullamcorper arcu. Donec mattis diam sit amet tincidunt aliquet.</p>’,now());

INSERT INTO `tab_noticias` VALUES(null,1,’Notícia exemplo 2′,'<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sapien nisl, elementum rutrum ex sit amet, facilisis luctus felis. Proin lobortis odio non facilisis blandit. Vivamus mollis facilisis quam sed eleifend. Sed quis nunc elit. Ut accumsan sit amet lorem nec gravida. Sed non cursus dui. Sed feugiat ultricies luctus. Quisque vitae mi cursus, convallis orci quis, aliquam purus. Nullam non massa id ex pretium dapibus non vitae erat. Sed aliquam ex dignissim, aliquet leo quis, tincidunt libero. In ac euismod massa. Nam quis sem eget libero interdum ultricies at a lacus.</p><p>Proin est tortor, feugiat at magna ac, tempus faucibus nunc. Aliquam quis orci a metus ultricies fringilla id vitae nunc. Curabitur nunc urna, suscipit et odio a, rhoncus rutrum nibh. Vestibulum ipsum erat, tempus nec semper non, feugiat eget sem. Ut vestibulum libero ipsum, a accumsan leo tristique et. Vestibulum nulla nisi, tincidunt vitae nisl sed, vulputate molestie urna. Pellentesque facilisis risus at pharetra elementum. Nullam elementum erat nulla, id commodo nisi euismod sed. Aenean quis ipsum vestibulum, vestibulum lectus eu, sagittis sapien. Vestibulum vel semper enim, nec malesuada lectus. Fusce feugiat nisl ac lacus convallis commodo. Donec sit amet turpis turpis. Ut rhoncus elit leo, in pharetra est molestie non. Donec semper, felis vitae luctus pretium, lectus erat venenatis elit, eget condimentum est mauris eu quam. Vivamus sit amet odio ut dui vulputate euismod in vel sapien.</p><p>Sed mattis lacus lacus, sed egestas ex condimentum eu. Aliquam id mollis magna. Duis accumsan ligula in enim semper suscipit. Vestibulum at mauris eu orci ultrices porttitor id quis nunc. Etiam id nisl porta, suscipit diam sed, rutrum augue. Nunc consectetur augue quis arcu euismod volutpat. Nulla convallis mi dui, in sollicitudin augue tincidunt id. Nulla erat justo, congue sit amet lectus eget, blandit elementum mauris. Nullam euismod non metus non consequat. Aenean non purus mollis, molestie felis id, ullamcorper arcu. Donec mattis diam sit amet tincidunt aliquet.</p>’,now());
INSERT INTO `tab_noticias` VALUES(null,1,’Notícia exemplo 3′,'<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sapien nisl, elementum rutrum ex sit amet, facilisis luctus felis. Proin lobortis odio non facilisis blandit. Vivamus mollis facilisis quam sed eleifend. Sed quis nunc elit. Ut accumsan sit amet lorem nec gravida. Sed non cursus dui. Sed feugiat ultricies luctus. Quisque vitae mi cursus, convallis orci quis, aliquam purus. Nullam non massa id ex pretium dapibus non vitae erat. Sed aliquam ex dignissim, aliquet leo quis, tincidunt libero. In ac euismod massa. Nam quis sem eget libero interdum ultricies at a lacus.</p><p>Proin est tortor, feugiat at magna ac, tempus faucibus nunc. Aliquam quis orci a metus ultricies fringilla id vitae nunc. Curabitur nunc urna, suscipit et odio a, rhoncus rutrum nibh. Vestibulum ipsum erat, tempus nec semper non, feugiat eget sem. Ut vestibulum libero ipsum, a accumsan leo tristique et. Vestibulum nulla nisi, tincidunt vitae nisl sed, vulputate molestie urna. Pellentesque facilisis risus at pharetra elementum. Nullam elementum erat nulla, id commodo nisi euismod sed. Aenean quis ipsum vestibulum, vestibulum lectus eu, sagittis sapien. Vestibulum vel semper enim, nec malesuada lectus. Fusce feugiat nisl ac lacus convallis commodo. Donec sit amet turpis turpis. Ut rhoncus elit leo, in pharetra est molestie non. Donec semper, felis vitae luctus pretium, lectus erat venenatis elit, eget condimentum est mauris eu quam. Vivamus sit amet odio ut dui vulputate euismod in vel sapien.</p><p>Sed mattis lacus lacus, sed egestas ex condimentum eu. Aliquam id mollis magna. Duis accumsan ligula in enim semper suscipit. Vestibulum at mauris eu orci ultrices porttitor id quis nunc. Etiam id nisl porta, suscipit diam sed, rutrum augue. Nunc consectetur augue quis arcu euismod volutpat. Nulla convallis mi dui, in sollicitudin augue tincidunt id. Nulla erat justo, congue sit amet lectus eget, blandit elementum mauris. Nullam euismod non metus non consequat. Aenean non purus mollis, molestie felis id, ullamcorper arcu. Donec mattis diam sit amet tincidunt aliquet.</p>’,now());
[/code]

Após criar a tabela e inserir os dados, vamos fazer a consulta, para isso iremos criar outro arquivo chamado:

noticias.php

[code lang=”php”]
<?php
require_once(‘ConexaoDatabase.php’);

class Noticias {

private $conexao;

public function listarNoticias() {
$sql = "SELECT id_noticia, titulo, texto, DATE_FORMAT(data_publicacao,’%d/%m/%Y’) as  data_publicacao FROM tab_noticias WHERE permissao=1 ORDER BY data_publicacao DESC, id_noticia DESC";
$this->conexao = new ConexaoDatabase();
$noticias = $this->conexao->fetchAll($sql);
return  $noticias;

}

public function abrirNoticia($id = 0) {
$sql = "SELECT id_noticia, titulo, texto, DATE_FORMAT(data_publicacao,’%d/%m/%Y’) as  data_publicacao FROM tab_noticias WHERE permissao=1 AND id_noticia=$id ORDER BY data_publicacao DESC, id_noticia DESC";
$this->conexao = new ConexaoDatabase();
$noticia = $this->conexao->fetch($sql);
return  $noticia;

}
}

$objNoticias = new Noticias();

$collectionNoticias = $objNoticias->listarNoticias();

if (!isset($_GET[‘id’])) {
if( !empty($collectionNoticias )) {
foreach($collectionNoticias  as $noticia) {
echo "<a href=\"?id=".$noticia->id_noticia."\">".$noticia->titulo."</a><br>";
}
}
} else {

$id = $_GET[‘id’];
$aNoticia = $objNoticias->abrirNoticia($id);

echo "<h1>".$aNoticia->titulo."</h1>";
echo "<small>".$aNoticia->data_publicacao."</small>";
echo "<div class=\"texto\">".$aNoticia->texto."</div>";
echo "<div class=\"back\" style=\"display:block;\">".
"<a href=\"javascript:void(0);\" onclick=\"history.back(1);\"><< VOLTAR</a></div>";

}
?>
[/code]

Vamos Falar sobre Zend Framework

Quando comecei a programar, isso já há uns 10 anos. Utilizava a linguagem do PHP 4.0, nessa época mal se falava em Frameworks, apesar de já terem o Zend desde 2005 e algumas comunidades a respeito, não era muito divulgado, então acabei chegando tarde a seu conhecimento, também não corri muito atrás na época, pois eu estava inventando a roda ainda… Com o tempo descobrimos o que é reaproveitamento de código, e aí ficamos “cada vez mais preguiços”, quero dizer, criamos mais códigos e trabalhamos até mais para no final trabalharmos menos, ou para melhorar o suporte de nossos sistemas, não que isso seja uma regra absoluta, mas tem diversas vantagens… Pois bem, burocratizamos tudo, se é que me entendem.

O Zend Framework se tornou uma ferramenta que permite criar um sistema com um longo período de prospecção mas que tem um resultado final muito satisfatório, além da facilidade tremenda de manutenção e modularidade, há uma eficiência de reutilização de códigos, fora de série. Fora as diversas outras possibilidades infinitas e inimagináveis que sua mente precisará descobrir afundando-se em seu estudo mais complexo e profundo entre cafés e energéticos durante a madrugada…

O que posso dizer é que o Zend Framework 2 (ZF2) possibilita fazer sistemas complexos seguros e eficientes, para empresas a longo prazo (a questão de prazo se deve considerar também quanto se tem progredido com o produto final do seu sistema), enquanto o Zend Framework 1.12, permite criar sites simples em pouco tempo, com prospecção independente de reaproveitamento.

Ambos tem suas vantagens e desvantagens.

Mas se vc começar a trabalhar com o ZF2, não vai mais querer voltar para o 1.12. “Perde se tempo no começo e ganha se tempo no futuro”.

O mais trabalhoso do ZF2 eu diria que é configurar as rotas, a integração do composer com o doctrine, e saber fazer o mapeamento do banco, o resto, é igual a qualquer outro framework. Mas a vantagem dele é que ele segue um padrão de projeto vale a pena ver aqui: www.php-fig.org

Para começar a instalar o ZendFramwork 2, vc irá precisa do ZendSkeleton, que é nada mais e nada menos que o esqueleto padrão do projeto: http://framework.zend.com/manual/2.0/en/user-guide/skeleton-application.html
e do composer: https://getcomposer.org/

Além disso o Zend Framework 2 conta com uma biblioteca cheia de recursos para você trabalhar, como paginação, indexação e pesquisa como Zend Lucene, etc. Você também pode adquirir complementos para expandir essa biblioteca instalando-os através do composer.

No próprio site do composer tem o caminho, mas eu vou facilitar, colocando ele aqui: https://packagist.org/, esse endereço vc consegue busca ferramentas para ampliar a Library do Zend.

Se você não tem ideia de como começar a instalar o Zend, vc pode assistir a essa vídeo aula grátis:
https://www.youtube.com/channel/UCsMR_iixPPlYl6QysW3kkyQ

Além disso, ele funciona basicamente assim:

Começa assim:
/config (nesta pasta fica as configurações padrões do doctrine, banco, e ativação dos modulos) que continua dentro da pasta /autoload que contém o autoload das classes, que se orientam pela declaração de “namespace” (requer no mínimo php 5.3 ou superior, recomendo 5.5, ZF1.12 utilizava o underline “_” para criar essa orientação de pastas, já com o namespace, essa prática se tornou obsoleta) para o mapeamento das classes, métodos etc.

Exemplo de configuração do banco:


/data/ são arquivos para download, armazenamento, etc.
/module/ (pasta onde ficam os módulos, os mini sistemas que irão em conjunto fazer a sua ferramenta ter o pacote de soluções modulares), dentro desta pasta vem a subpasta do modulo (no caso Album que seria um Application), e o arquivo de configuração do módulo: /module/Album/config/module.config.php ( é basicamente onde vc coloca as rotas do sistema e o mapeamento das views )
/module/Album/src/ (nesta pasta encontram-se a camada MVC do modulo)
/module/Album/src/Album/Controller/ (como o próprio nome diz, o controle, que faz basicamente o comando de chamar os modelos, que por sua vez estarão /module/Album/src/Album/Model/, que eu não acrescentei na imagem acima, mas eles estarão aí.
O arquivo Module.php é onde você mapeará o serviços que irão ser executados junto com sua aplicação.

Os serviços, estarão em uma pasta assim:
/module/Album/src/Model/Services/Service/Album.php

É nele que vc cria suas chamadas do banco e processos que deverão obter um comportamento através do repositório do seu modelo, que no caso poderia ser  uma consulta através da entidade do banco que foi mapeada, relacionando e obtendo heranças de métodos de outras entidades relacionais.

E neste caso seu modelo de entidade, ficará em uma outra pasta chamada:
/module/Album/src/Model/Entities/Entity/Album.php

E como disse, também tem essa outra camada chamada repositório que seria basicamente assim, que é o modelo propriamente dito:
/module/Album/src/Model/Repositories/Repository/Album.php

Esta camada é responsável por criar a mágica, a regra do negócio por assim dizer, neste arquivo vc faz a chamada dos serviços, faz a coleção e depois envia para a view.
a view ficará na pasta:
/module/Album/src/view/album/album-view.phtml
Lembrando que ela será mapeada no (/module/Album/config/module.config.php), como já havia dito.
Você também pode criar nesta pasta uma pasta chamada  /module/Album/src/view/album/partials/menu.phtml
e criar arquivos que funcionam como includes.

E também pode criar um layout padrão para que tenha sempre o mesmo cabeçalho e mesmo rodapé em todas as suas views desse módulo:
/module/Album/src/view/album/layout/layout.phtml

Para concluir a chamada do site começa numa pasta pública através do arquivo index.php, que é justamente onde vc disponibilizará tudo que for público, como imagens, css, javascripts, jquery, angularjs, etc…

/public/index.php
/public/css/style.css
/public/js/script.js
/public/lib/…
/public/core/…
/public/img/fig.jpg

etc…

E por fim tem a pasta /vendor/ que é onde estará o framework propriamente dito, nesta pasta você nem precisará mexer, a menos que saiba o que está fazendo.

Acredito que essas informações básicas já podem te dar um pontapé inicial para você começar a entender melhor e poder trabalhar com esse Framework poderoso.
E para tirar suas dúvidas, tem toda uma documentação acessível através desse site:

http://framework.zend.com/manual/2.0/en/index.html

Espero ter ajudado!

Como construir um sistema de busca a partir de páginas indexadas com o Zend_Search_Lucene

Estou começando a me acostumar a trabalhar com um Zend Framework v. 1.12 (ZF1), apesar dele já estar na versão 2, eu adotei essa versão por ter um colega de trabalho que já está mais habituado a trabalhar com ele, e está me ajudando a conhecê-lo melhor, além disso estou mais familiarizado a trabalhar com MVC  (Model View Controller), a ter que encarar, até então para mim, esta novidade do tal MVP  (Model View Presenter).

E nesta altura do campeonato, eis que me apareceu uma de suas facilidades, quanto a construção de um Search Engine. Como eu não pretendia utilizar banco de dados para fazer requisições de busca, eu resolvi utilizar algo que possa fazer uma busca básica em páginas estáticas. Daí me veio a questão de como eu poderia fazer isso, e pesquisando a fundo, descobri que existem alguns meios, você pode tanto usar SOLR ( http://lucene.apache.org/solr/ ) como o Zend_Search_Lucene, que já vem embutido na biblioteca do ZF1. Se quiser se aventurar na documentação, acesse por aqui: http://framework.zend.com/manual/1.12/en/zend.search.lucene.html.

Como eu já perdi horas quebrando a cabeça, nesta indexação resolvi publicar aqui minhas soluções, depois de ter  lido, relido, acessado vários fóruns, tirado várias dúvidas e ainda as tenho…, mas enfim, segue aqui até onde eu consegui avançar:

Primeiramente o Model de Indexação:

[code lang=”php”]
<?php
class Application_Model_IndexarPaginas {

private $public_dir_indice = null;
public $senhaToken;

/**
* @uses : O construtor apenas irá definir a senha que será tratada com um rash para que você possa indexar a página via URL de forma segura (se isso existe????).
*/
public function __construct() {
$this->public_dir_indice = preg_replace(‘/application/’, ”, realpath(APPLICATION_PATH)) . ‘public’ . DIRECTORY_SEPARATOR . ‘data’ . DIRECTORY_SEPARATOR . ‘indice’;
$this->public_dir_indice = is_dir($this->public_dir_indice) ? $this->public_dir_indice : false;

$this->senhaToken = ‘suasenha123’; //(Rash será em MD5) : bf8258ed5359f080693cd11365543ac3
//composite pattern
}
/**
* @return type array
* @uses : use este método para iniciar o sistema de indexação de páginas
*/
public function indexarTodas() {
// (esse processo é obrigatório, antes de qualquer outro processo deste mesmo modelo: IndexarPaginas)
return $this->indexarPaginas(‘insertall’);
}
/**
*
* @param type array $content
* @return type array
* @uses : use este método para incluir apenas uma página
* na sua lista pré-existente (execute o método acima antes de utilizar este a baixo)
* observe: $content se trata de uma lista array dos campos que serão gravados na indexação
*/
public function indexarUmaPagina(array $content) {
return $this->indexarPaginas(‘insert’, $content);
}

/**
*
* @param type string $string
* @return type string
* @uses : use para remover acentos
*/
private function removeAcentuacao($string) {
$acentos = array("À", "Á", "Â", "Ã", "Ä", "Å", "à", "á", "â", "ã", "ä", "å", "Ò", "Ó", "Ô", "Õ", "Ö", "Ø", "ò", "ó", "ô", "õ", "ö", "ø", "È", "É", "Ê", "Ë", "è", "é", "ê", "ë", "Ç", "ç", "Ì", "Í", "Î", "Ï", "ì", "í", "î", "ï", "Ù", "Ú", "Û", "Ü", "ù", "ú", "û", "ü", "ÿ", "Ñ", "ñ", "á", "à", "â", "ã", "é", "è", "ê", "í", "ì", "î", "ó", "ò", "ô", "õ", "ú", "ù", "ü", "û", "ç", "º", "ª", " ");
$sem_acentos = array("a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "o", "o", "o", "o", "o", "o", "o", "o", "o", "o", "o", "o", "e", "e", "e", "e", "e", "e", "e", "e", "c", "c", "i", "i", "i", "i", "i", "i", "i", "i", "u", "u", "u", "u", "u", "u", "u", "u", "y", "n", "n", "a", "a", "a", "a", "e", "e", "e", "i", "i", "i", "o", "o", "o", "o", "u", "u", "u", "u", "c", "o", "a", " ");
$string = str_replace($acentos, $sem_acentos, $string);
return strtolower($string);
}

/**
*
* @param type string $string
* @param type string $slug
* @return type string $string
* @uses : permite eliminar acentos, e separar espaços, traços, ou qualquer coisa para a variável $slug
*/
public function slugUrl($string, $slug = ‘ ‘) {
$string = $this->removeAcentuacao($string);
$string = strtolower($string);
if ($slug) {
$string = preg_replace(‘/[^a-z0-9]/i’, $slug, $string);
$string = preg_replace(‘/’ . $slug . ‘{2,}/i’, $slug, $string);
$string = trim($string, $slug);
}
return $string;
}

/**
* @param type string $param = sua senha
* @return boolean
* @uses : use este método para validar a senha no formulário
*/
public function checkToken($param) {
if (md5($param) == md5($this->senhaToken)) {
return true;
} else
return false;
}

/**
*
* @param type (string || int) $id
* @return array
* @uses : o Zend_lucene não é muito inteligente na questão de deletar ou atualizar registros,
* então, toda vez que vc for apagar ou atualizar um registro, você terá que reindexar tudo de novo…
* No caso abaixo, ele está deletando um registro a partir da ID do conteúdo que você tem indexado.
*/
public function deletarIndice($id) {
$parseQuery = "articleId:$id";
$query = Zend_Search_Lucene_Search_QueryParser::parse($parseQuery);
$index = Zend_Search_Lucene::open($this->public_dir_indice);
Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding(‘utf-8’);
Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8_CaseInsensitive());
$results = $index->find($query);

$msg = array();
$titulo = ”;
$url = ”;
$count = 0;
foreach ($results as $result) {

$doc = new Zend_Search_Lucene_Document();
$idDeleted = $result->articleId;
$index->delete($idDeleted);
$doc->addField(Zend_Search_Lucene_Field::text(‘url’, $result->url, ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::keyword(‘articleId’, $result->articleId, ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::text(‘postedDateTime’, $result->postedDateTime, ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::keyword(‘permission’, ‘0’));
$doc->addField(Zend_Search_Lucene_Field::text(‘title’, $result->title, ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::text(‘title_accent’, $result->title_accent, ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::text(‘contents’, $result->contents, ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::text(‘category’, $result->category, ‘utf-8’));
$count++;
$index->addDocument($doc);
}

$idDeleted = $result->articleId;
$titulo = $result->title;
$url = $result->url;
$index->commit();
if ($index->isDeleted($idDeleted)) {
$msg["msg"] = "Página excluída com sucesso!";
$msg["id"] = $idDeleted;
$msg["success"] = true;
}

return $msg;
}

/**
*
* @param array $articlesData
* @return array $msg
* @uses : este método é que fará a mágica da criação dos índices
*
*/
public function criarConteudoIndice(array $articlesData) {

$msg = array();
$count = 0;
if (is_array($articlesData) && count($articlesData)) {
$index = Zend_Search_Lucene::create($this->public_dir_indice);
Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding(‘utf-8’);
Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8_CaseInsensitive());

foreach ($articlesData as $articleData) {
$doc = new Zend_Search_Lucene_Document();
$doc->addField(Zend_Search_Lucene_Field::text(‘url’, $articleData["url"], ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::keyword(‘articleId’, $articleData["articleId"], ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::text(‘postedDateTime’, $articleData["postedDateTime"], ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::keyword(‘permission’, ‘1’));
$doc->addField(Zend_Search_Lucene_Field::text(‘title’, $articleData["title"], ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::text(‘title_accent’, $articleData["title_accent"], ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::text(‘contents’, $articleData["contents"], ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::text(‘category’, $articleData["category"], ‘utf-8’));

$msg[$count]["saida"] = "Página adicionada: " . $articleData["articleId"] . " – " . $articleData["title"] . " – URL: " . $articleData["url"];
$count++;
$index->addDocument($doc);
}

$index->commit();
$index->optimize();
return $msg;
}
}

public function atualizarConteudoIndice($params, $acao = ‘update’) {
$data = $this->searchContent($params[‘id’], "articleId", null);

$data_pub = ($params[‘data’] != ”) ? $params[‘data’] : date(‘Y-m-d H:i:s’);
$articlesData = $data[‘data’];
//$total = $data[‘total’];

$articleDataNovo = array(
‘url’ => $params[‘url’],
‘articleId’ => $params[‘articleId’],
‘postedDateTime’ => $data_pub,
‘title’ => $params[‘title’],
‘contents’ => $params[‘contents’],
‘category’ => $params[‘category’]
);

if (is_array($articlesData) && count($articlesData)) {

$index = Zend_Search_Lucene::open($this->public_dir_indice);
Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding(‘utf-8’);
Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8_CaseInsensitive());
$count = 0;
$msg = array();
foreach ($articlesData as $articleData) {

$doc = new Zend_Search_Lucene_Document();
if ($acao == ‘update’ && $articleData->articleId == $params[‘id’]) {
$index->delete($articleData->articleId);

$doc->addField(Zend_Search_Lucene_Field::text(‘url’, $articleDataNovo["url"], ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::keyword(‘articleId’, $articleDataNovo["articleId"], ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::text(‘postedDateTime’, $articleDataNovo["postedDateTime"], ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::keyword(‘permission’, ‘1’));
$doc->addField(Zend_Search_Lucene_Field::text(‘title’, $this->removeAcentuacao($articleDataNovo["title"]), ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::text(‘title_accent’, $articleDataNovo["title"], ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::text(‘contents’, $articleDataNovo["contents"], ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::text(‘category’, $articleDataNovo["category"], ‘utf-8’));
} else {
$doc->addField(Zend_Search_Lucene_Field::text(‘url’, $articleData->url, ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::keyword(‘articleId’, $articleData->articleId, ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::text(‘postedDateTime’, $articleData->postedDateTime, ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::keyword(‘permission’, $articleData->permission));
$doc->addField(Zend_Search_Lucene_Field::text(‘title’, $articleData->title, ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::text(‘title_accent’, $articleData->title_accent, ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::text(‘contents’, $articleData->contents, ‘utf-8’));
$doc->addField(Zend_Search_Lucene_Field::text(‘category’, $articleData->category, ‘utf-8’));
}

$action = ($acao == ‘update’) ? "Página atualizada: " : "Página adicionada: ";
$titulo = ($acao == ‘update’) ? $articleDataNovo["title"] : $articleData->title;
$url = ($acao == ‘update’) ? $articleDataNovo["url"] : $articleData->url;
$msg[$count][‘saida’] = $action . $params[‘id’] . " – " . $titulo . " – URL: " . $url . "
\n";
$index->addDocument($doc);
$count++;
}
$index->commit();
$index->optimize();
return $msg;
}
}

/**
*
* @param type string $acao = (insertall || insert || update )
* @param array $contentUpdate = será a lista que você deseja atualizar
* @return type
* @see : observe que há um modelo externo instanciado no método abaixo,
* este modelo é responsável por trazer a lista de todas as suas páginas
* isso será usado quando a ação for para indexar todas as sua páginas
* @uses : use este método para indexar as páginas
*/
public function indexarPaginas($acao = ‘insertall’, array $contentUpdate = null) {

$model = new Application_Model_Paginas();

$arrayArtigos = $model->getContent();
if ($acao == ‘insertall’ && count($arrayArtigos)) {
//aqui você cria tada a lista que será indexada
$getMsg = $this->criarConteudoIndice($arrayArtigos);
return $getMsg;
} else if (($acao == ‘insert’ || $acao == ‘update’) && count($contentUpdate)) {
//tanto no caso de inserir somente 1 registro novo como atualizar um existente,
//você deverá tratar tudo como um método de atualização, pois você terá
//que reindexar tudo somando esses itens novos e modificando os existentes
$getMsg = $this->atualizarConteudoIndice($contentUpdate, $acao);
return $getMsg;
}
}

/**
*
* @param type string $termo
* @param type string $campo
* @return type array
* @uses : este é o método que irá construir a busca a partir dos índices já criados no servidor
* observe que o termo = null, ele é definido por padrão, justamente porque a busca nula, trará tudo que estiver com a permissao = 1.
* Se vc quiser pode passar no parâmetro a letra "a" nos campos, aí ele irá desprezar a codição de permissão,
* quase não existe palavra sem a letra a… por isso, provavelmente você conseguirá trazer tudo.
*
*/
public function searchContent($termo = null, $campo = null) {

try {
$parse_search = ”;
if ($termo == ‘a’) {
$termo = "($termo)";
$parse_search = $termo;
} else if ($termo == null) {
$parse_search = "permission:1";
} else {
$parse_search = ($campo != null) ? " {$campo}:({$this->slugUrl($termo)}) AND permission:1" :
$parse_search = "(title_accent:({$termo})"
. " OR title:({$this->slugUrl($termo)})"
. " OR postedDateTime:({$this->slugUrl($termo)})"
. " OR articleId:({$this->slugUrl($termo)})"
. " OR url:({$this->slugUrl($termo)})) AND permission:1";
}

$query = Zend_Search_Lucene_Search_QueryParser::parse($parse_search);
$index = Zend_Search_Lucene::open($this->public_dir_indice);
$results = $index->find($query);

$data = array();
if ($index->count()) {
$count = 0;
foreach ($results as $result) {

if ($result->permission == ‘1’) {

$data[$count]["article_url"] = trim(strip_tags($result->url));
$data[$count]["article_title"] = $result->title;
$data[$count]["article_title_accent"] = $result->title_accent;
$data[$count]["article_description"] = trim(strip_tags($query->highlightMatches($result->contents)));
$data[$count]["article_date_time"] = $result->postedDateTime;
$data[$count]["article_data_brasil"] = $this->formatarData($result->postedDateTime, "ingles_to_brasil");
$data[$count]["article_id"] = $result->articleId;
$data[$count]["article_permission"] = $result->permission;
$data[$count]["article_category"] = $result->category;
$data[$count]["article_category_formated"] = $this->formatarCategoria($result->category);

$count++;
}
}
return array(
‘data’ => $data,
‘total’ => $count
);
}
} catch (Exception $exc) {
echo "Erro de tempo de execução!";
}
}

/**
*
* @param type string $termo
* @param type string $campo
* @return type try(array) || type string catch(erro)
* $uses : este é o método que realizará a busca no Lucene
*/
public function getBusca($termo, $campo = null) {

try {
$data = array();
$data = $this->searchContent($termo, $campo);
return array(
‘registros’ => $data[‘total’],
‘data’ => $data[‘data’],
‘palavra’ => $termo
);
} catch (Exception $e) {
echo "Erro: " . get_class($e) . "\n";
echo "Causa: " . $e->getMessage() . "\n";
}
}

}
[/code]

Para você poder capturar todas as classes do seu sistema em Zend, é preciso criar duas classes que estendam Zend_Controller_Response_Abstract e Zend_Controller_Request_Abstract  e implementá-las dentro do modelo que você irá buscá-las:

[code]

class Request extends Zend_Controller_Request_Abstract {

}

class Response extends Zend_Controller_Response_Abstract {

}

//depois você chamará elas no seu modelo de captura se elas forem requeridas:
require_once APPLICATION_PATH . "/controllers/Request.php";
require_once APPLICATION_PATH . "/controllers/Response.php";

[/code]

E agora o Model para capturar as páginas do seu site feito em Zend: (observe que é necessário criar duas classes, Request e Response vazias para poder utilizar este modelo adequadamente:

[code]
<?php
class Application_Model_Paginas {

/**
*
* @see : Observe que este será o endereço real para o C_URL capturar as páginas
* @var type string
*/
private $url_base = ‘http://www.seusite.com.br/’;
/**
*
* @param type string ($className = nome da classe)
* @return type string (métodos da Classe)
* @uses : use este método para capturar os métodos das classes (controllers) do seu sistema
*/
private function getClass($className) {
try {

$classes = array();
// $className = preg_replace(‘/(.*)\.php/’, ‘$1’, $directory[$key]);
$classes[$className][‘methods’] = get_class_methods($className);
} catch (Exception $exc) {
echo $exc->getMessage();
}
return $classes;
}

/**
*
* @param type string $method
* @return type string
* @uses : este método elimina os métodos que você não quer que os sistema indexe, pegando somente a lista de métodos com final Action
* do seu sistema
* dica: você pode colocar um parâmetro no começo dos métodos que você não deseja indexar como: noIndex
* exemplo: noIndexAbrirPaginaAction, noIndexListarRegistrosAction, etc…
*/
private function removerNoAction($method) {

$metodo = (preg_match(‘/(.*)Action$/’, $method) &&
!preg_match(‘/(gerarIndexadorAction|’
. ‘metodo1Action|’
. ‘metodo2Action|’
. ‘metodo3Action)$/’, $method) &&
!preg_match(‘/^noIndex(.*)$/’, $method)) ? $method : null;
return $metodo;
}
/**
*
* @param type $className = nome da classe
* @return type array
* @uses : este método filtra suas classes convertendo o nome como uma categoria,
* e constrói a URL do método para indexação
*/
public function getFilterClassMethods($className) {

$categoria = substr(strtolower(preg_replace(‘/([A-Z])/’, ‘-$1’, preg_replace(‘/^(.*)Controller$/’, ‘$1’, $className))), 1);
$lista = array();

$methods = $this->getClass($className);
// print_r($methods);

$keys = array_keys($methods);

//classes extendidas (Request, Response -> Abstract ) para poder instanciar os demais controllers do Zend
require_once APPLICATION_PATH . "/controllers/Request.php";
require_once APPLICATION_PATH . "/controllers/Response.php";

$classMethods = array();
$methodsArray = array();

foreach (array_keys($methods) as $class) {

//inclui a classe que fornecerá seus métodos
require_once APPLICATION_PATH . "/controllers/{$class}.php";

try {
// $c = new $class(new Request(), new Response());
$classMethods[$class][‘methods’] = get_class_methods($class);

foreach ($classMethods[$class][‘methods’] as $metodo) {
if ($this->removerNoAction($metodo) != null)
$methodsArray[] = array(
‘metodo’ => $metodo,
‘classe’ => $class,
‘classe_slug’ => $this->formatarCategoria($class),
‘categoria’ => preg_replace(‘/-/’, ‘ ‘, $this->formatarCategoria($class)),
‘url’ => $this->formataURL($this->formatarCategoria($class), $metodo)
);
}
} catch (Exception $exc) {
echo $exc->getTraceAsString();
}

return $methodsArray;
}
}
/**
*
* @param type string $text
* @return type string
* @uses : este método converte todo o texto em formato UTF-8
*/
private function converterUtf8($text) {
$text = iconv("windows-1252", "UTF-8//TRANSLIT", $text);
$text = iconv("ISO-8859-1", "UTF-8//TRANSLIT", $text);
return $text;
}

/**
*
* @param type string $url_metodo
* @return type string
* @uses : este método é o mais crucial para capturar sua HTML,
* muito cuidado ao utilizá-lo, pois ao indexar suas páginas ele entrará no laço
* e irá capturar a HTML inteira carregada e retornar ela numa variável
* certifique-se de que seu servidor esteja com permissão de curl habilitado
*/
public function capturarUrl($url_metodo) {

try {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url_metodo);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$saida = curl_exec($ch);
curl_close($ch);
} catch (Exception $e) {
$saida = file_get_contents($url_metodo);
}
return $saida;
}
/**
*
* @param type int $idInicial = inicia a indexação id com número 1
* @return type array
* @uses : use este método para capturar as páginas via C_URL, a partir dos métodos
* dos controller informados abaixo (precisam ser controles existentes no seu sistema
*
*/
public function listarPaginasController($idInicial = 1) {

$classes = array(
0 => ‘IndexController’,
1 => ‘ArtigosController’,
2 => ‘ContatoController’
);

$listarPaginas = array();
$id = $idInicial;

foreach ($classes as $classe) {
$metodos = $this->getFilterClassMethods($classe);

foreach ($metodos as $metodo) {
//aqui ele captura a URL e manda a HTML pra indexação lucene
$content = $this->capturarUrl($this->url_base . $metodo[‘url’]);

$listarPaginas[] = array(
"url" => $metodo[‘url’],
"title" => $this->formatarTitulo($content, true),
"title_accent" => $this->formatarTitulo($content),
"contents" => $this->removerHTMLContent($content),
"category" => $metodo[‘category’],
"postedDateTime" => date(‘Y-m-d H:i:s’),
"articleId" => $id
);
$id++;
}
}

return $listarPaginas;
}
/**
*
* @param type string $controller
* @param type string $metodo
* @return type string : url
* constrói a URL do seu sistema
*/
private function formataURL($controller, $metodo) {
return ‘/’ . $controller . ‘/’ . strtolower(preg_replace(‘/([A-Z])/’, ‘-$1’, preg_replace(‘/^(.*)Action$/’, ‘$1’, $metodo)));
}
/**
*
* @param type string $string
* @return type string
* @uses : remove acentos
*/
private function removeAcentuacao($string) {
$acentos = array("À", "Á", "Â", "Ã", "Ä", "Å", "à", "á", "â", "ã", "ä", "å", "Ò", "Ó", "Ô", "Õ", "Ö", "Ø", "ò", "ó", "ô", "õ", "ö", "ø", "È", "É", "Ê", "Ë", "è", "é", "ê", "ë", "Ç", "ç", "Ì", "Í", "Î", "Ï", "ì", "í", "î", "ï", "Ù", "Ú", "Û", "Ü", "ù", "ú", "û", "ü", "ÿ", "Ñ", "ñ", "á", "à", "â", "ã", "é", "è", "ê", "í", "ì", "î", "ó", "ò", "ô", "õ", "ú", "ù", "ü", "û", "ç", "º", "ª", " ");
$sem_acentos = array("a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "o", "o", "o", "o", "o", "o", "o", "o", "o", "o", "o", "o", "e", "e", "e", "e", "e", "e", "e", "e", "c", "c", "i", "i", "i", "i", "i", "i", "i", "i", "u", "u", "u", "u", "u", "u", "u", "u", "y", "n", "n", "a", "a", "a", "a", "e", "e", "e", "i", "i", "i", "o", "o", "o", "o", "u", "u", "u", "u", "c", "o", "a", " ");
$string = str_replace($acentos, $sem_acentos, $string);
return strtolower($string);
}
/**
*
* @param type string $html
* @return type string
* @uses : este método converterá sua HTML em texto corrido e removerá toda a acentuação
*/
private function removerHTMLContent($html) {
$content = preg_replace("/(\s|\n|\r)/", " ", trim(preg_replace("/\s+/", " ", strip_tags(preg_replace(‘/]*>(.*?)/is’, ”, $html)))));
return $this->removeAcentuacao($content);
}
/**
*
* @param type string $className
* @return type string
* @uses : este método transformará seu controle em um título de categoria
*/
private function formatarCategoria($className) {
$categoria = substr(strtolower(preg_replace(‘/([A-Z])/’, ‘-$1’, preg_replace(‘/^(.*)Controller$/’, ‘$1’, $className))), 1);
return $categoria;
}
/**
*
* @param type string $html
* @param type bool $sem_acento
* @return type string
* @uses : este método irá capturar o primeiro título que encontrar na sua HTML entre as tags <h1></h1>
* e retorná-lo como um texto único, e caso não encontre, ele irá salvar como Untitled.
* caso o parâmetro boleano $sem_acento seja true, ele irá remover acentos do seu título
*
*/
private function formatarTitulo($html, $sem_acento = false) {
$titulo = ”;
$tit = strip_tags(preg_replace(‘/<h1>(.*)<\/h1>/’, ‘/|#$1|#’, $html));
if ($tit != ” && preg_match(‘/|#/’, $tit)) {
$contTit = explode(‘|#’, $tit);
if (count($contTit) > 1) {
$titulo = $contTit[1];
}
} else
$titulo = ‘Untitled’;

$titulo = ($titulo != "") ? trim(strip_tags($titulo)) : ‘Untitled’;
return ($sem_acento) ? $this->slugUrl($titulo) : $titulo;
}
/**
*
* @return type array
* @uses : este método cria a listagem de páginas
*/
public function getContent() {
return $this->listarPaginasController(1);
}
/**
*
* @param type $pos
* @return (type array $articlesData || \Application_Model_Artigos)
* @uses : retorna a lista de páginas contruídas
*/
public function getPaginas($pos = null) {

$content = $this->getContent();
$itens = array();
$id = ($pos != null) ? $pos : 1;

if (!empty($content)) {
foreach ($content as $content) {
$itens[] = array(
"url" => $content[‘url’],
"title" => $content[‘title’],
"title_accent" => $content[‘title_accent’],
"contents" => $content[‘contents’],
"category" => $content[‘category’],
"postedDateTime" => $content[‘postedDateTime’],
"articleId" => $id
);
$id++;
}

$articlesData = array($itens);
asort($articlesData);
if ($pos != null) {
$artigo = (object) $articlesData[$pos];
return $artigo;
} else
return $articlesData;
} else
return $this;
}
/**
*
* @param type string $string
* @param type string $slug
* @return type string
* uses: remove acentos e trata os espaços
*/
public function slugUrl($string, $slug = ‘ ‘) {
$string = $this->removeAcentuacao($string);
// $string = iconv("UTF-8", "ASCII//TRANSLIT", $string);

$string = strtolower($string);
if ($slug) {
$string = preg_replace(‘/[^a-z0-9]/i’, $slug, $string);
$string = preg_replace(‘/’ . $slug . ‘{2,}/i’, $slug, $string);
$string = trim($string, $slug);
}
return $string;
}

}

[/code]

Implementando botão de Zoom (A+ / A- ) em texto com jQuery

[code]

<!doctype html>
<html lang="pt_BR">
<head>
<meta charset="UTF-8">
<title>Zoom em texto by Toca Digital</title>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
$(document).ready(function() {

var contador = 0;
//coloca os elementos que irão receber zoom no array
var obj_tratados = new Array(‘#texto’, ‘#texto h1’, ‘#texto h2’);
var reset_fonte = new Array();
var reset_linha = new Array();
var expandir_entrelinha = 10;

//captura os tamanhos padrões na tela para todos os elementos do array
setDefaultZoom(obj_tratados, reset_fonte, reset_linha);

$(‘#a_mais,#a_menos,#a_reset’).on(‘click’, function() {

var id = $(this).attr(‘id’);
var min = 9; //define o menor valor de zoom
var max = 28; //define o maior valor de zoom

for (var i in obj_tratados) {

var tratados = $(obj_tratados[i]);
var tamanho_fonte = strReplace(tratados.css(‘fontSize’), ‘px’, ”);
var tamanho_entrelinha = strReplace(tratados.css(‘lineHeight’), ‘px’, ”);

switch (id) {
case ‘a_mais’:
if (tamanho_fonte <= max) {
tamanho_fonte++;
tamanho_entrelinha++;
var val = (tamanho_entrelinha * expandir_entrelinha / 100) + tamanho_entrelinha;
tamanho_entrelinha = arredondarValor(val);
contador++;
}
break;
case ‘a_menos’:
if (tamanho_fonte >= min) {
tamanho_fonte–;
tamanho_entrelinha–;
var val = tamanho_entrelinha – (tamanho_entrelinha * expandir_entrelinha / 100);
tamanho_entrelinha = arredondarValor(val);
contador++;
}
break;
case ‘a_reset’: default:
tamanho_fonte = reset_fonte[i];
tamanho_entrelinha = reset_linha[i];
}
tratados.css({‘fontSize’: tamanho_fonte + ‘px’, ‘lineHeight’: tamanho_entrelinha + ‘px’});
}
return false;
});
function setDefaultZoom(obj_tratados, reset_fonte, reset_linha) {
for (var i in obj_tratados) {
var tratados = $(obj_tratados[i]);
if (contador == 0) {
reset_fonte[i] = strReplace(tratados.css(‘fontSize’), ‘px’, ”);
reset_linha[i] = strReplace(tratados.css(‘lineHeight’), ‘px’, ”);
}
}
}

});
function arredondarValor(valor) {
if (valor)
valor = Math.round(valor);
return valor;
}

function strReplace(valor, antigo, novo) {
if (valor)
valor = valor.replace(antigo, novo);
return valor;
}
</script>

</head>
<body>
<span id="controle_zoom">
<a href="javascript:void(0);" id="a_reset">A </a>&nbsp;|&nbsp;
<a href="javascript:void(0);" id="a_mais">A+</a>&nbsp;|&nbsp;
<a href="javascript:void(0);" id="a_menos">A-</a>
</span>
<div id="texto">
<h1>Seu título aqui</h1>
<h2>Seu subtítulo aqui</h2>
<p><strong>Lorem Ipsum</strong> é simplesmente uma simulação de texto da indústria tipográfica e de impressos, e vem sendo utilizado desde o século XVI, quando um impressor desconhecido pegou uma bandeja de tipos e os embaralhou para fazer um livro de modelos de tipos. Lorem Ipsum sobreviveu não só a cinco séculos, como também ao salto para a editoração eletrônica, permanecendo essencialmente inalterado. Se popularizou na década de 60, quando a Letraset lançou decalques contendo passagens de Lorem Ipsum, e mais recentemente quando passou a ser integrado a softwares de editoração eletrônica como Aldus PageMaker.</p>
</div>
</body>
</html>
[/code]

Classe para criptografar dados através de senha

[code lang=”php”]

<?php

class Criptografia{

private $senha;
private $valor;
private $chave_quebra;

public function __construct($valor = null,$senha = null,$chave_quebra = ‘ ‘){
$this->chave_quebra = $chave_quebra;
$this->valor = $valor;
$this->senha = $senha;
}
public function encriptar($valor,$chave_validacao, $quebrar_chave_em = ‘ ‘){

$string = strrev($valor);

$string = strtr($string, ") /abcdefghijklmnopqrstuvwxyz0123456789ÀÁÂÃÄÅàáâãäåÒÓÔÕÖØòóôõöøÈÉÊËèéêëÇçÌÍÎÏìíîïÙÚÛÜùúûüÿÑñ",
"_>ÀÁÂÃÄÅàáâãäåÒÓÔÕÖØ/òóôõöøÈÉÊËèéêëÇçÌÍÎÏìíîïÙÚÛÜùúûüÿÑñg3i1kzsurpnw4f6d8bh2j0lytqvoxm5e7c9");

$array = explode($quebrar_chave_em, $string);
$string = base64_encode(serialize($array));

return strrev (base64_encode ( base64_encode($quebrar_chave_em).’:’.$string.’:’.md5($chave_validacao) ));
}

public function desencriptar($valor_oculto,$chave_validacao){
$valor_oculto = base64_decode ( strrev($valor_oculto));
$valor = explode(‘:’,$valor_oculto);
if ($valor[2] == md5($chave_validacao)){

$string = implode(base64_decode($valor[0]),unserialize(base64_decode($valor[1])));

$string = strtr($string, ")>ÀÁÂÃÄÅàáâãäåÒÓÔÕÖØ/òóôõöøÈÉÊËèéêëÇçÌÍÎÏìíîïÙÚÛÜùúûüÿÑñg3i1kzsurpnw4f6d8bh2j0lytqvoxm5e7c9",
"_ /abcdefghijklmnopqrstuvwxyz0123456789ÀÁÂÃÄÅàáâãäåÒÓÔÕÖØòóôõöøÈÉÊËèéêëÇçÌÍÎÏìíîïÙÚÛÜùúûüÿÑñ");

return strrev($string);
}
else
return $valor_oculto.’ ( a senha é inválida )’;

}

public function getChave(){
return $this->encriptar($this->valor, $this->senha, $this->chave_quebra);
}
public function getDados(){
return $this->desencriptar( $this->getChave(), $this->senha);
}
}
//como utilizar a classe :::: (‘dado a ser criptografado’,’senha’, ‘caracter que será a quebra da chave’)

$encrypto = new Criptografia(‘Estou testando a criptografia deste dado’, ‘aqui a senha 1234’, ‘ ‘);
//imprime a chave
echo ‘chave: ‘.$encrypto->getChave();
//imprime os dados
echo ‘<br>dados: ‘.$encrypto->getDados();
?>

[/code]

Como funciona o MVC (Model-View-Controller)

Quando nos focamos nas regras de negócio, precisamos adequá-las a um modelo da aplicação. Isso significa que precisamos criar algumas regras dentro de uma estrutura ou plano de ação. Esta é basicamente, a ideia de um modelo.

Entendendo o papel do M – Model

Dentro de um Model podemos criar acessos ao banco de dados, validar ações, acessar documentos, efetuar cálculos, etc. Imagine, por exemplo, o caso de um usuário que deseja comprar um produto, e conforme ele adiciona os itens desejados ao carrinho de compras, o valor final é recalculado. Assim como quando ele finaliza o pedido, também há o cálculo total, onde entram os juros e os descontos, a partir da validação da conta deste usuário, e assim também é feito o calculado do frete, que por sua vez, valida o endereço, enfim… O Model é responsável por todos esses cálculos. Mas como o usuário seleciona um produto em um carrinho de compras por exemplo? Ou como ele insere o endereço para a entrega? Na View, é claro!

Entendendo o papel do V – View

A View só existe para um propósito: Mostrar dados! Na prática isso muitas vezes não acontece, mas deveria! Até porque existem outras linguagens que precisam de regras expostas, como é o caso do Javascript, embora estee também possa ter uma relação indireta com o Model. Mas pera lá, como assim indireta? É isso mesmo! Entendido o conceito básico do Model, e de como a View passa os valores digitados/selecionados para o Model. Mesmo sendo o Javascript, em parte, pertencente à View, é possível passar parâmetros, tanto via GET, como via POST, ou os dois métodos ao mesmo tempo, através da linguagem chamada jSON (para entendê-lo, acesse nosso artigo: http://www.tocadigital.com.br/2012/10/entenda-o-basico-de-json/) e isso só acontece com o aval de um cara chamado Controller, o controlador.

Entendendo o papel do C – Controller

Aqui temos um maestro! Temos regras de negócio no Controller? Não! Temos visualização no Controller? Não! O Controller simplesmente delega para o Model as solicitações da View. O Controller é burro no sentido de regras de negócio da aplicação. Ele é responsável por saber quem está pedindo algo e a quem enviará este algo, é ele quem toma as decisões! O Controller conhece a View que também conhece o Model, porém o Model não conhece a View, entretanto, a View observa o Model e este avisa quando seus dados foram atualizados, para a View mostrá-los.

Resumindo tudo:

Model
O Model simplesmente recebe a requisição, faz toda a mágica, persiste nos dados, valida informações e prepara os dados (atualiza) para que a View exiba para nós. O Model acaba não conhecendo ninguém, porém é ele que faz a maior parte do trabalho!

View
A View é a preguiçosa de plantão, fica só observando, esperando o retorno da atualização do Model, e quando este é retornado, a View mostra esta atualização para o usuário.

Controller
O Controller é o poderoso chefão, conhece a View e conhece o Model. Isto porque ele recebe as requisições do usuário da View e envia para o Model fazer algo com estas requisições.

Analogia dos Macacos MVC
– A View é muda, mas faz gestos (user gestures) para o Controller e escuta mudanças no Model;
– O Model é cego, mas escuta o Controller e fala para a View sobre as mudanças nele próprio;
– O Controller é surdo, fala para o Model quando mudar de estado e vê os gestos da View.

Em português modelo-visão-controlador, ou “CMS (cego-mudo-surdo… Metira!), brincadeirinha…”. Mas enfim, é um modelo de arquitetura de software que separa a representação da informação e sua estrutura lógica através da interação do usuário.

A melhor forma de se trabalhar (área de TI)

Uma coisa que permeia entre alguns colegas de trabalho da área de TI, é a forma correta de se trabalhar, ou pelo menos, como tornar o ambiente de trabalho saudável, menos cansativo, menos estressante, mais organizado, deixando tudo de maneira prática eficaz, ao alcance de todos. E ainda, qual seria a melhor técnica ou estratégia para agilizar processos e definir padrões em projetos, e como tornar algo tão sistêmico e progressivo, onde todos ganham com isso, trabalhando em equipe e alavancando a boa convivência entre todos os desenvolvedores.

Isso é uma utopia generalizada, não existe isso no nosso ramo, o “mundo perfeito”. A área de TI não foi feita para os fracos, e muito menos para quem quer ter seus problemas resolvidos por uma equipe consistente.

A realidade é bem ao contrário disso, por mais que nos esforcemos para dividir nosso conhecimento com os demais colegas de trabalho, sempre terá aquele que sabe mais do que você, ou aquele que sabe menos do que você. O fato é que todos que estão ali, estão no mesmo barco, e se ele afunda, você também afunda. Num ambiente de trabalho, ganha mais aquele que se propõe a dividir seu conhecimento. Por mais que falem ao contrário disso. Aquele que ensina, aprende junto. Você aprende mais quando “enxerga melhor”, o que quero dizer com isso é que você acaba aprendendo muito mais quando alguém analisa melhor e lhe apresenta uma solução mais inteligente que a sua. Aquela solução que você aprendeu errado ou fez por uma tal da gambiarra, ou simplesmente achou ser a melhor forma de resolver seu problema. E que acabou se tornando frequente no seu dia-a-dia.

E é justamente nisso que eu queria chegar, pois a forma correta de se trabalhar, é por esse caminho. Aprendendo, estudando, errando, experimentando coisas novas, ferramentas novas, mudando a forma que você acreditava ser a correta.

Os programadores em geral, sempre irão enfrentar problemas que se repetem, como pegar sistemas falhos, bancos mal relacionados, linguagem não orientada, frameworks problemáticos e mal desenhados, enfim… há uma infinidade de questões que podem tornar a vida de um programador um inferno.

Independente de tudo isso, todos, sem exceção, sempre vão ter que se dedicar e encontrar uma solução. Acabam destruindo noites, horas de trabalho, e até sua vida social para resolver problemas que as vezes tem soluções simples, justamente porque o sujeito não teve a capacidade de pedir ajuda para seus colegas, ou porque simplesmente se achou capaz de resolver sozinho e acabou fazendo a tal da gambiarra maldita, e terão também outros problemas maiores quase sem solução, mas enfim…

Tenho visto essa cena se repetir continuamente na nossa área, mas como tenho anos de experiência no ramo, eu aprendi a me virar, não sozinho, evidente, mesmo com tantos fóruns por aí, muitas vezes é insuficiente. Há questões que seus colegas já tiverem de enfrentar, que podem muitas vezes, serem parecidos com os seus. E o melhor a se fazer, nestas horas é dividir conhecimento. Não importa quanto você sabe, ou quem sabe mais ou menos do que você, mas quanto você se esforça para entender e compartilhar seus desafios na empresa e quanto você assumirá de responsabilidade pelo seu projeto. Esta é a forma correta de se trabalhar, na minha opinião.

Rebelde com causa

Quando eu era criança, parte da minha vida era baseada em um dos princípios ensinados pela minha avó, que era acreditar nas pessoas e ser bom para elas. Eu demorei a entender que nem tudo que eu fazia era bom para elas, mas demorei muito mais para entender que minha avó estava errada em uma coisa: Não devemos acreditar tanto assim nas pessoas; talvez fosse a minha ingenuidade de infância, ou o excesso de desejo de ser reconhecido pela minha dedicação em ser um bom menino, não sei ao certo, de fato, esta foi a válvula de escape que me fez sofrer em alguns momentos da minha infância. A falta de diálogo, a falta de oportunidade de expressar meus sentimentos, a falta da presença da minha mãe, a falta de sensibilidade do meu pai foram cruciais para causar uma enorme dificuldade de ser o menino bom que esperavam. Mas eu sempre me esforcei para ser o melhor que pudesse ser para as pessoas.

Já na minha pré-adolescência, procurei tentar ser algo diferente, o que me tornou um garoto bastante agressivo e cheio de si. Nessa fase da puberdade, nossos hormônios afloram, e tudo parece pior do que realmente é… Ainda acredito que minha revolta deve-se ao choque de realidade, foi o estopim da minha rebeldia. Bom, pelos menos tive uma causa justa para ter sido assim com as pessoas. Além de ter me tornado o alvo perfeito e cobiçado pelos adultos para despejar suas frustrações ou má-intenções. Ser um pirralho sem habilidades sociais permitiu que eu me prejudicasse muito neste sentido. Cheguei a passar por uma psicóloga, o que talvez possa ter contribuído para que eu retomasse a minha vida anterior (de tentar ser um bom menino).

Nessa idade eu não entendia muito bem como eu deveria agir com as pessoas, ou como funcionava a relação social entre os demais seres humanos, tentava agradar a minha maneira, que era acreditando e oferecendo meus objetos pessoais, fui etiquetado de “mão-aberta” por conta disso. Passei a dar valor a minha infância perdida, as atitudes de ser criança, se divertir, querer aproveitar aquilo que tinha perdido tentando agradar aos outros. E “os adultos”, novamente me etiquetavam de “infantil”, e foi assim até os 18 anos de idade. Até hoje eu sinto o peso da desconfiança das pessoas e a falta de fé em mim. Para as pessoas, aquilo que fiz no passado ainda me persegue no presente, elas não reconhecem e nem se dão ao luxo de reconhecer que eu mudei.

Mas eu tolero isso, porque hoje tenho habilidade social, espero que este texto seja útil para mudar a opinião daqueles que não sabem enxergar os filhos que tem, e que não sabem se desconectar do passado, pois o que devemos viver deve estar no presente, e o que houver de melhor deve ser preservado para que no futuro, nossos filhos se tornem melhores do que nós mesmos.