LafayetteCollegeLibraries/spot

View on GitHub
app/models/concerns/spot/nested_collection_behavior.rb

Summary

Maintainability
A
25 mins
Test Coverage
A
96%
# frozen_string_literal: true
module Spot
  # Updates +Collection#add_member_objects+ behavior by adding works to
  # this collection as well as any parent collections.
  #
  # @example
  #   class Collection < ActiveFedora::Base
  #     include Hyrax::CollectionBehavior
  #     include Spot::NestedCollectionBehavior
  #
  #   end
  #
  #   # note: Collection.create doesn't work like this, but let's pretend it does
  #   col_1 = Collection.create(title: ['Parent Collection'])
  #   col_2 = Collection.create(title: ['Child Collection'])
  #
  #   col_2.member_of_collections << col_1
  #
  #   work = Publication.create(title: ['Publication Work'])
  #   col_2.add_member_objects(work.id)
  #
  #   work.member_of_collections.include?(col_2)
  #   # => true
  #   work.member_of_collections.include?(col_1)
  #   # => true
  module NestedCollectionBehavior
    # Add items to a collection via their id values
    #
    # @param [Array<String>, String] new_member_ids
    # @return [Array<ActiveFedora::Base>]
    def add_member_objects(new_member_ids)
      collections_to_add = gather_collections_to_add
      collection_ids_to_add = collections_to_add.map(&:id)

      Array(new_member_ids).collect do |member_id|
        member = member_query_service(member_id)
        message = check_multiple_membership(item: member, collection_ids: collection_ids_to_add)

        if message
          member.errors.add(:collections, message)
        else
          member.member_of_collections += collections_to_add
          member.save!
        end

        member
      end
    end

    private

    # Go down (up?) the family tree until there are no more parent collections to add
    #
    # @return [Array<Collection>]
    def gather_collections_to_add
      collections_to_check = [self]

      [].tap do |collections|
        until collections_to_check.size.zero?
          col = collections_to_check.shift
          col.reindex_extent = Hyrax::Adapters::NestingIndexAdapter::LIMITED_REINDEX

          collections << col unless collections.include?(col)
          collections_to_check += col.member_of_collections
        end
      end
    end

    # Hyrax@3 uses +Hyrax.query_service.find_by_alternate_id+ to fetch an object. Hyrax@2
    # uses +ActiveFedora::Base.find+. This ought to allow us to upgrade without a fuss
    # (at least as far as this code is concerned). We can replace this after the upgrade.
    #
    # @param [String] id
    # @return [ActiveFedora::Base]
    # @todo replace with just a call to +find_by_alternate_id+ after we upgrade to hyrax@3
    #       and start switching to Wings
    def member_query_service(id)
      Hyrax.query_service.find_by_alternate_identifier(alternate_identifier: id, use_valkyrie: false)
    end

    # just a wrapper to clean up +#add_member_objects+
    def check_multiple_membership(item:, collection_ids:)
      Hyrax::MultipleMembershipChecker.new(item: item).check(collection_ids: collection_ids, include_current_members: true)
    end
  end
end