Bug 27424: Update schema file
[koha-ffzg.git] / Koha / Objects.pm
index 9184a23..133d0cb 100644 (file)
@@ -19,10 +19,13 @@ package Koha::Objects;
 
 use Modern::Perl;
 
-use Carp;
+use Carp qw( carp );
 use List::MoreUtils qw( none );
+use Class::Inspector;
 
 use Koha::Database;
+use Koha::Exceptions::Object;
+use Koha::DateUtils qw( dt_from_string );
 
 =head1 NAME
 
@@ -31,7 +34,7 @@ Koha::Objects - Koha Object set base class
 =head1 SYNOPSIS
 
     use Koha::Objects;
-    my @objects = Koha::Objects->search({ borrowernumber => $borrowernumber});
+    my $objects = Koha::Objects->search({ borrowernumber => $borrowernumber});
 
 =head1 DESCRIPTION
 
@@ -117,32 +120,30 @@ sub find_or_create {
     return $object;
 }
 
-=head3 Koha::Objects->search();
+=head3 search
 
-my @objects = Koha::Objects->search($params);
+    # scalar context
+    my $objects = Koha::Objects->search([$params, $attributes]);
+    while (my $object = $objects->next) {
+        do_stuff($object);
+    }
+
+This B<instantiates> the I<Koha::Objects> class, and generates a resultset
+based on the query I<$params> and I<$attributes> that are passed (like in DBIC).
 
 =cut
 
 sub search {
     my ( $self, $params, $attributes ) = @_;
 
-    if (wantarray) {
-        my @dbic_rows = $self->_resultset()->search($params, $attributes);
-
-        return $self->_wrap(@dbic_rows);
-
-    }
-    else {
-        my $class = ref($self) ? ref($self) : $self;
-        my $rs = $self->_resultset()->search($params, $attributes);
+    my $class = ref($self) ? ref($self) : $self;
+    my $rs = $self->_resultset()->search($params, $attributes);
 
-        return $class->_new_from_dbic($rs);
-    }
+    return $class->_new_from_dbic($rs);
 }
 
 =head3 search_related
 
-    my @objects = Koha::Objects->search_related( $rel_name, $cond?, \%attrs? );
     my $objects = Koha::Objects->search_related( $rel_name, $cond?, \%attrs? );
 
 Searches the specified relationship, optionally specifying a condition and attributes for matching records.
