Koha-clms/Koha/Objects/Mixin/ExtendedAttributes.pm

235 lines
6.9 KiB
Perl

package Koha::Objects::Mixin::ExtendedAttributes;
# Copyright 2024 PTFS Europe Ltd
#
# This file is part of Koha.
#
# Koha is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Koha is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Koha; if not, see <http://www.gnu.org/licenses>.
use Modern::Perl;
use Scalar::Util qw( reftype );
=head1 NAME
Koha::Objects::Mixin::ExtendedAttributes
=head2 Class methods
=head3 search
Overwrites the search method to include extended attributes rewrite and dynamic relation accessors
=cut
sub search {
my ( $self, $params, $attributes ) = @_;
my $class = ref($self) ? ref($self) : $self;
$self->handle_query_extended_attributes(
{
attributes => $attributes,
filtered_params => $params,
}
);
my $rs = $self->_resultset()->search( $params, $attributes );
return $class->_new_from_dbic($rs);
}
=head3 handle_query_extended_attributes
Checks for the presence of extended_attributes in a query
If present, it builds the dynamic extended attributes relations and rewrites the query to include the extended_attributes relation
=cut
sub handle_query_extended_attributes {
my ( $self, $args ) = @_;
my $attributes = $args->{attributes};
my $filtered_params = $args->{filtered_params};
if ( reftype( $attributes->{prefetch} )
&& reftype( $attributes->{prefetch} ) eq 'ARRAY'
&& grep ( /extended_attributes/, @{ $attributes->{prefetch} } ) )
{
my @array = $self->_get_extended_attributes_entries($filtered_params);
# Calling our private method to build the extended attributes relations
my @joins = $self->_build_extended_attributes_relations( \@array );
push @{ $attributes->{join} }, @joins;
}
}
=head3 _get_extended_attributes_entries
$self->_get_extended_attributes_entries( $filtered_params, 0 )
Recursive function that returns the rewritten extended_attributes query entries.
Given:
[
'-and',
[
{
'extended_attributes.code' => 'CODE_1',
'extended_attributes.attribute' => { 'like' => '%Bar%' }
},
{
'extended_attributes.attribute' => { 'like' => '%Bar%' },
'extended_attributes.code' => 'CODE_2'
}
]
];
Returns :
[
'CODE_1',
'CODE_2'
]
=cut
sub _get_extended_attributes_entries {
my ( $self, $params, @array ) = @_;
if ( reftype($params) && reftype($params) eq 'HASH' ) {
# rewrite additional_field_values table query params
@array = _rewrite_related_metadata_query( $params, 'field_id', 'value', @array )
if $params->{'extended_attributes.field_id'};
# rewrite borrower_attributes table query params
@array = _rewrite_related_metadata_query( $params, 'code', 'attribute', @array )
if $params->{'extended_attributes.code'};
# rewrite illrequestattributes table query params
@array = _rewrite_related_metadata_query( $params, 'type', 'value', @array )
if $params->{'extended_attributes.type'};
foreach my $key ( keys %{$params} ) {
return $self->_get_extended_attributes_entries( $params->{$key}, @array );
}
} elsif ( reftype($params) && reftype($params) eq 'ARRAY' ) {
foreach my $ea_instance (@$params) {
@array = $self->_get_extended_attributes_entries( $ea_instance, @array );
}
return @array;
} else {
return @array;
}
}
=head3 _rewrite_related_metadata_query
$extended_attributes_entries =
_rewrite_related_metadata_query( $params, 'field_id', 'value', @array )
Helper function that rewrites all subsequent extended_attributes queries to match the alias generated by the dbic self left join
Take the below example (patrons):
[
{
"extended_attributes.attribute":{"like":"%123%"},
"extended_attributes.code":"CODE_1"
}
],
[
{
"extended_attributes.attribute":{"like":"%abc%" },
"extended_attributes.code":"CODE_2"
}
]
It'll be rewritten as:
[
{
'extended_attributes_CODE_1.attribute' => { 'like' => '%123%' },
'extended_attributes_CODE_1.code' => 'CODE_1'
}
],
[
{
'extended_attributes_CODE_2.attribute' => { 'like' => '%abc%' },
'extended_attributes_CODE_2.code' => 'CODE_2'
}
]
=cut
sub _rewrite_related_metadata_query {
my ( $params, $key, $value, @array ) = @_;
if ( ref \$params->{ 'extended_attributes.' . $key } eq 'SCALAR' ) {
my $old_key_value = delete $params->{ 'extended_attributes.' . $key };
my $new_key_value = "extended_attributes_$old_key_value" . "." . $key;
$params->{$new_key_value} = $old_key_value;
my $old_value_value = delete $params->{ 'extended_attributes.' . $value };
my $new_value_value = "extended_attributes_$old_key_value" . "." . $value;
$params->{$new_value_value} = $old_value_value;
push @array, $old_key_value;
}
return @array;
}
=head3 _build_extended_attributes_relations
Method to dynamically add has_many relations for Koha classes that support extended_attributes.
Returns a list of relation accessor names.
=cut
sub _build_extended_attributes_relations {
my ( $self, $types ) = @_;
return if ( !grep ( /extended_attributes/, keys %{ $self->_resultset->result_source->_relationships } ) );
my $ea_config = $self->extended_attributes_config;
my $result_source = $self->_resultset->result_source;
for my $type ( @{$types} ) {
$result_source->add_relationship(
"extended_attributes_$type",
"$ea_config->{schema_class}",
sub {
my $args = shift;
return {
"$args->{foreign_alias}.$ea_config->{id_field}->{foreign}" =>
{ -ident => "$args->{self_alias}.$ea_config->{id_field}->{self}" },
"$args->{foreign_alias}.$ea_config->{key_field}" => { '=', $type },
};
},
{
accessor => 'multi',
join_type => 'LEFT',
cascade_copy => 0,
cascade_delete => 0,
is_depends_on => 0
},
);
}
return map { 'extended_attributes_' . $_ } @{$types};
}
1;