Added by Ralph Schindler, last edited by Ralph Schindler on Nov 13, 2008  (view change)

Labels

 
(None)

Zend Framework: Zend_Tool_Framework_Endpoint_Cli Component Proposal

Proposed Component Name Zend_Tool_Framework_Endpoint_Cli
Developer Notes http://framework.zend.com/wiki/display/ZFDEV/Zend_Tool_Framework_Endpoint_Cli
Proposers Ralph Schindler
Zend Liaison TBD
Revision 1.0 - 1 January 2008: Initial Draft. (wiki revision: 6)

Table of Contents

1. Overview

The Zend_Tool_Framework_Endpoint_Cli implementation aims to allow Zend_Tool_Framework to work within the command line environment. The goal is to setup an intuitive command line interface for dispatching "tooling requests" into the tooling subsystem.

2. References

  • None

3. Component Requirements, Constraints, and Acceptance Criteria

  • This component will implement a Zend_Tool_Framework endpoint.
  • This component will create an intuitive command line interface using common command line semantics.
  • This component will create globally accessible metadata about cli namings.

4. Dependencies on Other Framework Components

  • Zend_Tool_Framework
  • Zend_Filter
  • Zend_Console_Getopt
  • Zend_Exception

5. Theory of Operation

As mentioned in the overview, the primary goal of this component is to setup an intuitive interface on the command line for calling and executing "tooling requests". To do this, we must take several factors into account:

  • What should the command line argument structure look like? How can this be intuitive?
  • Provider names are in camel case and command line arguments are usually dash-separated, how can we maintain this consistency?
  • Will interactivity be supported? If so, how?
  • How can we maintain consistency with respect to other future endpoints?

Command Line Argument Structure

The command line application

First and foremost, the actual command line application should be short and concise. For this reason, this proposal suggests that the name of the command line application be "zf". This application should be installed into the PATH of the host operating system, and the rest of Zend Framework (including the whole of Zend_Tool), should be inside of an accessible include_path.

This means that specific operating systems should make use of semantics that are as specific as their needs. For example, on windows there might be a zf.bat file that calls the zf.php file. On *nix systems, there might be a zf.sh or zf command inside a path that calls out to the zf.php file.

The command line arguments

In OO design of Zend Framework, there is a level of consistency in class and method namings. More specifically, in most cases we attempt to stick with the following structure:

As you can see, when most classes follow the above structure when developing an API, it makes the API predictable and consistent. Those two tenants are two that we also wish to have with respect to the command line tool and its arguments.

Similar to how western languages (like english) are read and spoken, I propose we follow a command like syntax's:

The above allows us to build a command sytax that might look like: "zf show version", or "zf create project", or "zf create model.dbtable", so on and so forth. The primary objective is to build a command syntax with arguments that closely resembles spoken language commands.

Command Line Parameters

Commands from the command line are parsed and will attempt to dispatch/execute a specific method inside a Zend_Tool provider. As we can see inside the Zend_Tool_Framework proposal, providers are made up of Providers (the noun), actions (the verb), and optional specialties (the adjective/noun). Those elements are set inside a request object which is then passed down to a Zend_Tool_Framework dispatcher (also described in the Zend_Tool_Framework proposal).

Also included in this request object can be parameters. Parameters in the Zend_Tool Providers sense, are simply method arguments. For exmaple in this class:

we see that the show() method has an optional argument for "details". In order to properly model this on the command line, we will make use of command line "options". We will make use of Zend_Console_GetOpt to parse out options. Generally speaking, options are command line words that start with one or two dashes (-, or --).

Since in the above example the "details" option is specific to the "show version" command, it will be expected after the "noun" portion of the command, like this:

Multiple optional parameters can be included on the command line, and DO NOT have to be in the same order they appear in the actual class/method since they are referred to by their name.

Alternate Usage

It is allowed to have positional parameters in the command line endpoint. For example, if a method takes two methods Foo::bar($one, $two), then the following command line is allowed:

