Bug 14539

Summary: Introduction to castToObject(), aka. make a Koha::Object from various input types
Product: Koha Reporter: Olli-Antti Kivilahti <olli-antti.kivilahti>
Component: Architecture, internals, and plumbingAssignee: Olli-Antti Kivilahti <olli-antti.kivilahti>
Status: BLOCKED --- QA Contact: Testopia <testopia>
Severity: enhancement    
Priority: P5 - low CC: lari.taskula, mtompset
Version: master   
Hardware: All   
OS: All   
See Also: https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=15473
Change sponsored?: --- Patch complexity: Large patch
Documentation contact: Documentation submission:
Text to go in the release notes:
Version(s) released in:
Bug Depends on: 13995    
Bug Blocks: 14540, 13906, 13920, 14698, 19515    
Attachments: Bug 14539 - Introduction to castToObject(), aka. make a Koha::Object from various input types
Bug 14539 - Introduction to castToObject(), aka. make a Koha::Object from various input types
Bug 14539 - Introduction to castToObject(), aka. make a Koha::Object from various input types
Bug 14539 - Introduction to castToObject(), aka. make a Koha::Object from various input types
Bug 14539 - Introduction to cast() (ToObject), aka. make a Koha::Object from various input types and validate.
Bug 14539 - Introduction to cast() (ToObject), aka. make a Koha::Object from various input types and validate.
Bug 14539 - Koha::Objects->cast(). Introduction to cast() (ToObject), aka. make a Koha::Object from various input types and validate.
Bug 14539 - Koha::Objects->cast(). Introduction to cast() (ToObject), aka. make a Koha::Object from various input types and validate.
Bug 14539 - Koha::Objects->cast(). Introduction to cast() (ToObject), aka. make a Koha::Object from various input types and validate.
Bug 14539 - Koha::Objects->cast(). Introduction to cast() (ToObject), aka. make a Koha::Object from various input types and validate.
Bug 14539 - Koha::Objects->cast(). Introduction to cast() (ToObject), aka. make a Koha::Object from various input types and validate.

Description Olli-Antti Kivilahti 2015-07-16 13:06:26 UTC
Currently Koha is like an archeological dig site, we have different layers of dealing with various business objects.

We started with DBI and numerous ways of passing an HASH around. There is no telling if it will be a List of column => values, or a reference to HASH, or a HASH or just any of the business object's (eg. Borrower's) unique identifiers (userid, cardnumber, borrowernumber).

Then DBIx came to the rescue and now we are need to learn DBI and DBIx and SQL to do DB operatons in Koha. Migration to DBIx is on the way.

Finally we have Koha::Object and subclasses, which include and use the DBIx, but those are not directly compatible, since Koha::Object is not a subclass of DBIx::Class making life occasionally miserable.
Now we need to know 3 methods of DB accession.

I am really frustrated with all of those different layers of history, and making things work nicely across all different programming patterns, I have had great success in using a casting system, where we take any value and try to make a Koha::Object-subclass out of it.

So we try to cast a Scalar or a reference of Koha::Object-implementation or DBIx::ResultSet or HASH, to the desired Koha::Object-implementation.
This is a nice validation/entry function in any subroutine dealing with business objects, making sure that we always have the "correct" implementation of the same business object.

An example:
#Does this look familiar?
my $borrower = 1042; #A borrowernumber?
my $user = '121A0321312'; #A cardnumber? or userid?
my $borrower = {borrowernumber => 1043, cardnumber => '121A0321312', ...}; #HASH
my $borrower = Koha::Borrowers->find({borrowernumber => 1024});
my $borrower = $schema->resultset('Borrower')->find({borrowernumber => 1024});

#So when I call my subroutine with the $borrower I got using some function,
makeBorrowerHappy($borrower);
#Bad things most often happen.

#But if my makeBorrowerHappy()-function would cast its parameters to the
#correct type, there would be only merriment and fun!
sub makeBorrowerHappy {
    my ($borrower) = @_;
    $borrower = Koha::Borrowers::castToBorrower($borrower);

    ... #Do fun stuff!
}
#Whatever we throw at the subroutine, things just work (in theory)!

