# Extendendo o Zend_Tool

## Visão Geral do Zend_Tool

`Zend_Tool_Framework` é uma framework para expor as funcionalidades comuns, tais como a criação da estrutura do projeto, geração de código, geração de índice de pesquisa, e muito mais. Funcionalmente pode ser escrito e exposto por meio de classes PHP dentro do include_path do PHP, permitindo uma flexibilidade incrível de implementação. A funcionalidade pode ser consumida escrevendo implementação e/ou clientes de protocolo-específico -- tais como clientes console, XML-RPC, SOAP, e muito mais.

`Zend_Tool_Project` desenvolve e amplia os recursos do `Zend_Tool_Framework` ao de gerenciar um "projeto". Em geral, um "projeto" é um esforço planejado ou uma iniciativa. No mundo da informática, projetos em geral são uma coleção de recursos. Esses recursos podem ser arquivos, diretórios, bases de dados, esquemas, imagens, estilos e muito mais.

## Extensões do Zend_Tool_Framework

### Arquitetura Geral

`Zend_Tool_Framework` fornece o seguinte:

- Interfaces comuns e abstratas que permitem a desenvolvedores criar funcionalidades e capacidades que são invocadas por clientes da ferramenta.

- Funcionalidade base de clientes e uma implementação concreta do console que conectam ferramentas externas e interfaces para o Zend_Tool_Framework. O cliente do console pode ser utilizado em ambientes CLI, como console unix e o console do Windows.

- Interfaces de "Provider" e "Manifest" que podem ser usadas pela ferramenta do sistema. "Providers" representam o aspecto functional do framework, e define as ações que os clientes da ferramenta podem chamar. "Manifests" age como registros de metadados que proveem contexto adicional para os vários providers definidos.

- Um sistema de loading introspectivo que irá examinar o ambiente a procura de providers e determinar o que é necessário para chama-los.

- Uma conjunto padrão de sistemas de providers que permite o sistema relatar o que todos os recursos do sistemas são, bem como fornecer um feedback útil. Ele também inclui um compreessível "Systema de Ajuda".

Definições que você deve estar ciente de através deste manual com relação ao `Zend_Tool_Framework` incluem:

- `Zend_Tool_Framework` - O framework que expõe recursos da ferramenta.

- Tooling Client - Uma ferramenta de desenvolvimento que se conecta ao e consome `Zend_Tool_Framework`.

- Client - O subsistema do `Zend_Tool_Framework` que expoe uma interface tal que tooling clients podem conectar, pesquisar e executar comandos.

- Console Client / Command Line Interface / `zf.php` - A tooling client para a linha de comando.

- Provider - Um subsistema e uma coleção de funcionalidades internas que o framework exporta.

- Manifest - Um subsistema para definição, organização, e divulgação de dados exigidos pelo provider.

- `Zend_Tool_Project` Provider - Um conjunto de providers especificamente para criação e manutenção de projetos baseados no Zend Framework.

### Entendendo o Cliente CLI

A CLI, ou ferramenta de linha de comando (internamente conhecida como ferramenta de console), é atualmente a interface primária para enviar pedidos ao `Zend_Tool` requests. Com a ferramenta CLI, desenvolvedores podem enviar pedidos para a ferramenta dentro da "janela de linha de comando", também comumente conhecida como janela do "terminal". Este ambiente é predominante em embientes *unix, mas também tem uma implementação comum no Windows como o `cmd.exe`, console2 e também com o projeto Cygwin.

#### Configuração da ferramenta CLI

Para distribuir pedidos via cliente de linha de comando, primeiro você precisa configurar o cliente para que seu sistema possa manipular os comandos "zf". O cliente de linha de comando, para todos as intenções e propósitos, é o arquivo `.sh` ou `.bat` que é provido com a sua distribuição do Zend Framework. No trunk, ele pode ser encontrado aqui: http://framework.zend.com/svn/framework/standard/trunk/bin/.

Como você pode ver, existem 3 arquivos no diretório `/bin/`: `zf.php`, `zf.sh`, e `zf.bat`. O `zf.sh` e o `zf.bat` são os pacotes específicos do sistema operacional: `zf.sh` para ambientes *nix, e `zf.bat` para ambientes Win32. Estes empacotadores clientes são responsáveis por procurar o php.exe correto, achando o `zf.php`, e passando o pedido para o cliente. O `zf.php`, é responsável por manipular a identificação do seu ambiente, construindo um include_path adequado, e passar o que é fornecido na linha de comando para o componente de biblioteca adequado para a expedição.

