[Zend] Progressive CLI options fetching

Discussion for various published PHP frameworks, including Zend Framework, CodeIgniter, Kohana, CakePHP, Yii, Symfony, and others.

Moderator: General Moderators

Post Reply
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

[Zend] Progressive CLI options fetching

Post by VladSun »

I'm building a CLI code generator framework - plugin based. In the "main loop" I fetch the --command option, create the appropriate "command" plugin object and initialize it. The plugin in turn, fetches the options needed by itself.
The problem is, the "main loop" doesn't know what options would be needed by the plugin, but still need to fetch the --command option. And when I try to fetch it Zend_Console_Getopt throws an exception - "Unrecognized XXX option" because the plugin to be loaded has not "described" its options yet.

So, I've made a quick and dirty solution:

Code: Select all

<?php
class ZendEx_Console_Getopt extends \Zend_Console_Getopt
{
	const CONFIG_PERMIT_UNKNOWN = 'permitUknown';

	public function __construct($rules, $argv = null, $getoptConfig = array())
	{
		parent::__construct($rules, $argv, $getoptConfig);
		$this->_options[CONFIG_PERMIT_UNKNOWN] = false;
	}

	public function resetParsing()
	{
		$this->_parsed = false;
	}

	protected function _parseSingleOption($flag, &$argv)
	{
		if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) {
			$flag = strtolower($flag);
		}
		if (!isset($this->_ruleMap[$flag])) {

			/**
			 * @hack Do not die on unrecognized options
			 */
			if ($this->_getoptConfig[self::CONFIG_PERMIT_UNKNOWN])
				return null;

			require_once 'Zend/Console/Getopt/Exception.php';
			throw new \Zend_Console_Getopt_Exception(
				"Option \"$flag\" is not recognized.",
				$this->getUsageMessage());
		}
		$realFlag = $this->_ruleMap[$flag];
		switch ($this->_rules[$realFlag]['param']) {
			case 'required':
				if (count($argv) > 0) {
					$param = array_shift($argv);
					$this->_checkParameterType($realFlag, $param);
				} else {
					require_once 'Zend/Console/Getopt/Exception.php';
					throw new \Zend_Console_Getopt_Exception(
						"Option \"$flag\" requires a parameter.",
						$this->getUsageMessage());
				}
				break;
			case 'optional':
				if (count($argv) > 0 && substr($argv[0], 0, 1) != '-') {
					$param = array_shift($argv);
					$this->_checkParameterType($realFlag, $param);
				} else {
					$param = true;
				}
				break;
			default:
				$param = true;
		}
		$this->_options[$realFlag] = $param;
	}
}
And later I simply use:

Code: Select all

$getopt->setOption(\CryoGen\ZendEx_Console_Getopt::CONFIG_PERMIT_UNKNOWN, true);
Is there something I'm missing in Zend_Console_Getopt? Do I really need this hack?
There are 10 types of people in this world, those who understand binary and those who don't
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Re: [Zend] Progressive CLI options fetching

Post by josh »

I'm not terribly familiar with this component but I don't find it surprising that it would require all options to be defined at the start (part of their design goals was to detect "invalid" & "unrecognized" options which you undid). My advice would be that your application needs to figure out the aggregate of all options it could need defined. Basically loop thru all plugins and build up the list of all options.

For example if plugin A & B both have a param --param and one of them uses an int the other a varchar, I'd make it defined as a varchar so it can accept both types of datum.

You'd probably want to involve Zend_Cache so you're not re-building this meta-data of available options on each invocation.

Probably better yet
Have each plugin have it's own CLI "child" script ("commandA.php"). Have a master script ("master.php") that invokes the child scripts. The master script runs your hack, the child scripts run strict parameter checking. The master script would invoke the child script behind the scenes.

So they'd invoke it like:

./master.php commandA --option=val

./master.php commandA runs thru your non validating CLI thing. It then takes all the arguments or even just a raw string of the rest of the options, and uses passthru(). The child script will this way still complain when it is sent invalid options, and master.php does not validating of it's own anymore (your hack).
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

Re: [Zend] Progressive CLI options fetching

Post by VladSun »

Thanks, josh.

The problem is that any of the plugins may or may not have its own plugins with another options set, etc. :)
And I don't want to have some kind of a "plugin registration" in order to have the knowledge of all possible options.

Indeed, I "fix" my hack latter:

Code: Select all

class Application_Options_Reader_CLI extends Application_Options_Reader_Abstract
{
	/**
	 *
	 * @var \CryoGen\ZendEx_Console_Getopt
	 */
	public		$getopt;

	public function __construct()
	{
		$this->getopt = new \CryoGen\ZendEx_Console_Getopt(null);
	}

	public function start()
	{
		$this->getopt->setOption(\CryoGen\ZendEx_Console_Getopt::CONFIG_PERMIT_UNKNOWN, true);
		$this->getopt->resetParsing();
	}
	
	// This will NOW throw an \Zend_Console_Getopt_Exception if any of the options is not recognized
	public function finish()
	{
		$this->getopt->resetParsing();
		$this->getopt->setOption(\CryoGen\ZendEx_Console_Getopt::CONFIG_PERMIT_UNKNOWN, false);
		$this->getopt->parse();
	}
...
after all option processing should have been done, I call the finish() method which will "restore" the "original" Zend_Console_Getopt behavior and force options parsing.
There are 10 types of people in this world, those who understand binary and those who don't
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Re: [Zend] Progressive CLI options fetching

Post by josh »

You should consider contributing to Zend Framework, I like the way you handle it. They do require unit tests tho.
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

Re: [Zend] Progressive CLI options fetching

Post by VladSun »

Thanks again, josh :D

I'll try to contribute it, though it's not even mentioned in the TODO list in Zend_Console_Getopt class file.
There are 10 types of people in this world, those who understand binary and those who don't
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Re: [Zend] Progressive CLI options fetching

Post by josh »

VladSun wrote: it's not even mentioned in the TODO list in Zend_Console_Getopt class file.
That's not their main way of tracking things, the tracker is! Also you can propose new features, you have to write an RFC like document other people can comment on, and then the Zend board of directors will approve it and give you an SVN branch.
Post Reply