source: spip-zone/_modeles_/outils/mm/mm/mm_funcs.php @ 100587

Last change on this file since 100587 was 100587, checked in by briethings@…, 5 years ago

Modèle MM : multi-modifications (utilise xx_call)

File size: 23.9 KB
Line 
1<?php
2/*-------------------------------------------#
3# *Briefings* - Licensed under the EUPL v1.0 #
4# http://ec.europa.eu/idabc/en/document/7330 #
5#-------------------------------------------*/
6#
7#--------------------------------------------------------------------------MAIN
8#
9/*array*/ function mm_features_restrict(&$objects_features) {
10/*                 ==================== */
11  $docs_allowed_for = explode(
12    COMMA,
13    xx_sql_seek('!valeur', SPIP_ . 'meta WHERE nom="documents_objets"')
14  );
15  foreach ($objects_features as $mainObj => &$features) {
16    if (
17      # documents not allowed for the current mainObj
18      !in_array(SPIP_ . $mainObj, $docs_allowed_for)
19    and
20      ($row = array_search('documents', $features)) !==FALSE
21    ) {
22      array_splice($features, $row, 1);
23    }
24  }
25}
26#
27/*string*/ function mm_object_choice($objects_features) {
28/*                  ================ */
29  foreach ($objects_features as $objName => $features) {
30    if ($features) {
31      $choice[$objName] =
32        $objName . ' <em>[' . implode(COMMA . SP, $features)  . ']</em>';
33    }
34  }
35  return $choice;
36}
37#
38/*string*/ function mm_feature_choice($objects_features, $features_ref, $actions_ref
39/*                  ================= */
40) {
41  #
42  # Register features for all objects
43  foreach ($objects_features as $objName => $features) {
44    foreach ($features as $featureName) {
45      # register feature if not yet:
46      if (!isset($feature_groups[$featureName])) {
47        $feature_groups[$featureName] = 'mm_feature';
48      }
49      # affect involved object group:
50      $feature_groups[$featureName] .= ' mm_feature_' . $objName;
51    }
52  }
53  #
54  # Create options
55  foreach ($feature_groups as $featureName => $group) {
56    $feature = $features_ref[$featureName];
57    $intro = $feature['banner'] . SP . $featureName;
58    #
59    # Register actions for current feature
60    $inputs = [];
61    foreach ($feature['actions'] as $actionName) {
62      $action = $actions_ref[$actionName]['define'];
63      # $inputs: <xx_ids_input>s built from action definition
64      $inputs[$actionName] = EXCLAMATION_MARK . implode(
65        # (EXCLAMATION_MARK: all the returned HTML must be in content part)
66        NL,
67        array_map(
68          function($inputName, $inputDef) use ($featureName, $actionName) {
69            # common case: $inputDef is [<text>, <check_1>, <check_2>, ...]
70            $func = 'xx_ids_input';
71            $args = [
72              # shortName:
73              $featureName . '_' . $inputName,
74              # text:
75              xx_parse_specif($inputDef[0], ['featureName' => $featureName]),
76            ];
77            if ($actionName == 'statusChange') {
78              # $inputDef is [<text>, array <list>, <option_all>]
79              $func = 'xx_html_select';
80              $args[] = $inputDef[1];
81              $args[] = in_array('all', $inputDef) ? ['all' => 'TOUS'] : NULL;
82            } else {
83              $args[1] = EXCLAMATION_MARK . $args[1]; # (add xx_find link)
84              $args[] = in_array('unique', $inputDef);
85              $args[] = in_array('notall', $inputDef);
86            }
87            $args[] = 'xx_input_simple';
88            return call_user_func_array($func, $args);
89          },
90          array_keys($action), # input names
91          $action              # input definitions
92        )
93      );
94    }
95    #
96    # Create radio group of inputs:
97    $suboptions = xx_html_radio('feature_' . $featureName, NULL, $inputs);
98    #
99    # Finally create full option for current feature:
100    $result[] = xx_html_option(
101      $featureName,                             # short_name
102      $intro . EXCLAMATION_MARK . $suboptions,  # text (label, content)
103      "xx_subdiv mm_detail $group $featureName" # classes
104    );
105  }
106  return implode(NL, $result);
107}
108#
109/*bool*/ function mm_check_specifs(&$common_data, array $others) {
110/*                ================ */
111  list ($mainObj, $mainObjIds) = $others;
112  $objects_ref = $common_data['objects_ref'];
113  $features_ref = $common_data['features_ref'];
114  $actions_ref = $common_data['actions_ref'];
115  #
116  # Check user-input validity for all selected features
117  foreach ($features_ref as $featureName => $feature) {
118    if (xx_param_value($featureName)) {
119      # (this feature is selected)
120      if ($actionName = xx_param_value('feature_' . $featureName)) {
121        # (an action is selected for the feature)
122        $refersObj = isset($feature['refers'][$mainObj])
123          ? $feature['refers'][$mainObj]
124          : $feature['refers']['*'];
125        # -------------------------------------------------------<action check>
126        $selection_exists = TRUE;
127        $actionIdent = $feature['banner'] . SP. $featureName;
128        xx_outnest('<h4>Contrôle de l\'option "' . $actionIdent . '"');
129        #xx_out('Contrôle de l\'option "' . $actionIdent . '"');
130        $values = []; 
131        $check_compat_ids = [];
132        #
133        # Iterate inputs for the current action on the current feature
134        foreach ($actions_ref[$actionName]['define'] as $key => $step) {
135          # ------------------------------------------------------<input check>
136          xx_outnest('<h5>Elément "' . $key . '"');
137          $itemName = $featureName . '_' . $key;
138          $input = xx_param_value($itemName);
139          $step_ident = $key . ' = "' . xx_explicit_contents($input) . '" : ';
140          #
141          # Check current input
142          if ($actionName == 'statusChange') {
143            # no unary check needed, translate "all" option:
144            $value = $input == 'all' ? [] : [$input]; # mimick "*" for "TOUS"
145          } else {
146            # check if not empty:
147            if (!$input) {
148              mm_check_error($common_data, $step_ident . 'manquant' );
149              xx_outnest();
150              continue;
151            }
152            # get ids list, using the specified constraints:
153            $value = xx_ids_list(
154              $input,
155              in_array('unique', $step),
156              in_array('notall', $step),
157              in_array('expand', $step)
158            );
159            # check if valid:
160            if ($value === NULL) {
161              mm_check_error($common_data, $step_ident . ' invalide');
162              xx_outnest();
163              continue;
164            }
165            # enforce "expand" when "*" was entered:
166            if (in_array('expand', $step) and !$value) {
167              $value = xx_get_list(
168                $objects_ref[$refersObj]['own_id'],
169                $objects_ref[$refersObj]['table']
170              );
171            }
172            # when required, prepare to check existence:
173            if (in_array('exists', $step)) {
174              # register ids to check:
175              xx_array_feed($check_exists[$refersObj], $value);
176            }
177            # when required, perform additional checks
178            if (isset($feature['check'])) {
179            # check if allowed:
180              if (
181                in_array('allowed', $step)
182              and
183                in_array('allowed', $feature['check'])
184              and
185                !mm_check_allowed(
186                  $value, $mainObj, $mainObjIds, $featureName, $common_data)
187              ) {
188                xx_outnest();
189                continue;
190              }
191              # when required, prepare to check compatibility:
192              if (
193                in_array('compat', $step)
194              and
195                in_array('compat', $feature['check'])
196              ) {
197                # register ids into '+' or '-':
198                $check_compat_ids[array_search('compat', $step)] =
199                  xx_ids_expand($value);
200              }
201            }
202          }
203          #
204          # Register accepted item value
205          $values[$key] = $value;
206          xx_trace($step_ident . 'OK');
207          xx_outnest();
208          # -----------------------------------------------------</input check>
209        }
210        #
211        # When action involves 2 inputs, look for duplicates between them.
212        if (
213          count($values) > 1
214        and
215          array_intersect(xx_ids_expand(reset($values)), next($values))
216        ) {
217          mm_check_error(
218            $common_data,
219            'Doublon entre ' .
220            implode(' et ', array_keys($actions_ref[$actionName]['define']))
221          );
222        }
223        #
224        # Check compatibility.
225        mm_check_compatibility(
226          $check_compat_ids, $mainObj, $mainObjIds, $featureName, $common_data);
227        # ------------------------------------------------------</action check>
228      }
229      # register full action values:
230      $common_data['todo'][$featureName][$actionName] = $values;
231    }
232  }
233  #
234  # Check existence of referred objects.
235  if (@$check_exists) {
236    xx_outnest('<h4>Contrôle d\'existence des entités à rajouter');
237    foreach ($check_exists as $refObj => $ids) {
238      $ident = $objects_ref[$refObj]['own_id'];
239      $found_ids = xx_get_list(
240        $ident,
241        $objects_ref[$refObj]['table'] . ' WHERE ' . xx_sql_in($ident, $ids));
242      if ($diff = array_diff($ids, ($found_ids ? $found_ids : []))) {
243        mm_check_error(
244          $common_data,
245          'Parmi les ' . $refObj . ', il manque l\'id : ' . implode (COMMA, $diff));
246      }
247    }
248    xx_outnest();
249  }
250  #
251  # Finalize
252  if (!@$selection_exists) {
253    echo BR . 'Aucune sélection !';
254  }
255  return @$selection_exists AND !$common_data['error'];
256}
257#
258/*bool*/ function mm_execute(&$common_data, array $others) {
259/*                ========== */
260  list ($mainObj, $mainObjIds) = $others;
261  #
262  # Prepare general data
263  $objects_ref = $common_data['objects_ref'];
264  $features_ref = $common_data['features_ref'];
265  $actions_ref = $common_data['actions_ref'];
266  $mainObjTable = $objects_ref[$mainObj]['table'];
267  $mainObjInstance = $objects_ref[$mainObj]['instance'];
268  $mainObjIdent = $objects_ref[$mainObj]['own_id'];
269  $mainParentIdent = $objects_ref[$mainObj]['parent_id'];
270    $local_ref = [
271      'mainObj'         => $mainObj,
272      'mainObjTable'    => $mainObjTable,
273      'mainObjIdent'    => $mainObjIdent,
274      'mainObjIds'      => $mainObjIds,
275      'mainObjInstance' => $mainObjInstance,
276      'mainParentIdent' => $mainParentIdent,
277    ];
278  $common_data['side_changes'] = [];
279  #
280  # Iterate selected features to perform selected actions
281  # $common_data['todo'] = [
282  #   $featureName => [
283  #   (auteurs | documents | mots | parents | statuts)
284  #     $actionName => [
285  #     (linkUpdate | linkdDrop | linkAdd | parentChange | statusChange)
286  #       $key => [
287  #       (depuis, vers | moins | plus | ancien, nouveau | ancien, nouveau)
288  #         $ids_list
289  #       ]
290  #     ]
291  #   ]
292  # ]
293  foreach ($common_data['todo'] as $featureName => $actions) {
294    foreach ($actions as $actionName => $items) {
295      #
296      # Prepare current action data
297      $feature = $features_ref[$featureName];
298      $refersObj = isset($feature['refers'][$mainObj])
299        ? $feature['refers'][$mainObj]
300        : $feature['refers']['*'];
301      $refersIdent = $objects_ref[$refersObj]['own_id'];
302      $targetObjSpecif = $feature['target']['obj'];
303      $targetObj = $targetObjSpecif
304        ? $targetObjSpecif
305        : $mainObj;
306      $targetTable = $objects_ref[$targetObj]['table'];
307      $targetFieldSpecif = $feature['target']['field'];
308      $targetField = $targetFieldSpecif
309        ? $objects_ref[$targetObj][$targetFieldSpecif]
310        : $refersIdent;
311      $local_ref['targetField'] = $targetField;
312      $local_ref['items'] = $items;
313      $local_ref['feature'] = $feature;
314      $local_ref['featureName'] = $featureName;
315      $local_ref['actionName'] = $actionName;
316      #
317      # Iterate execution steps for current action
318      xx_outnest('<h4>' . $feature['banner'] . SP. $featureName);
319      foreach ($actions_ref[$actionName]['exec'] as $opeName => $ope) {
320        #
321        # Register side-changes implied on involved objects before action
322        mm_register_side_changes($common_data, $local_ref, 'pre');
323        #
324        # Trace involved data
325        xx_outnest('<h5>Exécution');
326        $changes = [];
327        foreach ($items as $key => $data) {
328          sort($data);
329          $data = xx_ids_expand($data, /*flat*/ TRUE);
330          $changes[] = $key . SP . ($data ? $data : '(tous)');
331        }
332        xx_trace(implode(' -> ', $changes));
333        #
334        # Build WHERE clause if needed
335        $where_clause = '1=1';
336        if (isset($ope['where'])) {
337          $where = [];
338          foreach ($ope['where'] as $key => $value) {
339            $where[] = xx_sql_in(
340              xx_parse_specif($key, $local_ref),
341              xx_parse_specif($value, $local_ref)
342            );
343          }
344          $where_clause = implode(' AND ', $where);
345        }
346        #
347        # Execute required action
348        switch ($opeName) {
349          case 'delete':
350            if (!xx_sql_execute('
351              DELETE FROM ' . $targetTable . '
352              WHERE ' . $where_clause
353            )) {
354              return FALSE;
355            }
356            break;
357          case 'insert':
358            # get *real* ids list from the registered one, because:
359            # . if it contains ranges, they may include non-existing objects
360            # . when "*" is given, it's only an empty list
361            $mainObjSet = xx_get_list(
362              $mainObjIdent,
363              $mainObjTable . ' WHERE ' . xx_sql_in($mainObjIdent, $mainObjIds)
364            );
365            foreach ($items[$ope['values']] as $featureId) {
366              foreach ($mainObjSet as $mainObjId) {
367                $values[] = '(' .
368                  $featureId . ',' .
369                  $mainObjId . ',' .
370                  '"' . $mainObjInstance . '"' .
371                ')';
372              }
373            }
374            if (!xx_sql_execute('
375              INSERT IGNORE INTO ' . $targetTable . '
376              (' . $refersIdent . ', id_objet, objet)
377              VALUES ' . implode(COMMA, $values)
378            )) {
379              return FALSE;
380            }
381            break;
382          case 'update':
383            if (!xx_sql_execute('
384              UPDATE ' . $targetTable . '
385              SET ' . xx_sql_in($targetField, $items[$ope['value']]) . '
386              WHERE ' . $where_clause
387            )) {
388              return FALSE;
389            }
390            break;
391        }
392        xx_outnest();
393      }
394      #
395      # Register side-changes implied on involved objects before action
396      mm_register_side_changes($common_data, $local_ref, 'post');
397      xx_outnest();
398    }
399  }
400  # all actions ended successfully
401  return TRUE;
402}
403#
404/*void*/ function mm_side_changes($common_data, array $others) {
405/*                =============== */
406  if (!xx_work()) {
407    xx_out('(uniquement à l\'exécution réelle des opérations)');
408    return TRUE;
409  }
410  list ($mainObj, $mainObjIds) = $others;
411  $side_changes = $common_data['side_changes'];
412  if (!$side_changes) {
413    xx_out('Aucune');
414    return TRUE;
415  }
416  #
417  # Execute required side-changes due to previous actions
418  #xx_p($side_changes);##
419  foreach ($side_changes as $key => $ids) {
420    $func = 'xx_update_' . $key;
421    if (!$func($ids, $mainObj, $common_data['objects_ref'])) {
422      $failed = TRUE;
423    }
424  }
425  return !@$failed;
426}
427#---------------------------------------------------------------------------SUB
428#
429/*bool*/ function mm_check_allowed(
430/*                ================ */
431  $ids, $mainObj, $mainObjIds, $featureName, &$common_data
432  # ($ids are those of the new features )
433) {
434  $not_allowed_ids = [];
435  $text = 'Ces ' . $featureName . ' ne sont pas autorisés pour les ' . $mainObj;
436  switch ($featureName) {
437    case _MOT:
438      xx_outnest('<h5>Contrôle d\'autorisation des mots pour les ' . $mainObj);
439      # new MOTs must be allowed for the current mainObj:
440      foreach ($ids as $id) {
441        if (
442          ($constraints = xx_mot_constraints($id))
443        and
444          !in_array($mainObj, $constraints['tables'])
445        ) {
446          $not_allowed_ids[] = $id;
447        }
448      }
449      break;
450    case 'parents':
451      switch ($mainObj) {
452        case _RUB:
453          xx_outnest('<h5>Contrôle de cohérence de la hiérarchie des rubriques');
454          # 1. processed RUBs must be not-sectors:
455          if ($not_allowed_ids = xx_get_list(
456            'id_rubrique',
457            SPIP_RUB . ' WHERE ' . xx_sql_in('id_rubrique', $mainObjIds) .
458            ' AND id_parent=0'
459          )) {
460            $text = 'Une rubrique-secteur ne peut pas changer de parent';
461            break;
462          }
463          # 2. new parent RUB must not belong to processed RUBs:
464          if ($not_allowed_ids = array_intersect($mainObjIds, $ids)) {
465            $text = 'Une rubrique ne peut pas être son propre parent';
466            break;
467          }
468          # 3. a processed RUB must not belong to the new parent RUB's parents:
469          if ($not_allowed_ids =
470            array_intersect($mainObjIds, xx_rub_parents($ids[0]))
471            # (there is only 1 new parent RUB)
472          ) {
473            $text = 'Une rubrique ne peut pas devenir enfant de son enfant ' .
474              'actuel, direct ou indirect';
475            break;
476          }
477          break;
478        case _BRV:
479          xx_outnest('<h5>Contrôle de l\'emploi de secteurs seulement');
480          # new parent RUBs must be sectors:
481          $not_allowed_ids = xx_get_list(
482            'id_rubrique',
483            SPIP_RUB . ' WHERE ' . xx_sql_in('id_rubrique', $ids) .
484            ' AND id_parent!=0'
485          );
486        break;
487      }
488      break;
489  }
490  if ($not_allowed_ids) {
491    mm_check_error(
492      $common_data, $text . ' : ' . implode(COMMA, $not_allowed_ids));
493  }
494  xx_outnest();
495  return !$not_allowed_ids;
496}
497#
498/*void*/ function mm_check_compatibility(
499/*                ====================== */
500  $check_compat_ids, $mainObj, $mainObjIds, $featureName, &$common_data
501) {
502  $objects_ref = $common_data['objects_ref'];
503  $mainObjTable = $objects_ref[$mainObj]['table'];
504  $mainObjIdent = $objects_ref[$mainObj]['own_id'];
505  $mainObjInstance = $objects_ref[$mainObj]['instance'];
506  $mainObjName = substr($mainObj, 0, -1);
507  switch ($featureName) {
508    case _MOT:
509      xx_outnest('<h5>Contrôle de compatibilité des groupes-mots à usage unique');
510      #
511      # Get '-' and '+' changes ids ("unique" only).
512      $unique_ids_changes = [];
513      foreach ($check_compat_ids as $sense => $ids) {
514        $unique_ids_changes[$sense] = xx_mot_filter_unique($ids);
515      }
516      #xx_p($unique_ids_changes);##
517      #
518      # Look for duplicate groups among '+'.
519      $duplicates = [];
520      foreach (array_count_values($unique_ids_changes['+']) as $group => $count) {
521        if ($count > 1) {
522          $duplicates[$group] = array_keys($unique_ids_changes['+'], $group);
523        }
524      }
525      if ($duplicates) {
526        foreach ($duplicates as $group => $ids) {
527          mm_check_error(
528            $common_data,
529            'Le groupe ' . $group . ' n\'accepte qu\'un mot à la fois, parmi : ' .
530            implode(COMMA, $ids)
531          );
532        }
533        xx_outnest();
534        break;
535      }
536      #
537      # Check how changes result for each involved mainObj.
538      $collisions = [];
539      $mainObjIds = $mainObjIds
540        ? xx_ids_expand($mainObjIds)
541        : xx_get_list($mainObjIdent, $mainObjTable);
542      foreach ($mainObjIds as $mainObjId) {
543        $unique_ids_current = [];
544        # get currently affected ids ("unique" only):
545        $unique_ids_current = xx_mot_filter_unique(xx_get_list(
546          'id_mot',
547          SPIP_MOL . ' WHERE objet="' . $mainObjInstance . '"' .
548          ' AND ' . xx_sql_in('id_objet', $mainObjId)
549        ));
550        # keep only currently affected ids not also belonging to changes:
551        foreach ($unique_ids_changes as $changes) {
552          $unique_ids_current = array_diff_assoc($unique_ids_current, $changes);
553        }
554        #xx_p($unique_ids_current, '+ ' . $mainObjName . SP . $mainObjId);##
555        # then look for group collisions with '+' changes:
556        if ($obj_collisions =
557          array_intersect($unique_ids_current, $unique_ids_changes['+'])
558        ) {
559          foreach ($obj_collisions as $id => $group) {
560            mm_check_error(
561              $common_data,
562              $mainObjName . SP . $mainObjId .
563              ' : collision dans le groupe-mots ' . $group .
564              ' (ancien mot ' . $id . ', nouveau mot ' .
565              array_search($group, $unique_ids_changes['+']) . ')'
566            );
567          }
568        }
569      }
570      xx_outnest();
571      break;
572  }
573}
574#
575/*void*/ function mm_check_error(&$common_data, $diagnostic) {
576/*                ============== */
577  xx_out($diagnostic, 'xx_error');
578  $common_data['error'] = TRUE;
579}
580#
581/*string*/ function mm_func_value($func_def, $main_arg = NULL) {
582/*                  =============
583  Expected $func_def is an array (<func>, <arg1>, <arg2>, ...).
584  Returns the result of funcName(<main_arg>, <arg1>, <arg2>, ...).
585*/
586  if (!$arguments = array_splice($func_def, 1)) {
587    $arguments = [];
588  }
589  array_unshift($arguments, $main_arg);
590  $funcName = $func_def[0];
591  return call_user_func_array($funcName, $arguments);
592}
593#
594/*void*/ function mm_register_side_changes(&$common_data, $local_ref, $level) {
595/*                ========================
596  First look for current feature "implies" index and iterate its kinds.
597  For each implies-kind which involves the current mainObj, looks for the same
598  kind from the current action, in the given level.
599  If found, follows its specifications to register the involved objects and ids.
600*/
601  $actions_ref = $common_data['actions_ref'];
602  if (($feature_implies = $local_ref['feature']['implies'])) {
603    $announced = FALSE;
604    foreach ($feature_implies as $implies_kind => $involved_objects) {
605      if (
606        in_array($local_ref['mainObj'], $involved_objects)
607      and
608        ($action_implies =
609          @$actions_ref[$local_ref['actionName']]['implies'][$level][$implies_kind])
610      ) {
611        # current side-change kind ($implies_kind) involves current mainObj
612        # and exists for current level of current action:
613        if (!$announced) {
614          xx_outnest('<h5>' . ($level == 'pre' ? 'Pré' : 'Post') .
615            '-recensement des objets concernés par les mises à jour induites');
616          $announced = TRUE;
617        }
618        foreach ($action_implies as $domain => $ids) {
619          # $ids may be an array:
620          unset($all_ids);
621          $ids = is_array($ids) ? $ids : [$ids];
622          foreach ($ids as $ids_part) {
623            $ids_part = xx_parse_specif($ids_part, $local_ref);
624            if ($ids_part == [] or (isset($all_ids) and $all_ids == [])) {
625              # [] means "all", so it must overwrite anything else:
626              $all_ids = [];
627            } else {
628              # normal case:
629              xx_array_feed($all_ids, $ids_part);
630            }
631          }
632          # finally register all involved ids:
633          xx_trace(
634            $implies_kind . ' -> ' .
635            xx_parse_specif($domain, $local_ref) . ' : ' .
636            ($all_ids ? implode(COMMA, $all_ids) : '(tous)')
637          );
638          xx_array_feed($common_data['side_changes'][$implies_kind], $all_ids);
639        }
640      }
641    }
642    if ($announced) {
643      xx_outnest();
644    }
645  }
646}
647#
648/*string*/ function mm_status_selector($status_ref) {
649/*                  ==================
650  Expected $status_ref is an array(<object> => array(<status>)).
651  Returns a list suitable to use in xx_html_select(), as an array registering
652  all distinct <status>es found in $status, each looking like
653    <status>!class="<classes>"
654  where <classes> include:
655  . mm_statusOption (always)
656  . mm_statusOption_<object> for each involved <object>
657*/
658  foreach ($status_ref as $object => $statuses) {
659    foreach ($statuses as $status) {
660      if (!isset($list[$status])) {
661        $list[$status] = $status . EXCLAMATION_MARK . 'class="mm_statusOption"';
662      }
663      $list[$status] =
664        substr_replace($list[$status], ' mm_statusOption_' . $object . '"', -1);
665    }
666  }
667  return $list;
668}
669#------------------------------------------------------------ON-DEMAND VARNAMES
670#
671/*array*/ function mm_mainObjParents($local_ref) {
672/*                 ================= */
673  $result = xx_get_list(
674    $local_ref['mainParentIdent'],
675    $local_ref['mainObjTable'] . ' WHERE ' .
676    xx_sql_in($local_ref['mainObjIdent'], $local_ref['mainObjIds'])
677  );
678  return $result;
679}
Note: See TracBrowser for help on using the repository browser.