package WebGUI::Asset::MatrixListing;
=head1 LEGAL
-------------------------------------------------------------------
WebGUI is Copyright 2001-2009 Plain Black Corporation.
-------------------------------------------------------------------
Please read the legal notices (docs/legal.txt) and the license
(docs/license.txt) that came with this distribution before using
this software.
-------------------------------------------------------------------
http://www.plainblack.com info@plainblack.com
-------------------------------------------------------------------
=cut
use strict;
use Tie::IxHash;
use Class::C3;
use base qw(WebGUI::AssetAspect::Comments WebGUI::Asset);
use WebGUI::Utility;
=head1 NAME
Package WebGUI::Asset::MatrixListing
=head1 DESCRIPTION
Describe your New Asset's functionality and features here.
=head1 SYNOPSIS
use WebGUI::Asset::MatrixListing;
=head1 METHODS
These methods are available from this class:
=cut
#-------------------------------------------------------------------
=head2 addRevision
This method exists for demonstration purposes only. The superclass
handles revisions to MatrixListing Assets.
=cut
sub addRevision {
my $self = shift;
my $newSelf = $self->next::method(@_);
return $newSelf;
}
#-------------------------------------------------------------------
=head2 definition ( session, definition )
defines asset properties for MatrixListing instances.
=head3 session
=head3 definition
A hash reference passed in from a subclass definition.
=cut
sub definition {
my $class = shift;
my $session = shift;
my $definition = shift;
my %properties;
tie %properties, 'Tie::IxHash';
my $i18n = WebGUI::International->new($session, "Asset_MatrixListing");
%properties = (
screenshots => {
tab =>"properties",
fieldType =>"image",
defaultValue =>undef,
maxAttachments =>20,
label =>$i18n->get("screenshots label"),
hoverHelp =>$i18n->get("screenshots description")
},
description => {
tab =>"properties",
fieldType =>"HTMLArea",
defaultValue =>undef,
label =>$i18n->get("description label"),
hoverHelp =>$i18n->get("description description")
},
version => {
tab =>"properties",
fieldType =>"text",
defaultValue =>undef,
label =>$i18n->get("version label"),
hoverHelp =>$i18n->get("version description")
},
score => {
defaultValue =>0,
autoGenerate =>0,
noFormPost =>1,
},
views => {
defaultValue =>0,
autoGenerate =>0,
noFormPost =>1,
},
compares => {
defaultValue =>0,
autoGenerate =>0,
noFormPost =>1,
},
clicks => {
defaultValue =>0,
autoGenerate =>0,
noFormPost =>1,
},
viewsLastIp => {
defaultValue =>undef,
autoGenerate =>0,
noFormPost =>1,
},
comparesLastIp => {
defaultValue =>undef,
autoGenerate =>0,
noFormPost =>1,
},
clicksLastIp => {
defaultValue =>undef,
autoGenerate =>0,
noFormPost =>1,
},
maintainer => {
tab =>"properties",
fieldType =>"user",
defaultValue =>$session->user->userId,
label =>$i18n->get("maintainer label"),
hoverHelp =>$i18n->get("maintainer description")
},
manufacturerName => {
tab =>"properties",
fieldType =>"text",
defaultValue =>undef,
label =>$i18n->get("manufacturerName label"),
hoverHelp =>$i18n->get("manufacturerName description")
},
manufacturerURL => {
tab =>"properties",
fieldType =>"url",
defaultValue =>undef,
label =>$i18n->get("manufacturerURL label"),
hoverHelp =>$i18n->get("manufacturerURL description")
},
productURL => {
tab =>"properties",
fieldType =>"url",
defaultValue =>undef,
label =>$i18n->get("productURL label"),
hoverHelp =>$i18n->get("productURL description")
},
lastUpdated => {
defaultValue =>time(),
autoGenerate =>0,
noFormPost =>1,
},
);
push(@{$definition}, {
assetName=>$i18n->get('assetName'),
icon=>'MatrixListing.gif',
autoGenerateForms=>1,
tableName=>'MatrixListing',
className=>'WebGUI::Asset::MatrixListing',
properties=>\%properties
});
return $class->next::method($session, $definition);
}
#-------------------------------------------------------------------
=head2 duplicate
This method exists for demonstration purposes only. The superclass
handles duplicating MatrixListing Assets. This method will be called
whenever a copy action is executed
=cut
sub duplicate {
my $self = shift;
my $newAsset = $self->next::method(@_);
return $newAsset;
}
#-------------------------------------------------------------------
=head2 getAutoCommitWorkflowId
Gets the WebGUI::VersionTag workflow to use to automatically commit MatrixListings.
By specifying this method, you activate this feature.
=cut
sub getAutoCommitWorkflowId {
my $self = shift;
return $self->getParent->get("submissionApprovalWorkflowId");
}
#-------------------------------------------------------------------
=head2 getEditForm ( )
Returns the TabForm object that will be used in generating the edit page for this asset.
=cut
sub getEditForm {
my $self = shift;
my $session = $self->session;
my $db = $session->db;
my $matrixId = $self->getParent->getId;
my $i18n = WebGUI::International->new($session, 'Asset_MatrixListing');
my $func = $session->form->process("func");
my $form = WebGUI::HTMLForm->new($session);
if ($func eq "add" || ( $func eq "editSave" && $session->form->process("assetId") eq "new")) {
$form->hidden(
-name =>'assetId',
-value =>'new',
);
$form->hidden(
-name =>'class',
-value =>'WebGUI::Asset::MatrixListing',
);
}
$form->hidden(
-name =>'func',
-value =>'editSave',
);
$form->text(
-name =>'title',
-defaultValue =>'Untitled',
-label =>$i18n->get("product name label"),
-hoverHelp =>$i18n->get('product name description'),
-value =>$self->getValue('title'),
);
$form->image(
-name =>'screenshots',
-defaultValue =>undef,
-maxAttachments =>20,
-label =>$i18n->get("screenshots label"),
-hoverHelp =>$i18n->get("screenshots description"),,
-value =>$self->getValue('screenshots'),
);
$form->HTMLArea(
-name =>'description',
-defaultValue =>undef,
-label =>$i18n->get("description label"),
-hoverHelp =>$i18n->get("description description"),
-value =>$self->getValue('description'),
);
$form->text(
-name =>'version',
-defaultValue =>undef,
-label =>$i18n->get("version label"),
-hoverHelp =>$i18n->get("version description"),
-value =>$self->getValue('version'),
);
$form->text(
-name =>'manufacturerName',
-defaultValue =>undef,
-label =>$i18n->get("manufacturerName label"),
-hoverHelp =>$i18n->get("manufacturerName description"),
-value =>$self->getValue('manufacturerName'),
);
$form->url(
-name =>'manufacturerURL',
-defaultValue =>undef,
-label =>$i18n->get("manufacturerURL label"),
-hoverHelp =>$i18n->get("manufacturerURL description"),
-value =>$self->getValue('manufacturerURL'),
);
$form->url(
-name =>'productURL',
-defaultValue =>undef,
-label =>$i18n->get("productURL label"),
-hoverHelp =>$i18n->get("productURL description"),
-value =>$self->getValue('productURL'),
);
foreach my $category (keys %{$self->getParent->getCategories}) {
$form->raw('
'.$category.'
');
my $attributes;
if ($session->form->process('func') eq 'add'){
$attributes = $db->read("select * from Matrix_attribute where category = ? and assetId = ?",
[$category,$matrixId]);
}
else{
$attributes = $db->read("select * from Matrix_attribute as attribute
left join MatrixListing_attribute as listing using(attributeId)
where listing.matrixListingId = ? and category =? and attribute.assetId = ?",
[$self->getId,$category,$matrixId]);
}
while (my $attribute = $attributes->hashRef) {
$attribute->{label} = $attribute->{name};
$attribute->{subtext} = $attribute->{description};
$attribute->{name} = 'attribute_'.$attribute->{attributeId};
$form->dynamicField(%{$attribute});
}
}
$form->submit();
return $form;
}
#-------------------------------------------------------------------
=head2 hasRated ( )
Returns whether the user has already rated this listing or not.
=cut
sub hasRated {
my $self = shift;
my $session = $self->session;
my $hasRated = $self->session->db->quickScalar("select count(*) from MatrixListing_rating where
((userId=? and userId<>'1') or (userId='1' and ipAddress=?)) and listingId=?",
[$session->user->userId,$session->env->get("HTTP_X_FORWARDED_FOR"),$self->getId]);
return $hasRated;
}
#-------------------------------------------------------------------
=head2 incrementCounter ( counter )
Increments one of the Matrix Listing's counters.
=head3 counter
The name of the counter to increment this should be 'views', 'clicks' or 'compares').
=cut
sub incrementCounter {
my $self = shift;
my $db = $self->session->db;
my $counter = shift;
my $currentIp = $self->session->env->get("HTTP_X_FORWARDED_FOR");
unless ($self->get($counter."LastIp") eq $currentIp) {
$self->update({
$counter."LastIp" => $currentIp,
$counter => $self->get($counter)+1
});
}
return undef;
}
#-------------------------------------------------------------------
=head2 indexContent ( )
Making private. See WebGUI::Asset::indexContent() for additonal details.
=cut
sub indexContent {
my $self = shift;
my $indexer = $self->next::method;
$indexer->setIsPublic(0);
return undef;
}
#-------------------------------------------------------------------
=head2 prepareView ( )
See WebGUI::Asset::prepareView() for details.
=cut
sub prepareView {
my $self = shift;
$self->next::method();
my $template = WebGUI::Asset::Template->new($self->session, $self->getParent->get('detailTemplateId'));
$template->prepare;
$self->{_viewTemplate} = $template;
return undef;
}
#-------------------------------------------------------------------
=head2 processPropertiesFromFormPost ( )
Used to process properties from the form posted.
=cut
sub processPropertiesFromFormPost {
my $self = shift;
my $session = $self->session;
my $score = 0;
$self->next::method(@_);
my $attributes = $session->db->read("select * from Matrix_attribute where assetId = ?",[$self->getParent->getId]);
while (my $attribute = $attributes->hashRef) {
my $name = 'attribute_'.$attribute->{attributeId};
my $value;
if ($attribute->{fieldType} eq 'MatrixCompare'){
$value = $session->form->process($name);
$score = $score + $value;
}
else{
$value = $session->form->process($name,$attribute->{fieldType},$attribute->{defaultValue},$attribute);
}
$session->db->write("replace into MatrixListing_attribute (matrixId, matrixListingId, attributeId, value)
values (?, ?, ?, ?)",
[$self->getParent->getId,$self->getId,$attribute->{attributeId},$value]);
}
$self->update({score => $score});
$self->requestAutoCommit;
return undef;
}
#-------------------------------------------------------------------
=head2 purge ( )
This method is called when data is purged by the system.
removes collateral data associated with a MatrixListing when the system
purges it's data.
=cut
sub purge {
my $self = shift;
my $db = $self->session->db;
$db->write("delete from MatrixListing_attribute where matrixListingId=?",[$self->getId]);
$db->write("delete from MatrixListing_rating where listingId=?" ,[$self->getId]);
$db->write("delete from MatrixListing_ratingSummary where listingId=?" ,[$self->getId]);
return $self->next::method;
}
#-------------------------------------------------------------------
=head2 purgeRevision ( )
This method is called when data is purged by the system.
=cut
sub purgeRevision {
my $self = shift;
return $self->next::method;
}
#-------------------------------------------------------------------
=head2 setRatings ( ratings )
Sets the ratings for a matrix listing
=head3 ratings
A hashref containing the ratings to set for this listing.
=cut
sub setRatings {
my $self = shift;
my $ratings = shift;
my $session = $self->session;
my $db = $session->db;
my $matrixId = $self->getParent->getId;
foreach my $category (keys %{$self->getParent->getCategories}) {
if ($ratings->{$category}) {
$db->write("insert into MatrixListing_rating
(userId, category, rating, timeStamp, listingId, ipAddress, assetId) values (?,?,?,?,?,?,?)",
[$session->user->userId,$category,$ratings->{$category},$session->datetime->time(),$self->getId,
$session->env->get("HTTP_X_FORWARDED_FOR"),$matrixId]);
}
my $sql = "from MatrixListing_rating where listingId=? and category=?";
my $sum = $db->quickScalar("select sum(rating) $sql", [$self->getId,$category]);
my $count = $db->quickScalar("select count(*) $sql", [$self->getId,$category]);
my $half = round($count/2);
my $mean = $sum / ($count || 1);
my $median = $db->quickScalar("select rating $sql limit $half,$half",[$self->getId,$category]);
$db->write("replace into MatrixListing_ratingSummary
(listingId, category, meanValue, medianValue, countValue, assetId)
values (?,?,?,?,?,?)",[$self->getId,$category,$mean,$median,$count,$matrixId]);
}
return undef;
}
#-------------------------------------------------------------------
=head2 view ( hasRated )
Updates the score of a MatrixListing.
=cut
sub updateScore {
my $self = shift;
my $score = $self->session->db->quickScalar("select sum(value) from MatrixListing_attribute
left join Matrix_attribute using(attributeId)
where matrixListingId = ? and fieldType = 'MatrixCompare'",[$self->getId]);
$self->update({score => $score});
return undef;
}
#-------------------------------------------------------------------
=head2 view ( hasRated )
method called by the container www_view method.
=head3 hasRated
A boolean indicating if the user has rated this listing.
=head3 emailSent
A boolean indicating if an email to the listing maintianer was sent.
=cut
sub view {
my $self = shift;
my $hasRated = shift || $self->hasRated;
my $emailSent = shift;
my $session = $self->session;
my $db = $session->db;
my $i18n = WebGUI::International->new($self->session, "Asset_MatrixListing");
my @categories = keys %{$self->getParent->getCategories};
# Increment views before getting template var hash so that the views tmpl_var has the incremented value.
$self->incrementCounter("views");
my $var = $self->get;
if ($emailSent){
$var->{emailSent} = 1;
}
$var->{controls} = $self->getToolbar;
$var->{comments} = $self->getFormattedComments();
$var->{productName} = $var->{title};
$var->{lastUpdated_epoch} = $self->get('lastUpdated');
$var->{lastUpdated_date} = $session->datetime->epochToHuman($self->get('lastUpdated'),"%z");
$var->{manufacturerUrl_click} = $self->getUrl("func=click;manufacturer=1");
$var->{productUrl_click} = $self->getUrl("func=click");
$self->session->style->setScript($self->session->url->extras('yui/build/yahoo/yahoo-min.js'),
{type => 'text/javascript'});
$self->session->style->setScript($self->session->url->extras('yui/build/dom/dom-min.js'),
{type => 'text/javascript'});
$self->session->style->setScript($self->session->url->extras('yui/build/event/event-min.js'),
{type => 'text/javascript'});
$self->session->style->setScript($self->session->url->extras('yui/build/json/json-min.js'), {type =>
'text/javascript'});
$self->session->style->setScript($self->session->url->extras('yui/build/connection/connection-min.js'),
{type => 'text/javascript'});
$self->session->style->setScript($self->session->url->extras('yui/build/get/get-min.js'), {type =>
'text/javascript'});
$self->session->style->setScript($self->session->url->extras('yui/build/element/element-beta-min.js'), {type =>
'text/javascript'});
$self->session->style->setScript($self->session->url->extras('yui/build/datasource/datasource-min.js'),
{type => 'text/javascript'});
$self->session->style->setScript($self->session->url->extras('yui/build/datatable/datatable-min.js'),
{type =>'text/javascript'});
$self->session->style->setScript($self->session->url->extras('yui/build/button/button-min.js'),
{type =>'text/javascript'});
$self->session->style->setScript($self->session->url->extras('wobject/Matrix/matrixListing.js'), {type =>
'text/javascript'});
$self->session->style->setLink($self->session->url->extras('yui/build/datatable/assets/skins/sam/datatable.css'),
{type =>'text/css', rel=>'stylesheet'});
# Attributes
foreach my $category (@categories) {
my $attributes;
my @attribute_loop;
my $categoryLoopName = $session->url->urlize($category)."_loop";
$attributes = $db->read("select * from Matrix_attribute as attribute
left join MatrixListing_attribute as listing using(attributeId)
where listing.matrixListingId = ? and category =? and attribute.assetId = ?",
[$self->getId,$category,$self->getParent->getId]);
while (my $attribute = $attributes->hashRef) {
$attribute->{label} = $attribute->{name};
if ($attribute->{fieldType} eq 'MatrixCompare'){
$attribute->{value} = WebGUI::Form::MatrixCompare->new($session,$attribute)->getValueAsHtml;
}
push(@attribute_loop,$attribute);
}
$var->{$categoryLoopName} = \@attribute_loop;
push(@{$var->{category_loop}},{
categoryLabel => $category,
attribute_loop => \@attribute_loop,
});
}
# Screenshots
if ($var->{screenshots}) {
my $file = WebGUI::Form::File->new($session,{ value=>$var->{screenshots} });
my $storage = $file->getStorageLocation;
my @files;
@files = @{ $storage->getFiles } if (defined $storage);
$var->{screenshots} = qq|
|;
}
# Rating form
my %rating;
tie %rating, 'Tie::IxHash';
%rating = (
1=>"1 - ".$i18n->get('worst label'),
2=>2,
3=>3,
4=>4,
5=>"5 - ".$i18n->get('respectable label'),
6=>6,
7=>7,
8=>8,
9=>9,
10=>"10 - ".$i18n->get('best label')
);
my $ratingsTable = "
\n
".$i18n->get('mean label')."
".$i18n->get('median label')."
".$i18n->get('count label')."
\n";
my $ratingForm = WebGUI::HTMLForm->new($session,
-extras =>'class="content"',
-tableExtras=>'class="content"'
);
$ratingForm = WebGUI::HTMLForm->new($session,
-extras =>'class="ratingForm"',
-tableExtras=>'class="ratingForm"'
);
$ratingForm->hidden(
-name =>"listingId",
-value =>$self->getId
);
$ratingForm->hidden(
-name =>"func",
-value =>"rate"
);
foreach my $category (@categories) {
my ($mean,$median,$count) = $db->quickArray("select meanValue, medianValue, countValue
from MatrixListing_ratingSummary
where listingId=? and category=?",[$self->getId,$category]);
$ratingsTable .= '