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