Fixed some bugs and refactored some parts of the SQLForm.

This commit is contained in:
Martin Kamerbeek 2006-09-29 13:16:11 +00:00
parent 2d2b780ed6
commit 9096e6f9fe
2 changed files with 212 additions and 76 deletions

View file

@ -4,6 +4,10 @@
- fix: leftover discussion template variables in Default Article template
- fix: Stock Data asset insufficiently robust handling erroneous data
- refactor: move getEditForm data into definition for Collaboration asset
- Fixed some bugs in the SQLForm. Also refactored parts of the SQLForm to
reduce the number of database queries and lessen the amount of data being
uploaded when images are put in the form. (Martin Kamerbeek / Procolix)
7.0.8
- Fixed a couple of minor bugs with the default values of the Request

View file

@ -3,7 +3,7 @@ package WebGUI::Asset::Wobject::SQLForm;
=head1 LEGAL
-------------------------------------------------------------------
SQLForm is Copyright 2006 Procolix
/SQLForm is Copyright 2006 Procolix
-------------------------------------------------------------------
Please read the legal notices (legal.txt) and the license
(license.txt) that came with this distribution before using
@ -22,6 +22,7 @@ use WebGUI::Asset::Wobject;
use WebGUI::Utility;
use WebGUI::DatabaseLink;
use WebGUI::International;
use WebGUI::User;
use Storable;
use Tie::IxHash;
@ -636,6 +637,8 @@ sub _getFieldProperties {
my $self = shift;
$fieldId = shift;
return $self->{_fieldPropertiesCache}->{$fieldId} if exists ($self->{_fieldPropertiesCache}->{$fieldId});
$dbLink = $self->_getDbLink;
%definition = $self->session->db->buildHash("select property, value from SQLForm_fieldDefinitions where fieldId = ".$self->session->db->quote($fieldId));
@ -679,6 +682,8 @@ my $sth = $dbLink->db->unconditionalRead($definition{sqlQuery}." order by ".$de
$properties->{processedDefaultValue} = WebGUI::Macro::process($self->session, $definition{defaultValue});
$properties->{fieldId} = $fieldId;
$self->{_fieldPropertiesCache}->{$fieldId} = {%definition, %$properties};
return {%definition, %$properties};
}
@ -720,6 +725,57 @@ sub _getDatabaseInfo {
return $databaseDefinition;
}
#-------------------------------------------------------------------
=head2 _getFileFromDatabase ( recordId, fieldName, [ revision ] )
Returns the file contents and mime type of files stored in file fields.
=head3 recordId
The recordId of the record you want the file contents of.
=head3 fieldName
The the name of the column containing the actual file data.
=head3 revision
The revision number of the record you wan to select. If this is omitted the most
recent revision will be fetched.
=cut
sub _getFileFromDatabase {
my ($constraint, $dbLink);
my $self = shift;
my $recordId = shift || return undef;
my $fieldName = shift || return undef;
my $revision = shift;
$dbLink = $self->_getDbLink;
if ($revision =~ m/^\d+$/) {
$constraint = '__revision='.$self->session->db->quote($revision);
} else {
$constraint = '__archived = 0';
}
my $sql =
'select '.
' __'.$fieldName.'_mimeType, '.
$fieldName.
' from '.
$self->get('tableName').
' where '.
'__recordId='.$self->session->db->quote($recordId).' and '.
$constraint;
return $dbLink->db->quickArray($sql);
}
#-------------------------------------------------------------------
=head2 _getManagementLinks ( )
@ -805,6 +861,26 @@ sub _resolveFieldConstraintType {
#-------------------------------------------------------------------
=head2 _uncacheFieldProperties ( fieldId )
Removes the cached properties of the given field. Fiekd properties are automatically cached
by _getFieldProperties.
=head3 fieldId
The GUID of the field to uncache the properties of.
=cut
sub _uncacheFieldProperties {
my $self = shift;
my $fieldId = shift;
delete($self->{_fieldPropertiesCache}->{$fieldId});
}
#-------------------------------------------------------------------
=head2 definition ( )
The asset definition of the SQLForm.
@ -1821,6 +1897,7 @@ sub www_editFieldSave {
} else {
$fieldId = $self->session->form->process("fid");
$properties = $self->session->db->buildHashRef("select property, value from SQLForm_fieldDefinitions where fieldId=".$self->session->db->quote($fieldId));
$self->_uncacheFieldProperties($fieldId);
}
# If no value (or zero) is given for any of these values just discard them and use the WebGUI defaults.
@ -2216,6 +2293,7 @@ sub _getFieldValue {
if ($field->{canHaveMultipleValues} && !$readOnly) {
$fieldValue = [ $recordValues->{$field->{fieldName}} ];
$fieldValue = [ $self->session->request->param($field->{fieldName}) ] if (defined $self->session->form->process($field->{fieldName}));
$fieldValue = join(', ', @$fieldValue) if ($readOnly);
}
# Handle file uploads
@ -2225,8 +2303,8 @@ sub _getFieldValue {
} else {
$fieldValue = '<a href="'.$self->session->url->page('func=viewFile;rid='.$self->session->form->process("rid").';fid='.$_, $self->getUrl).'">';
if ($recordValues->{'__'.$field->{fieldName}.'_mimeType'} =~ /^image/i) {
$fieldValue .= '<img width="100" src="'.
$self->session->url->page('func=viewFile;rid='.$self->session->form->process("rid").'&fid='.$_, $self->getUrl).'" />';
$fieldValue .= '<img src="'.
$self->session->url->page('func=viewThumbnail;rid='.$self->session->form->process("rid").'&fid='.$_, $self->getUrl).'" />';
} else {
$fieldValue .= WebGUI::Internation::get('click here for file', 'Asset_SQLForm');
}
@ -2273,28 +2351,31 @@ sub _getFormElement {
$fieldValue = $field->{allOptions}->{$fieldValue} if ($field->{hasOptions} && $readOnly);
$maxLength = $field->{maxFieldLength} || $allowedDbFieldTypes->{$field->{dbFieldType}}->{maxLength};
# Set up form element parameters
$fieldParameters->{name} = $field->{fieldName};
$fieldParameters->{value} = $fieldValue;
$fieldParameters->{options} = $field->{options} if ($field->{hasOptions});
$fieldParameters->{options}->{''} = '-leave empty-' if (!$field->{isRequired});
$fieldParameters->{multiple} = $field->{multipleAllowed} == 1;
$fieldParameters->{$field->{widthParam}} = $field->{formFieldWidth} if ($field->{formFieldWidth});
$fieldParameters->{$field->{heightParam}} = $field->{formFieldHeight} if ($field->{formFieldHeight});
$fieldParameters->{maxlength} = $maxLength;
$fieldParameters->{extras} = 'onkeyup="if (this.value.length > '.$maxLength.') {this.value = this.value.substring(0,'.$maxLength.');}"';
$fieldParameters->{id} = 'sqlform'.$field->{fieldId};
# Construct the form element
if ($readOnly) {
$formElement = $fieldValue;
} else {
# Set up form element parameters
$fieldParameters->{options} = $field->{options};
# make sure that previously selected items still appear for this for element, even if
# if is set to a set difference.
@{$fieldParameters->{options}}{@$fieldValue} = @{$field->{allOptions}}{@$fieldValue} if ($fieldValue && $field->{hasOptions});
$fieldParameters->{options}->{''} = '-leave empty-' if (!$field->{isRequired});
$fieldParameters->{name} = $field->{fieldName};
$fieldParameters->{value} = $fieldValue unless ($fieldType eq 'file');
$fieldParameters->{multiple} = $field->{multipleAllowed} == 1;
$fieldParameters->{$field->{widthParam}} = $field->{formFieldWidth} if ($field->{formFieldWidth});
$fieldParameters->{$field->{heightParam}} = $field->{formFieldHeight} if ($field->{formFieldHeight});
$fieldParameters->{maxlength} = $maxLength;
$fieldParameters->{extras} = 'onkeyup="if (this.value.length > '.$maxLength.') {this.value = this.value.substring(0,'.$maxLength.');}"';
$fieldParameters->{id} = 'sqlform'.$field->{fieldId};
# Show file if a file is uploaded
$formElement = $fieldValue.'<br />' if ($fieldType eq 'file' && $fieldValue);
# Add form element
$cmd = 'WebGUI::Form::'.$fieldType.'($self->session, $fieldParameters)';
$formElement = eval($cmd);
$formElement .= eval($cmd);
$self->session->errorHandler->fatal('Could not instanciate formelement via WebGUI::Form: '.$@) if ($@);
if ($fieldType eq 'selectList' && !$field->{isRequired}) {
@ -3110,49 +3191,57 @@ sub www_viewHistory {
return $self->session->privilege->insufficient() unless ($self->canView);
my $dbLink = $self->_getDbLink;
my $output = $self->_getManagementLinks;
my $recordId = $self->session->form->process("rid");
my $recordId = $self->session->form->process('rid');
my @fields = $self->session->db->buildArray(
" select distinct t1.value ".
" from SQLForm_fieldDefinitions as t1, SQLForm_fieldOrder as t2 ".
" where t1.fieldId=t2.fieldId and t1.assetId=t2.assetId and t1.property='fieldName' and t1.assetId=".$self->session->db->quote($self->getId).
" order by t2.rank"
);
my @fieldNames = $self->session->db->buildArray(
" select distinct t1.value ".
" from SQLForm_fieldDefinitions as t1, SQLForm_fieldOrder as t2 ".
" where t1.fieldId=t2.fieldId and t1.assetId=t2.assetId and t1.property='displayName' and t1.assetId=".$self->session->db->quote($self->getId).
" order by t2.rank"
my @includeMetaFields = qw|__recordId __initDate __userId __revision|;
my @metaFieldHeadings = ("Record ID", "Changed on", "Changed by", "Revision #");
my @fieldIds = $self->session->db->buildArray(
" select fieldId "
." from SQLForm_fieldOrder "
." where assetId=".$self->session->db->quote($self->getId)
." order by rank"
);
my $sth = $dbLink->db->read("select ".
" t1.__recordId, from_unixtime(t1.__initDate) as __initDate, ".
" t1.__userId, t1.__revision, ".
join(', ', map {"t1.$_"} @fields).
" from ".$self->get('tableName')." as t1".
" where t1.__recordId=".$self->session->db->quote($recordId).
" order by t1.__revision");
$output .= '<br /><table border="0" cellspacing="0" cellpadding="3px" >';
my $tableHeading = '<tr><th>'.join('</th><th>', (@metaFieldHeadings, map {$self->_getFieldProperties($_)->{displayName}} @fieldIds)).'</th></tr>';
$output .= '<tr align="left"><th>Rev</th><th>Init date</th><th style="border-right: 2px solid black">User</th>';
$output .= '<th align="left">'.join('</th><th align="left">', @fieldNames).'</th></tr>';
my %userCache;
while (my %row = $sth->hash) {
$userCache{$row{__userId}} = WebGUI::User->new($self->session, $row{__userId}) unless (exists $userCache{$row{__userId}});
my $username = $userCache{$row{__userId}}->username || $row{__userId};
$output .= '<tr align="right" style="border: 10px solid #bbb">';
$output .= '<td align="right" style="border: 1px solid #bbb">'.$row{__revision}.'</td>';
$output .= '<td align="right" style="border: 1px solid #bbb">'.$row{__initDate}.'</td>';
$output .= '<td align="right" style="border: 1px solid #bbb; border-right: 2px solid black">'.$username.'</td>';
$output .= '<td align="right" style="border: 1px solid #bbb">'.join('</td><td align="right" style="border: 1px solid #bbb">', map {$row{$_}} @fields).'</td>';
$output .= '</tr>';
my $sth = $dbLink->db->read('select * from '.$self->get('tableName').' where __recordId='.$dbLink->db->quote($recordId).' order by __revision');
my ($tableBody);
while (my $row = $sth->hashRef) {
$row->{__initDate} = $self->session->datetime->epochToHuman($row->{__initDate});
$row->{__userId} = WebGUI::User->new($self->session, $row->{__userId})->username;
$tableBody .= '<tr>';
$tableBody .= '<td>'.join('</td><td>', map {$row->{$_}} @includeMetaFields).'</td>';
foreach (@fieldIds) {
my $field = $self->_getFieldProperties($_);
$tableBody .= '<td>';
if ($field->{formFieldType} eq 'file') {
$tableBody .= '<a href="'.$self->getUrl('func=viewFile;rid='.$row->{__recordId}.';rev='.$row->{__revision}.';fid='.$_).'">';
if ($row->{'__'.$field->{fieldName}.'_mimeType'} =~ /^image/) {
$tableBody .= '<img src="'.$self->getUrl('func=viewThumbnail;rid='.$row->{__recordId}.';rev='.$row->{__revision}.';fid='.$_).'">';
} else {
$tableBody .= 'Click here for file.';
}
$tableBody .= '</a>';
} else {
if ($field->{hasOptions}) {
$tableBody .= $field->{allOptions}->{$row->{$field->{fieldName}}};
} else {
$tableBody .= $row->{$field->{fieldName}};
}
}
$tableBody .= '</td>';
}
$tableBody .= '</tr>';
}
my $output = $self->_getManagementLinks;
$output .= '<style type="text/css">.historyTable td, th { border: 1px solid #ccc; padding: 2px; }</style>';
$output .= '<table class="historyTable">';
$output .= $tableHeading;
$output .= $tableBody;
$output .= '</table>';
$dbLink->disconnect;
@ -3163,7 +3252,7 @@ sub www_viewHistory {
=head2 www_viewFile ( )
Returns the file saved in a file upolad field, and sets the mime-type to the correct value. Pass the record id
Returns the file saved in a file upload field, and sets the mime-type to the correct value. Pass the record id
via form param 'rid' and the field id of the upload field through form param 'fid'. Optionally you can pass the
revision number in form param 'rev'; otherwise the latest revision is used.
@ -3175,27 +3264,14 @@ sub www_viewFile {
return $self->session->privilege->insufficient() unless ($self->canView);
my $dbLink = $self->_getDbLink;
my $fieldId = $self->session->form->process('fid');
my $recordId = $self->session->form->process('rid');
my $revision = $self->session->form->process('rev');
$field = $self->_getFieldProperties($self->session->form->process("fid"));
$field = $self->_getFieldProperties($fieldId);
if ($field->{formFieldType} eq 'file') {
if ($self->session->form->process("rev") =~ m/^\d+$/) {
$revision = '__revision='.$self->session->db->quote($self->session->form->process("rev"));
} else {
$revision = '__archived=0';
}
my $sql =
'select '.
' __'.$field->{fieldName}.'_mimeType, '.
$field->{fieldName}.
' from '.
$self->get('tableName').
' where '.
'__recordId='.$self->session->db->quote($self->session->form->process("rid")).' and '.
$revision;
my ($mimeType, $data) = $dbLink->db->quickArray($sql);
my ($mimeType, $data) = $self->_getFileFromDatabase($recordId, $field->{fieldName}, $revision);
$self->session->http->setMimeType($mimeType);
return $data;
@ -3204,6 +3280,61 @@ sub www_viewFile {
return "No file found";
}
#-------------------------------------------------------------------
=head2 www_viewThumbnail ( )
Returns a thumbnail of the image stored in an upload field.
This particular caching scheme is used in stead of storage, since privileges should still be checked.
=cut
sub www_viewThumbnail {
my ($field, $revision, $thumbnailData);
my $self = shift;
return $self->session->privilege->insufficient() unless ($self->canView);
my $fieldId = $self->session->form->process('fid');
my $recordId = $self->session->form->process('rid');
my $revision = $self->session->form->process('rev');
$field = $self->_getFieldProperties($self->session->form->process("fid"));
if ($field->{formFieldType} eq 'file') {
my $cache = WebGUI::Cache->new($self->session, ["sqlform",$recordId,$fieldId,$revision], 24*60*60);
$thumbnailData = $cache->get;
unless ($thumbnailData) {
my ($mimeType, $data) = $self->_getFileFromDatabase($recordId, $field->{fieldName}, $revision);
# Create thumbnail. I use this method b/c it seems to be impossible to feed
# image magick scalars containing pictures. Even using IO::Scalar or PerlIO::Scalar.
# This is b/c Image::Magick cannot handle perl GLOBS.
my $tempStorage = WebGUI::Storage::Image->createTemp($self->session);
$tempStorage->addFileFromScalar('tempthumb.png', $data);
$tempStorage->generateThumbnail('tempthumb.png', 100);
open my $FH1, "<", $tempStorage->getPath().'/thumb-tempthumb.png';
while (<$FH1>) {
$thumbnailData .= $_;
}
close $FH1;
$tempStorage->delete;
$cache->set($thumbnailData);
}
$self->session->http->setMimeType('image/png');
return $thumbnailData;
}
return "No file found";
}
#-------------------------------------------------------------------
=head2 www_restoreRecord ( )
@ -3833,8 +3964,7 @@ my $searchType = ($self->session->form->process("searchType") || $self->session-
return undef if (!@constraints);
# Construct the search query
my $sql = " select distinct ".join(', ', @selectColumns); #t1.__recordId, t1.__deletionDate, t1.__deletedBy, t1.__initDate, t1.__userId, t1.__deleted, t1.__archived, t1.__revision ";
# $sql .= ", ".join(", \n", map {"t1.".$fieldProperties->{$_}->{fieldName}} @$showFields)."\n";
my $sql = " select distinct ".join(', ', @selectColumns);
$sql .= " from ".$self->get('tableName').' as t1 ';
$sql .= " left join ".join(" left join \n", @joinSequence)."\n" if (@joinSequence);
$sql .= " where ";
@ -3945,7 +4075,9 @@ my $value;
if ($fieldProperties->{$_}->{formFieldType} eq 'file') {
$props->{'record.value.isFile'} = 1;
$props->{'record.value.isImage'} = 1 if ($row{'__'.$fieldProperties->{$_}->{fieldName}.'_mimeType'} =~ m/^image/);
print "[".'__'.$fieldProperties->{$_}->{fieldName}.'_mimeType'."]";
$props->{'record.value.thumbnailUrl'} =
$self->getUrl('func=viewThumbnail;rid='.$row{__recordId}.';fid='.$_);
$props->{'record.value.downloadUrl'} =
$self->getUrl('func=viewFile;rid='.$row{__recordId}.';fid='.$_);
}