Finalmente, você quer garantir duas coisas para fazer tudo funcionar independentemente do sistema operacional em que você está:

1. `zf.sh/zf.bat` acessível a partir do path do sistema. Esta é a capacidade de chamar `zf` de qualquer lugar na sua linha de comando, independentemente de qual é o seu diretório de trabalho atual.

2. `ZendFramework/library` estar no seu include_path.

Nota: enquanto os acima são os requisitos ideais, você pode simplesmente baixar o Zend Framework e esperar que ele funcione como `./path/to/zf.php` algum comando..

#### Configurando a ferramenta CLI em Sistemas Unix-like

A configuração mais comum no ambiente *nix, é copiar o `zf.sh` e o `zf.php` no mesmo diretório que o seu binário PHP. Isto pode geralmente ser achado nos seguintes lugares:

    /usr/bin
    /usr/local/bin
    /usr/local/ZendServer/bin/
    /Applications/ZendServer/bin/

Para achar a localização do seu binário PHP, você pode executar 'which php' na linha de comando. Isto retornará a localização do binário do PHP que você está usando para rodar scripts PHP no seu ambiente.

O próximo passo é certificar que a biblioteca Zend Framework está configurada corretamente dentro do sistema de include_path do PHP. Para achar onde seu include_path está localizado, você pode executar `php -i` e olhar para a variável include_path, o mais sucintamente, executar `php -i | grep include_path`. Uma vez que você tenha achado onde seu include_path está localizado (isto irá geralmente estar em algum lugar como `/usr/lib/php`, `/usr/share/php`, `/usr/local/lib/php`, ou similar), certifique que o conteúdos do diretório `/library/` estão colocados dentro do seu diretório include_path especificado.

Uma vez que você tenha terminado estas duas coisas, você deve ser capaz de digitar um comando e obter devolta a resposta adequada como:

Se vocÊ não ver isto digitado na saída, volte e verifique sua configuração para ter certeza que tem todas as partes necessárias in devido lugar.

Existem uma combinação de configurações alternativas que você pode querer empregar dependendo das configurações dos servidores, seu nível de acesso, ou por outras razões.

Configuração Alternativa envolve guardar o download do Zend Framework junto como está, e criar um link de um local `PATH` para o `zf.sh`. O que isto significa é que você coloca o conteúdo do download do Zend Framework em uma localização tal como `/usr/local/share/ZendFramework`, ou mais localmente como `/home/username/lib/ZendFramework`, e cria um link simbólico para o `zf.sh`.

Assumindo que você quer colocar o link dentro de `/usr/local/bin` (isto pode também funcionar colocando o link dentro de `/home/username/bin/` por exemplo) você poderia dgitar um comando similar a este:

    ln -s /usr/local/share/ZendFramework/bin/zf.sh /usr/local/bin/zf

    # OU (por exemplo)
    ln -s /home/username/lib/ZendFramework/bin/zf.sh /home/username/bin/zf

Isto irá criar um link que você poderá ser capaz de acessar globalmente na linha de comando.

#### Configurando a ferramenta CLI no Windows

A confuguração mais comum no ambiente Win32, é copiar o `zf.bat` e o `zf.php` para dentr do mesmo diretório do seu binário PHP. Este pode geralmente ser achado nos seguintes lugares:

    C:\PHP
    C:\Program Files\ZendServer\bin\
    C:\WAMP\PHP\bin

Você deve ser capaz de rodar `php.exe` na linha de comando. Se você não for capaz, primeiro verifique a documentação que veio com sua distribuição PHP, ou tenha certeza que o caminho para o `php.exe` está na sua variável de ambiente `PATH` do Windows.

O próximo passo é ter certeza que a biblioteca do Zend Framework está configurada corretamente dentro do sistema de include_path do PHP. Para achar onde seu include_path está localizado, você pode digitar `php -i` e olhar para a variável include_path, ou mais sucintamente executar `php -i | grep include_path` se você tem um Cygwin configurado com grep disponível. Uma vez você tenha achado onde seu include_path está localizado(isto irá geralmente ser algo como `C:\PHP\pear`, `C:\PHP\share`,`C:\Program%20Files\ZendServer\share` ou similar), verifique que os conteúdos do diretório library/ estão postos dentro do seu diretório include_pathespecificado.

Uma vez tenha terminado aquilas duas coisas, você deve ser capaz de enviar um comando e receber o devida resposta como:

Se você não ver isto digitado na saída, volte e verifique sua configuração para ter certeza que você tem todas as partes necessárias no lugar correto.