Even better, if the $borrower already is a DBIx-derivative or Koha::Borrower, we don't even do anything, other than simple if statements. So minimally expensive, maximally productive.
Comment 1 Olli-Antti Kivilahti 2015-07-16 13:09:29 UTC Comment hidden (obsolete)
Comment 2 Olli-Antti Kivilahti 2015-07-17 12:31:27 UTC Comment hidden (obsolete)
Comment 3 Olli-Antti Kivilahti 2015-07-22 11:24:48 UTC Comment hidden (obsolete)
Comment 4 Olli-Antti Kivilahti 2015-07-24 14:03:30 UTC Comment hidden (obsolete)
Comment 5 Olli-Antti Kivilahti 2015-07-31 10:32:43 UTC Comment hidden (obsolete)
Comment 6 Olli-Antti Kivilahti 2015-08-17 11:59:25 UTC
Created attachment 41530 [details] [review]
Bug 14539 - Introduction to cast() (ToObject), aka. make a Koha::Object from various input types and validate.
Comment 7 Zeno Tajoli 2015-09-01 08:20:13 UTC
Patch complexity is 'Large' because this change has many architectural connections
Comment 8 Mark Tompsett 2016-02-02 21:04:46 UTC
bug 15473 conflicts with this.
Comment 9 Lari Taskula 2017-05-08 10:51:09 UTC
Created attachment 63235 [details] [review]
Bug 14539 - Koha::Objects->cast(). Introduction to cast() (ToObject), aka. make a Koha::Object from various input types and validate.

Finds a Borrower-object (or any other type) from various different types of inputs.
Also doubles as a validator function, dying if input is improper.

USAGE:
    my $member = C4::Members::GetMember(borrowernumber => $borrowernumber);
    my $borrower = Koha::Borrowers->cast($member);

Currently Koha is like an archeological dig site, we have different layers of
dealing with various business objects.

We started with DBI and numerous ways of passing an HASH around. There is no
telling if it will be a List of column => values, or a reference to HASH, or a
HASH or just any of the business object's (eg. Borrower's) unique identifiers
(userid, cardnumber, borrowernumber).

Then DBIx came to the rescue and now we are need to learn DBI and DBIx and SQL
to do DB operatons in Koha. Migration to DBIx is on the way.

Finally we have Koha::Object and subclasses, which include and use the DBIx,
but those are not directly compatible, since Koha::Object is not a subclass of
DBIx::Class making life occasionally miserable.
Now we need to know 3 methods of DB accession.

I am really frustrated with all of those different layers of history, and
making things work nicely across all different programming patterns, I have
had great success in using a casting system, where we take any value and try
to make a Koha::Object-subclass out of it.

So we try to cast a Scalar or a reference of Koha::Object-implementation or
DBIx::ResultSet or HASH, to the desired Koha::Object-implementation.
This is a nice validation/entry function in any subroutine dealing with
business objects, making sure that we always have the "correct" implementation
of the same business object.

Unit tests included demonstrating the feature and possible pitfalls.
Comment 10 Lari Taskula 2017-05-08 11:07:03 UTC
Created attachment 63236 [details] [review]
Bug 14539 - Koha::Objects->cast(). Introduction to cast() (ToObject), aka. make a Koha::Object from various input types and validate.

Finds a Patron-object (or any other type) from various different types of inputs.
Also doubles as a validator function, dying if input is improper.

USAGE:
    my $member = C4::Members::GetMember(borrowernumber => $borrowernumber);
    my $borrower = Koha::Patrons->cast($member);

Currently Koha is like an archeological dig site, we have different layers of
dealing with various business objects.

We started with DBI and numerous ways of passing an HASH around. There is no
telling if it will be a List of column => values, or a reference to HASH, or a
HASH or just any of the business object's (eg. Borrower's) unique identifiers
(userid, cardnumber, borrowernumber).

Then DBIx came to the rescue and now we are need to learn DBI and DBIx and SQL
to do DB operatons in Koha. Migration to DBIx is on the way.

Finally we have Koha::Object and subclasses, which include and use the DBIx,
but those are not directly compatible, since Koha::Object is not a subclass of
DBIx::Class making life occasionally miserable.
Now we need to know 3 methods of DB accession.

I am really frustrated with all of those different layers of history, and
making things work nicely across all different programming patterns, I have
had great success in using a casting system, where we take any value and try
to make a Koha::Object-subclass out of it.

So we try to cast a Scalar or a reference of Koha::Object-implementation or
DBIx::ResultSet or HASH, to the desired Koha::Object-implementation.
This is a nice validation/entry function in any subroutine dealing with
business objects, making sure that we always have the "correct" implementation
of the same business object.

Unit tests included demonstrating the feature and possible pitfalls.
Comment 11 Lari Taskula 2017-05-08 11:10:52 UTC
Created attachment 63237 [details] [review]
Bug 14539 - Koha::Objects->cast(). Introduction to cast() (ToObject), aka. make a Koha::Object from various input types and validate.

Finds a Patron-object (or any other type) from various different types of inputs.
Also doubles as a validator function, dying if input is improper.

USAGE:
    my $member = C4::Members::GetMember(borrowernumber => $borrowernumber);
    my $borrower = Koha::Patrons->cast($member);

Currently Koha is like an archeological dig site, we have different layers of
dealing with various business objects.

