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á: 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. 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: 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: 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: 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: 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: 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: 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: _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 necessidades crescem, você pode achar que você 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. Just as each tooling request can be isolated to a method within a class, the parameters of a tooling request can also be isolated in a very well known place. Parameters of the action methods of a provider can include the same parameters you want your client to utilize when calling that provider and action combination. For example, if you wanted to accept a name in the above example, you would probably do this in OO code: The above example can then be called via the command line zf say hello Joe. "Joe" will be supplied to the provider as a parameter of the method call. Also note, as you see that the parameter is optional, that means it is also optional on the command line, so that zf say hello will still work, and default to the name "Ralph". Prompt the User for Input There are cases when the workflow of your provider requires to prompt the user for input. This can be done by requesting the client to ask for more the required input by calling: _registry ->getClient() ->promptInteractiveInput("Whats your name?"); $name = $nameResponse->getContent(); echo 'Hello' . $name . ', from my provider!'; } } ]]> This command throws an exception if the current client is not able to handle interactive requests. In case of the default Console Client however you will be asked to enter the name. Pretending to execute a Provider Action Another interesting feature you might wish to implement is pretendability. Pretendabilty is the ability for your provider to "pretend" as if it is doing the requested action and provider combination and give the user as much information about what it would do without actually doing it. This might be an important notion when doing heavy database or filesystem modifications that the user might not otherwise want to do. Pretendability is easy to implement. There are two parts to this feature: 1) marking the provider as having the ability to "pretend", and 2) checking the request to ensure the current request was indeed asked to be "pretended". This feature is demonstrated in the code sample below. _registry->getRequest()->isPretend()) { echo 'I would say hello to ' . $name . '.'; } else { echo 'Hello' . $name . ', from my provider!'; } } } ]]> To run the provider in pretend mode just call: Verbose and Debug modes You can also run your provider actions in "verbose" or "debug" modes. The semantics in regard to this actions have to be implemented by you in the context of your provider. You can access debug or verbose modes with: _registry->getRequest()->isVerbose()) { echo "Hello::say has been called\n"; } if($this->_registry->getRequest()->isDebug()) { syslog(LOG_INFO, "Hello::say has been called\n"); } } } ]]> Accessing User Config and Storage Using the Enviroment variable ZF_CONFIG_FILE or the .zf.ini in your home directory you can inject configuration parameters into any Zend_Tool provider. Access to this configuration is available via the registry that is passed to your provider if you extend Zend_Tool_Framework_Provider_Abstract. _registry->getConfig()->username; if(!empty($username)) { echo "Hello $username!"; } else { echo "Hello!"; } } } ]]> The returned configuration is of the type Zend_Tool_Framework_Client_Config but internally the __get() and __set() magic methods proxy to a Zend_Config of the given configuration type. The storage allows to save arbitrary data for later reference. This can be useful for batch processing tasks or for re-runs of your tasks. You can access the storage in a similar way like the configuration: _registry->getStorage()->get("myUsername"); echo "Hello $aValue!"; } } ]]> The API of the storage is very simple: When designing your providers that are config or storage aware remember to check if the required user-config or storage keys really exist for a user. You won't run into fatal errors when none of these are provided though, since empty ones are created upon request. Zend_Tool_Project Extensions Zend_Tool_Project exposes a rich set of functionality and capabilities that make the task of creating new providers, specficially those targetting project easier and more manageable. Overall Architecture This same concept applies to Zend Framework projects. In Zend Framework projects, you have controllers, actions, views, models, databases and so on and so forth. In terms of Zend_Tool, we need a way to track these types of resources - thus Zend_Tool_Project. Zend_Tool_Project is capable of tracking project resources throughout the development of a project. So, for example, if in one command you created a controller, and in the next command you wish to create an action within that controller, Zend_Tool_Project is gonna have to know about the controller file you created so that you can (in the next action), be able to append that action to it. This is what keeps our projects up to date and stateful. Another important point to understand about projects is that typically, resources are organized in a hierarchical fashion. With that in mind, Zend_Tool_Project is capable of serializing the current project into a internal representation that allows it to keep track of not only what resources are part of a project at any given time, but also where they are in relation to one another. Creating Providers Project specific providers are created in the same fashion as plain framework providers, with one exception: project providers must extend the Zend_Tool_Project_Provider_Abstract. This class comes with some significant functionality that helps developers load existing project, obtian the profile object, and be able to search the profile, then later store any changes to the current project profile. _loadExistingProfile(); /* ... do project stuff here */ $this->_storeProfile(); } } ]]>