
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi Oliver, I think this is a great idea! Thanks a lot. Thomas Oliver Tappe schrieb:
Hi there,
attached is a function I have found useful in some of the OTRS-modules I worked on recently. It is called CheckParams() and its purpose is to offer an intuitive and flexible way of checking the params-hash that has been passed into a method.
Currently, many methods contain code like this:
# check all needed objects foreach (qw(ConfigObject LogObject DBObject TimeObject MainObject)) { die "Got no $_" if (!$Self->{$_}); }
plus more checks for additional parameters that must be passed in via the %Params hash.
When using CheckParams, the code looks like this:
# check all needed objects CheckParams($Self, sub { 'ConfigObject' => '!Class=Kernel::Config', 'DBObject' => '!Class=Kernel::System::DB', 'LogObject' => '!Class=Kernel::System::Log', 'MainObject' => '!Class=Kernel::System::Main', 'TimeObject' => '!Class=Kernel::System::Time', });
As you can see, you pass CheckParam() the hash-ref that shall be checked and a specification (for performance reasons this should always be an anonymous subroutine). In the specification, you simply declare the supported parameters, whether or not they are required (!) or optional (?) or if they have to be of a specific class (Class=...).
CheckParams() supports checking of more complex data structures, too:
CheckParams($Params, sub { 'GeneralAttrs' => { 'From' => '!', 'To' => '!', }, 'JobAttrs' => { 'Creator' => '!', 'Changes' => [ { 'Action' => 'm{^(create|change|delete|sync)$}', 'Path' => '!', 'Content' => '?', } ], } });
This code snippet makes sure that the given $Params-hash contains two elements (GeneralAttrs & JobAttrs), each of which has to follow the specified substructures.
As I believe this function could be useful throughout OTRS (now that we have the 2.2-branch), I'd like to add it to the framework. I can see two ways of doing that:
1.) non-OO style: add some kind of helper module (e.g. Utils.pm) and add CheckParams() as a *function* to that. 2.) OO style: add a new module Utils/Params.pm which contains a *class-method* Check(), such that you'd have to invoke it like this Utils::Params->Check($Params, sub { ... });
So what do you think? Do you like the idea in general at all? If so, how should that functionality be integrated (OO- or non-OO-style)?
Please fire any suggestions or questions to this list or directly my way.
cheers, Oliver
------------------------------------------------------------------------
=item CheckParams()
Utility function that can be used by any method that accepts param-hashes to check if the given parameters actually match the expectations.
Each individual parameter has a specification that describes the expectation that the calling function has towards this param. The following specifications are supported:
* '!' - the parameter is required * '?' - the parameter is optional * 'm{regex}' - the parameter must match the given regex * '!Class=...' - the parameter is required and must be an object of the given class * '?Class=...' - if the parameter has been given, it must be an object of the given class
The function will confess for any unknown, missing, or non-matching param.
=cut
sub CheckParams { my $Params = shift or confess('need to pass in params-hashref!'); my $ParamsSpec = shift or confess('need to pass in params-spec-hashref (or -sub)!');
# TODO: allow to switch off this function via configuration in production # environments, as it is rather heavy
# fetch param-spec from function, if that has been given: if (ref($ParamsSpec) eq 'CODE') { $ParamsSpec = $ParamsSpec->(); }
# print a warning for any unknown parameters that have been given: my @UnknownParams = grep { !exists $ParamsSpec->{$_}; } keys %$Params; if (@UnknownParams) { my $UnknownParamsStr = join ',', @UnknownParams; confess("Enocuntered unknown params: '$UnknownParamsStr'!\n"); }
# check if all required params have been specified: foreach my $Param (keys %$ParamsSpec) { my $Spec = $ParamsSpec->{$Param}; if (ref($Spec) eq 'HASH') { # Handle nested specs by recursion: my $SubParams = $Params->{$Param}; if (!defined $SubParams) { confess("Required param '$Param' is missing!"); } CheckParams($SubParams, $Spec); } elsif (ref($Spec) eq 'ARRAY') { # Handle nested spec arrays by looped recursion: my $SubParams = $Params->{$Param}; if (!defined $SubParams) { confess("Required param '$Param' is missing!"); } elsif (ref($SubParams) ne 'ARRAY') { confess("Value for param '$Param' must be an array-ref!"); } foreach my $SubParam (@$SubParams) { CheckParams($SubParam, $Spec->[0]); } } elsif ($Spec eq '!') { # required parameter: if (!exists $Params->{$Param}) { confess("Required param '$Param' is missing!"); } } elsif ($Spec =~ m{^\!Class=(.+)$}i) { my $Class = $1; # required parameter ... if (!exists $Params->{$Param}) { confess("Required param '$Param' is missing!"); } # ... of specific class if (!$Params->{$Param}->isa($Class)) { confess("Param '$Param' is not a '$Class', but that is required!"); } } elsif ($Spec eq '?') { # optional parameter - nothing to do } elsif ($Spec =~ m{^\?Class=(.+)$}i) { my $Class = $1; # optional parameter ... if (exists $Params->{$Param}) { # ... of specific class if (!$Params->{$Param}->isa($Class)) { confess("Param '$Param' is not a '$Class', but that is required!"); } } } elsif ($Spec =~ m{^m{(.+)}$}) { # try to match given regex: my $Regex = $1; my $Value = $Params->{$Param}; if ($Value !~ m{$Regex}) { confess("Required param '$Param' isn't matching regex '$Regex' (given value was '$Value')!"); } } else { # complain about unknown spec: confess("Unknown param-spec '$Spec' encountered!"); } }
return scalar 1; }
------------------------------------------------------------------------
_______________________________________________ OTRS mailing list: dev - Webpage: http://otrs.org/ Archive: http://lists.otrs.org/pipermail/dev To unsubscribe: http://lists.otrs.org/cgi-bin/listinfo/dev
- -- ((otrs)) :: OTRS GmbH :: Europaring 4 :: D - 94315 Straubing Fon: +49 (0) 9421 56818 0 :: Fax: +49 (0) 9421 56818 18 http://www.otrs.com/ :: Communication with success! Geschäftsführer: André Mindermann Handelsregister: HRB 9452 Bad Homburg Steuernummer: 003/240/97521 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.5 (GNU/Linux) Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org iD8DBQFG6RNm5VEHpl41kC8RAjs/AJwJxS/7WT0DFvW2lnhzW0HfM90H4QCg53Md 7KDeKDBtOAzb6/hy7glajrc= =WCAg -----END PGP SIGNATURE-----