Existe uma combinação de configurações alternativas que você pode querer empregar dependendo das configurações do seu servidor, do seu nível de acesso, ou de outras razões.

Configuração Alternativa envolve guardar o download do Zend Framework junto como está, e alterar ambos seu sistema de `PATH` bem como o arquivo `php.ini`. No seu ambiente de usuário, tenha certeza de adcionar `C:\Path\To\ZendFramework\bin`, então seu arquivo `zf.bat` será executável. Também, altere o arquivo `php.ini` certificando que `C:\Path\To\ZendFramework\library` está no seu include_path.

#### Outras Considerações de Configuração

Se por alguma razão você não quiser a biblioteca do Zend Framework dentro do seu include_path, existe uma outra opção. Existem duas variáveis de ambiente especiais que o `zf.php` irá utilizar para determinar a localização da sua instalação do Zend Framework.

A primeira é `ZEND_TOOL_INCLUDE_PATH_PREPEND`, que irá preceder o valor da variável de ambiente para o sistema de (`php.ini`) include_path include_path antes da carga do cliente.

Alternativamente, você pode querer usar `ZEND_TOOL_INCLUDE_PATH` para substituir completamente o sistema de include_path para um que faça sentido especialmente para a ferramente de linha de comando `zf`.

### Criando Providers

Em geral, um provider, por si só, é nada mais que o a casca para um desenvolvedor para agrupar-se algumas das capacidades que eles desejam enviar com um o cliente de linha de comando (ou outro). Ele é um análogo para o que um "controller" é dentro da sua aplicação MVC.

#### Como o Zend_Tool encontra seus Providers

Por padrão `Zend_Tool` usa o BasicLoader para encontrar todos os providers que você pode rodar. Ele itera recursivamente todos os diretórios do include path e abre todos os arquivos que terminam com "Manifest.php" ou "Provider.php". Todas as classes naqueles arquivos são inspecionadas se implementam ou `Zend_Tool_Framework_Provider_Interface` ou `Zend_Tool_Framework_Manifest_ProviderManifestable`. Instancias da interface do provider implementam a real funcionalidade e todos os métodos públicos estão acessíveis como actions do provider. A interface ProviderManifestable de qualquer forma requer a implementação de um metodo `getProviders()` que reforna um array de instâncias da interface provider.

As seguintes regras de nomeação aplicaveis em como você pode acessar os providers que foram encontrados pelo IncludePathLoader:

- A última parte da sua divisão do classname por underscore é usado para o nome do provedor, por exemplo, "My_Provider_Hello" permite ao seu provider a ser acessível pelo nome de "hello".

- Se o seu provider tem um método `getName()` ele irá ser usado ao invés da maneira anterior para determinar o nome.

- Se o seu provider tem um prefixo "Provider", por exemplo ele é chamado de `My_HelloProvider`, isto será retirado do nome, assim o provider será chamado "hello".

O IncludePathLoader não permite links simbólicos, que significa que você não pode linkar funcionalmente o provider no seus inclide paths, eles tem que estar fisicamente presentes nos inclide paths.

##### Expondo Seus Providers com um Manifest

Você pode expor seus providers para `Zend_Tool` oferecendo um manifest com a nome de arquivo especial terminando com "Manifest.php". Um Provider Manifest é uma implementação do Zend_Tool_Framework_Manifest_ProviderManifestable e requer o método `getProviders()` para retornar uma array providers instânciados. Em antecipação do seu primeiro próprio provider `My_Component_HelloProvider` nós iremos criar o seguinte manifest:

    class My_Component_Manifest
        implements Zend_Tool_Framework_Manifest_ProviderManifestable
    {
        public function getProviders()
        {
            return array(
                new My_Component_HelloProvider()
            );
        }
    }

#### Instruções Básicas para Criação de Providers

Como um exemplo, se um desenvolvedor quer adicionar a capacidade de apresentar a versão de um arquivos de dados que seu componente de terceiros está usando, exite apenas uma classe que o desenvolvedor precisaria implementar. Asumindo que o componente é chamado `My_Component`, Ele poderia criar uma classe chamada `My_Component_HelloProvider` em um arquivo nomeado de `HelloProvider.php` em algum lugar no include_path. Esta classe implementaria `Zend_Tool_Framework_Provider_Interface`, e o corpo deste arquivo apenas teria que parecer com o seguinte:

    class My_Component_HelloProvider
        implements Zend_Tool_Framework_Provider_Interface
    {
        public function say()
        {
            echo 'Hello from my provider!';
        }
    }

