diff --git a/includes/orphaned_objects.inc b/includes/orphaned_objects.inc index 606a988d..4941bab5 100644 --- a/includes/orphaned_objects.inc +++ b/includes/orphaned_objects.inc @@ -145,7 +145,7 @@ function islandora_get_orphaned_objects() { $connection = islandora_get_tuque_connection(); // SPARQL: get orphaned objects, exclude any with a living parent. $object_query = << +!prefix SELECT DISTINCT ?object ?title WHERE { ?object ; @@ -156,22 +156,26 @@ WHERE { } . FILTER (!bound(?model)) - # Filter by "parent" relationships - isMemberOf, isMemberOfCollection, isPageOf. - FILTER (?p = || ?p = || ?p = ) + # Filter by "parent" relationships + FILTER (!dead_parent_relationships) -# Exclude objects with live parents - isMemberOf, isMemberOfCollection, isPageOf. - OPTIONAL { - {?object ?liveparent } - UNION {?object ?liveparent } - UNION { ?object ?liveparent } . - ?liveparent . + # Exclude objects with live parents + OPTIONAL { + !live_parent_relationships . + ?liveparent . } !optionals !filters FILTER (!bound(?liveparent)) } ORDER BY ?object EOQ; - + $parent_relationships = module_invoke_all('islandora_solution_pack_child_relationships', 'all'); + $parent_relationships['prefix'] = array_unique($parent_relationships['prefix']); + $parent_relationships['predicate'] = array_unique($parent_relationships['predicate']); + if (count($parent_relationships['predicate']) == 0) { + // No predicates to search for. Exit early. + return array(); + } $optionals = (array) module_invoke('islandora_xacml_api', 'islandora_basic_collection_get_query_optionals', 'view'); $filter_modules = array( 'islandora_xacml_api', @@ -184,10 +188,16 @@ EOQ; $filter_map = function ($filter) { return "FILTER($filter)"; }; + $parent_map = function ($parent) { + return "?object $parent ?liveparent"; + }; // Use separate queries for different object types. $sparql_query_objects = format_string($object_query, array( '!optionals' => !empty($optionals) ? ('OPTIONAL {{' . implode('} UNION {', $optionals) . '}}') : '', '!filters' => !empty($filters) ? implode(' ', array_map($filter_map, $filters)) : '', + '!dead_parent_relationships' => '?p = ' . implode(' || ?p = ', $parent_relationships['predicate']), + '!live_parent_relationships' => '{' . implode(' } UNION { ', array_map($parent_map, $parent_relationships['predicate'])) . '}', + '!prefix' => implode("\n", $parent_relationships['prefix']), )); $results = $connection->repository->ri->sparqlQuery($sparql_query_objects); return $results; diff --git a/islandora.api.php b/islandora.api.php index c5de95e1..1cdb9205 100644 --- a/islandora.api.php +++ b/islandora.api.php @@ -966,3 +966,30 @@ function hook_islandora_datastream_filename_alter(&$filename, AbstractDatastream ); } } + +/** + * Allow solution packs to register relationships used for children. + * + * @param string|array $cmodels + * This takes either: + * - string: the string 'all'. Function returns all child relationships. + * - array: an array of cmodel PIDs to return the relationships for. + * + * @return array + * - prefix (array): This is is a valid snip-it of SPARQL to register + * prefixes used in the predicates array. + * - predicate (array): This array contains predicates used by the solution + * pack for child objects. + */ +function hook_islandora_solution_pack_child_relationships($cmodels) { + if ($cmodels === 'all' || in_array('my:cmodel_pid', $cmodels)) { + return array( + 'prefix' => array('PREFIX islandora: '), + 'predicate' => array( + '', + '', + '', + ), + ); + } +} diff --git a/islandora.module b/islandora.module index f9276404..337212e8 100644 --- a/islandora.module +++ b/islandora.module @@ -2215,3 +2215,12 @@ function islandora_islandora_breadcrumbs_backends() { ), ); } + +/** + * Implements hook_islandora_solution_pack_child_relationships + */ +function islandora_islandora_solution_pack_child_relationships($cmodels) { + // Return empty arrays from core implementation so that these keys always + // exist when the hook is called, even if no module responds. + return array('predicate' => array(), 'prefix' => array()); +}