From Code to Community: Sponsoring The Perl and Raku Conference 2025 Learn more

# $Id: /local/Mango/trunk/lib/Mango/Provider/Products.pm 133 2007-04-21T03:49:26.663475Z claco $
use strict;
BEGIN {
use Scalar::Util ();
__PACKAGE__->mk_group_accessors('component_class', qw/attribute_class tag_class/);
__PACKAGE__->mk_group_accessors('inherited', qw/attribute_source_name tag_source_name/);
};
__PACKAGE__->attribute_class('Mango::Attribute');
__PACKAGE__->attribute_source_name('ProductAttributes');
__PACKAGE__->tag_class('Mango::Tag');
__PACKAGE__->tag_source_name('Tags');
__PACKAGE__->result_class('Mango::Product');
__PACKAGE__->source_name('Products');
sub get_by_sku {
my ($self, $sku) = @_;
return $self->search({
sku => $sku
})->first;
};
sub search {
my ($self, $filter, $options) = @_;
$filter ||= {};
$options ||= {};
if (my $tags = delete $filter->{'tags'}) {
my $count;
if (@{$tags}) {
foreach my $tag (@{$tags}) {
if (Scalar::Util::blessed $tag) {
if ($tag->isa('Mango::Tag')) {
$tag = $tag->name;
} else {
Mango::Exception->throw('NOT_A_TAG');
};
};
if (!$count) {
$count = 1;
$filter->{'tag.name'} = $tag;
} else {
$filter->{'tag_' . $count . '.name'} = $tag;
};
$count++
};
$options->{'distinct'} = 1;
if (defined $options->{'join'}) {
if (!ref $options->{'join'} || ref $options->{'join'} eq 'HASH') {
$options->{'join'} = [$options->{'join'}];
};
} else {
$options->{'join'} = [];
};
push @{$options->{'join'}}, map {{'map_product_tag' => 'tag'}} @{$tags};
};
};
return $self->SUPER::search($filter, $options);
};
sub create {
my ($self, $data) = (shift, shift);
my $attributes = delete $data->{'attributes'};
my $tags = delete $data->{'tags'};
my $product = $self->SUPER::create($data, @_);
if ($attributes) {
$product->add_attributes(@{$attributes});
};
if ($tags) {
$product->add_tags(@{$tags});
};
return $product;
};
sub add_attribute {
my @attributes = shift->add_attributes(@_);
return shift @attributes;
};
sub add_attributes {
my ($self, $product, @data) = @_;
my $resultset = $self->schema->resultset($self->attribute_source_name);
my @added;
if (Scalar::Util::blessed($product)) {
if ($product->isa('Mango::Product')) {
$product = $product->id;
} else {
Mango::Exception->throw('NOT_A_PRODUCT');
};
};
foreach my $attribute (@data) {
if (Scalar::Util::blessed $attribute) {
if ($attribute->isa('Mango::Attribute')) {
$attribute = {$attribute->get_columns};
} else {
Mango::Exception->throw('NOT_A_ATTRIBUTE');
};
};
$attribute->{'product_id'} = $product;
push @added, $self->attribute_class->new({
$resultset->update_or_create($attribute, {key => 'product_attribute_name'})->get_inflated_columns,
meta => {
provider => $self,
parent => $product
}
});
};
return @added;
};
sub search_attributes {
my ($self, $product, $filter, $options) = @_;
$filter ||= {};
$options ||= {};
if (Scalar::Util::blessed($product)) {
if ($product->isa('Mango::Product')) {
$product = $product->id;
} else {
Mango::Exception->throw('NOT_A_PRODUCT');
};
};
$filter->{'product_id'} = $product;
my $resultset = $self->schema->resultset($self->attribute_source_name)->search(
$filter, $options
);
my @results = map {
$self->attribute_class->new({
$_->get_inflated_columns,
meta => {
provider => $self,
parent => $product
}
})
} $resultset->all;
if (wantarray) {
return @results;
} else {
return Mango::Iterator->new({
data => \@results,
pager => $options->{'page'} ? $resultset->pager : undef
});
};
};
sub delete_attributes {
my ($self, $product, $filter) = @_;
my $resultset = $self->schema->resultset($self->attribute_source_name);
$filter ||= {};
if (Scalar::Util::blessed($product)) {
if ($product->isa('Mango::Product')) {
$product = $product->id;
} else {
Mango::Exception->throw('NOT_A_PRODUCT');
};
};
$filter->{'product_id'} = $product;
return $resultset->search($filter)->delete_all;
};
sub update_attribute {
my ($self, $attribute) = @_;
my $resultset = $self->schema->resultset($self->attribute_source_name);
return $resultset->find($attribute->id)->update(
{$attribute->get_columns}
);
};
sub add_tag {
my @tags = shift->add_tags(@_);
return shift @tags;
};
sub add_tags {
my ($self, $product, @data) = @_;
my $resultset = $self->schema->resultset($self->tag_source_name);
my @added;
if (Scalar::Util::blessed($product)) {
if ($product->isa('Mango::Product')) {
$product = $product->id;
} else {
Mango::Exception->throw('NOT_A_PRODUCT');
};
};
foreach my $tag (@data) {
if (Scalar::Util::blessed $tag) {
if ($tag->isa('Mango::Tag')) {
$tag = {$tag->get_columns};
} else {
Mango::Exception->throw('NOT_A_TAG');
};
} elsif (!ref $tag) {
$tag = {name => $tag};
};
next unless $tag->{'name'};
my $newtag = $resultset->find_or_create($tag);
$newtag->related_resultset('map_product_tag')->find_or_create({
product_id => $product,
tag_id => $newtag->id
});
push @added, $self->tag_class->new({
$newtag->get_inflated_columns,
meta => {
provider => $self,
parent => $product
}
});
};
return @added;
};
sub search_tags {
my ($self, $product, $filter, $options) = @_;
$filter ||= {};
$options ||= {};
if (Scalar::Util::blessed($product)) {
if ($product->isa('Mango::Product')) {
$product = $product->id;
} else {
Mango::Exception->throw('NOT_A_PRODUCT');
};
};
$filter->{'products'} = {
'id' => $product
};
return $self->tags($filter, $options);
};
sub delete_tags {
my ($self, $product, $filter) = @_;
my $resultset = $self->schema->resultset($self->tag_source_name);
$filter ||= {};
if (Scalar::Util::blessed($product)) {
if ($product->isa('Mango::Product')) {
$product = $product->id;
} else {
Mango::Exception->throw('NOT_A_PRODUCT');
};
};
return $resultset->search(
$filter
)->related_resultset('map_product_tag')->search({
'product_id' => $product
})->delete_all;
};
sub tags {
my ($self, $filter, $options) = @_;
$filter ||= {};
$options ||= {};
my $pfilter = delete $filter->{'products'} || {};
foreach my $key (keys %{$pfilter}) {
next if $key =~ /^me\./;
$pfilter->{"me.$key"} = delete $pfilter->{$key};
};
foreach my $key (keys %{$filter}) {
next if $key =~ /^tag\./;
$pfilter->{"tag.$key"} = delete $filter->{$key};
};
my @results = map {
$self->tag_class->new({
$_->get_inflated_columns,
meta => {
provider => $self
}
})
} $self->resultset->search(
$pfilter
)->related_resultset('map_product_tag')->related_resultset('tag')->search(
$filter, $options
)->all;
if (wantarray) {
return @results;
} else {
return Mango::Iterator->new({
data => \@results
});
};
};
1;
__END__
=head1 NAME
Mango::Provider::Products - Provider class for product information
=head1 SYNOPSIS
my $provider = Mango::Provider::Products->new;
my $product = $provider->get_by_id(23);
=head1 DESCRIPTION
Mango::Provider::Products is the provider class responsible for creating,
deleting, updating and searching product information, including product
tags and attributes.
=head1 CONSTRUCTOR
=head2 new
=over
=item Arguments: \%options
=back
Creates a new product provider object. If options are passed to new, those are
sent to C<setup>.
my $provider = Mango::Provider::Products->new;
See L<Mango::Provider/new> and L<Mango::Provider::DBIC/new> for a list of other
possible options.
=head1 METHODS
=head2 add_attributes
=over
=item Arguments: $product, @attributes
=back
Adds the specified attributes to the specified product. C<product> can be a
Mango::Product object or a product id. C<attributes> can be a list of attribute
data hashes or Mango::Attribute objects.
$provider->add_attributes(23, {name => 'Attribute', value => 'Value'}, $attributeobect, ...)
=head2 add_attribute
Same as C<add_attributes>.
=head2 add_tags
=over
=item Arguments: $product, @tags
=back
Adds the specified tags to the specified product. C<product> can be a
Mango::Product object or a product id. C<tags> can be a list of tag strings
or Mango::Tag objects.
$provider->add_tags(23, 'computer', $tagobect, ...)
=head2 add_tag
Same as C<add_tags>.
=head2 create
=over
=item Arguments: \%data
=back
Creates a new Mango::Product object using the supplied data.
my $product = $provider->create({
sku => 'ABC-1234',
price => 2.34,
description => 'The best product ever'
});
print $role->name;
In addition to using the column names, the following special keys are available:
=over
=item attributes
This can be an anonymous array containing Mango::Attribute objects or hashes
of attribute data (or both):
my $product = $provider->create({
sku => 'ABC-1234',
price => 2.34,
description => 'The best product ever',
attributes => [
{name => 'Attribute1', value => 'Value1'},
$attributeobject
]
});
=item tags
This can be an anonymous array containing Mango::Tag objects or tag strings
(or both):
my $product = $provider->create({
sku => 'ABC-1234',
price => 2.34,
description => 'The best product ever',
tags => [
qw/computer linux/,
$tagobject
]
});
=back
=head2 delete
=over
=item Arguments: \%filter
=back
Deletes products from the provider matching the supplied filter.
$provider->delete({
id => 23
});
In addition to using the column names, the following special keys are available:
=over
=item user
This can be a user id, or a user object for which this profile is assigned to.
$provider->delete({
user => $user
});
It is recommended that you use this key, rather than setting the foreign key
column manually in case it changes later.
=back
=head2 delete_attributes
=over
=item Arguments: $product, $filter
=back
Deletes attributes matching the specified filter form the specified product.
C<product> can be a Mango::Product object or a product id.
$provider->delete_attributes(23, {name => 'AttributeName'});
=head2 delete_tags
=over
=item Arguments: $product, $filter
=back
Deletes tags matching the specified filter form the specified product.
C<product> can be a Mango::Product object or a product id.
$provider->delete_tags(23, {name => [qw/computer linux/]});
=head2 get_by_id
=over
=item Arguments: $id
=back
Returns a Mango::Product object matching the specified id.
my $product = $provider->get_by_id(23);
Returns undef if no matching product can be found.
=head2 get_by_sku
=over
=item Arguments: $sku
=back
Returns a Mango::PRoduct object matching the specified id.
my $product = $provider->get_by_sku('ABC-1234');
Returns undef if no matching product can be found.
=head2 search
=over
=item Arguments: \%filter, \%options
=back
Returns a list of Mango::Product objects in list context, or a Mango::Iterator
in scalar context matching the specified filter.
my @products = $provider->search({
sku => 'A%'
});
my $iterator = $provider->search({
sku => 'A%'
});
In addition to using the column names, the following special keys are available:
=over
=item tags
This can be an anonymous array containing Mango::Tag objects or tag strings
(or both):
my $products = $provider->search({
sku => 'A%',
tags => [
'computer',
$tagobject
]
});
=back
See L<DBIx::Class::Resultset/ATTRIBUTES> for a list of other possible options.
=head2 search_attributes
=over
=item Arguments: $product, $filter, $options
=back
Returns a list of Mango::Attribute objects in list context, or a Mango::Iterator
in scalar context matching the specified filter.
$provider->search_attributes(23, {name => 'A'%});
=head2 search_tags
=over
=item Arguments: $product, $filter, $options
=back
Returns a list of Mango::Tag objects in list context, or a Mango::Iterator
in scalar context matching the specified filter.
$provider->search_tags(23, {name => [qw/computer linux/]});
=head2 tags
Returns a list of Mango::Tag objects in list context, or a Mango::Iterator
in scalar context matching the specified filter.
my $tags = $provider->tags;
Only tags that are assigned to at least on product are returned. In addition to
using the column names, the following special keys are available:
=over
=item products
This is a hash containing a filter applied against products before returning
those products tags.
my $tags = $provider->tags({
products => {
sku => 'A%'
}
});
=back
=head2 update
=over
=item Arguments: $product
=back
Sets the 'updated' column to DateTime->now and saves any changes made to the
product back to the underlying store.
my $product = $provider->create(\%data);
$product->price(10.95);
$provider->update($product);
=head2 update_attribute
=over
=item Arguments: $attribute
=back
Sets the 'updated' column to DateTime->now and saves any changes made to the
product back to the underlying store.
$attribute->value('AttributeValue');
$provider->update_attribute($attribute);
=head1 SEE ALSO
L<Mango::Provider>, L<Mango::Provider::DBIC>, L<Mango::Product>,
L<Mango::Tag>, L<Mango::Attribute>, L<DBIx::Class>
=head1 AUTHOR
Christopher H. Laco
CPAN ID: CLACO
claco@chrislaco.com