Dado o códifo acima, e assumindo que o desenvolvedor deseja acessar esta funcionalidade através do cliente de console, a chamada se pareceria com isto:

    % zf say hello
    Hello from my provider!

#### O objeto response

Como assumido na arquitetura da sessão `Zend_Tool` permite unir diferentes cliente para usar o seus providers `Zend_Tool`. Para manter a conformidade com diferentes clientes você deve usar o objeto de resposta para retornar mensagens de seus providers em vez de usar `echo()` ou um mecanismo de saída semelhante. Reescrevendo nosso provider hello com este conhecimento isto vai se parecer com:

    class My_Component_HelloProvider
        extends Zend_Tool_Framework_Provider_Abstract
    {
        public function say()
        {
            $this->_registry
                 ->getResponse()
                 ->appendContent("Hello from my provider!");
        }
    }

Como você pode ser ele extende o `Zend_Tool_Framework_Provider_Abstract` para ter acesso ao Registry que guarda a instância do `Zend_Tool_Framework_Client_Response`.

#### Informações sobre Desenvolvimento Avançado

##### Passando variáveis para o Provider

O exemplo "Hello World" acima é ótimo para comandos simples, mas o que dizer sobre algo mais avançado? Como seu script e ferramentas necessitam crescer, você pode achar que precisa da capacidade de aceitar variáveis. Bem como assinaturas de função têm parâmetros, a sua chamada para a ferramenta também podem aceitar parâmetros.

Assim como cada requisição à ferramenta podem ser isolado a um método dentro de uma classe, os parâmetros de uma requisição à ferramenta também podem ser isolado em um lugar muito conhecido. Parâmetros dos métodos de ação de um provider podem incluir os mesmos parâmetros que você deseja que o seu cliente utilize ao chamar o provider e combinação de ações. Por exemplo, se você quiser aceitar um nome no exemplo acima, você provavelmente fazer isso em um código OO:

    class My_Component_HelloProvider
        implements Zend_Tool_Framework_Provider_Interface
    {
        public function say($name = 'Ralph')
        {
            echo 'Hello' . $name . ', from my provider!';
        }
    }

O exemplo acima pode então ser chamado via linha de comando `zf say hello Joe`. "Joe" será fornecido ao provider como um parametro do método chamado. Também note, como pode ser que o parametro é opcional, isto significa que ele é também opcional na linha de comando, assim `zf say hello` ainda funcionará, e por padrão o nome será "Ralph".

##### Solicitar Entrada ao Usuário

Existem casos quando o workflow do seu provider requer solicitar o usuário entrada de dados. Isto pode ser feito, solicitando o cliente a pedir mais entradas necessárias chamando:

    class My_Component_HelloProvider
        extends Zend_Tool_Framework_Provider_Abstract
    {
        public function say($name = 'Ralph')
        {
            $nameResponse = $this->_registry
                                 ->getClient()
                                 ->promptInteractiveInput("Whats your name?");
            $name = $nameResponse->getContent();

            echo 'Hello' . $name . ', from my provider!';
        }
    }

Este comando dispara uma exceção se o cliente corrente não é capaz de manipular requisições interativas. No caso de o Cliente do Console padrão, contudo, você será solicitado a digitar o nome.

##### Fingindo para executar um Provider Action

Outra funcionalidade interessante que você pode desejar implementar é fingimento. Fingimento é a capacidade de seu provedor para "fingir" como se estivesse fazendo a ação solicitada e combinação de provedor e dar ao usuário o máximo de informações sobre o que faria sem realmente fazesse. Isso pode ser uma noção importante ao fazer banco de dados pesado ​​ou modificações do sistema de arquivos que o usuário não poderiam querer fazer.

Fingimento é fácil de implementar. Existem duas partes para esta funcionalidade: 1) marcando o provider como tendo a habilidade para "fingir", e 2) verificando a requisição para garantir a requisição corrente foi de fato solicitada a ser "pretended". Esta funcionalidade é demostrada no simples código abaixo.

    class My_Component_HelloProvider
        extends    Zend_Tool_Framework_Provider_Abstract
        implements Zend_Tool_Framework_Provider_Pretendable
    {
        public function say($name = 'Ralph')
        {
            if ($this->_registry->getRequest()->isPretend()) {
                echo 'I would say hello to ' . $name . '.';
            } else {
                echo 'Hello' . $name . ', from my provider!';
            }
        }
    }

Para rodar o provider em modo fingido apenas chame:

    % zf --pretend say hello Ralph
    I would say hello Ralph.

##### Modos Verboso e Debug

