Sites Dinâmicos

Sites dinâmicos são sites gerenciáveis por sistemas de CMS (Content Management System), através de uma plataforma online, que é acessada por login e senha, é possível manipular todo o conteúdo gerenciável do Mais »

Modelagem 3D

Se sua empresa precisa de ilustrações em 3D, venha falar com a Toca Digital e conheça o nosso trabalho. A modelagem 3D (modelagem tridimensional)  é o processo de desenvolvimento de uma representação Mais »

Ganhe tempo na construção de seu site

  Não perca seu tempo com empresas que vão deixar você na mão, montamos seu site com os melhores recursos da internet, ferramentas de gereciamento de conteúdo e de controle estatístico. Com Mais »

 

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:

<?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";
        }
    }

}

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:


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";

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:

<?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;
 }

}

Switch to our mobile site