From 02d24c4e4cf9e27c9c03bc551f01949d8fb2cfd7 Mon Sep 17 00:00:00 2001 From: Len Kranendonk Date: Thu, 22 Jul 2004 18:51:07 +0000 Subject: [PATCH] Added proxying by alternate criteria to WobjectProxy --- docs/upgrades/upgrade_6.1.1-6.2.0.sql | 4 + lib/WebGUI/Form.pm | 53 ++++++ lib/WebGUI/HTMLForm.pm | 26 +-- lib/WebGUI/MetaData.pm | 133 +++++++++++++- lib/WebGUI/Page.pm | 6 +- lib/WebGUI/Wobject.pm | 3 +- lib/WebGUI/Wobject/WobjectProxy.pm | 173 +++++++++++++++++- lib/WebGUI/i18n/English/MetaData.pm | 6 +- lib/WebGUI/i18n/English/WobjectProxy.pm | 65 +++++++ www/extras/wobject/WobjectProxy/hline.gif | Bin 0 -> 848 bytes .../wobject/WobjectProxy/querybuilder.css | 42 +++++ .../wobject/WobjectProxy/querybuilder.js | 35 ++++ www/extras/wobject/WobjectProxy/vline.gif | Bin 0 -> 869 bytes 13 files changed, 515 insertions(+), 31 deletions(-) create mode 100644 www/extras/wobject/WobjectProxy/hline.gif create mode 100644 www/extras/wobject/WobjectProxy/querybuilder.css create mode 100644 www/extras/wobject/WobjectProxy/querybuilder.js create mode 100644 www/extras/wobject/WobjectProxy/vline.gif diff --git a/docs/upgrades/upgrade_6.1.1-6.2.0.sql b/docs/upgrades/upgrade_6.1.1-6.2.0.sql index 6c9d738a0..b8e77f1b5 100644 --- a/docs/upgrades/upgrade_6.1.1-6.2.0.sql +++ b/docs/upgrades/upgrade_6.1.1-6.2.0.sql @@ -49,3 +49,7 @@ INSERT INTO settings (name, value) values ("metaDataEnabled", 0); DELETE FROM settings WHERE name = "passiveProfilingEnabled"; INSERT INTO settings (name, value) values ("passiveProfilingEnabled", 0); +alter table WobjectProxy add proxyByCriteria int default 0; +alter table WobjectProxy add resolveMultiples varchar(30) default "mostRecent"; +alter table WobjectProxy add proxyCriteria text default NULL; + diff --git a/lib/WebGUI/Form.pm b/lib/WebGUI/Form.pm index c84b01f0a..230b6952f 100644 --- a/lib/WebGUI/Form.pm +++ b/lib/WebGUI/Form.pm @@ -24,6 +24,7 @@ use WebGUI::SQL; use WebGUI::Style; use WebGUI::Template; use WebGUI::URL; +use WebGUI::Utility; =head1 NAME @@ -459,7 +460,59 @@ sub dateTime { '; } +#------------------------------------------------------------------- +=head2 dynamicField ( fieldType , hashRef ) + +Returns a dynamic configurable field. + +=over + +=item fieldType + +The field type to use. The field name is the name of the method from this forms package. + +=item options + +The field options. See the documentation for the desired field for more information. + +=back + +=cut + +sub dynamicField { + my $fieldType = shift; + my $param = shift; + + # Set options for fields that use a list. + if (isIn($fieldType,qw(selectList checkList radioList))) { + delete $param->{size}; + my %options; + tie %options, 'Tie::IxHash'; + foreach (split(/\n/, $param->{possibleValues})) { + s/\s+$//; # remove trailing spaces + $options{$_} = $_; + } + if (exists $param->{options} && ref($param->{options}) eq "HASH") { + %options = (%{$param->{options}} , %options); + } + $param->{options} = \%options; + } + # Convert value to list for selectList / checkList + if (isIn($fieldType,qw(selectList checkList)) && ref $param->{value} ne "ARRAY") { + my @defaultValues; + foreach (split(/\n/, $param->{value})) { + s/\s+$//; # remove trailing spaces + push(@defaultValues, $_); + } + $param->{value} = \@defaultValues; + } + + # Return the appropriate field. + no strict 'refs'; + return &$fieldType($param); + +} #------------------------------------------------------------------- diff --git a/lib/WebGUI/HTMLForm.pm b/lib/WebGUI/HTMLForm.pm index a223fc4f3..525e5ad8c 100644 --- a/lib/WebGUI/HTMLForm.pm +++ b/lib/WebGUI/HTMLForm.pm @@ -726,33 +726,9 @@ sub dynamicField { $param{$1} = $param{$key}; delete $param{$key}; } - # Set options for fields that use a list. - if (isIn($fieldType,qw(selectList checkList radioList))) { - delete $param{size}; - my %options; - tie %options, 'Tie::IxHash'; - foreach (split(/\n/, $param{possibleValues})) { - s/\s+$//; # remove trailing spaces - $options{$_} = $_; - } - $param{options} = \%options; - } - # Convert value to list for selectList / checkList - if (isIn($fieldType,qw(selectList checkList)) && ref $param{value} ne "ARRAY") { - my @defaultValues; - foreach (split(/\n/, $param{value})) { - s/\s+$//; # remove trailing spaces - push(@defaultValues, $_); - } - $param{value} = \@defaultValues; - } - - - my $cmd = "WebGUI::Form::".$fieldType; my $output; if (_uiLevelChecksOut($param{uiLevel})) { - no strict "refs"; - $output = &$cmd(\%param); + $output = WebGUI::Form::dynamicField($fieldType, \%param); $output .= _subtext($param{subtext}); $output = $self->_tableFormRow($param{label},$output); } else { diff --git a/lib/WebGUI/MetaData.pm b/lib/WebGUI/MetaData.pm index 5b9034e00..d67313a6a 100644 --- a/lib/WebGUI/MetaData.pm +++ b/lib/WebGUI/MetaData.pm @@ -18,6 +18,7 @@ package WebGUI::MetaData; use strict; use WebGUI::Session; use WebGUI::SQL; +use WebGUI::Macro; use Tie::IxHash; =head1 NAME @@ -42,8 +43,9 @@ These functions/methods are available from this package: #------------------------------------------------------------------- + -=head2 getFieldTypes ( ) +=head2 getFieldTypes () Returns an array ref with supported metadata field types. @@ -164,6 +166,8 @@ sub getMetaDataFields { Saves posted metadata for requested wobjectId +=over + =item wobjectId The Id from the wobject you want to save metadata for. @@ -203,6 +207,8 @@ sub metaDataSave { Deletes the metadata for requested wobjectId +=over + =item wobjectId The Id from the wobject you want to delete metadata for. @@ -222,6 +228,8 @@ sub metaDataDelete { Duplicates Metadata +=over + =item fromWobjectId The original wobject Id @@ -246,5 +254,128 @@ sub MetaDataDuplicate { } +#------------------------------------------------------------------- + +=head2 getWobjectByCriteria ( hashRef ) + +This function will search for a wobject that match a metadata criteria set. +If no wobject is found, undef will be returned. + +=over + +=item hashRef + +A typical hashRef for this function will look like: + +{ + proxiedNamespace => "Article", + resolveMultiples => "random", + proxyCriteria => "State = Wisconsin AND Country != Sauk" +} + +Most of the time this will be a: + +WebGUI::SQL->quickHashRef("select * from WobjectProxy where wobjectId=$proxiedId"); + +=back + +=cut + +sub getWobjectByCriteria { + my $wobjectProxy = shift; + my $criteria = $wobjectProxy->{proxyCriteria}; + my $order = $wobjectProxy->{resolveMultiples}; + my $namespace = $wobjectProxy->{proxiedNamespace}; + my $wobjectId = $wobjectProxy->{wobjectId}; + + # Once a wobject is found, we will stick to that wobject, + # to prevent the proxying of multiple- depth wobjects like Surveys and USS. + my $scratchId; + if ($wobjectId) { + $scratchId = "WobjectProxy_" . $wobjectId; + if($session{scratch}{$scratchId}) { + return $session{scratch}{$scratchId}; + } + } + + # $criteria = "State = Wisconsin AND Country != Sauk"; + # + # State = Wisconsin AND Country != Sauk + # | | | + # |- $field |_ $operator |- $value + # |_ $attribute |_ $attribute + my $operator = qr/<>|!=|=|>=|<=|>|<|like/i; + my $attribute = qr/['"][^()|=>unconditionalRead($sql); + while (my ($data) = $sth->array) { + push (@wids, $data); + } + $sth->finish; + + # No matching wobjects found. + if (scalar(@wids) == 0) { + return undef; + } + my $wid; + # Grab a wid from the results + if ($order = 'random') { + $wid = $wids[ rand @wids ]; + } else { + #default order is mostRecent + $wid = $wids[0]; # 1st element in list is most recent. + } + + # Store the matching wobjectId in user scratch. + WebGUI::Session::setScratch($scratchId,$wid) if ($scratchId); + + return $wid; +} + 1; diff --git a/lib/WebGUI/Page.pm b/lib/WebGUI/Page.pm index 288d44e36..96d20f723 100644 --- a/lib/WebGUI/Page.pm +++ b/lib/WebGUI/Page.pm @@ -31,6 +31,7 @@ use WebGUI::Style; use WebGUI::Template; use WebGUI::Utility; use DBIx::Tree::NestedSet; +use WebGUI::MetaData; our @ISA = qw(DBIx::Tree::NestedSet); @@ -478,7 +479,10 @@ sub generate { if (${$wobject}{namespace} eq "WobjectProxy") { my $originalWobject = $wobject; my ($wobjectProxy) = WebGUI::SQL->quickHashRef("select * from WobjectProxy where wobjectId=".${$wobject}{wobjectId},WebGUI::SQL->getSlave); - $wobject = WebGUI::SQL->quickHashRef("select * from wobject where wobject.wobjectId=".$wobjectProxy->{proxiedWobjectId},WebGUI::SQL->getSlave); + if($wobjectProxy->{proxyByCriteria}) { + $wobjectProxy->{proxiedWobjectId} = WebGUI::MetaData::getWobjectByCriteria($wobjectProxy) || $wobjectProxy->{proxiedWobjectId}; + } + $wobject = WebGUI::SQL->quickHashRef("select * from wobject where wobject.wobjectId=".$wobjectProxy->{proxiedWobjectId},WebGUI::SQL->getSlave); if (${$wobject}{namespace} eq "") { $wobject = $originalWobject; } else { diff --git a/lib/WebGUI/Wobject.pm b/lib/WebGUI/Wobject.pm index 377533f8a..72c630843 100644 --- a/lib/WebGUI/Wobject.pm +++ b/lib/WebGUI/Wobject.pm @@ -1476,7 +1476,8 @@ sub www_edit { -uiLevel=>5, -value=>$meta->{$field}{value}, -extras=>qq/title="$meta->{$field}{description}"/, - -possibleValues=>$meta->{$field}{possibleValues} + -possibleValues=>$meta->{$field}{possibleValues}, + -options=>{"", WebGUI::International::get("Select...","MetaData")} ); } } diff --git a/lib/WebGUI/Wobject/WobjectProxy.pm b/lib/WebGUI/Wobject/WobjectProxy.pm index a75987c7d..49974ea87 100644 --- a/lib/WebGUI/Wobject/WobjectProxy.pm +++ b/lib/WebGUI/Wobject/WobjectProxy.pm @@ -22,6 +22,7 @@ use WebGUI::Page; use WebGUI::TabForm; use WebGUI::Template; use WebGUI::Wobject; +use WebGUI::MetaData; our @ISA = qw(WebGUI::Wobject); @@ -64,7 +65,19 @@ sub new { proxiedTemplateId=>{ fieldType=>"template", defaultValue=>1 - } + }, + proxyByCriteria=>{ + fieldType=>"yesNo", + defaultValue=>0, + }, + resolveMultiples=>{ + fieldType=>"selectList", + defaultValue=>"mostRecent", + }, + proxyCriteria=>{ + fieldType=>"textarea", + defaultValue=>"", + }, } ); bless $self, $class; @@ -111,13 +124,171 @@ sub www_edit { -label=>WebGUI::International::get(1,$_[0]->get("namespace")), -value=>''.$data[1].' ('.$_[0]->get("proxiedWobjectId").')' ); + $properties->yesNo( + -name=>"proxyByCriteria", + -value=>$_[0]->getValue("proxyByCriteria"), + -label=>WebGUI::International::get("Proxy by alternate criteria?",$_[0]->get("namespace")), + -extras=>q|Onchange=" + if (this.form.proxyByCriteria[0].checked) { + this.form.resolveMultiples.disabled=false; + this.form.proxyCriteria.disabled=false; + } else { + this.form.resolveMultiples.disabled=true; + this.form.proxyCriteria.disabled=true; + }"| + ); + my $extras; + if ($_[0]->getValue("proxyByCriteria") == 0) { + $extras = 'disabled=true'; + } + $properties->selectList( + -name=>"resolveMultiples", + -value=>[ $_[0]->getValue("resolveMultiples") ], + -label=>WebGUI::International::get("Resolve Multiples?",$_[0]->get("namespace")), + -options=>{ + mostRecent=>WebGUI::International::get("Most Recent",$_[0]->get("namespace")), + random=>WebGUI::International::get("Random",$_[0]->get("namespace")), + }, + -extras=>$extras + ); + + $properties->readOnly( + -value=>$_[0]->_drawQueryBuilder(), + -label=>WebGUI::International::get("Criteria",$_[0]->get("namespace")), + + ); return $_[0]->SUPER::www_edit( -properties=>$properties->printRowsOnly, -layout=>$layout->printRowsOnly, -headingId=>2, -helpId=>"wobject proxy add/edit" ); +} +#------------------------------------------------------------------- +sub _drawQueryBuilder { + # Initialize operators + my @textFields = qw|text yesNo selectList radioList|; + my %operator; + foreach (@textFields) { + $operator{$_} = { + "=" => WebGUI::International::get("is",$_[0]->get("namespace")), + "!=" => WebGUI::International::get("isnt",$_[0]->get("namespace")) + }; + } + $operator{integer} = { + "=" => WebGUI::International::get("equal to",$_[0]->get("namespace")), + "!=" => WebGUI::International::get("not equal to",$_[0]->get("namespace")), + "<" => WebGUI::International::get("less than",$_[0]->get("namespace")), + ">" => WebGUI::International::get("greater than",$_[0]->get("namespace")) + }; + + # Get the fields and count them + my $fields = WebGUI::MetaData::getMetaDataFields(); + my $fieldCount = scalar(keys %$fields); + + unless ($fieldCount) { # No fields found.... + return 'No metadata defined yet. + Click here to define metadata attributes.'; + } + + # Static form fields + my $proxyCriteriaField = WebGUI::Form::textarea({ + name=>"proxyCriteria", + value=>$_[0]->getValue("proxyCriteria"), + }); + my $conjunctionField = WebGUI::Form::selectList({ + name=>"conjunction", + options=>{ + "AND" => WebGUI::International::get("AND",$_[0]->get("namespace")), + "OR" => WebGUI::International::get("OR",$_[0]->get("namespace"))}, + value=>["OR"], + extras=>'class="qbselect"', + }); + + # html + my $output; + $output .= ''; + $output .= ''; + + $output .= qq| + + + + + + + + + + + + + + + + + + |; + + # Here starts the field loop + foreach my $field (keys %$fields) { + my $fieldLabel = $fields->{$field}{fieldName}; + my $fieldType = $fields->{$field}{fieldType} || "text"; + + # The operator select field + my $opFieldName = "op_field".$fields->{$field}{fieldId}; + my $opField = WebGUI::Form::selectList({ + name=>$opFieldName, + uiLevel=>5, + options=>$operator{$fieldType}, + extras=>'class="qbselect"' + }); + # The value select field + my $valFieldName = "val_field".$fields->{$field}{fieldId}; + my $valueField = WebGUI::Form::dynamicField($fieldType, { + name=>$valFieldName, + uiLevel=>5, + extras=>qq/title="$fields->{$field}{description}" class="qbselect"/, + possibleValues=>$fields->{$field}{possibleValues}, + }); + # An empty row + $output .= qq| + + + + + + + + |; + + # Table row with field info + $output .= qq| + + + + + + + + |; + } + # Close the table + $output .= "
$proxyCriteriaField
+
+ $conjunctionField +

$fieldLabel

+ $opField + + $valueField + +
"; + + return $output; } #------------------------------------------------------------------- diff --git a/lib/WebGUI/i18n/English/MetaData.pm b/lib/WebGUI/i18n/English/MetaData.pm index dfaa9eb2b..76096939a 100644 --- a/lib/WebGUI/i18n/English/MetaData.pm +++ b/lib/WebGUI/i18n/English/MetaData.pm @@ -50,8 +50,10 @@ our $I18N = { message => q|Enable passive profiling ?|, lastUpdated=> 1089039511, }, - - + 'Select...' => { + message => q|Select...|, + lastUpdated=> 1089039511, + }, }; 1; diff --git a/lib/WebGUI/i18n/English/WobjectProxy.pm b/lib/WebGUI/i18n/English/WobjectProxy.pm index 48e7b1b3a..e49f8813b 100644 --- a/lib/WebGUI/i18n/English/WobjectProxy.pm +++ b/lib/WebGUI/i18n/English/WobjectProxy.pm @@ -79,6 +79,71 @@ Set to "yes" to use the template of the wobject proxy instead of the original te lastUpdated => 1053183804, context => q|Asking the user if s/he would like to use the description specified in the wobject proxy or the original description of the original wobject.| }, + 'Proxy by alternate criteria?' => { + message => q|Proxy by alternate criteria?|, + lastUpdated => 1053183804, + context => q|Asking the user if s/he would like to use alternate criteria to find a matching a wobject to proxy.| + }, + 'Resolve Multiples?' => { + message => q|Resolve Multiples?|, + lastUpdated => 1053183804, + context => q|Asking the user what sort order (random / most recent) to use if multiple hits are found.| + }, + 'Most Recent' => { + message => q|Most Recent|, + lastUpdated => 1053183804, + context => q|Selectlist item for "Resolve Multiples?"| + }, + 'Random' => { + message => q|Random|, + lastUpdated => 1053183804, + context => q|Selectlist item for "Resolve Multiples?"| + }, + 'Criteria' => { + message => q|Criteria|, + lastUpdated => 1053183804, + context => q|Label for the criteria textarea| + }, + 'AND' => { + message => q|AND|, + lastUpdated => 1053183804, + context => q|Part of the WobjectProxy Query Builder| + }, + 'OR' => { + message => q|OR|, + lastUpdated => 1053183804, + context => q|Part of the WobjectProxy Query Builder| + }, + 'is' => { + message => q|is|, + lastUpdated => 1053183804, + context => q|Part of the WobjectProxy Query Builder| + }, + 'isnt' => { + message => q|isn't|, + lastUpdated => 1053183804, + context => q|Part of the WobjectProxy Query Builder| + }, + "less than" => { + message => q|less than|, + lastUpdated => 1053183804, + context => q|Part of the WobjectProxy Query Builder| + }, + "equal to" => { + message => q|equal to|, + lastUpdated => 1053183804, + context => q|Part of the WobjectProxy Query Builder| + }, + "greater than" => { + message => q|greater than|, + lastUpdated => 1053183804, + context => q|Part of the WobjectProxy Query Builder| + }, + "not equal to" => { + message => q|not equal to|, + lastUpdated => 1053183804, + context => q|Part of the WobjectProxy Query Builder| + }, }; diff --git a/www/extras/wobject/WobjectProxy/hline.gif b/www/extras/wobject/WobjectProxy/hline.gif new file mode 100644 index 0000000000000000000000000000000000000000..2d350cd548494671111d9d5bc7efcccfa9d67252 GIT binary patch literal 848 zcmZ?wbhEHb6k!lyXlED&qaiS&LqPE-3nK#qBZCeo6hL``fkT&pnM1~7!-9j&9Ku>L oCpIiR+%BLj$KtSY(a~-RTC0M7LnBme*a literal 0 HcmV?d00001 diff --git a/www/extras/wobject/WobjectProxy/querybuilder.css b/www/extras/wobject/WobjectProxy/querybuilder.css new file mode 100644 index 000000000..cf81e283b --- /dev/null +++ b/www/extras/wobject/WobjectProxy/querybuilder.css @@ -0,0 +1,42 @@ +.qbtd { + height: 20px; + background-image: url(/extras/wobject/WobjectProxy/hline.gif); + padding-left: 5px; + padding-right: 5px; +} + +.qbtdleft { + height: 20px; + background-image: url(/extras/wobject/WobjectProxy/hline.gif); + padding-right: 5px; +} + +.qbtdright { + height: 20px; + background-image: url(/extras/wobject/WobjectProxy/vline.gif); + background-repeat: repeat-y; + align: right; +} + +.qbfieldLabel { + text-align: left; + font-size: 12px; + border-style: solid; + border-width: 1px; + padding-right: 4px; + padding-left: 4px; + background-color: white; +} + +.qbselect { + height: 20px; + font-size: 12px; +} + +.qbText { + background-color: white; + text-align: left; + font-size: 12px; + +} + diff --git a/www/extras/wobject/WobjectProxy/querybuilder.js b/www/extras/wobject/WobjectProxy/querybuilder.js new file mode 100644 index 000000000..9eca475d2 --- /dev/null +++ b/www/extras/wobject/WobjectProxy/querybuilder.js @@ -0,0 +1,35 @@ +function addCriteria ( fieldname, opform, valform ) { + var form = opform.form; + var operator = getValue(opform); + var value = getValue(valform); + var criteria = form.proxyCriteria.value; + var conjunction = ""; + var re = /^\s*$/; + if(! re.test(criteria)) { + conjunction = " " + getValue(form.conjunction) + " "; + } + if(/\s+/.test(fieldname)) { + fieldname = '"' + fieldname + '"'; + } + var statement = fieldname + " " + operator + " " + '"' + value + '"'; + form.proxyCriteria.value = criteria + conjunction + statement; +} + +function getValue(sel) { + if(sel.type == "text") { + return sel.value; + } + for(i=0;i