where onevalue will be passed in as $one parameters, and twovalue will be passed in via $two parameter.

Command Line Naming Semantics

With all of the above examples, there should be one lingering question: How does Version become version? How does any camelCase name become the dash-separated name we see on the command line? AND, will this information be available to me when using OTHER endpoints.

The answer to this question is simple: we will make use of the Zend_Tool_Framework Metadata (Manifest) mechanism. As we noted inside the Zend_Tool_Framework proposal, the metadata manifest can be utilized to attach and store information and metadata to any of the providers and actions within the system. In our case here, we want to store naming information.

When the Zend_Tool_Framework system bootstraps itself (ie: it looks for providers and manifests inside the include_path), it will pick up on Zend_Tool_Framework_Endpoint_Cli_Manifest. This manifest will create a "command line" version of all of the necessary namings for its own use.

To do this, it will make use of Zend_Filter_Words_CamelCaseToDash to make this translation. These translations are then put inside the Zend_Tool_Framework global manifest for later usage. By nature of the Manifest system, regardless of if the CLI tool or some other tool is consuming the Zend_Tool_Framework system, this metadata will always be available. So, this means, if IDE XYZ was to implement an endpoint into the Zend_Tool_Framework system, it will have access to the cli namings setup by Zend_Tool_Framework_Endpoint_Cli_Manifest.

6. Milestones / Tasks

Describe some intermediate state of this component in terms of design notes, additional material added to this page, and / code. Note any significant dependencies here, such as, "Milestone #3 can not be completed until feature Foo has been added to ZF component XYZ." Milestones will be required for acceptance of future proposals. They are not hard, and many times you will only need to think of the first three below.

  • Milestone 1: design notes will be published here
  • Milestone 2: Working prototype checked into the incubator supporting use cases #1, #2, ...
  • Milestone 3: Working prototype checked into the incubator supporting use cases #3 and #4.
  • Milestone 4: Unit tests exist, work, and are checked into SVN.
  • Milestone 5: Initial documentation exists.

If a milestone is already done, begin the description with "[DONE]", like this:

  • Milestone #: [DONE] Unit tests ...

7. Class Index

  • Zend_Tool_Framework_Endpoint_Cli
  • Zend_Tool_Framework_Endpoint_Cli_Manifest
  • Zend_Tool_Framework_Endpoint_Cli_OptionParser

8. Use Cases

Show the version from the "version provider"

Show the major part of the version from the "version provider"

Show the major part of the version (as passed as a parameter) from the "version provider"

Create a new project from the "project provider"

Create a new controller inside a project from the "controller provider"

9. Class Skeletons

Zend_Tool_Framework_Endpoint_Cli

Zend_Tool_Framework_Endpoint_Cli_GetoptParser

Zend_Tool_Framework_Endpoint_Cli_Manifest

Whilst I see why function params map to --arg on the command line, it adds a extra characters to the command line syntax for arguments that are required. It also makes the cli interface harder to use as you have to remember the argument's name too.

e.g. is it:
zf create controller --name foo or zf create controller --class foo ?

ideally, I'd want to type:
zf create controller foo
as the command makes no sense without the foo.

Similarly to add the "list" action to the "foo" controller, I'd want to do something like:
zf create controller.action foo list

rather than:
zf create controller.action --name foo --action-name list
or zf create controller.action --name list --controller-name foo

For optional/advanced params, then the --arg syntax is fine, e.g to create a controller and the initial set of actions, I can imagine a syntax something like:
zf create controller news --actions index,archive,view
which would work well.

Obviously, I bet this would be harder to code!

Regards,

Rob...

I could see the option name being dropped in cases where the provider author wants to default to a specific option- in this case 'name'. I would be hesitant about doing this for more than one option, however, because order then must be significant. I'd argue that you could just make a mirrored single option in your example: 'zf create controller.action list.foo'. IN this case the list.foo would be passed to the provider as a single required option. Let's call it full-name, which would be specified in the manifest or elsewhere as the default option. The provider can then break this option up as necessary.