We started with DBI and numerous ways of passing an HASH around. There is no
telling if it will be a List of column => values, or a reference to HASH, or a
HASH or just any of the business object's (eg. Patron's) unique identifiers
(userid, cardnumber, borrowernumber).

Then DBIx came to the rescue and now we are need to learn DBI and DBIx and SQL
to do DB operatons in Koha. Migration to DBIx is on the way.

Finally we have Koha::Object and subclasses, which include and use the DBIx,
but those are not directly compatible, since Koha::Object is not a subclass of
DBIx::Class making life occasionally miserable.
Now we need to know 3 methods of DB accession.

I am really frustrated with all of those different layers of history, and
making things work nicely across all different programming patterns, I have
had great success in using a casting system, where we take any value and try
to make a Koha::Object-subclass out of it.

So we try to cast a Scalar or a reference of Koha::Object-implementation or
DBIx::ResultSet or HASH, to the desired Koha::Object-implementation.
This is a nice validation/entry function in any subroutine dealing with
business objects, making sure that we always have the "correct" implementation
of the same business object.

Unit tests included demonstrating the feature and possible pitfalls.
Comment 12 Lari Taskula 2017-05-08 11:13:48 UTC
Rebased on master, renamed occurrences of "Borrower" to "Patron", still blocked by 13995 but patches from both Bugs should apply at the time of this comment.
Comment 13 Lari Taskula 2017-05-08 14:30:20 UTC
Created attachment 63243 [details] [review]
Bug 14539 - Koha::Objects->cast(). Introduction to cast() (ToObject), aka. make a Koha::Object from various input types and validate.

Finds a Patron-object (or any other type) from various different types of inputs.
Also doubles as a validator function, dying if input is improper.

USAGE:
    my $member = C4::Members::GetMember(borrowernumber => $borrowernumber);
    my $borrower = Koha::Patrons->cast($member);

Currently Koha is like an archeological dig site, we have different layers of
dealing with various business objects.

We started with DBI and numerous ways of passing an HASH around. There is no
telling if it will be a List of column => values, or a reference to HASH, or a
HASH or just any of the business object's (eg. Patron's) unique identifiers
(userid, cardnumber, borrowernumber).

Then DBIx came to the rescue and now we are need to learn DBI and DBIx and SQL
to do DB operatons in Koha. Migration to DBIx is on the way.

Finally we have Koha::Object and subclasses, which include and use the DBIx,
but those are not directly compatible, since Koha::Object is not a subclass of
DBIx::Class making life occasionally miserable.
Now we need to know 3 methods of DB accession.

I am really frustrated with all of those different layers of history, and
making things work nicely across all different programming patterns, I have
had great success in using a casting system, where we take any value and try
to make a Koha::Object-subclass out of it.

So we try to cast a Scalar or a reference of Koha::Object-implementation or
DBIx::ResultSet or HASH, to the desired Koha::Object-implementation.
This is a nice validation/entry function in any subroutine dealing with
business objects, making sure that we always have the "correct" implementation
of the same business object.

Unit tests included demonstrating the feature and possible pitfalls.
Comment 14 Lari Taskula 2017-05-08 15:15:41 UTC
Created attachment 63246 [details] [review]
Bug 14539 - Koha::Objects->cast(). Introduction to cast() (ToObject), aka. make a Koha::Object from various input types and validate.

Finds a Patron-object (or any other type) from various different types of inputs.
Also doubles as a validator function, dying if input is improper.

USAGE:
    my $member = C4::Members::GetMember(borrowernumber => $borrowernumber);
    my $borrower = Koha::Patrons->cast($member);

Currently Koha is like an archeological dig site, we have different layers of
dealing with various business objects.

We started with DBI and numerous ways of passing an HASH around. There is no
telling if it will be a List of column => values, or a reference to HASH, or a
HASH or just any of the business object's (eg. Patron's) unique identifiers
(userid, cardnumber, borrowernumber).

Then DBIx came to the rescue and now we are need to learn DBI and DBIx and SQL
to do DB operatons in Koha. Migration to DBIx is on the way.

Finally we have Koha::Object and subclasses, which include and use the DBIx,
but those are not directly compatible, since Koha::Object is not a subclass of
DBIx::Class making life occasionally miserable.
Now we need to know 3 methods of DB accession.

I am really frustrated with all of those different layers of history, and
making things work nicely across all different programming patterns, I have
had great success in using a casting system, where we take any value and try
to make a Koha::Object-subclass out of it.

So we try to cast a Scalar or a reference of Koha::Object-implementation or
DBIx::ResultSet or HASH, to the desired Koha::Object-implementation.
This is a nice validation/entry function in any subroutine dealing with
business objects, making sure that we always have the "correct" implementation
of the same business object.

Unit tests included demonstrating the feature and possible pitfalls.