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.
The following naming rules apply on how you can access the providers
that were found by the IncludePathLoader:
The last part of your classname split by underscore is used
for the provider name, e.g. "My_Provider_Hello" leads to your
provider being accessible by the name "hello".
If your provider has a method getName()
it will be used instead of the previous method to determine
the name.
If your provider has "Provider" as prefix, e.g. it is called
My_HelloProvider it will be stripped
from the name so that the provider will be called "hello".
The IncludePathLoader does not follow symlinks, that means
you cannot link provider functionality into your include paths,
they have to be physically present in the include paths.
Exposing Your Providers with a Manifest
You can expose your providers to Zend_Tool by
offering a manifest with a special filename ending with "Manifest.php".
A Provider Manifest is an implementation of the
Zend_Tool_Framework_Manifest_ProviderManifestable
and requires the getProviders() method to return
an array of instantiated providers. In anticipation of our first
own provider My_Component_HelloProvider
we will create the following manifest:
Basic Instructions for Creating Providers
As an example, if a developer wants to add the capability of showing
the version of a datafile that his 3rd party component is working
from, there is only one class the developer would need to implement.
Assuming the component is called My_Component, he would
create a class named My_Component_HelloProvider in a
file named HelloProvider.php somewhere on the
include_path. This class would implement
Zend_Tool_Framework_Provider_Interface, and the body of
this file would only have to look like the following:
Given that code above, and assuming the developer wishes to access
this functionality through the console client, the call would look
like this:
The response object
As discussed in the architecture section Zend_Tool allows
to hook different clients for using your Zend_Tool
providers. To keep compliant with different clients you should use the response
object to return messages from your providers instead of using
echo() or a similiar output mechanism. Rewritting our
hello provider with this knowledge it looks like:
_registry
->getResponse()
->appendContent("Hello from my provider!");
}
}
]]>
As you can see one has to extend the
Zend_Tool_Framework_Provider_Abstract to gain access to
the Registry which holds the
Zend_Tool_Framework_Client_Response instance.
Advanced Development Information
Passing Variables to a Provider
The above "Hello World" example is great for simple commands, but
what about something more advanced? As your scripting and tooling
needs grow, you might find that you need the ability to accept
variables. Much like function signatures have parameters, your
tooling requests can also accept parameters.
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();
}
}
]]>