PageRenderTime 98ms CodeModel.GetById 71ms app.highlight 21ms RepoModel.GetById 1ms app.codeStats 0ms

/app/models/ca_list_items.php

https://bitbucket.org/Sinfin/pawtucket
PHP | 626 lines | 425 code | 68 blank | 133 comment | 29 complexity | a71832c648149fd0a7463d08a0cc1ceb MD5 | raw file
  1<?php
  2/** ---------------------------------------------------------------------
  3 * app/models/ca_list_items.php : table access class for table ca_list_items
  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/BundlableLabelableBaseModelWithAttributes.php');
 38require_once(__CA_LIB_DIR__.'/ca/IHierarchy.php');
 39require_once(__CA_MODELS_DIR__.'/ca_lists.php');
 40require_once(__CA_MODELS_DIR__.'/ca_places.php');
 41require_once(__CA_MODELS_DIR__.'/ca_locales.php');
 42
 43
 44BaseModel::$s_ca_models_definitions['ca_list_items'] = array(
 45 	'NAME_SINGULAR' 	=> _t('list item'),
 46 	'NAME_PLURAL' 		=> _t('list items'),
 47 	'FIELDS' 			=> array(
 48 		'item_id' => array(
 49				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_HIDDEN, 
 50				'IDENTITY' => true, 'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
 51				'IS_NULL' => false, 
 52				'DEFAULT' => '',
 53				'LABEL' => _t('CollectiveAccess id'), 'DESCRIPTION' => _t('Unique numeric identifier used by CollectiveAccess internally to identify this item')
 54		),
 55		'parent_id' => array(
 56				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_OMIT, 
 57				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
 58				'IS_NULL' => true, 
 59				'DEFAULT' => '',
 60				'LABEL' => _t('Parent'), 'DESCRIPTION' => _t('Parent list item for this item')
 61		),
 62		'list_id' => array(
 63				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_OMIT, 
 64				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
 65				'IS_NULL' => false, 
 66				'DEFAULT' => '',
 67				'LABEL' => _t('List'), 'DESCRIPTION' => _t('List item belongs to')
 68		),
 69		'type_id' => array(
 70				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_SELECT, 
 71				'DISPLAY_WIDTH' => 40, 'DISPLAY_HEIGHT' => 1,
 72				'DISPLAY_FIELD' => array('ca_list_items.item_value'),
 73				'DISPLAY_ORDERBY' => array('ca_list_items.item_value'),
 74				'IS_NULL' => true, 
 75				'LIST_CODE' => 'list_item_types',
 76				'DEFAULT' => '',
 77				'LABEL' => _t('Type'), 'DESCRIPTION' => _t('Indicates the type of the list item.')
 78		),
 79		'idno' => array(
 80				'FIELD_TYPE' => FT_TEXT, 'DISPLAY_TYPE' => DT_FIELD, 
 81				'DISPLAY_WIDTH' => 70, 'DISPLAY_HEIGHT' => 1,
 82				'IS_NULL' => false, 
 83				'DEFAULT' => '',
 84				'LABEL' => _t('Identifier'), 'DESCRIPTION' => _t('Unique identifier for this list item'),
 85				'BOUNDS_LENGTH' => array(0,255)
 86		),
 87		'idno_sort' => array(
 88				'FIELD_TYPE' => FT_TEXT, 'DISPLAY_TYPE' => DT_OMIT, 
 89				'DISPLAY_WIDTH' => 70, 'DISPLAY_HEIGHT' => 1,
 90				'IS_NULL' => false, 
 91				'DEFAULT' => '',
 92				'LABEL' => _t('Identifier sort'), 'DESCRIPTION' => _t('Sortable value for identifier'),
 93				'BOUNDS_LENGTH' => array(0,255)
 94		),
 95		'item_value' => array(
 96				'FIELD_TYPE' => FT_TEXT, 'DISPLAY_TYPE' => DT_FIELD, 
 97				'DISPLAY_WIDTH' => 70, 'DISPLAY_HEIGHT' => 1,
 98				'IS_NULL' => false, 
 99				'DEFAULT' => '',
100				'LABEL' => _t('Item value'), 'DESCRIPTION' => _t('Value of this list item; is stored in database when this item is selected'),
101				'BOUNDS_LENGTH' => array(0,255)
102		),
103		'color' => array(
104				'FIELD_TYPE' => FT_TEXT, 'DISPLAY_TYPE' => DT_COLORPICKER, 
105				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
106				'IS_NULL' => false, 
107				'DEFAULT' => '',
108				'LABEL' => _t('Item color'), 'DESCRIPTION' => _t('Color to display item in')
109		),
110		'icon' => array(
111				'FIELD_TYPE' => FT_MEDIA, 'DISPLAY_TYPE' => DT_FIELD, 
112				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
113				'IS_NULL' => false, 
114				'DEFAULT' => '',
115				"MEDIA_PROCESSING_SETTING" => 'ca_icons',
116				'LABEL' => _t('Item icon'), 'DESCRIPTION' => _t('Optional icon to use with item')
117		),
118		'rank' => array(
119				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_FIELD, 
120				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
121				'IS_NULL' => false, 
122				'DEFAULT' => '',
123				'LABEL' => _t('Sort order'), 'DESCRIPTION' => _t('Sort order'),
124		),
125		'hier_left' => array(
126				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_OMIT, 
127				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
128				'IS_NULL' => false, 
129				'DEFAULT' => '',
130				'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.'
131		),
132		'hier_right' => array(
133				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_OMIT, 
134				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
135				'IS_NULL' => false, 
136				'DEFAULT' => '',
137				'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.'
138		),
139		'is_enabled' => array(
140				'FIELD_TYPE' => FT_BIT, 'DISPLAY_TYPE' => DT_SELECT, 
141				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
142				'IS_NULL' => false, 
143				'DEFAULT' => '1',
144				'LABEL' => _t('Is enabled?'), 'DESCRIPTION' => _t('If checked this item is selectable and can be used in cataloguing.')
145		),
146		'is_default' => array(
147				'FIELD_TYPE' => FT_BIT, 'DISPLAY_TYPE' => DT_SELECT, 
148				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
149				'IS_NULL' => false, 
150				'DEFAULT' => '',
151				'LABEL' => _t('Is default?'), 'DESCRIPTION' => _t('If checked this item will be the default selection for the list.')
152		),
153		'validation_format' => array(
154				'FIELD_TYPE' => FT_TEXT, 'DISPLAY_TYPE' => DT_OMIT, 
155				'DISPLAY_WIDTH' => 255, 'DISPLAY_HEIGHT' => 1,
156				'IS_NULL' => false, 
157				'DEFAULT' => '',
158				'LABEL' => _t('Validation format'), 'DESCRIPTION' => _t('NOT CURRENTLY SUPPORTED; WILL BE A PERL-COMPATIBLE REGEX APPLIED TO VALIDATE INPUT'),
159				'BOUNDS_LENGTH' => array(0,255)
160		),
161		'access' => array(
162				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_SELECT, 
163				'DISPLAY_WIDTH' => 40, 'DISPLAY_HEIGHT' => 1,
164				'IS_NULL' => false, 
165				'DEFAULT' => 0,
166				'BOUNDS_CHOICE_LIST' => array(
167					_t('Not accessible to public') => 0,
168					_t('Accessible to public') => 1
169				),
170				'LIST' => 'access_statuses',
171				'LABEL' => _t('Access'), 'DESCRIPTION' => _t('Indicates if the list item is accessible to the public or not. ')
172		),
173		'status' => array(
174				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_SELECT, 
175				'DISPLAY_WIDTH' => 40, 'DISPLAY_HEIGHT' => 1,
176				'IS_NULL' => false, 
177				'DEFAULT' => 0,
178				'BOUNDS_CHOICE_LIST' => array(
179					_t('Newly created') => 0,
180					_t('Editing in progress') => 1,
181					_t('Editing complete - pending review') => 2,
182					_t('Review in progress') => 3,
183					_t('Completed') => 4
184				),
185				'LIST' => 'workflow_statuses',
186				'LABEL' => _t('Status'), 'DESCRIPTION' => _t('Indicates the current state of the list item.')
187		),
188		// 'deleted' => array(
189// 				'FIELD_TYPE' => FT_BIT, 'DISPLAY_TYPE' => DT_OMIT, 
190// 				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
191// 				'IS_NULL' => false, 
192// 				'DEFAULT' => 0,
193// 				'LABEL' => _t('Is deleted?'), 'DESCRIPTION' => _t('Indicates if list item is deleted or not.')
194// 		)
195 	)
196);
197
198class ca_list_items extends BundlableLabelableBaseModelWithAttributes implements IHierarchy {
199	# ---------------------------------
200	# --- Object attribute properties
201	# ---------------------------------
202	# Describe structure of content object's properties - eg. database fields and their
203	# associated types, what modes are supported, et al.
204	#
205
206	# ------------------------------------------------------
207	# --- Basic object parameters
208	# ------------------------------------------------------
209	# what table does this class represent?
210	protected $TABLE = 'ca_list_items';
211	      
212	# what is the primary key of the table?
213	protected $PRIMARY_KEY = 'item_id';
214
215	# ------------------------------------------------------
216	# --- Properties used by standard editing scripts
217	# 
218	# These class properties allow generic scripts to properly display
219	# records from the table represented by this class
220	#
221	# ------------------------------------------------------
222
223	# Array of fields to display in a listing of records from this table
224	protected $LIST_FIELDS = array('idno');
225
226	# When the list of "list fields" above contains more than one field,
227	# the LIST_DELIMITER text is displayed between fields as a delimiter.
228	# This is typically a comma or space, but can be any string you like
229	protected $LIST_DELIMITER = ' ';
230
231	# What you'd call a single record from this table (eg. a "person")
232	protected $NAME_SINGULAR;
233
234	# What you'd call more than one record from this table (eg. "people")
235	protected $NAME_PLURAL;
236
237	# List of fields to sort listing of records by; you can use 
238	# SQL 'ASC' and 'DESC' here if you like.
239	protected $ORDER_BY = array('idno');
240
241	# Maximum number of record to display per page in a listing
242	protected $MAX_RECORDS_PER_PAGE = 20; 
243
244	# How do you want to page through records in a listing: by number pages ordered
245	# according to your setting above? Or alphabetically by the letters of the first
246	# LIST_FIELD?
247	protected $PAGE_SCHEME = 'alpha'; # alpha [alphabetical] or num [numbered pages; default]
248
249	# If you want to order records arbitrarily, add a numeric field to the table and place
250	# its name here. The generic list scripts can then use it to order table records.
251	protected $RANK = 'rank';
252	
253	
254
255	# ------------------------------------------------------
256	# Hierarchical table properties
257	# ------------------------------------------------------
258	protected $HIERARCHY_TYPE				=	__CA_HIER_TYPE_MULTI_MONO__;
259	protected $HIERARCHY_LEFT_INDEX_FLD 	= 	'hier_left';
260	protected $HIERARCHY_RIGHT_INDEX_FLD 	= 	'hier_right';
261	protected $HIERARCHY_PARENT_ID_FLD		=	'parent_id';
262	protected $HIERARCHY_DEFINITION_TABLE	=	'ca_lists';
263	protected $HIERARCHY_ID_FLD				=	'list_id';
264	protected $HIERARCHY_POLY_TABLE			=	null;
265	
266	# ------------------------------------------------------
267	# Change logging
268	# ------------------------------------------------------
269	protected $UNIT_ID_FIELD = null;
270	protected $LOG_CHANGES_TO_SELF = true;
271	protected $LOG_CHANGES_USING_AS_SUBJECT = array(
272		"FOREIGN_KEYS" => array(
273			'list_id'
274		),
275		"RELATED_TABLES" => array(
276			
277		)
278	);
279	
280	# ------------------------------------------------------
281	# Attributes
282	# ------------------------------------------------------
283	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
284	protected $ATTRIBUTE_TYPE_LIST_CODE = 'list_item_types';		// list code (ca_lists.list_code) of list defining types for this table
285	
286	# ------------------------------------------------------
287	# Labels
288	# ------------------------------------------------------
289	protected $LABEL_TABLE_NAME = 'ca_list_item_labels';
290	
291	# ------------------------------------------------------
292	# Self-relations
293	# ------------------------------------------------------
294	protected $SELF_RELATION_TABLE_NAME = 'ca_list_items_x_list_items';
295	
296	# ------------------------------------------------------
297	# ID numbering
298	# ------------------------------------------------------
299	protected $ID_NUMBERING_ID_FIELD = 'idno';				// name of field containing user-defined identifier
300	protected $ID_NUMBERING_SORT_FIELD = 'idno_sort';		// name of field containing version of identifier for sorting (is normalized with padding to sort numbers properly)
301	protected $ID_NUMBERING_CONTEXT_FIELD = 'list_id';		// name of field to use value of for "context" when checking for duplicate identifier values; if not set identifer is assumed to be global in scope; if set identifer is checked for uniqueness (if required) within the value of this field
302	
303	# ------------------------------------------------------
304	# Search
305	# ------------------------------------------------------
306	protected $SEARCH_CLASSNAME = 'ListItemSearch';
307	protected $SEARCH_RESULT_CLASSNAME = 'ListItemSearchResult';
308	
309	# ------------------------------------------------------
310	# $FIELDS contains information about each field in the table. The order in which the fields
311	# are listed here is the order in which they will be returned using getFields()
312
313	protected $FIELDS;
314	
315	# ------------------------------------------------------
316	# --- Constructor
317	#
318	# This is a function called when a new instance of this object is created. This
319	# standard constructor supports three calling modes:
320	#
321	# 1. If called without parameters, simply creates a new, empty objects object
322	# 2. If called with a single, valid primary key value, creates a new objects object and loads
323	#    the record identified by the primary key value
324	#
325	# ------------------------------------------------------
326	public function __construct($pn_id=null) {
327		parent::__construct($pn_id);	# call superclass constructor
328	}
329	# ------------------------------------------------------
330	protected function initLabelDefinitions() {
331		parent::initLabelDefinitions();
332		$this->BUNDLES['ca_objects'] = array('type' => 'related_table', 'repeating' => true, 'label' => _t('Related objects'));
333		$this->BUNDLES['ca_entities'] = array('type' => 'related_table', 'repeating' => true, 'label' => _t('Related entities'));
334		$this->BUNDLES['ca_places'] = array('type' => 'related_table', 'repeating' => true, 'label' => _t('Related places'));
335		$this->BUNDLES['ca_occurrences'] = array('type' => 'related_table', 'repeating' => true, 'label' => _t('Related occurrences'));
336		$this->BUNDLES['ca_collections'] = array('type' => 'related_table', 'repeating' => true, 'label' => _t('Related collections'));
337		$this->BUNDLES['ca_storage_locations'] = array('type' => 'related_table', 'repeating' => true, 'label' => _t('Related storage locations'));
338		
339		$this->BUNDLES['ca_loans'] = array('type' => 'related_table', 'repeating' => true, 'label' => _t('Related loans'));
340		$this->BUNDLES['ca_movements'] = array('type' => 'related_table', 'repeating' => true, 'label' => _t('Related movements'));
341		
342		$this->BUNDLES['ca_list_items'] = array('type' => 'related_table', 'repeating' => true, 'label' => _t('Related vocabulary terms'));
343		
344		$this->BUNDLES['hierarchy_navigation'] = array('type' => 'special', 'repeating' => false, 'label' => _t('Hierarchy navigation'));
345		$this->BUNDLES['hierarchy_location'] = array('type' => 'special', 'repeating' => false, 'label' => _t('Location in hierarchy'));
346	}
347 	# ------------------------------------------------------
348	public function insert($pa_options=null) {
349		if (!$this->inTransaction()) {
350			$this->setTransaction(new Transaction());
351		}
352		if ($this->get('is_default')) {
353			$this->getDb()->query("
354				UPDATE ca_list_items 
355				SET is_default = 0 
356				WHERE list_id = ?
357			", (int)$this->get('list_id'));
358		}
359		$vn_rc = parent::insert($pa_options);
360		
361		if ($this->getPrimaryKey()) {
362			$t_list = new ca_lists();
363			$t_list->setTransaction($this->getTransaction());
364			
365			
366			if (($t_list->load($this->get('list_id'))) && ($t_list->get('list_code') == 'place_hierarchies') && ($this->get('parent_id'))) {
367				// insert root or place hierarchy when creating non-root items in 'place_hierarchies' list
368				$t_locale = new ca_locales();
369				$va_locales = $this->getAppConfig()->getList('locale_defaults');
370				$vn_locale_id = $t_locale->localeCodeToID($va_locales[0]);
371				
372				// create root in ca_places
373				$t_place = new ca_places();
374				$t_place->setTransaction($this->getTransaction());
375				$t_place->setMode(ACCESS_WRITE);
376				$t_place->set('hierarchy_id', $this->getPrimaryKey());
377				$t_place->set('locale_id', $vn_locale_id);
378				$t_place->set('type_id', null);
379				$t_place->set('parent_id', null);
380				$t_place->set('idno', 'Root node for '.$this->get('idno'));
381				$t_place->insert();
382				
383				if ($t_place->numErrors()) {
384					$this->delete();
385					$this->errors = array_merge($this->errors, $t_place->errors);
386					return false;
387				}
388				
389				$t_place->addLabel(
390					array(
391						'name' => 'Root node for '.$this->get('idno')
392					),
393					$vn_locale_id, null, true
394				);
395			}
396		}
397		
398		if ($this->numErrors()) {
399			$this->getTransaction()->rollback();
400		} else {
401			$this->getTransaction()->commit();
402		}
403		return $vn_rc;
404	}
405	# ------------------------------------------------------
406	public function update($pa_options=null) {
407		if (!$this->inTransaction()) {
408			$this->setTransaction(new Transaction());
409		}
410		if ($this->get('is_default')) {
411			$this->getDb()->query("
412				UPDATE ca_list_items 
413				SET is_default = 0 
414				WHERE list_id = ?
415			", (int)$this->get('list_id'));
416		}
417		$vn_rc = parent::update($pa_options);
418		
419		if ($this->numErrors()) {
420			$this->getTransaction()->rollback();
421		} else {
422			$this->getTransaction()->commit();
423		}
424		return $vn_rc;
425	}
426	# ------------------------------------------------------
427	/**
428	 * Return array containing information about all lists, including their root_id's
429	 */
430	 public function getHierarchyList($pb_vocabularies=false) {
431	 	$t_list = new ca_lists();
432	 	
433	 	$va_hierarchies = caExtractValuesByUserLocale($t_list->getListOfLists());
434		
435		$o_db = $this->getDb();
436		
437		$va_hierarchy_ids = array();
438		foreach($va_hierarchies as $vn_list_id => $va_list_info) {
439			$va_hierarchy_ids[] = intval($vn_list_id);
440		}
441		
442		if (!sizeof($va_hierarchy_ids)) { return array(); }
443		
444		// get root for each hierarchy
445		$qr_res = $o_db->query("
446			SELECT cli.item_id, cli.list_id, count(*) children
447			FROM ca_list_items cli
448			LEFT JOIN ca_list_items AS cli2 ON cli.item_id = cli2.parent_id
449			INNER JOIN ca_lists AS l ON l.list_id = cli.list_id
450			WHERE 
451				cli.parent_id IS NULL and cli.list_id IN (".join(',', $va_hierarchy_ids).") ".($pb_vocabularies ? " AND (l.use_as_vocabulary = 1)" : "")."
452			GROUP BY
453				cli.item_id
454		");
455		
456		while ($qr_res->nextRow()) {
457			$vn_hierarchy_id = $qr_res->get('list_id');
458			$va_hierarchies[$vn_hierarchy_id]['list_id'] = $qr_res->get('list_id');		// when we need to edit the list
459			$va_hierarchies[$vn_hierarchy_id]['item_id'] = $qr_res->get('item_id');	
460			
461			$qr_children = $o_db->query("
462				SELECT count(*) children
463				FROM ca_list_items cli
464				WHERE 
465					cli.parent_id = ?
466			", (int)$qr_res->get('item_id'));
467			$vn_children_count = 0;
468			if ($qr_children->nextRow()) {
469				$vn_children_count = $qr_children->get('children');
470			}
471			$va_hierarchies[$vn_hierarchy_id]['children'] = intval($vn_children_count);
472			$va_hierarchies[$vn_hierarchy_id]['has_children'] = ($vn_children_count > 0) ? 1 : 0;
473		}
474		
475		// sort by label
476		$va_hierarchies_indexed_by_label = array();
477		foreach($va_hierarchies as $vs_k => $va_v) {
478			$va_hierarchies_indexed_by_label[$va_v['name']][$vs_k] = $va_v;
479		}
480		ksort($va_hierarchies_indexed_by_label);
481		$va_sorted_hierarchies = array();
482		foreach($va_hierarchies_indexed_by_label as $vs_l => $va_v) {
483			foreach($va_v as $vs_k => $va_hier) {
484				$va_sorted_hierarchies[$vs_k] = $va_hier;
485			}
486		}
487		return $va_sorted_hierarchies;
488	 }
489	 # ------------------------------------------------------
490	 /**
491	 * Returns name of hierarchy for currently loaded item or, if specified, item with item_id = to optional $pn_id parameter
492	 */
493	 public function getHierarchyName($pn_id=null) {
494	 	if ($pn_id) {
495	 		$t_item = new ca_list_items($pn_id);
496	 		$vn_hierarchy_id = $t_item->get('list_id');
497	 	} else {
498	 		$vn_hierarchy_id = $this->get('list_id');
499	 	}
500	 	$t_list = new ca_lists();
501	 	$t_list->load($vn_hierarchy_id);
502	 	
503	 	return $t_list->getLabelForDisplay(false);
504	 }
505	 # ------------------------------------------------------
506	/**
507	 * Returns a flat list of all items in the specified list referenced by items in the specified table
508	 * (and optionally a search on that table)
509	 */
510	public function getReferenced($pm_table_num_or_name, $pn_type_id=null, $pa_reference_limit_ids=null, $pn_access=null, $pn_restrict_to_relationship_hierarchy_id=null) {
511		if (is_numeric($pm_table_num_or_name)) {
512			$vs_table_name = $this->getAppDataModel()->getTableName($pm_table_num_or_name);
513		} else {
514			$vs_table_name = $pm_table_num_or_name;
515		}
516		
517		if (!($t_ref_table = $this->getAppDatamodel()->getInstanceByTableName($vs_table_name, true))) {
518			return null;
519		}
520		
521		
522		if (!$vs_table_name) { return null; }
523		
524		$o_db = $this->getDb();
525		$va_path = $this->getAppDatamodel()->getPath($this->tableName(), $vs_table_name);
526		array_shift($va_path); // remove table name from path
527		
528		$vs_last_table = $this->tableName();
529		$va_joins = array();
530		foreach($va_path as $vs_rel_table_name => $vn_rel_table_num) {
531			$va_rels = $this->getAppDatamodel()->getRelationships($vs_last_table, $vs_rel_table_name);
532			$va_rel = $va_rels[$vs_last_table][$vs_rel_table_name][0];
533			
534			
535			$va_joins[] = "INNER JOIN {$vs_rel_table_name} ON {$vs_last_table}.".$va_rel[0]." = {$vs_rel_table_name}.".$va_rel[1];
536			
537			$vs_last_table = $vs_rel_table_name;
538		}
539		
540		$va_sql_wheres = array();
541		if (is_array($pa_reference_limit_ids) && sizeof($pa_reference_limit_ids)) {
542			$va_sql_wheres[] = "({$vs_table_name}.".$t_ref_table->primaryKey()." IN (".join(',', $pa_reference_limit_ids)."))";
543		}
544		
545		if (!is_null($pn_access)) {
546			$va_sql_wheres[] = "({$vs_table_name}.access = ".intval($pn_access).")";
547		}
548		
549		if ($pn_restrict_to_relationship_hierarchy_id > 0) {
550			$va_sql_wheres[] = "(ca_list_items.list_id = {$pn_restrict_to_relationship_hierarchy_id})";
551		}
552		
553		// get item counts
554		$vs_sql = "
555			SELECT ca_list_items.item_id, count(*) cnt
556			FROM ca_list_items
557			".join("\n", $va_joins)."
558			".(sizeof($va_sql_wheres) ? " WHERE ".join(' AND ', $va_sql_wheres) : "")."
559			GROUP BY
560				ca_list_items.item_id, {$vs_table_name}.".$t_ref_table->primaryKey()."
561		";
562		$qr_items = $o_db->query($vs_sql);
563		
564		$va_item_counts = array();
565		while($qr_items->nextRow()) {
566			$va_item_counts[$qr_items->get('item_id')]++;
567		}
568		
569		$vs_sql = "
570			SELECT ca_list_items.item_id, ca_list_items.idno, ca_list_item_labels.*, count(*) c
571			FROM ca_list_items
572			INNER JOIN ca_list_item_labels ON ca_list_item_labels.item_id = ca_list_items.item_id
573			".join("\n", $va_joins)."
574			WHERE
575				(ca_list_item_labels.is_preferred = 1)
576				".(sizeof($va_sql_wheres) ? " AND ".join(' AND ', $va_sql_wheres) : "")."
577			GROUP BY
578				ca_list_item_labels.label_id
579			ORDER BY 
580				ca_list_item_labels.name_plural
581		";
582		
583		$qr_items = $o_db->query($vs_sql);
584		
585		$va_items = array();
586		while($qr_items->nextRow()) {
587			$vn_item_id = $qr_items->get('item_id');
588			$va_items[$vn_item_id][$qr_items->get('locale_id')] = array_merge($qr_items->getRow(), array('cnt' => $va_item_counts[$vn_item_id]));
589		}
590		
591		return caExtractValuesByUserLocale($va_items);
592	}
593	# ------------------------------------------------------
594	/**
595	 *
596	 */
597	public function getListItemIDsByName($pn_list_id, $ps_name, $pn_parent_id=null) {
598		$o_db = $this->getDb();
599		
600		if ($pn_parent_id) {
601			$qr_res = $o_db->query("
602				SELECT DISTINCT cap.item_id
603				FROM ca_list_items cap
604				INNER JOIN ca_list_item_labels AS capl ON capl.item_id = cap.item_id
605				WHERE
606					(capl.name_singular = ? OR capl.name_plural = ?) AND cap.parent_id = ? AND cap.list_id = ?
607			", (string)$ps_name, (string)$ps_name, (int)$pn_parent_id, (int)$pn_list_id);
608		} else {
609			$qr_res = $o_db->query("
610				SELECT DISTINCT cap.item_id
611				FROM ca_list_items cap
612				INNER JOIN ca_list_item_labels AS capl ON capl.item_id = cap.item_id
613				WHERE
614					(capl.name_singular = ? OR capl.name_plural = ?) AND cap.list_id = ?
615			", (string)$ps_name, (string)$ps_name, (int)$pn_list_id);
616
617		}
618		$va_item_ids = array();
619		while($qr_res->nextRow()) {
620			$va_item_ids[] = $qr_res->get('item_id');
621		}
622		return $va_item_ids;
623	}
624	# ------------------------------------------------------
625}
626?>