Você pode também rodar as suas actions do provider em modo "verboso" ou "debug". A semântica em relação a esta ações devem ser implementadas por você no contexto do seu provedor. Você pode acessar o modo debug ou verboso com:

    class My_Component_HelloProvider
        implements Zend_Tool_Framework_Provider_Interface
    {
        public function say($name = 'Ralph')
        {
            if($this->_registry->getRequest()->isVerbose()) {
                echo "Hello::say has been called\n";
            }
            if($this->_registry->getRequest()->isDebug()) {
                syslog(LOG_INFO, "Hello::say has been called\n");
            }
        }
    }

##### Acessando Configuração e Armazenamento de Usuário

Usando a variável de Ambiente ZF_CONFIG_FILE ou o .zf.ini em seu diretório home você pode injetar parametros configuração em qualquer provider `Zend_Tool`. Acesso a esta configuração está disponível via registry que é passado para seu provider se você extender `Zend_Tool_Framework_Provider_Abstract`.

    class My_Component_HelloProvider
        extends Zend_Tool_Framework_Provider_Abstract
    {
        public function say()
        {
            $username = $this->_registry->getConfig()->username;
            if(!empty($username)) {
                echo "Hello $username!";
            } else {
                echo "Hello!";
            }
        }
    }

A configuração retornada está no tipo `Zend_Tool_Framework_Client_Config` mas internamente os métodos mágicos `__get()` and `__set()` encaminham para um `Zend_Config` do tipo de configuração fornecida.

O armazenamento permite salvar dados arbitrarios para referenciar depois. Isto pode ser útil para tarefas de processamento em lote ou para re-executar sua tarefa. Você pode acessar o armazenamento em uma caminho similar ao da configuração:

    class My_Component_HelloProvider
        extends Zend_Tool_Framework_Provider_Abstract
    {
        public function say()
        {
            $aValue = $this->_registry->getStorage()->get("myUsername");
            echo "Hello $aValue!";
        }
    }

A API para o armazenamento é muito simples:

    class Zend_Tool_Framework_Client_Storage
    {
        public function setAdapter($adapter);
        public function isEnabled();
        public function put($name, $value);
        public function get($name, $defaultValue=null);
        public function has($name);
        public function remove($name);
        public function getStreamUri($name);
    }

Ao projetar seus providers que estarão cientes do armazenamento e da configuração lembre-se de verificar se configurações de usuário ou chaves de armazenamento necessárias realmente existem para um usuário. Você não vai executar em erros fatais quando nenhuma dessas existir porém, desde que eles estejam vazios, são criados mediante solicitação.

## Extensões Zend_Tool_Project

`Zend_Tool_Project` expoe um rico conjunto de funcionalidades e capacidades que faz o tarefa de criação de novos providers, especificamente visando projetos mais fáceis e mais gerenciáveis.

### Arquitetura Geral

Este mesmo conceito se aplica aos projetos Zend Framework. Em projetos de Zend Framework, você tem controllers, actions, views, models, bancos de dados e assim por diante. Em Termos de `Zend_Tool`, nós precisamos de um caminho para rastrear estes tipos de recursos - portanto `Zend_Tool_Project`.

`Zend_Tool_Project` é capaz de rastrear os recursos do projeto ao longo do desenvolvimento de um projeto. Então, por exemplo, se em um comando você criar um controller, e no próximo comando você quiser criar uma action sem o controller, `Zend_Tool_Project` vai ter de saber sobre o arquivo controller que você criou de modo que você pode (na próxima ação), ser capaz de acrescentar a action a ele. Isto é o que mantém os nossos projetos em dia e monitorado.

Outro ponto importante para entender é sobre projetos é que tipicamente, recursos são organizados em uma forma hierarquica. Com que em mente, `Zend_Tool_Project` é capaz de serializar o projeto corrente em uma representação interna que permite lhe permite acompanhar não só que recursos são parte de um projeto em um dado momento, mas também onde eles estão em relação uns aos outros.

### Criando Providers

Providers específicos de projeto são criados da mesma forma como providers de serviços, com uma exceção: os providers de projeto devem estender de `Zend_Tool_Project_Provider_Abstract`. Esta classe vem com algumas funcionalidades significativas que ajudam os desenvolvedores a caregar o projeto existente, obter o objeto de profile, e ser capaz de pesquisar o profile, e depois armazenar quaisquer alterações ao profile do projeto atual.

    class My_Component_HelloProvider
        extends Zend_Tool_Project_Provider_Abstract
    {
        public function say()
        {
            $profile = $this->_loadExistingProfile();

            /* ... do project stuff here */

            $this->_storeProfile();
        }
    }