Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
page_asset_listing.inc
1 <?php
18 require_once SQ_PACKAGES_PATH.'/cms/listing_engine/listing_engine.inc';
19 
33 {
34 
35 
42  function __construct($assetid=0)
43  {
44  parent::__construct($assetid);
45 
46  }//end constructor
47 
48 
65  function getAssetList()
66  {
67  $group_by = $this->attr('group_by');
68 
69  $logic = $this->attr('all_root_nodes') ? 'AND' : 'OR';
70 
71  // this is the list of all type codes that we are going to show
72  // we pass this list to the getLinks and getChildren functions (below) to narrow
73  // the query down a bit
74  // if there are no types to list, we cant list anything
75  $wanted_types = $this->attr('types');
76  if (empty($wanted_types)) {
77  trigger_localised_error('CMS0019', E_USER_NOTICE);
78  return Array();
79  }
80 
81  // get the root assets whose sub-assets/children we are displaying
82  // This may come from the parameter map, but the dynamic value must be a child of the static value
83  // if there are no root assets, we will use ourselves and print our children
84  $root_asset_ids = $this->getRootNodes();
85 
86  $sort_info = $this->getSortInfo();
87 
88  $link_value_wanted = NULL;
89  if ($this->attr('link_value_filter_enabled')) {
90  // the data stored in the DB was encoded to protect against cross scripting so we use htmlentities
91  $link_value_wanted = htmlentities($this->attr('link_value_filter'));
92  }
93 
94  $assets_to_list = $this->_getAssetList($group_by, $logic, $wanted_types, $root_asset_ids, $sort_info, $link_value_wanted);
95 
96  return $assets_to_list;
97 
98  }//end getAssetList()
99 
100 
124  function _getAssetList($group_by, $logic, $wanted_types, $root_asset_ids, $sort_info, $link_value_wanted=NULL)
125  {
126  $assets_to_list = NULL;
127 
128  // access
129  $list_permission = $this->attr('list_permission');
130  $list_effective = $this->attr('list_effective');
131 
132  $parameter_map =& $this->getAttribute('parameter_map');
133  $raw_assets_to_list = $parameter_map->getParameterValue('asset_selection');
134  if (!empty($raw_assets_to_list)) {
135  $assets_to_list = Array();
136 
137  if (!is_array($raw_assets_to_list)) {
138  // If passed as an array, treat it similar to replacement
139  // root nodes. In other words, asset IDs (including that of LDAP user) separated by commas.
140  preg_match_all('|[0-9]+(:([0-9a-z_\-\s\(\)\\\]+=[0-9a-z_\-\s\(\)\\\]+,)*[0-9a-z_\-\s\(\)\\\]+=[0-9a-z_\-\s\(\)\\\]+)?|i', $raw_assets_to_list, $matches);
141  $list_keys = $matches[0];
142  $raw_assets_to_list = Array();
143  foreach ($list_keys as $raw_assetid) {
144  if ($raw_assetid) {
145  $raw_assets_to_list[$raw_assetid] = 1;
146  }
147  }
148  }
149 
150  foreach ($raw_assets_to_list as $raw_asset => $enabled) {
151  $list_asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($raw_asset);
152  if (is_null($list_asset)) continue;
153 
154  // Ok, we have the asset, let's check permissions
155  $allowed = FALSE;
156  switch ($list_permission) {
157 
158  case SQ_PERMISSION_READ :
159  $allowed = $list_asset->readAccess();
160  break;
161 
162  case SQ_PERMISSION_WRITE :
163  $allowed = $list_asset->writeAccess();
164  break;
165 
166  case SQ_PERMISSION_ADMIN :
167  $allowed = $list_asset->adminAccess();
168  break;
169 
170  }
171 
172  if (!$allowed) continue;
173 
174  // Now, let's check that the asset(s) are under the root nodes
175  $parents = $GLOBALS['SQ_SYSTEM']->am->getParents($list_asset->id);
176 
177  $allowed = FALSE;
178  foreach ($parents as $parent_id => $parent_type) {
179  if (in_array($parent_id, $root_asset_ids)) {
180  $allowed = TRUE;
181  }
182  }
183 
184  if (!$allowed) continue;
185 
186  $assets_to_list[$list_asset->id][0]['type_code'] = $list_asset->type();
187 
188  }//end foreach
189 
190  return $assets_to_list;
191 
192  } else {
193  $dynamic_asset_selection = $parameter_map->getParameters();
194  if (in_array('asset_selection', $dynamic_asset_selection) && $this->attr('dynamic_asset_selection_option') == 'empty_result') {
195  return Array();
196  }
197  }//end if
198 
199  // if we are showing an A-Z listing but the user has not selected a proper sort field,
200  // we will use the 'name' attribute of the asset to work out the listing
201  if ($group_by == 'letter') {
202  if (empty($sort_info) || !($sort_info['type'] == 'field') || ($sort_info['params']['field'] != 'short_name')) {
203  $letter_sort_by = 'name';
204  } else {
205  $letter_sort_by = $sort_info['params']['field'];
206  }
207  }
208 
209  if (!is_null($link_value_wanted)) {
210  $link_value_wanted = Array(
211  'link_value' => Array($link_value_wanted),
212  'equal' => $this->attr('link_value_filter_logic'),
213  );
214  }
215 
216  if ($this->attr('subs_only')) {
217 
218  $side_of_link = ($this->attr('direction') == 'down') ? 'major' : 'minor';
219  $link_type = ($side_of_link == 'major') ? 'minor' : 'major';
220  $links = Array();
221 
222  switch ($group_by) {
223 
224  case 'letter' :
225  foreach ($root_asset_ids as $root_asset_id) {
226  $links_query = $GLOBALS['SQ_SYSTEM']->am->generateGetLinksQuery($root_asset_id, $this->attr('link_types'), array_keys($wanted_types), FALSE, $side_of_link, $link_value_wanted, NULL, NULL, $letter_sort_by, $list_permission, $list_effective);
227  if (empty($links_query)) return Array();
228  // the table alias is 'l' rather than 'a' as the query queries the view sq_vw_ast_lnk_minor
229  // which returns the results from the asset table, using the table alias 'l'
230  $links_query['sql_array']['select'] .= ', SUBSTR(l.'.$letter_sort_by.', 1, 1) AS first_letter';
231 
232  $links = NULL;
233 
234  try {
235  $query = MatrixDAL::preparePdoQuery(implode(' ', $links_query['sql_array']));
236 
237  foreach ($links_query['bind_vars'] as $bind_var => $bind_value) {
238  MatrixDAL::bindValueToPdo($query, $bind_var, $bind_value);
239  }
240 
241  $links = MatrixDAL::executePdoAll($query);
242  } catch (Exception $e) {
243  throw new Exception($e->getMessage().' (in '.$e->getFile().' on line '.$e->getLine().')');
244  }
245 
246  $new_assets_to_list = Array();
247  foreach ($links as $link_info) {
248  $new_assets_to_list[$link_info[$link_type.'id']] = Array(
249  0 => Array(
250  'type_code' => $link_info[$link_type.'_type_code'],
251  'first_letter' => $link_info['first_letter'],
252  ),
253  );
254  }
255 
256  $assets_to_list = $this->_combineAssets($logic, $new_assets_to_list, $assets_to_list);
257  }//end foreach
258 
259  break;
260 
261  case 'random' :
262  case 'number' :
263  case 'grouped' :
264  foreach ($root_asset_ids as $root_asset_id) {
265  $links = $GLOBALS['SQ_SYSTEM']->am->getLinks($root_asset_id, $this->attr('link_types'), array_keys($wanted_types), FALSE, $side_of_link, $link_value_wanted, NULL, NULL, NULL, $list_permission, $list_effective);
266  $new_assets_to_list = Array();
267  foreach ($links as $link_info) {
268  $new_assets_to_list[$link_info[$link_type.'id']] = Array( 0 => Array('type_code' => $link_info[$link_type.'_type_code']));
269  }
270 
271  $assets_to_list = $this->_combineAssets($logic, $new_assets_to_list, $assets_to_list);
272  }
273 
274 
275  break;
276  }//end switch
277 
278  } else {
279  $min_depth = ($this->attr('min_depth') === '') ? NULL : $this->attr('min_depth');
280  $max_depth = ($this->attr('max_depth') === '') ? NULL : $this->attr('max_depth');
281 
282  // if the min/max are both set to 0, return only the root nodes and forego any other processing
283  if ($min_depth === '0' && $max_depth === '0') {
284  $assets_to_list = $this->_combineRootNodes(Array(), $root_asset_ids, $wanted_types);
285  return empty($assets_to_list) ? Array() : $assets_to_list;
286  }
287 
288  switch ($group_by) {
289  case 'letter' :
290  foreach ($root_asset_ids as $root_asset_id) {
291  if ($this->attr('direction') == 'down') {
292  $root_asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($root_asset_id);
293  $ret_val = $GLOBALS['SQ_SYSTEM']->am->generateGetChildrenQuery($root_asset, array_keys($wanted_types), FALSE, NULL, $letter_sort_by, $list_permission, $list_effective, TRUE, $min_depth, $max_depth, TRUE, $link_value_wanted);
294  $sql_array = $ret_val['sql_array'];
295  $bind_vars = $ret_val['bind_vars'];
296  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($root_asset);
297  $table_alias = 'a';
298  } else {
299  $table_alias = 'll';
300  $ret_val = $GLOBALS['SQ_SYSTEM']->am->generateGetParentsQuery($root_asset_id, array_keys($wanted_types), FALSE, $letter_sort_by, $list_permission, $list_effective, $min_depth, $max_depth, $link_value_wanted);
301  $sql_array = $ret_val['sql_array'];
302  $bind_vars = $ret_val['bind_vars'];
303  }
304  if (empty($ret_val)) $new_assets_to_list = Array();
305 
306  $sql_array['select'] .= ', SUBSTR('.$table_alias.'.'.$letter_sort_by.', 1, 1) AS first_letter';
307  if (strpos($sql_array['group_by'], ($table_alias.'.'.$letter_sort_by)) === FALSE) {
308  $sql_array['group_by'] .= ', '.$table_alias.'.'.$letter_sort_by;
309  }
310  // we need to add the first_letter column to the union so that we have the right
311  // number of columns in both sides of the union
312  $sql_array['union_select'] .= ', null AS first_letter';
313 
314  $new_assets_to_list = Array();
315  try {
316  $query = MatrixDAL::preparePdoQuery(implode(' ', $sql_array));
317  foreach ($bind_vars as $bind_var => $bind_value) {
318  MatrixDAL::bindValueToPdo($query, $bind_var, $bind_value);
319  }
320  $new_assets_to_list = MatrixDAL::executePdoGroupedAssoc($query);
321  } catch (Exception $e) {
322  throw new Exception($e->getMessage());
323  }
324 
325 
326  $assets_to_list = $this->_combineAssets($logic, $new_assets_to_list, $assets_to_list);
327  }//end foreach
328  break;
329 
330  case 'grouped' :
331 
332  // If there is one grouping type and it's "group by direct
333  // parent", we can cache the direct parents now and then
334  // groupAssetsRecursively() in Listing Engine can use them,
335  // instead of calculating the parents once for each asset
336 
337  $grouping_attr = $this->attr('asset_grouping');
338 
339  if ((count($grouping_attr) == 1) && ($grouping_attr[0]['group_type'] == 'parent_asset') && array_get_index($grouping_attr[0], 'direct_parent_only', FALSE)) {
340  $group = $grouping_attr[0];
341 
342  $links_sql = 'SELECT DISTINCT
343  minorid, majorid
344  FROM
345  '.SQ_TABLE_RUNNING_PREFIX.'ast_lnk
346  WHERE minorid IN (%s)';
347 
348  $types_sql = '
349  AND majorid IN
350  (
351  SELECT assetid FROM sq_ast WHERE %s
352  )';
353 
354 
355  if (!empty($group['restrict_types']['type_code'])) {
356  $types_sub_sql = Array();
357 
358  $inherited_types = Array();
359  $non_inherited_types = Array();
360 
361  // Need to handle which of these type codes are
362  // inherited, and which are not
363  foreach ($group['restrict_types']['type_code'] as $key => $type) {
364  if ($group['restrict_types']['inherit'][$key]) {
365  $inherited_types[] = MatrixDAL::quote($type);
366  } else {
367  $uninherited_types[] = MatrixDAL::quote($type);
368  }
369  }
370 
371  if (!empty($uninherited_types)) {
372  $types_sub_sql[] = '(type_code IN ('.implode(', ', $uninherited_types).'))';
373  }
374 
375  if (!empty($inherited_types)) {
376  $types_sub_sql[] = '(type_code IN
377  (
378  SELECT
379  type_code
380  FROM
381  '.SQ_TABLE_RUNNING_PREFIX.'ast_typ_inhd
382  WHERE inhd_type_code IN ('.implode(', ', $inherited_types).')))';
383  }
384 
385  $types_sub_sql = implode(' OR ', $types_sub_sql);
386  $types_sql = sprintf($types_sql, $types_sub_sql);
387 
388  $links_sql .= $types_sql;
389  }//end if
390 
391  $sqls = Array();
392 
393  $bind_vars = Array();
394  foreach ($root_asset_ids as $root_asset_id) {
395  $root_asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($root_asset_id);
396 
397  $bind_prefix = 'gc_'.$root_asset_id.'_';
398  $ret_val = $GLOBALS['SQ_SYSTEM']->am->generateGetChildrenQuery($root_asset, array_keys($wanted_types), FALSE, NULL, NULL, $list_permission, $list_effective, TRUE, $min_depth, $max_depth, TRUE, $link_value_wanted, $bind_prefix);
399  $sql = $ret_val['sql_array'];
400  $bind_vars = array_merge($bind_vars, $ret_val['bind_vars']);
401 
402  $sql['select'] = str_replace(', a.type_code', '', $sql['select']);
403  $sql['union_select'] = str_replace(', null', '', $sql['union_select']);
404 
405  $sql = implode(' ', $sql);
406  $sqls[] = '('.sprintf($links_sql, $sql).')';
407 
408  }
409 
410  $sql = implode(' UNION ', $sqls);
411 
412  $links = NULL;
413  try {
414  $query = MatrixDAL::preparePdoQuery($sql);
415  foreach ($bind_vars as $bind_var => $bind_value) {
416  MatrixDAL::bindValueToPdo($query, $bind_var, $bind_value);
417  }
418  $links = MatrixDAL::executePdoGrouped($query);
419  } catch (Exception $e) {
420  throw new Exception($e->getMessage());
421  }
422 
423  $childids = array_keys($links);
424  $direct_parents = Array();
425  $restrict_types = array_get_index($group, 'restrict_types', Array());
426  $direct_parent_only = array_get_index($group, 'direct_parent_only', FALSE);
427  foreach ($childids as $childid) {
428  foreach ($links[$childid] as $key => $direct_parent) {
429  if (count($links[$childid]) > 1) {
430  // resort to calling getGroupableParentAssetids() only if there is more than one parent
431  // otherwise the resulting direct parents may lie outside the root node
432  $direct_parents[$childid] = $this->getGroupableParentAssetids($childid, $restrict_types, $direct_parent_only);
433  continue;
434  } else {
435  $direct_parents[$childid][] = $direct_parent[0];
436  }
437  }
438  }
439 
440  $this->_tmp['direct_parent_grouping'] = $direct_parents;
441  }//end if
442 
443  // Intentionally fall through; we still need to do the query
444 
445  case 'number' :
446  case 'random' :
447  if ($this->attr('direction') == 'down') {
448  foreach ($root_asset_ids as $root_asset_id) {
449  $asset_list = $GLOBALS['SQ_SYSTEM']->am->getChildren($root_asset_id, array_keys($wanted_types), FALSE, NULL, NULL, $list_permission, $list_effective, $min_depth, $max_depth, TRUE, $link_value_wanted);
450 
451  $assets_to_list = $this->_combineAssets($logic, $asset_list, $assets_to_list);
452  }
453  } else {
454  foreach ($root_asset_ids as $root_asset_id) {
455  // we are now formating the asset_list the way it should be
456  // the function getParents is used at many places in Matrix therefore we are adding the following code to format
457  // the returned array. This might affect the performances of the asset listing.
458  $asset_list = Array();
459  $new_asset_list = $GLOBALS['SQ_SYSTEM']->am->getParents($root_asset_id, array_keys($wanted_types), FALSE, NULL, $list_permission, $list_effective, $min_depth, $max_depth, TRUE, $link_value_wanted);
460  foreach ($new_asset_list as $k => $v) {
461  $asset_list[$k] = Array( 0 => Array('type_code' => $v));
462  }
463  $assets_to_list = $this->_combineAssets($logic, $asset_list, $assets_to_list);
464  }
465  }
466 
467  break;
468  }//end switch
469 
470  // if the min set to 0, show asset list with root nodes
471  if ($min_depth === '0' && $max_depth !== '0') {
472  $assets_to_list = $this->_combineRootNodes($assets_to_list, $root_asset_ids, $wanted_types);
473  }
474 
475  }//end else subs_only
476 
477  if (empty($assets_to_list)) return Array();
478  return $assets_to_list;
479 
480  }//end _getAssetList()
481 
482 
493  function _getSortedAssetLists($assets_to_list, $sort_info)
494  {
495  return parent::sortAssetList($assets_to_list, $sort_info);
496 
497  }//end _getSortedAssetLists()
498 
499 
517  function _combineAssets($logic='OR', $new_assets=Array(), $existing=NULL)
518  {
519  if (is_null($existing)) return $new_assets;
520 
521  if ($logic !== 'AND') {
522  // OR logic: as it was before, just add 'em
523  $existing += $new_assets;
524  } else {
525  // AND logic: Oh how we long for PHP 5.1 and array_intersect_key()
526  // So we need to do this instead...
527  foreach ($existing as $assetid => $data) {
528  if (!isset($new_assets[$assetid])) {
529  unset($existing[$assetid]);
530  }
531  }
532  }
533 
534  return $existing;
535 
536  }//end _combineAssets()
537 
538 
549  function _combineRootNodes($assets=Array(), $root_nodes=Array(), $types=Array())
550  {
551  foreach ($root_nodes as $root_node) {
552  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($root_node);
553  if (!is_null($asset)) {
554  foreach ($types as $wanted_type => $include) {
555  if ($asset instanceof $wanted_type) {
556  $assets[$root_node] = Array(
557  Array(
558  'type_code' => $asset->type(),
559  'sort_value'=> $asset->short_name,
560  'first_letter'=> substr($asset->short_name, 0 , 1),
561  ),
562  );
563  }//end if
564  }//end foreach
565  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($asset);
566  }//end if
567  }//end foreach
568 
569  return $assets;
570 
571  }//end _combineRootNodes()
572 
573 
574 }//end class
575 ?>