PageRenderTime 60ms CodeModel.GetById 6ms app.highlight 43ms RepoModel.GetById 1ms app.codeStats 1ms

/app/models/ca_objects.php

https://bitbucket.org/Sinfin/pawtucket
PHP | 1171 lines | 828 code | 105 blank | 238 comment | 145 complexity | c495a080fd1fa7d38769206b6f350445 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2/** ---------------------------------------------------------------------
   3 * app/models/ca_objects.php : table access class for table ca_objects
   4 * ----------------------------------------------------------------------
   5 * CollectiveAccess
   6 * Open-source collections management software
   7 * ----------------------------------------------------------------------
   8 *
   9 * Software by Whirl-i-Gig (http://www.whirl-i-gig.com)
  10 * Copyright 2008-2011 Whirl-i-Gig
  11 *
  12 * For more information visit http://www.CollectiveAccess.org
  13 *
  14 * This program is free software; you may redistribute it and/or modify it under
  15 * the terms of the provided license as published by Whirl-i-Gig
  16 *
  17 * CollectiveAccess is distributed in the hope that it will be useful, but
  18 * WITHOUT ANY WARRANTIES whatsoever, including any implied warranty of 
  19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  20 *
  21 * This source code is free and modifiable under the terms of 
  22 * GNU General Public License. (http://www.gnu.org/copyleft/gpl.html). See
  23 * the "license.txt" file for details, or visit the CollectiveAccess web site at
  24 * http://www.CollectiveAccess.org
  25 * 
  26 * @package CollectiveAccess
  27 * @subpackage models
  28 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License version 3
  29 * 
  30 * ----------------------------------------------------------------------
  31 */
  32 
  33 /**
  34   *
  35   */
  36
  37require_once(__CA_LIB_DIR__."/ca/IBundleProvider.php");
  38require_once(__CA_LIB_DIR__."/ca/BundlableLabelableBaseModelWithAttributes.php");
  39require_once(__CA_MODELS_DIR__."/ca_object_representations.php");
  40require_once(__CA_MODELS_DIR__."/ca_objects_x_object_representations.php");
  41
  42
  43BaseModel::$s_ca_models_definitions['ca_objects'] = array(
  44 	'NAME_SINGULAR' 	=> _t('object'),
  45 	'NAME_PLURAL' 		=> _t('objects'),
  46 	'FIELDS' 			=> array(
  47		'object_id' => array(
  48				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_HIDDEN, 
  49				'IDENTITY' => true, 'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
  50				'IS_NULL' => false, 
  51				'DEFAULT' => '',
  52				'LABEL' => 'Object id', 'DESCRIPTION' => 'Unique identifier for the object.'
  53		),
  54		'parent_id' => array(
  55				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_OMIT, 
  56				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
  57				'IS_NULL' => true, 
  58				'DEFAULT' => '',
  59				'LABEL' => 'Parent id', 'DESCRIPTION' => 'Identifier of parent object; is null if object is root of hierarchy.'
  60		),
  61		'hier_object_id' => array(
  62				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_OMIT, 
  63				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
  64				'IS_NULL' => false, 
  65				'DEFAULT' => '',
  66				'LABEL' => 'Object hierarchy', 'DESCRIPTION' => 'Identifier of object that is root of the object hierarchy.'
  67		),
  68		'lot_id' => array(
  69				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_HIDDEN, 
  70				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
  71				'IS_NULL' => true, 
  72				'DEFAULT' => '',
  73				'LABEL' => _t('Lot'), 'DESCRIPTION' => _t('Lot this object belongs to; is null if object is not part of a lot.')
  74		),
  75		'locale_id' => array(
  76				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_SELECT, 
  77				'DISPLAY_WIDTH' => 40, 'DISPLAY_HEIGHT' => 1,
  78				'IS_NULL' => true, 
  79				'DISPLAY_FIELD' => array('ca_locales.name'),
  80				'DEFAULT' => '',
  81				'LABEL' => _t('Locale'), 'DESCRIPTION' => _t('The locale from which the object originates.')
  82		),
  83		'source_id' => array(
  84				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_SELECT, 
  85				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
  86				'IS_NULL' => true, 
  87				'DEFAULT' => '',
  88				'LIST_CODE' => 'object_sources',
  89				'LABEL' => _t('Source'), 'DESCRIPTION' => _t('Administrative source of object. This value is often used to indicate the administrative sub-division or legacy database from which the object originates, but can also be re-tasked for use as a simple classification tool if needed.')
  90		),
  91		'type_id' => array(
  92				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_SELECT, 
  93				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
  94				'IS_NULL' => false, 
  95				'DEFAULT' => '',
  96				'LIST_CODE' => 'object_types',
  97				'LABEL' => _t('Type'), 'DESCRIPTION' => _t('The type of the object. In CollectiveAccess every object has a single "instrinsic" type that determines the set of descriptive, technical and administrative metadata that can be applied to it. As such this type is "low-level" and directly tied to the form of the object - eg. photograph, book, analog video recording, etc.')
  98		),
  99		'idno' => array(
 100				'FIELD_TYPE' => FT_TEXT, 'DISPLAY_TYPE' => DT_FIELD, 
 101				'DISPLAY_WIDTH' => 40, 'DISPLAY_HEIGHT' => 1,
 102				'IS_NULL' => false, 
 103				'DEFAULT' => '',
 104				'LABEL' => _t('Object identifier'), 'DESCRIPTION' => _t('A unique alphanumeric identifier for this object. This is usually equivalent to the "accession number" in museum settings.'),
 105				'BOUNDS_LENGTH' => array(0,255)
 106		),
 107		'idno_sort' => array(
 108				'FIELD_TYPE' => FT_TEXT, 'DISPLAY_TYPE' => DT_OMIT, 
 109				'DISPLAY_WIDTH' => 40, 'DISPLAY_HEIGHT' => 1,
 110				'IS_NULL' => false, 
 111				'DEFAULT' => '',
 112				'LABEL' => 'Sortable object identifier', 'DESCRIPTION' => 'Value used for sorting objects on identifier value.',
 113				'BOUNDS_LENGTH' => array(0,255)
 114		),
 115		'item_status_id' => array(
 116				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_SELECT, 
 117				'DISPLAY_WIDTH' => 40, 'DISPLAY_HEIGHT' => 1,
 118				'IS_NULL' => true, 
 119				'DEFAULT' => '',
 120				'LIST_CODE' => 'object_statuses',
 121				'LABEL' => _t('Accession status'), 'DESCRIPTION' => _t('Indicates accession/collection status of object. (eg. accessioned, pending accession, loan, non-accessioned item, etc.)')
 122		),
 123		'acquisition_type_id' => array(
 124				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_SELECT, 
 125				'DISPLAY_WIDTH' => 40, 'DISPLAY_HEIGHT' => 1,
 126				'IS_NULL' => true, 
 127				'DEFAULT' => '',
 128				'LIST_CODE' => 'object_acq_types',
 129				'LABEL' => _t('Acquisition method'), 'DESCRIPTION' => _t('Indicates method employed to acquire the object.')
 130		),
 131		'source_info' => array(
 132				'FIELD_TYPE' => FT_VARS, 'DISPLAY_TYPE' => DT_OMIT, 
 133				'DISPLAY_WIDTH' => 88, 'DISPLAY_HEIGHT' => 15,
 134				'IS_NULL' => false, 
 135				'DEFAULT' => '',
 136				'LABEL' => 'Source information', 'DESCRIPTION' => 'Serialized array used to store source information for object information retrieved via web services [NOT IMPLEMENTED YET].'
 137		),
 138		'hier_left' => array(
 139				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_OMIT, 
 140				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
 141				'IS_NULL' => false, 
 142				'DEFAULT' => '',
 143				'LABEL' => 'Hierarchical index - left bound', 'DESCRIPTION' => 'Left-side boundary for nested set-style hierarchical indexing; used to accelerate search and retrieval of hierarchical record sets.'
 144		),
 145		'hier_right' => array(
 146				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_OMIT, 
 147				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
 148				'IS_NULL' => false, 
 149				'DEFAULT' => '',
 150				'LABEL' => 'Hierarchical index - right bound', 'DESCRIPTION' => 'Right-side boundary for nested set-style hierarchical indexing; used to accelerate search and retrieval of hierarchical record sets.'
 151		),
 152		'extent' => array(
 153				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_FIELD, 
 154				'DISPLAY_WIDTH' => 20, 'DISPLAY_HEIGHT' => 1,
 155				'IS_NULL' => false, 
 156				'DEFAULT' => '',
 157				'LABEL' => _t('Extent'), 'DESCRIPTION' => _t('The extent of the object. This is typically the number of discrete items that compose the object represented by this record. It is stored as a whole number (eg. 1, 2, 3...).')
 158		),
 159		'extent_units' => array(
 160				'FIELD_TYPE' => FT_TEXT, 'DISPLAY_TYPE' => DT_FIELD, 
 161				'DISPLAY_WIDTH' => 20, 'DISPLAY_HEIGHT' => 1,
 162				'IS_NULL' => false, 
 163				'DEFAULT' => '',
 164				'LABEL' => _t('Extent units'), 'DESCRIPTION' => _t('Units of extent value. (eg. pieces, items, components, reels, etc.)'),
 165				'BOUNDS_LENGTH' => array(0,255)
 166		),
 167		'access' => array(
 168				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_SELECT, 
 169				'DISPLAY_WIDTH' => 40, 'DISPLAY_HEIGHT' => 1,
 170				'IS_NULL' => false, 
 171				'DEFAULT' => 0,
 172				'BOUNDS_CHOICE_LIST' => array(
 173					_t('Not accessible to public') => 0,
 174					_t('Accessible to public') => 1
 175				),
 176				'LIST' => 'access_statuses',
 177				'LABEL' => _t('Access'), 'DESCRIPTION' => _t('Indicates if object is accessible to the public or not.')
 178		),
 179		'status' => array(
 180				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_SELECT, 
 181				'DISPLAY_WIDTH' => 40, 'DISPLAY_HEIGHT' => 1,
 182				'IS_NULL' => false, 
 183				'DEFAULT' => 0,
 184				'BOUNDS_CHOICE_LIST' => array(
 185					_t('Newly created') => 0,
 186					_t('Editing in progress') => 1,
 187					_t('Editing complete - pending review') => 2,
 188					_t('Review in progress') => 3,
 189					_t('Completed') => 4
 190				),
 191				'LIST' => 'workflow_statuses',
 192				'LABEL' => _t('Status'), 'DESCRIPTION' => _t('Indicates the current state of the object record.')
 193		),
 194		'deleted' => array(
 195				'FIELD_TYPE' => FT_BIT, 'DISPLAY_TYPE' => DT_OMIT, 
 196				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
 197				'IS_NULL' => false, 
 198				'DEFAULT' => 0,
 199				'LABEL' => _t('Is deleted?'), 'DESCRIPTION' => _t('Indicates if the object is deleted or not.'),
 200				'BOUNDS_VALUE' => array(0,1)
 201		),
 202		'rank' => array(
 203				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_FIELD, 
 204				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
 205				'IS_NULL' => false, 
 206				'DEFAULT' => '',
 207				'LABEL' => _t('Sort order'), 'DESCRIPTION' => _t('Sort order'),
 208		)
 209	)
 210);
 211
 212class ca_objects extends BundlableLabelableBaseModelWithAttributes implements IBundleProvider {
 213	# ---------------------------------
 214	# --- Object attribute properties
 215	# ---------------------------------
 216	# Describe structure of content object's properties - eg. database fields and their
 217	# associated types, what modes are supported, et al.
 218	#
 219
 220	# ------------------------------------------------------
 221	# --- Basic object parameters
 222	# ------------------------------------------------------
 223	# what table does this class represent?
 224	protected $TABLE = 'ca_objects';
 225	      
 226	# what is the primary key of the table?
 227	protected $PRIMARY_KEY = 'object_id';
 228
 229	# ------------------------------------------------------
 230	# --- Properties used by standard editing scripts
 231	# 
 232	# These class properties allow generic scripts to properly display
 233	# records from the table represented by this class
 234	#
 235	# ------------------------------------------------------
 236
 237	# Array of fields to display in a listing of records from this table
 238	protected $LIST_FIELDS = array('idno');
 239
 240	# When the list of "list fields" above contains more than one field,
 241	# the LIST_DELIMITER text is displayed between fields as a delimiter.
 242	# This is typically a comma or space, but can be any string you like
 243	protected $LIST_DELIMITER = ' ';
 244
 245	# What you'd call a single record from this table (eg. a "person")
 246	protected $NAME_SINGULAR;
 247
 248	# What you'd call more than one record from this table (eg. "people")
 249	protected $NAME_PLURAL;
 250
 251	# List of fields to sort listing of records by; you can use 
 252	# SQL 'ASC' and 'DESC' here if you like.
 253	protected $ORDER_BY = array('idno');
 254
 255	# Maximum number of record to display per page in a listing
 256	protected $MAX_RECORDS_PER_PAGE = 20; 
 257
 258	# How do you want to page through records in a listing: by number pages ordered
 259	# according to your setting above? Or alphabetically by the letters of the first
 260	# LIST_FIELD?
 261	protected $PAGE_SCHEME = 'alpha'; # alpha [alphabetical] or num [numbered pages; default]
 262
 263	# If you want to order records arbitrarily, add a numeric field to the table and place
 264	# its name here. The generic list scripts can then use it to order table records.
 265	protected $RANK = 'rank';
 266	
 267	# ------------------------------------------------------
 268	# Hierarchical table properties
 269	# ------------------------------------------------------
 270	protected $HIERARCHY_TYPE				=	__CA_HIER_TYPE_ADHOC_MONO__;
 271	protected $HIERARCHY_LEFT_INDEX_FLD 	= 	'hier_left';
 272	protected $HIERARCHY_RIGHT_INDEX_FLD 	= 	'hier_right';
 273	protected $HIERARCHY_PARENT_ID_FLD		=	'parent_id';
 274	protected $HIERARCHY_DEFINITION_TABLE	=	'ca_objects';
 275	protected $HIERARCHY_ID_FLD				=	'hier_object_id';
 276	protected $HIERARCHY_POLY_TABLE			=	null;
 277	
 278	# ------------------------------------------------------
 279	# Change logging
 280	# ------------------------------------------------------
 281	protected $UNIT_ID_FIELD = null;
 282	protected $LOG_CHANGES_TO_SELF = true;
 283	protected $LOG_CHANGES_USING_AS_SUBJECT = array(
 284		"FOREIGN_KEYS" => array(
 285			'lot_id'
 286		),
 287		"RELATED_TABLES" => array(
 288		
 289		)
 290	);
 291
 292	# ------------------------------------------------------
 293	# Labeling
 294	# ------------------------------------------------------
 295	protected $LABEL_TABLE_NAME = 'ca_object_labels';
 296	
 297	# ------------------------------------------------------
 298	# Attributes
 299	# ------------------------------------------------------
 300	protected $ATTRIBUTE_TYPE_ID_FLD = 'type_id';			// name of type field for this table - attributes system uses this to determine via ca_metadata_type_restrictions which attributes are applicable to rows of the given type
 301	protected $ATTRIBUTE_TYPE_LIST_CODE = 'object_types';	// list code (ca_lists.list_code) of list defining types for this table
 302	
 303	# ------------------------------------------------------
 304	# Self-relations
 305	# ------------------------------------------------------
 306	protected $SELF_RELATION_TABLE_NAME = 'ca_objects_x_objects';
 307	
 308	# ------------------------------------------------------
 309	# ID numbering
 310	# ------------------------------------------------------
 311	protected $ID_NUMBERING_ID_FIELD = 'idno';				// name of field containing user-defined identifier
 312	protected $ID_NUMBERING_SORT_FIELD = 'idno_sort';		// name of field containing version of identifier for sorting (is normalized with padding to sort numbers properly)
 313	
 314	# ------------------------------------------------------
 315	# Search
 316	# ------------------------------------------------------
 317	protected $SEARCH_CLASSNAME = 'ObjectSearch';
 318	protected $SEARCH_RESULT_CLASSNAME = 'ObjectSearchResult';
 319	
 320	# ------------------------------------------------------
 321	# $FIELDS contains information about each field in the table. The order in which the fields
 322	# are listed here is the order in which they will be returned using getFields()
 323
 324	protected $FIELDS;
 325	
 326	# ------------------------------------------------------
 327	# --- Constructor
 328	#
 329	# This is a function called when a new instance of this object is created. This
 330	# standard constructor supports three calling modes:
 331	#
 332	# 1. If called without parameters, simply creates a new, empty objects object
 333	# 2. If called with a single, valid primary key value, creates a new objects object and loads
 334	#    the record identified by the primary key value
 335	#
 336	# ------------------------------------------------------
 337	public function __construct($pn_id=null) {
 338		parent::__construct($pn_id);
 339	}
 340	# ------------------------------------------------------
 341	protected function initLabelDefinitions() {
 342		parent::initLabelDefinitions();
 343		$this->BUNDLES['ca_object_representations'] = array('type' => 'related_table', 'repeating' => true, 'label' => _t('Media representations'));
 344		$this->BUNDLES['ca_objects'] = array('type' => 'related_table', 'repeating' => true, 'label' => _t('Related objects'));
 345		$this->BUNDLES['ca_entities'] = array('type' => 'related_table', 'repeating' => true, 'label' => _t('Related entities'));
 346		$this->BUNDLES['ca_places'] = array('type' => 'related_table', 'repeating' => true, 'label' => _t('Related places'));
 347		$this->BUNDLES['ca_occurrences'] = array('type' => 'related_table', 'repeating' => true, 'label' => _t('Related occurrences'));
 348		$this->BUNDLES['ca_collections'] = array('type' => 'related_table', 'repeating' => true, 'label' => _t('Related collections'));
 349		$this->BUNDLES['ca_storage_locations'] = array('type' => 'related_table', 'repeating' => true, 'label' => _t('Related storage locations'));
 350		$this->BUNDLES['ca_loans'] = array('type' => 'related_table', 'repeating' => true, 'label' => _t('Related loans'));
 351		$this->BUNDLES['ca_movements'] = array('type' => 'related_table', 'repeating' => true, 'label' => _t('Related movements'));
 352		
 353		$this->BUNDLES['ca_object_lots'] = array('type' => 'related_table', 'repeating' => true, 'label' => _t('Related lot'));
 354		$this->BUNDLES['ca_object_events'] = array('type' => 'related_table', 'repeating' => true, 'label' => _t('Related events'));
 355		
 356		$this->BUNDLES['ca_list_items'] = array('type' => 'related_table', 'repeating' => true, 'label' => _t('Related vocabulary terms'));
 357		$this->BUNDLES['ca_sets'] = array('type' => 'special', 'repeating' => true, 'label' => _t('Sets'));
 358		
 359		$this->BUNDLES['hierarchy_navigation'] = array('type' => 'special', 'repeating' => false, 'label' => _t('Hierarchy navigation'));
 360		$this->BUNDLES['hierarchy_location'] = array('type' => 'special', 'repeating' => false, 'label' => _t('Location in hierarchy'));
 361	}
 362	# ------------------------------------------------------
 363	public function delete($pb_delete_related=false){
 364		// nuke related representations
 365		foreach($this->getRepresentations() as $va_rep){
 366			$this->removeRepresentation($va_rep["representation_id"]);
 367		}
 368
 369		return parent::delete($pb_delete_related);
 370	}
 371	# ------------------------------------------------------
 372	/**
 373	 * @param array $pa_options
 374	 *		duplicate_media
 375	 */
 376	public function duplicate($pa_options=null) {
 377		$vb_we_set_transaction = false;
 378		if (!$this->inTransaction()) {
 379			$this->setTransaction($o_t = new Transaction($this->getDb()));
 380			$vb_we_set_transaction = true;
 381		} else {
 382			$o_t = $this->getTransaction();
 383		}
 384		
 385		if ($t_dupe = parent::duplicate($pa_options)) {
 386			$vb_duplicate_media = isset($pa_options['duplicate_media']) && $pa_options['duplicate_media'];
 387		
 388			if ($vb_duplicate_media) { 
 389				// Try to link representations
 390				$o_db = $this->getDb();
 391				
 392				$qr_res = $o_db->query("
 393					SELECT *
 394					FROM ca_objects_x_object_representations
 395					WHERE object_id = ?
 396				", (int)$this->getPrimaryKey());
 397				
 398				$va_reps = array();
 399				while($qr_res->nextRow()) {
 400					$va_reps[$qr_res->get('representation_id')] = $qr_res->getRow();
 401				}
 402				
 403				$t_object_x_rep = new ca_objects_x_object_representations();
 404				foreach($va_reps as $vn_representation_id => $va_rep) {
 405					$t_object_x_rep->setMode(ACCESS_WRITE);
 406					$va_rep['object_id'] = $t_dupe->getPrimaryKey();
 407					$t_object_x_rep->set($va_rep);
 408					$t_object_x_rep->insert();
 409					
 410					if ($t_object_x_rep->numErrors()) {
 411						$this->errors = $t_object_x_rep->errors;
 412						if ($vb_we_set_transaction) { $this->removeTransaction(false);}
 413						return false;
 414					}
 415				}
 416			}
 417		}
 418		
 419		
 420		if ($vb_we_set_transaction) { $this->removeTransaction(true);}
 421		return $t_dupe;
 422	}
 423	# ------------------------------------------------------
 424	
 425 	# ------------------------------------------------------
 426 	# Representations
 427 	# ------------------------------------------------------
 428 	/**
 429 	 * Returns information about representations linked to the currently loaded object. Use this if you want to get the urls, tags and other information for all representations associated with a given object.
 430 	 *
 431 	 * @param array $pa_versions An array of media versions to include information for. If you omit this then a single version, 'preview170', is assumed by default.
 432 	 * @param array $pa_version_sizes Optional array of sizes to force specific versions to. The array keys are version names; the values are arrays with two keys: 'width' and 'height'; if present these values will be used in lieu of the actual values in the database
 433 	 * @param array $pa_options An optional array of options to use when getting representation information. Supported options are:
 434 	 *		return_primary_only - If true then only the primary representation will be returned
 435 	 *		return_with_access - Set to an array of access values to filter representation through; only representations with an access value in the list will be returned
 436 	 *		checkAccess - synonym for return_with_access
 437 	 *		.. and options supported by getMediaTag() .. [they are passed through]
 438 	 *		
 439 	 */
 440 	public function getRepresentations($pa_versions=null, $pa_version_sizes=null, $pa_options=null) {
 441 		if (!($vn_object_id = $this->getPrimaryKey())) { return null; }
 442 		if (!is_array($pa_options)) { $pa_options = array(); }
 443 		
 444 		if (!is_array($pa_versions)) { 
 445 			$pa_versions = array('preview170');
 446 		}
 447 		
 448 		if (isset($pa_options['return_primary_only']) && $pa_options['return_primary_only']) {
 449 			$vs_is_primary_sql = ' AND (caoor.is_primary = 1)';
 450 		} else {
 451 			$vs_is_primary_sql = '';
 452 		}
 453 		
 454 		if ($pa_options['checkAccess']) { $pa_options['return_with_access'] = $pa_options['checkAccess']; }
 455 		if (is_array($pa_options['return_with_access']) && sizeof($pa_options['return_with_access']) > 0) {
 456 			$vs_access_sql = ' AND (caor.access IN ('.join(", ", $pa_options['return_with_access']).'))';
 457 		} else {
 458 			$vs_access_sql = '';
 459 		}
 460 		
 461 		$o_db = $this->getDb();
 462 		
 463 		$qr_reps = $o_db->query("
 464 			SELECT caor.representation_id, caor.media, caoor.is_primary, caor.access, caor.status, l.name, caor.locale_id, caor.media_metadata, caor.type_id, caor.idno, caor.idno_sort
 465 			FROM ca_object_representations caor
 466 			INNER JOIN ca_objects_x_object_representations AS caoor ON caor.representation_id = caoor.representation_id
 467 			LEFT JOIN ca_locales AS l ON caor.locale_id = l.locale_id
 468 			WHERE
 469 				caoor.object_id = ? 
 470 				{$vs_is_primary_sql}
 471 				{$vs_access_sql}
 472 			ORDER BY
 473 				caoor.rank, caoor.is_primary DESC
 474 		", (int)$vn_object_id);
 475
 476 		$va_reps = array();
 477 		$t_rep = new ca_object_representations();
 478 		while($qr_reps->nextRow()) {
 479 			$vn_rep_id = $qr_reps->get('representation_id');
 480 			
 481 			$va_tmp = $qr_reps->getRow();
 482 			$va_tmp['tags'] = array();
 483 			$va_tmp['urls'] = array();
 484 			
 485 			$va_info = $qr_reps->getMediaInfo('media');
 486 			$va_tmp['info'] = array('original_filename' => $va_info['ORIGINAL_FILENAME']);
 487 			foreach ($pa_versions as $vs_version) {
 488 				if (is_array($pa_version_sizes) && isset($pa_version_sizes[$vs_version])) {
 489 					$vn_width = $pa_version_sizes[$vs_version]['width'];
 490 					$vn_height = $pa_version_sizes[$vs_version]['height'];
 491 				} else {
 492 					$vn_width = $vn_height = 0;
 493 				}
 494 				
 495 				if ($vn_width && $vn_height) {
 496 					$va_tmp['tags'][$vs_version] = $qr_reps->getMediaTag('media', $vs_version, array_merge($pa_options, array('viewer_width' => $vn_width, 'viewer_height' => $vn_height)));
 497 				} else {
 498 					$va_tmp['tags'][$vs_version] = $qr_reps->getMediaTag('media', $vs_version, $pa_options);
 499 				}
 500 				$va_tmp['urls'][$vs_version] = $qr_reps->getMediaUrl('media', $vs_version);
 501 				$va_tmp['paths'][$vs_version] = $qr_reps->getMediaPath('media', $vs_version);
 502 				$va_tmp['info'][$vs_version] = $qr_reps->getMediaInfo('media', $vs_version);
 503 				
 504 				$va_tmp['dimensions'][$vs_version] = caGetRepresentationDimensionsForDisplay($qr_reps, 'original', array());
 505 			}
 506 			
 507 				
 508			if (isset($va_info['INPUT']['FETCHED_FROM']) && ($vs_fetched_from_url = $va_info['INPUT']['FETCHED_FROM'])) {
 509				$va_tmp['fetched_from'] = $vs_fetched_from_url;
 510				$va_tmp['fetched_on'] = (int)$va_info['INPUT']['FETCHED_ON'];
 511			}
 512 			
 513 			$va_tmp['num_multifiles'] = $t_rep->numFiles($vn_rep_id);
 514 			$va_reps[$vn_rep_id] = $va_tmp;
 515 		}
 516 		
 517 		$va_labels = $t_rep->getPreferredDisplayLabelsForIDs(array_keys($va_reps));
 518 		foreach($va_labels as $vn_rep_id => $vs_label) {
 519 			$va_reps[$vn_rep_id]['label'] = $vs_label;
 520 		}
 521 		return $va_reps;
 522 	}
 523 	# ------------------------------------------------------
 524 	/**
 525 	 * Finds and returns information about representations meeting the specified criteria. Returns information in the same format as getRepresentations()
 526 	 *
 527 	 * @param array $pa_options Array of criteria options to use when selecting representations. Options include: 
 528 	 *		mimetypes = array of mimetypes to return
 529 	 *		sortby = if set, representations are return sorted using the criteria in ascending order. Valid values are 'filesize' (sort by file size), 'duration' (sort by length of time-based media)
 530 	 * @return array List of representations. Each entry in the list is an associative array of the same format as returned by getRepresentations() and includes properties, tags and urls for the representation.
 531 	 */
 532 	public function findRepresentations($pa_options) {
 533 		$va_mimetypes = array();
 534 		if (isset($pa_options['mimetypes']) && (is_array($pa_options['mimetypes'])) && (sizeof($pa_options['mimetypes']))) {
 535 			$va_mimetypes = array_flip($pa_options['mimetypes']);
 536 		}
 537 		
 538 		$vs_sortby = null;
 539 		if (isset($pa_options['sortby']) && $pa_options['sortby'] && in_array($pa_options['sortby'], array('filesize', 'duration'))) {
 540 			$vs_sortby = $pa_options['sortby'];
 541 		}
 542 		
 543 		$va_reps = $this->getRepresentations(array('original'));
 544 		$va_found_reps = array();
 545 		foreach($va_reps as $vn_i => $va_rep) {
 546 			if((sizeof($va_mimetypes)) && isset($va_mimetypes[$va_rep['info']['original']['MIMETYPE']])) {
 547 				switch($vs_sortby) {
 548 					case 'filesize':
 549 						$va_found_reps[$va_rep['info']['original']['FILESIZE']][] = $va_rep;
 550 						break;
 551 					case 'duration':
 552 						$vn_duration = $va_rep['info']['original']['PROPERTIES']['duration'];
 553 						$va_found_reps[$vn_duration][] = $va_rep;
 554 						break;
 555 					default:
 556 						$va_found_reps[] = $va_rep;
 557 						break;
 558 				}
 559 			}
 560 		}
 561 		
 562 		if ($vs_sortby) {
 563 			ksort($va_found_reps);
 564 			
 565 			$va_tmp = array();
 566 			foreach($va_found_reps as $va_found_rep_groups) {
 567 				foreach($va_found_rep_groups as $va_found_rep) {
 568 					$va_tmp[] = $va_found_rep;
 569 				}
 570 			}
 571 			$va_found_reps = $va_tmp;
 572 		}
 573 		
 574 		return $va_found_reps;
 575 	}
 576 	# ------------------------------------------------------
 577 	# Representations
 578 	# ------------------------------------------------------
 579 	/**
 580 	 *
 581 	 */
 582 	public function getRepresentationIDs($pa_options=null) {
 583 		if (!($vn_object_id = $this->getPrimaryKey())) { return null; }
 584 		if (!is_array($pa_options)) { $pa_options = array(); }
 585 		
 586 		if (!is_array($pa_versions)) { 
 587 			$pa_versions = array('preview170');
 588 		}
 589 		
 590 		if (isset($pa_options['return_primary_only']) && $pa_options['return_primary_only']) {
 591 			$vs_is_primary_sql = ' AND (caoor.is_primary = 1)';
 592 		} else {
 593 			$vs_is_primary_sql = '';
 594 		}
 595 		
 596 		if (is_array($pa_options['return_with_access']) && sizeof($pa_options['return_with_access']) > 0) {
 597 			$vs_access_sql = ' AND (caor.access IN ('.join(", ", $pa_options['return_with_access']).'))';
 598 		} else {
 599 			$vs_access_sql = '';
 600 		}
 601
 602 		
 603 		$o_db = $this->getDb();
 604 		$qr_reps = $o_db->query("
 605 			SELECT caor.representation_id, caoor.is_primary
 606 			FROM ca_object_representations caor
 607 			INNER JOIN ca_objects_x_object_representations AS caoor ON caor.representation_id = caoor.representation_id
 608 			WHERE
 609 				caoor.object_id = ? 
 610 				{$vs_is_primary_sql}
 611 				{$vs_access_sql}
 612 		", (int)$vn_object_id);
 613 		
 614 		$va_rep_ids = array();
 615 		while($qr_reps->nextRow()) {
 616 			$va_rep_ids[$qr_reps->get('representation_id')] = ($qr_reps->get('is_primary') == 1) ? true : false;
 617 		}
 618 		return $va_rep_ids;
 619 	}
 620 	# ------------------------------------------------------
 621 	/**
 622 	 * Returns number of representations attached to the currently loaded object
 623 	 *
 624 	 * @param array $pa_options Optional array of options. Supported options include:
 625 	 *		return_with_type - A type to restrict the count to. Can be either an integer type_id or item_code string
 626 	 *		return_with_access - An array of access values to restrict counts to
 627 	 *
 628 	 * @return integer The number of representations
 629 	 */
 630 	public function getRepresentationCount($pa_options=null) {
 631 		if (!($vn_object_id = $this->getPrimaryKey())) { return null; }
 632 		if (!is_array($pa_options)) { $pa_options = array(); }
 633 		
 634 		$vs_type_sql = '';
 635 		if (isset($pa_options['return_with_type']) && $pa_options['return_with_type']) {
 636 			if (!is_numeric($pa_options['return_with_type'])) {
 637 				$t_list = new ca_lists();
 638 				$pa_options['return_with_type'] = $t_list->getItemIDFromList('object_representation_types', $pa_options['return_with_type']);
 639 			}
 640 			if (intval($pa_options['return_with_type']) > 0) {
 641 				$vs_type_sql = ' AND (caor.type_id = '.intval($pa_options['return_with_type']).')';
 642 			}
 643 		} 
 644 		
 645 		if (is_array($pa_options['return_with_access']) && sizeof($pa_options['return_with_access']) > 0) {
 646 			$vs_access_sql = ' AND (caor.access IN ('.join(", ", $pa_options['return_with_access']).'))';
 647 		} else {
 648 			$vs_access_sql = '';
 649 		}
 650 		
 651 		$o_db = $this->getDb();
 652 		
 653 		$qr_reps = $o_db->query("
 654 			SELECT count(*) c
 655 			FROM ca_object_representations caor
 656 			INNER JOIN ca_objects_x_object_representations AS caoor ON caor.representation_id = caoor.representation_id
 657 			LEFT JOIN ca_locales AS l ON caor.locale_id = l.locale_id
 658 			WHERE
 659 				caoor.object_id = ? 
 660 				{$vs_type_sql}
 661 				{$vs_access_sql}
 662 		", (int)$vn_object_id);
 663
 664		$qr_reps->nextRow();
 665		
 666		return (int)$qr_reps->get('c');
 667 	}
 668 	# ------------------------------------------------------
 669 	/**
 670 	 * Returns primary representation for the object; versions specified in $pa_versions are returned. See description
 671 	 * of getRepresentations() for a description of returned values.
 672 	 */
 673 	public function getPrimaryRepresentation($pa_versions=null, $pa_version_sizes=null, $pa_options=null) {
 674 		if (!is_array($pa_options)) { $pa_options = array(); }
 675 		if(is_array($va_reps = $this->getRepresentations($pa_versions, $pa_version_sizes, array_merge($pa_options, array('return_primary_only' => 1))))) {
 676 			return array_pop($va_reps);
 677 		}
 678 		return array();
 679 	}
 680 	# ------------------------------------------------------
 681 	/**
 682 	 * Returns representation_id of primary representation for the object.
 683 	 */
 684 	public function getPrimaryRepresentationID($pa_options=null) {
 685 		if (!is_array($pa_options)) { $pa_options = array(); }
 686 		$va_rep_ids = $this->getRepresentationIDs(array_merge($pa_options, array('return_primary_only' => 1)));
 687 		if (!is_array($va_rep_ids)) { return null; }
 688 		foreach($va_rep_ids as $vn_representation_id => $vb_is_primary) {
 689 			if ($vb_is_primary) { return $vn_representation_id; }
 690 		}
 691 		return null;
 692 	}
 693 	# ------------------------------------------------------
 694 	/**
 695 	 * Returns ca_object_representations instance loaded with primary representation for the current ca_objects row
 696 	 */
 697 	public function getPrimaryRepresentationInstance($pa_options=null) {
 698 		if (!is_array($pa_options)) { $pa_options = array(); }
 699 		if (!($vn_rep_id = $this->getPrimaryRepresentationID($pa_options))) { return null; }
 700 		
 701 		$t_rep = new ca_object_representations($vn_rep_id);
 702 		
 703 		return ($t_rep->getPrimaryKey()) ? $t_rep : null;
 704 	}
 705 	# ------------------------------------------------------
 706 	/** 
 707 	 * Add media represention to currently loaded object
 708 	 *
 709 	 * @param $ps_media_path - the path to the media you want to add
 710 	 * @param $pn_type_id - the item_id of the representation type, in the ca_list with list_code 'object_represention_types'
 711 	 * @param $pn_locale_id - the locale_id of the locale of the representation
 712 	 * @param $pn_status - the status code for the representation (as defined in item_value fields of items in the 'workflow_statuses' ca_list)
 713 	 * @param $pn_access - the access code for the representation (as defined in item_value fields of items in the 'access_statuses' ca_list)
 714 	 * @param $pb_is_primary - if set to true, representation is designated "primary." Primary representation are used in cases where only one representation is required (such as search results). If a primary representation is already attached to this object, then it will be changed to non-primary as only one representation can be primary at any given time. If no primary representations exist, then the new representation will always be marked primary no matter what the setting of this parameter (there must always be a primary representation, if representations are defined).
 715 	 * @param $pa_values - array of attributes to attach to new representation
 716 	 * @param $pa_options - an array of options passed through to BaseModel::set() when creating the new representation. Currently supported options:
 717 	 *		original_filename - the name of the file being uploaded; will be recorded in the database and used as the filename when the file is subsequently downloaded
 718 	 *		rank - a numeric rank used to order the representations when listed
 719 	 */
 720 	public function addRepresentation($ps_media_path, $pn_type_id, $pn_locale_id, $pn_status, $pn_access, $pb_is_primary, $pa_values=null, $pa_options=null) {
 721 		if (!($vn_object_id = $this->getPrimaryKey())) { return null; }
 722 		if (!$pn_locale_id) { $pn_locale_id = ca_locales::getDefaultCataloguingLocaleID(); }
 723 		
 724 		$t_rep = new ca_object_representations();
 725 		$t_rep->setMode(ACCESS_WRITE);
 726 		$t_rep->set('type_id', $pn_type_id);
 727 		$t_rep->set('locale_id', $pn_locale_id);
 728 		$t_rep->set('status', $pn_status);
 729 		$t_rep->set('access', $pn_access);
 730 		$t_rep->set('media', $ps_media_path, $pa_options);
 731 		
 732 		
 733 		if (is_array($pa_values)) {
 734 			if (isset($pa_values['idno'])) {
 735 				$t_rep->set('idno', $pa_values['idno']);
 736 			}
 737			foreach($pa_values as $vs_element => $va_value) { 					
 738				if (is_array($va_value)) {
 739					// array of values (complex multi-valued attribute)
 740					$t_rep->addAttribute(
 741						array_merge($va_value, array(
 742							'locale_id' => $pn_locale_id
 743						)), $vs_element);
 744				} else {
 745					// scalar value (simple single value attribute)
 746					if ($va_value) {
 747						$t_rep->addAttribute(array(
 748							'locale_id' => $pn_locale_id,
 749							$vs_element => $va_value
 750						), $vs_element);
 751					}
 752				}
 753			}
 754		}
 755 		
 756 		$t_rep->insert();
 757 		
 758 		if ($t_rep->numErrors()) {
 759 			$this->errors = array_merge($this->errors, $t_rep->errors());
 760 			return false;
 761 		}
 762 		
 763 		$vs_label = (isset($pa_values['name']) && $pa_values['name']) ? $pa_values['name'] : '['._t('BLANK').']';
 764 		
 765 		$t_rep->addLabel(array('name' => $vs_label), $pn_locale_id, null, true);
 766 		if ($t_rep->numErrors()) {
 767 			$this->errors = array_merge($this->errors, $t_rep->errors());
 768 			return false;
 769 		}
 770 		
 771 		$t_oxor = new ca_objects_x_object_representations();
 772 		$t_oxor->setMode(ACCESS_WRITE);
 773 		$t_oxor->set('object_id', $vn_object_id);
 774 		$t_oxor->set('representation_id', $t_rep->getPrimaryKey());
 775 		$t_oxor->set('is_primary', $pb_is_primary ? 1 : 0);
 776 		$t_oxor->set('rank', isset($pa_options['rank']) ? (int)$pa_options['rank'] : null);
 777 		$t_oxor->insert();
 778 		
 779 		
 780 		if ($t_oxor->numErrors()) {
 781 			$this->errors = array_merge($this->errors, $t_oxor->errors());
 782 			$t_rep->delete();
 783 			if ($t_rep->numErrors()) {
 784 				$this->errors = array_merge($this->errors, $t_rep->errors());
 785 			}
 786 			return false;
 787 		}
 788 		return $t_oxor->getPrimaryKey();
 789 	}
 790 	# ------------------------------------------------------
 791 	/**
 792 	 *
 793 	 */
 794 	public function editRepresentation($pn_representation_id, $ps_media_path, $pn_locale_id, $pn_status, $pn_access, $pb_is_primary, $pa_values=null, $pa_options=null) {
 795 		if (!($vn_object_id = $this->getPrimaryKey())) { return null; }
 796 		
 797 		$t_rep = new ca_object_representations();
 798 		if (!$t_rep->load(array('representation_id' => $pn_representation_id))) {
 799 			$this->postError(750, _t("Representation id=%1 does not exist", $pn_representation_id), "ca_objects->editRepresentation()");
 800 			return false;
 801 		} else {
 802			$t_rep->setMode(ACCESS_WRITE);
 803			$t_rep->set('locale_id', $pn_locale_id);
 804			$t_rep->set('status', $pn_status);
 805			$t_rep->set('access', $pn_access);
 806			
 807			if ($ps_media_path) {
 808				$t_rep->set('media', $ps_media_path, $pa_options);
 809			}
 810			
 811			if (is_array($pa_values)) {
 812				if (isset($pa_values['idno'])) {
 813					$t_rep->set('idno', $pa_values['idno']);
 814				}
 815				foreach($pa_values as $vs_element => $va_value) { 					
 816					if (is_array($va_value)) {
 817						// array of values (complex multi-valued attribute)
 818						$t_rep->replaceAttribute(
 819							array_merge($va_value, array(
 820								'locale_id' => $pn_locale_id
 821							)), $vs_element);
 822					} else {
 823						// scalar value (simple single value attribute)
 824						if ($va_value) {
 825							$t_rep->replaceAttribute(array(
 826								'locale_id' => $pn_locale_id,
 827								$vs_element => $va_value
 828							), $vs_element);
 829						}
 830					}
 831				}
 832			}
 833			
 834			$t_rep->update();
 835			
 836			if ($t_rep->numErrors()) {
 837				$this->errors = array_merge($this->errors, $t_rep->errors());
 838 				return false;
 839			}
 840			
 841			$t_oxor = new ca_objects_x_object_representations();
 842			if (!$t_oxor->load(array('object_id' => $vn_object_id, 'representation_id' => $pn_representation_id))) {
 843				$this->postError(750, _t("Representation id=%1 is not related to object id=%2", $pn_representation_id, $vn_object_id), "ca_objects->editRepresentation()");
 844				return false;
 845			} else {
 846				$t_oxor->setMode(ACCESS_WRITE);
 847				$t_oxor->set('is_primary', $pb_is_primary ? 1 : 0);
 848				
 849				if (isset($pa_options['rank']) && ($vn_rank = (int)$pa_options['rank'])) {
 850					$t_oxor->set('rank', $vn_rank);
 851				}
 852				
 853				$t_oxor->update();
 854				
 855				if ($t_oxor->numErrors()) {
 856					$this->errors = array_merge($this->errors, $t_oxor->errors());
 857					return false;
 858				}
 859			}
 860			
 861			return true;
 862		}
 863		return false;
 864 	}
 865 	# ------------------------------------------------------
 866 	/**
 867 	 * Remove a single representation from the currently loaded object. Note that the representation will be removed from the database completed, so if it is also linked to other objects it will be removed from them as well.
 868 	 *
 869 	 * @param int $pn_representation_id The representation_id of the representation to remove
 870 	 * @return bool True if delete succeeded, false if there was an error. You can get the error messages by calling getErrors() on the ca_objects instance.
 871 	 */
 872 	public function removeRepresentation($pn_representation_id) {
 873 		if(!$this->getPrimaryKey()) { return null; }
 874 		
 875 		$t_rep = new ca_object_representations();
 876 		if (!$t_rep->load(array('representation_id' => $pn_representation_id))) {
 877 			$this->postError(750, _t("Representation id=%1 does not exist", $pn_representation_id), "ca_objects->removeRepresentation()");
 878 			return false;
 879 		} else {
 880 			$t_rep->setMode(ACCESS_WRITE);
 881 			$t_rep->delete(true);
 882 			
 883 			if ($t_rep->numErrors()) {
 884 				$this->errors = array_merge($this->errors, $t_rep->errors());
 885 				return false;
 886 			}
 887 			
 888 			return true;
 889 		}
 890 		
 891 		return false;
 892 	}
 893 	# ------------------------------------------------------
 894 	/**
 895 	 * Removes all representations from the currently loaded object.
 896 	 *
 897 	 * @return bool True if delete succeeded, false if there was an error. You can get the error messages by calling getErrors() on the ca_objects instance.
 898 	 */
 899 	public function removeAllRepresentations() {
 900 		if (is_array($va_reps = $this->getRepresentations())) {
 901 			foreach($va_reps as $vn_i => $va_rep_info) {
 902 				if (!$this->removeRepresentation($va_rep_info['representation_id'])) {
 903 					// Representation remove failed
 904 					return false;
 905 				}
 906 			}
 907 		}
 908 		return false;
 909 	}
 910 	# ------------------------------------------------------
 911 	#
 912 	# ------------------------------------------------------
 913	/**
 914	 * Return array containing information about all hierarchies, including their root_id's
 915	 * For non-adhoc hierarchies such as places, this call returns the contents of the place_hierarchies list
 916	 * with some extra information such as the # of top-level items in each hierarchy.
 917	 *
 918	 * For an ad-hoc hierarchy like that of an object, there is only ever one hierarchy to display - that of the current object.
 919	 * So for adhoc hierarchies we just return a single entry corresponding to the root of the current object hierarchy
 920	 */
 921	 public function getHierarchyList($pb_dummy=false) {
 922	 	$vn_pk = $this->getPrimaryKey();
 923	 	if (!$vn_pk) { return null; }		// have to load a row first
 924	 	
 925	 	$vs_label = $this->getLabelForDisplay(false);
 926	 	$vs_hier_fld = $this->getProperty('HIERARCHY_ID_FLD');
 927	 	$vs_parent_fld = $this->getProperty('PARENT_ID_FLD');
 928	 	$vn_hier_id = $this->get($vs_hier_fld);
 929	 	
 930	 	if ($this->get($vs_parent_fld)) { 
 931	 		// currently loaded row is not the root so get the root
 932	 		$va_ancestors = $this->getHierarchyAncestors();
 933	 		if (!is_array($va_ancestors) || sizeof($va_ancestors) == 0) { return null; }
 934	 		$t_object = new ca_objects($va_ancestors[0]);
 935	 	} else {
 936	 		$t_object =& $this;
 937	 	}
 938	 	
 939	 	$va_children = $t_object->getHierarchyChildren(null, array('idsOnly' => true));
 940	 	$va_object_hierarchy_root = array(
 941	 		$t_object->get($vs_hier_fld) => array(
 942	 			'object_id' => $vn_pk,
 943	 			'name' => $vs_label,
 944	 			'hierarchy_id' => $vn_hier_id,
 945	 			'children' => sizeof($va_children)
 946	 		),
 947	 		'object_id' => $vn_pk,
 948			'name' => $vs_label,
 949			'hierarchy_id' => $vn_hier_id,
 950			'children' => sizeof($va_children)
 951	 	);
 952	 	
 953	 	return $va_object_hierarchy_root;
 954	}
 955	# ------------------------------------------------------
 956	/**
 957	 * Returns name of hierarchy for currently loaded row or, if specified, row identified by optional $pn_id parameter
 958	 */
 959	 public function getHierarchyName($pn_id=null) {
 960	 	if (!$pn_id) { $pn_id = $this->getPrimaryKey(); }
 961	 	
 962		$va_ancestors = $this->getHierarchyAncestors($pn_id, array('idsOnly' => true));
 963		if (is_array($va_ancestors) && sizeof($va_ancestors)) {
 964			$vn_parent_id = array_pop($va_ancestors);
 965			$t_object = new ca_objects($vn_parent_id);
 966			return $t_object->getLabelForDisplay(false);
 967		} else {			
 968			if ($pn_id == $this->getPrimaryKey()) {
 969				return $this->getLabelForDisplay(false);
 970			} else {
 971				$t_object = new ca_objects($pn_id);
 972				return $t_object->getLabelForDisplay(false);
 973			}
 974		}
 975	 }
 976	 # ------------------------------------------------------------------
 977	/**
 978	 * Returns associative array, keyed by primary key value with values being
 979	 * the preferred label of the row from a suitable locale, ready for display 
 980	 * 
 981	 * @param array $pa_ids indexed array of primary key values to fetch labels for
 982	 * @param array $pa_versions
 983	 * @param array $pa_options
 984	 * @return array List of media
 985	 */
 986	public function getPrimaryMediaForIDs($pa_ids, $pa_versions, $pa_options = null) {
 987		if (!is_array($pa_ids) || !sizeof($pa_ids)) { return array(); }
 988		if (!is_array($pa_options)) { $pa_options = array(); }
 989		$va_access_values = $pa_options["checkAccess"];
 990		if (isset($va_access_values) && is_array($va_access_values) && sizeof($va_access_values)) {
 991			$vs_access_where = ' AND orep.access IN ('.join(',', $va_access_values).')';
 992		}
 993		$o_db = $this->getDb();
 994		$qr_res = $o_db->query("
 995			SELECT oxor.object_id, orep.media
 996			FROM ca_object_representations orep
 997			INNER JOIN ca_objects_x_object_representations AS oxor ON oxor.representation_id = orep.representation_id
 998			WHERE
 999				(oxor.object_id IN (".join(',', $pa_ids).")) AND oxor.is_primary = 1 {$vs_access_where}
1000		");
1001		
1002		$va_media = array();
1003		while($qr_res->nextRow()) {
1004			$va_media_tags = array();
1005			foreach($pa_versions as $vs_version) {
1006				$va_media_tags['tags'][$vs_version] = $qr_res->getMediaTag('ca_object_representations.media', $vs_version);
1007				$va_media_tags['info'][$vs_version] = $qr_res->getMediaInfo('ca_object_representations.media', $vs_version);
1008			}
1009			$va_media[$qr_res->get('object_id')] = $va_media_tags;
1010		}
1011		return $va_media;
1012	}
1013 	# ------------------------------------------------------
1014	/**
1015	 * Returns associative array of type names
1016	 */
1017	public function getTypeNamesForIDs($pa_ids) {
1018		if (!is_array($pa_ids) || !sizeof($pa_ids)) { return array(); }
1019		$o_db = $this->getDb();
1020		$ids = join(',', $pa_ids);
1021		$qr_res = $o_db->query("
1022			SELECT objects.object_id id, labels.name_singular name, labels.locale_id locale
1023				FROM ca_list_item_labels labels
1024				INNER JOIN ca_objects objects ON objects.type_id = labels.item_id
1025				WHERE (objects.object_id IN ({$ids}))
1026		");
1027		
1028		$va_typeNames = array();
1029		while($qr_res->nextRow()) {
1030			$va_typeNames[$qr_res->get('id')] = $qr_res->get('name');
1031		}
1032		return $va_typeNames;
1033	}
1034 	# ------------------------------------------------------	
1035	public function getCollectionSiblings($count = 5, $type_ids = false, $pa_options = null) {
1036		if (!is_array($pa_options)) { $pa_options = array(); }
1037		if ($pa_options['checkAccess']) { $pa_options['return_with_access'] = $pa_options['checkAccess']; }
1038		$access = $pa_options['return_with_access'];
1039		$id = $this->get('ca_objects_x_collections.collection_id', array('returnAsArray' => true));
1040		$siblings = array();
1041		foreach ($id as $i) {
1042			$t_collection = new ca_collections($i);
1043			$siblings = array_merge($siblings, $t_collection->get('ca_objects_x_collections.object_id', array('returnAsArray' => true, 'checkAccess' => $access)));
1044		}
1045		foreach ($siblings as $n => $id) {
1046			// unset own id
1047			if ($id == $this->get('object_id')) {
1048				unset($siblings[$n]);
1049			}
1050		}
1051		if (count($siblings) == 0) {
1052			// return random items
1053			$ids = array_keys($this->getRandomItems(5, array('hasRepresentations' => 1, 'checkAccess' => $access)));
1054			$siblings = array();
1055			foreach ($ids as $id) {
1056				$siblings[$id] = new ca_objects($id);
1057			}
1058			$return = $siblings;
1059		} else {
1060			// return siblings
1061			if ($count > count($siblings)) { $count = count($siblings); }
1062			$rk = array_rand($siblings, $count);
1063			$t_siblings = array();
1064			foreach ($rk as $v) {
1065				$obj = new ca_objects($siblings[$v]);
1066				$t_siblings[$obj->get('object_id')] = $obj;
1067			}
1068			if ($type_ids) {
1069				$return = array('siblings' => $t_siblings, 'type_ids' => array());
1070				foreach (array_keys($t_siblings) as $id) {
1071					$return['type_ids'][$id] = $t_siblings[$id]->get('type_id');
1072				}
1073			} else {
1074				$return = $t_siblings;
1075			}
1076		}
1077		return $return;	
1078	}
1079 	# ------------------------------------------------------	
1080	public function getIdnoSiblings($pa_options = null) {
1081		if (!is_array($pa_options)) { $pa_options = array(); }
1082		if ($pa_options['checkAccess']) { $pa_options['return_with_access'] = $pa_options['checkAccess']; }
1083		$idno = $this->get('idno');
1084		$position = strpos($idno, '/');
1085		// can we parse the idno?
1086		if ($position) {
1087			$idno = substr($idno, 0, -$position);
1088			$access = $pa_options['return_with_access'];
1089			if (sizeof($access)) {
1090				$access = implode(', ', $access);
1091			} else {
1092				$access = $this->get('access');
1093			}
1094			$o_db = $this->getDb();
1095			$qr_res = $o_db->query("
1096				SELECT o.object_id id, o.idno idno
1097					FROM ca_objects o
1098					WHERE o.idno LIKE '{$idno}%'
1099						AND o.access IN ({$access})
1100					ORDER BY o.idno
1101			");
1102			$siblings = array();
1103			while($qr_res->nextRow()) {
1104				$siblings[] = $qr_res->getRow();
1105			}
1106			$n = 0;
1107			while (isset($siblings[$n]) && intval($siblings[$n]['id']) != $this->get('object_id')) {
1108				$n++;
1109			}
1110			$next = false; $prev = false;
1111			if (isset($siblings[$n+1])) $next = $siblings[$n+1]['id']; 
1112			if (isset($siblings[$n-1])) $prev = $siblings[$n-1]['id'];
1113			// return 10 siblings
1114			$objects = false;
1115			if (sizeof($siblings) > 1) {
1116				$objects = array();
1117				if ($prev) $objects[] = new ca_objects($prev);
1118				if ($next) {
1119					$arr = array_slice($siblings, $n+1);
1120					foreach ($arr as $key => $val) {
1121						$arr[$key] = new ca_objects($val['id']);
1122					}
1123					$objects = array_slice(array_merge($objects, $arr), 0, 5);
1124				}
1125			}
1126			$return = array(
1127				'next_id' => $next,
1128				'prev_id' => $prev,
1129				'siblings' => $objects
1130			);
1131		} else {
1132			$return = false;
1133		}
1134		return $return;
1135	}	
1136 	# ------------------------------------------------------	
1137	public function getCollectionHierarchy($locale, $pa_options = null) {
1138		if (!is_array($pa_options)) { $pa_options = array(); }
1139		if ($pa_options['checkAccess']) { $pa_options['return_with_access'] = $pa_options['checkAccess']; }
1140		$access = $pa_options['return_with_access'];
1141		$id = $this->get('ca_objects_x_collections.collection_id', array('returnAsArray' => true, 'checkAccess' => $access));
1142		if (sizeof($id) == 0) return false;
1143		if (sizeof($access) == 0) return false;
1144		$access = implode(', ', $access);
1145		$id = $id[0];
1146		$t_collection = new ca_collections($id);
1147		$left = $t_collection->get('hier_left');
1148		$hier_id = $t_collection->get('hier_collection_id');
1149		$lang_code = $locale;
1150		$o_db = $this->getDb();
1151		$qr_res = $o_db->query("
1152			SELECT cl.name AS name, parent.collection_id
1153			FROM ca_collections AS node JOIN ca_collections AS parent
1154				JOIN ca_collection_labels AS cl ON parent.collection_id = cl.collection_id
1155				JOIN ca_locales AS lo ON cl.locale_id = lo.locale_id				
1156			WHERE node.hier_left BETWEEN parent.hier_left AND parent.hier_right
1157				AND (parent.hier_collection_id = {$hier_id} AND node.hier_collection_id = {$hier_id})
1158				AND parent.access IN ({$access})
1159				AND lo.language = '{$lang_code}'
1160				AND node.collection_id = {$id}
1161			ORDER BY node.hier_left;
1162		");
1163		$tree = array();
1164		while($qr_res->nextRow()) {
1165			$tree[] = $qr_res->getRow();
1166		}
1167
1168		return $tree;
1169	}	
1170}
1171?>
1172

Large files files are truncated, but you can click here to view the full file