From 953af3dc4de5424356951f1bf4f70d44a63e57e8 Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Mon, 15 Sep 2025 12:14:13 +0100 Subject: [PATCH] Bug 40808: Add DBIx::Class schema for accountline_links polymorphic relationships This patch adds the DBIx::Class schema definitions for the new accountline_links table and updates the existing accountlines schema. Changes: - New Koha::Schema::Result::AccountlineLink with polymorphic relationships - Updated Koha::Schema::Result::Accountline to include has_many relationship - Supports modern link types: hold, checkout, article_request - Includes validation methods for link integrity - Optimized for common query patterns with covering indexes The polymorphic design allows linking account lines to any entity type without adding nullable foreign key columns to the accountlines table. --- Koha/Schema/Result/Accountline.pm | 19 ++- Koha/Schema/Result/AccountlineLink.pm | 196 ++++++++++++++++++++++++++ 2 files changed, 213 insertions(+), 2 deletions(-) create mode 100644 Koha/Schema/Result/AccountlineLink.pm diff --git a/Koha/Schema/Result/Accountline.pm b/Koha/Schema/Result/Accountline.pm index ea1a8b7bd34..67b989c510f 100644 --- a/Koha/Schema/Result/Accountline.pm +++ b/Koha/Schema/Result/Accountline.pm @@ -249,6 +249,21 @@ __PACKAGE__->has_many( { cascade_copy => 0, cascade_delete => 0 }, ); +=head2 accountline_links + +Type: has_many + +Related object: L + +=cut + +__PACKAGE__->has_many( + "accountline_links", + "Koha::Schema::Result::AccountlineLink", + { "foreign.accountlines_id" => "self.accountlines_id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); + =head2 article_requests Type: has_many @@ -445,8 +460,8 @@ __PACKAGE__->belongs_to( ); -# Created by DBIx::Class::Schema::Loader v0.07049 @ 2024-02-08 14:18:03 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:aVLdvK1lek01lZ0mbaCwZQ +# Created by DBIx::Class::Schema::Loader v0.07051 @ 2025-09-15 11:50:54 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:QxV/akDZqlrowb+OeH4mQA =head2 patron diff --git a/Koha/Schema/Result/AccountlineLink.pm b/Koha/Schema/Result/AccountlineLink.pm new file mode 100644 index 00000000000..bc18dbca6f8 --- /dev/null +++ b/Koha/Schema/Result/AccountlineLink.pm @@ -0,0 +1,196 @@ +use utf8; +package Koha::Schema::Result::AccountlineLink; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +=head1 NAME + +Koha::Schema::Result::AccountlineLink + +=cut + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +=head1 TABLE: C + +=cut + +__PACKAGE__->table("accountline_links"); + +=head1 ACCESSORS + +=head2 link_id + + data_type: 'integer' + is_auto_increment: 1 + is_nullable: 0 + +=head2 accountlines_id + + data_type: 'integer' + is_foreign_key: 1 + is_nullable: 0 + +foreign key to accountlines.accountlines_id + +=head2 link_type + + data_type: 'varchar' + is_nullable: 0 + size: 32 + +Type of linked entity: hold, old_hold, checkout, old_checkout, article_request, etc. + +=head2 linked_id + + data_type: 'integer' + is_nullable: 0 + +ID of the linked entity + +=head2 created_on + + data_type: 'timestamp' + datetime_undef_if_invalid: 1 + default_value: current_timestamp + is_nullable: 0 + +=cut + +__PACKAGE__->add_columns( + "link_id", + { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, + "accountlines_id", + { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, + "link_type", + { data_type => "varchar", is_nullable => 0, size => 32 }, + "linked_id", + { data_type => "integer", is_nullable => 0 }, + "created_on", + { + data_type => "timestamp", + datetime_undef_if_invalid => 1, + default_value => \"current_timestamp", + is_nullable => 0, + }, +); + +=head1 PRIMARY KEY + +=over 4 + +=item * L + +=back + +=cut + +__PACKAGE__->set_primary_key("link_id"); + +=head1 UNIQUE CONSTRAINTS + +=head2 C + +=over 4 + +=item * L + +=item * L + +=item * L + +=back + +=cut + +__PACKAGE__->add_unique_constraint( + "accountline_link_unique", + ["accountlines_id", "link_type", "linked_id"], +); + +=head1 RELATIONS + +=head2 accountline + +Type: belongs_to + +Related object: L + +=cut + +__PACKAGE__->belongs_to( + "accountline", + "Koha::Schema::Result::Accountline", + { accountlines_id => "accountlines_id" }, + { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" }, +); + + +# Created by DBIx::Class::Schema::Loader v0.07051 @ 2025-09-15 11:50:54 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:xnOrV5Pdyzk+lMWHm8S1XQ + +=head2 linked_object + +Returns the linked object based on link_type and linked_id. +This is a polymorphic relationship. + +=cut + +sub linked_object { + my ($self) = @_; + + my $type_map = { + 'hold' => ['Reserve', 'reserve_id'], + 'old_hold' => ['OldReserve', 'reserve_id'], + 'checkout' => ['Issue', 'issue_id'], + 'old_checkout' => ['OldIssue', 'issue_id'], + 'article_request' => ['ArticleRequest', 'id'], + }; + + my ($result_class, $key_field) = @{$type_map->{$self->link_type} || []}; + return unless $result_class; + + return $self->result_source->schema->resultset($result_class)->find({ + $key_field => $self->linked_id + }); +} + +=head2 linked_object_class + +Returns the Koha::Object class name for the linked object + +=cut + +sub linked_object_class { + my ($self) = @_; + + my $class_map = { + 'hold' => 'Koha::Hold', + 'old_hold' => 'Koha::Old::Hold', + 'checkout' => 'Koha::Checkout', + 'old_checkout' => 'Koha::Old::Checkout', + 'article_request' => 'Koha::ArticleRequest', + }; + + return $class_map->{$self->link_type}; +} + +=head2 validate_link_integrity + +Validates that the linked entity actually exists + +=cut + +sub validate_link_integrity { + my ($self) = @_; + + my $linked_object = $self->linked_object; + return defined($linked_object) ? 1 : 0; +} + +# You can replace this text with custom code or comments, and it will be preserved on regeneration +1; \ No newline at end of file -- 2.51.0