XP Class Runner
thekid opened this issue · 0 comments
Scope of Change
A runner script (similar to the unittest runner) will be created to run
classes as scripts.
Rationale
Simplify command line utilities development.
Functionality
Overview
Instead of writing a complete script we now declare a class as follows:
<?php
class DumpNews extends Command {
var
$id = 0,
$conn = NULL;
#[@arg(position= 0)]
function setNewsId($id) {
$this->id= $id;
}
#[@inject(type= 'rdbms.DBConnection', name= 'news')]
function setConnection(&$conn) {
$this->conn= &$conn;
}
function run() {
$this->out->writeLine(xp::stringOf($conn->select(
'* from news where news_id= %d',
$this->id
)));
}
}
?>
We can run this class by using the cli-runner:
$ xpcli -c ~/.xp/news/ de.thekid.blog.DumpNews 1
Rules
* The class must extend the util.cmd.Command class
* Arguments and resources are injected by means of annotated methods
* We use an output stream to write data
* The class can be reused in different environments because it is not
dependant on anything console-specific.
The xpcli runner
Usage:
$ xpcli [runner-args]* [fully.qualified.ClassName] [class-args]*
The runner-args are any arguments beginning with a dash ("-"). The class
name argument is the first argument without a dash in front of it.
Runner-args:
* -c | --config
Path to configuration files, defaults to "etc/".
Class-args:
* -? | --help
Always supported. Shows a usage generated from the @arg-methods' apidoc
comments.
The runner goes through the following steps when invoked:
-
Extract runner arguments
-
Load command class
-
Check for -? or --help and show a usage
-
Configure the property manager
-
In case a database.ini exists in the property manager's configuration
file path, configure the connection manager with it -
In case a log.ini exists in the property manager's configuration
file path, configure the logger with it -
Perform dependency injection. In case an exception is thrown from any
of the methods, stop. -
Pass arguments. In case an argument is missing or an exception is thrown
from any of the methods, stop. -
Invoke the run() method
The util.cmd.Command class
<?php
class Command extends Object {
var
$out = NULL,
$err = NULL;
/**
* Run method
*
* @model abstract
* @access public
*/
function run() { }
}
?>
The out and err members are created by the runner and are
PrintOutputStream objects. For the console runner, they write data
to STDOUT and STDERR.
The @arg annotation
This annotation marks methods as parameter acceptors.
* Methods that wish to accept a command line argument must have exactly
one argument.
* This argument may have a default value.
* If the method does not have a default value, the parameter passing
stops hard at this point.
* Otherwise, the method is invoked without arguments, so that the
default value will be passed.
How to accept arguments:
- Positional argument
<?php
#[@arg(position= 0)]
function setFirstArgument($v) { }
?>
This will take the first command line argument
- Named argument
<?php
#[@arg(name= 'verbosity')]
function setVerbosity($v) { }
?>
This will take the value passed as --verbosity= or -v
- Auto-named argument
<?php
#[@arg]
function setClassname($v) { }
?>
This will take the value passed as --classname= or -c
The argument name is calculated by using a lowercase version of the
method name and stripping a leading "set".
- Existance argument
<?php
#[@arg]
function setDebug() {
$this->debug= TRUE;
}
?>
This method will be called only if --debug is supplied.
The argument name is calculated by using a lowercase version of the
method name and stripping a leading "set".
Note for cases 2), 3) and 4): The short argument's name is calculated by using
the first character of the long argument's name. It can be overwritten to
resolve ambiguous names by adding a short= '[CHARACTER]' to the @arg
annotation.
The @Inject annotation
This annotation marks methods as resource injectors.
* Resources are one of the following: database connections, logger
categories, properties.
* Resources are configured by property objects:
- The property manager's lookup path is set to "etc/" per default
and may be set via xpcli -c <path>
- The connection manager is configured by database.ini
- The logger is configured by log.ini
- Injecting database connections
<?php
#[@inject(type= 'rdbms.DBConnection', name= 'news')]
function setConnection(&$conn) { }
?>
This method will receive a DBConnection instance (via
ConnectionManager::getInstance()->getByHost('news', 0))
- Injecting logger categories
<?php
#[@inject(type= 'util.log.LogCategory', name= 'default')]
function setTrace(&$cat) { }
?>
This method will receive a LogCategory instance (via
Logger::getInstance()->getCategory('default'))
- Injecting properties
<?php
#[@inject(type= 'util.Properties', name= 'app')]
function setApplicationConfig(&$conf) { }
?>
This method will receive a LogCategory instance (via
PropertyManager::getInstance()->getProperties('app'))
Security considerations
n/a
Speed impact
n/a
Dependencies
- xp-framework/rfc #88
I/O Streams API
Related documents
- http://experiments.xp-framework.net/?people,friebe,cli
Experiment - http://xp-framework.net/downloads/experiments/xpcli-5.0.0-alpha.tar.gz
Download (contains xpcli.php and supporting classes for PHP5)