@@ -153,22 +154,123 @@ sub search_related {
     my ( $self, $rel_name, @params ) = @_;
 
     return if !$rel_name;
-    if (wantarray) {
-        my @dbic_rows = $self->_resultset()->search_related($rel_name, @params);
-        return if !@dbic_rows;
-        my $object_class = _get_objects_class( $dbic_rows[0]->result_class );
 
-        eval "require $object_class";
-        return _wrap( $object_class, @dbic_rows );
+    my $rs = $self->_resultset()->search_related($rel_name, @params);
+    return if !$rs;
+    my $object_class = _get_objects_class( $rs->result_class );
+
+    eval "require $object_class";
+    return _new_from_dbic( $object_class, $rs );
+}
+
+=head3 delete
+
+=cut
+
+sub delete {
+    my ($self) = @_;
+
+    if ( Class::Inspector->function_exists( $self->object_class, 'delete' ) ) {
+        my $objects_deleted;
+        $self->_resultset->result_source->schema->txn_do( sub {
+            $self->reset; # If we iterated already over the set
+            while ( my $o = $self->next ) {
+                $o->delete;
+                $objects_deleted++;
+            }
+        });
+        return $objects_deleted;
+    }
+
+    return $self->_resultset->delete;
+}
+
+=head3 update
+
+    my $objects = Koha::Objects->new; # or Koha::Objects->search
+    $objects->update( $fields, [ { no_triggers => 0/1 } ] );
+
+This method overloads the DBIC inherited one so if code-level triggers exist
+(through the use of an overloaded I<update> or I<store> method in the Koha::Object
+based class) those are called in a loop on the resultset.
+
+If B<no_triggers> is passed and I<true>, then the DBIC update method is called
+directly. This feature is important for performance, in cases where no code-level
+triggers should be triggered. The developer will explicitly ask for this and QA should
+catch wrong uses as well.
+
+=cut
+
+sub update {
+    my ($self, $fields, $options) = @_;
+
+    Koha::Exceptions::Object::NotInstantiated->throw(
+        method => 'update',
+        class  => $self
+    ) unless ref $self;
+
+    my $no_triggers = $options->{no_triggers};
+
+    if (
+        !$no_triggers
+        && ( Class::Inspector->function_exists( $self->object_class, 'update' )
+          or Class::Inspector->function_exists( $self->object_class, 'store' ) )
+      )
+    {
+        my $objects_updated;
+        $self->_resultset->result_source->schema->txn_do( sub {
+            while ( my $o = $self->next ) {
+                $o->update($fields);
+                $objects_updated++;
+            }
+        });
+        return $objects_updated;
+    }
+
+    return $self->_resultset->update($fields);
+}
+
+=head3 filter_by_last_update
 
-    } else {
-        my $rs = $self->_resultset()->search_related($rel_name, @params);
-        return if !$rs;
-        my $object_class = _get_objects_class( $rs->result_class );
+my $filtered_objects = $objects->filter_by_last_update
 
-        eval "require $object_class";
-        return _new_from_dbic( $object_class, $rs );
+days exclusive by default (will be inclusive if days_inclusive is passed and set)
+from inclusive
+to   inclusive
+
+=cut
+
+sub filter_by_last_update {
+    my ( $self, $params ) = @_;
+    my $timestamp_column_name = $params->{timestamp_column_name} || 'timestamp';
+    my $days_inclusive = $params->{days_inclusive} || 0;
+    my $conditions;
+    Koha::Exceptions::MissingParameter->throw(
+        "Missing mandatory parameter: days or from or to")
+      unless exists $params->{days}
+          or exists $params->{from}
+          or exists $params->{to};
+
+    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
+    if ( exists $params->{days} ) {
+        my $dt = Koha::DateUtils::dt_from_string();
+        my $operator = $days_inclusive ? '<=' : '<';
+        $conditions->{$operator} = $dtf->format_date( $dt->subtract( days => $params->{days} ) );
+    }
+    if ( exists $params->{from} ) {
+        my $from = ref($params->{from}) ? $params->{from} : dt_from_string($params->{from});
+        $conditions->{'>='} = $dtf->format_date( $from );
+    }
+    if ( exists $params->{to} ) {
+        my $to = ref($params->{to}) ? $params->{to} : dt_from_string($params->{to});
+        $conditions->{'<='} = $dtf->format_date( $to );
     }
+
+    return $self->search(
+        {
+            $timestamp_column_name => $conditions
+        }
+    );
 }
 
 =head3 single
@@ -237,7 +339,29 @@ sub last {
     return $object;
 }
 
+=head3 empty
+
+    my $empty_rs = Koha::Objects->new->empty;
+
+Sets the resultset empty. This is handy for consistency on method returns
+(e.g. if we know in advance we won't have results but want to keep returning
+an iterator).
+
+=cut
+
+sub empty {
+    my ($self) = @_;
+
+    Koha::Exceptions::Object::NotInstantiated->throw(
+        method => 'empty',
+        class  => $self
+    ) unless ref $self;
 
+    $self = $self->search(\'0 = 1');
+    $self->_resultset()->set_cache([]);
+
+    return $self;
+}
 
 =head3 Koha::Objects->reset();
 
@@ -431,14 +555,14 @@ The autoload method is used call DBIx::Class method on a resultset.
 
 Important: If you plan to use one of the DBIx::Class methods you must provide
 relevant tests in t/db_dependent/Koha/Objects.t
-Currently count, pager, update and delete are covered.
+Currently count, is_paged, pager, result_class, single and slice are covered.
 
 =cut
 
 sub AUTOLOAD {
     my ( $self, @params ) = @_;
 
-    my @known_methods = qw( count is_paged pager update delete result_class single slice );
+    my @known_methods = qw( count is_paged pager result_class single slice );
     my $method = our $AUTOLOAD;
     $method =~ s/.*:://;