本文整理汇总了PHP中tlObjectWithDB类的典型用法代码示例。如果您正苦于以下问题:PHP tlObjectWithDB类的具体用法?PHP tlObjectWithDB怎么用?PHP tlObjectWithDB使用的例子?那么, 这里精选的类代码示例或许可以为您提供帮助。
在下文中一共展示了tlObjectWithDB类的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的PHP代码示例。
示例1: __construct
/**
* class constructor
*
* @param resource &$db reference to database handler
* @param integer $tplanId
**/
public function __construct(&$db, &$tplanId = null)
{
$this->db = $db;
$this->testPlanID = $tplanId;
// tlObjectWithDB::__construct($db);
parent::__construct($this->db);
}
示例2: getBareBonesReq
/**
*
*
*/
function getBareBonesReq($dbHandler, $reqID)
{
$debugMsg = ' Function: ' . __FUNCTION__;
$tables = tlObjectWithDB::getDBTables(array('requirements', 'nodes_hierarchy'));
$sql = " /* {$debugMsg} */ SELECT REQ.req_doc_id, NH_REQ.name " . " FROM {$tables['requirements']} REQ " . " JOIN {$tables['nodes_hierarchy']} NH_REQ\tON NH_REQ.id = REQ.id " . " WHERE REQ.id = " . intval($reqID);
$bones = $dbHandler->get_recordset($sql);
return $bones[0];
}
示例3: __construct
/**
* class constructor
*
* @param $db [ref] resource the database connection
*/
function __construct(&$db)
{
tlObjectWithDB::__construct($db);
$this->repositoryType = self::getType();
$this->repositoryCompressionType = self::getCompression();
$this->repositoryPath = self::getPathToRepository();
$this->attachmentCfg = config_get('attachments');
}
示例4: __construct
/**
* class constructor
*
* @param $db [ref] resource the database connection
*/
function __construct(&$db)
{
tlObjectWithDB::__construct($db);
$this->attachmentCfg = config_get('attachments');
$prop2init = array('type', 'compressionType', 'path');
foreach ($prop2init as $prop) {
$this->{$prop} = $this->attachmentCfg->repository->{$prop};
}
}
示例5: doExport
function doExport(&$dbHandler, $filename)
{
$tables = tlObjectWithDB::getDBTables(array('custom_fields', 'cfield_node_types'));
$adodbXML = new ADODB_XML("1.0", "ISO-8859-1");
$sql = " SELECT name,label,type,possible_values,default_value,valid_regexp, " . " length_min,length_max,show_on_design,enable_on_design,show_on_execution," . " enable_on_execution,show_on_testplan_design,enable_on_testplan_design, " . " node_type_id,required " . " FROM {$tables['custom_fields']} CF,{$tables['cfield_node_types']} " . " WHERE CF.id=field_id ";
$adodbXML->setRootTagName('custom_fields');
$adodbXML->setRowTagName('custom_field');
$content = $adodbXML->ConvertToXMLString($dbHandler->db, $sql);
downloadContentsToFile($content, $filename);
exit;
}
示例6: doExport
function doExport(&$dbHandler, $filename)
{
$adodbXML = new ADODB_XML("1.0", "ISO-8859-1");
$adodbXML->setRootTagName('users');
$adodbXML->setRowTagName('user');
$tables = tlObjectWithDB::getDBTables(array('users'));
$fieldSet = 'id,login,role_id,email,first,last,locale,default_testproject_id,active';
$sql = " SELECT {$fieldSet} FROM {$tables['users']} ";
$content = $adodbXML->ConvertToXMLString($dbHandler->db, $sql);
downloadContentsToFile($content, $filename);
exit;
}
示例7: doExport
function doExport(&$db, $filename, $testproject_id)
{
$debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
$tables = tlObjectWithDB::getDBTables(array('platforms'));
$adodbXML = new ADODB_XML("1.0", "UTF-8");
$sql = "/* {$debugMsg} */ SELECT name,notes " . " FROM {$tables['platforms']} PLAT " . " WHERE PLAT.testproject_id=" . intval($testproject_id);
$adodbXML->setRootTagName('platforms');
$adodbXML->setRowTagName('platform');
$content = $adodbXML->ConvertToXMLString($db->db, $sql);
downloadContentsToFile($content, $filename);
exit;
}
示例8: __construct
public function __construct(&$dbHandler)
{
$this->db = $dbHandler;
$this->tprojectMgr = new testproject($dbHandler);
$this->tables = tlObjectWithDB::getDBTables(array('tcversions', 'nodes_hierarchy', 'testplan_tcversions', 'cfield_design_values'));
$this->cfg = new stdClass();
$this->cfg->showTestCaseID = config_get('treemenu_show_testcase_id');
$this->cfg->glueChar = config_get('testcase_cfg')->glue_character;
$this->cfg->nodeTypeCode = $this->tprojectMgr->tree_manager->get_available_node_types();
$this->cfg->nodeCodeType = array_flip($this->cfg->nodeTypeCode);
$this->cfg->results = config_get('results');
$this->cfg->renderTestSpecNode = new stdClass();
$this->cfg->renderTestSpecNode->key2del = array_merge(array_keys($this->cfg->results['status_code']), array('node_type_id', 'parent_id', 'node_order', 'node_table', 'tcversion_id', 'external_id', 'version', 'testcase_count'));
}
示例9: prepareTestSpecNode
/**
* @internal revisions
* 20121010 - asimon - TICKET 4353: added active/inactive filter
*/
function prepareTestSpecNode(&$db, &$tprojectMgr, $tprojectID, &$node, &$map_node_tccount, $filters = null, $options = null)
{
static $status_descr_list;
static $debugMsg;
static $tables;
static $my;
static $filtersApplied;
static $decoding_info;
static $tcFilterByKeywords;
static $doFilterOn;
if (!$tables) {
$debugMsg = 'Class: ' . __CLASS__ . ' - ' . 'Method: ' . __FUNCTION__ . ' - ';
$tables = tlObjectWithDB::getDBTables(array('tcversions', 'nodes_hierarchy', 'testplan_tcversions'));
$decoding_info = array('node_id_descr' => array_flip($tprojectMgr->tree_manager->get_available_node_types()));
$my = array();
$my['options'] = array('hideTestCases' => 0);
$my['filters'] = array('keywords' => null);
$my['options'] = array_merge($my['options'], (array) $options);
$my['filters'] = array_merge($my['filters'], (array) $filters);
if ($doFilterOn['keywords'] = !is_null($my['filters']['keywords'])) {
$tcFilterByKeywords = $tprojectMgr->getTCasesFilteredByKeywords($tprojectID, $my['filters']['keywords'], $my['filters']['keywords_filter_type']);
if (is_null($tcFilterByKeywords)) {
// tree will be empty
$node = null;
$tcase_counters['testcase_count'] = 0;
return $tcase_counters;
}
}
// Critic for logic that prune empty branches
// TICKET 4353: added active/inactive filter
$filtersApplied = $doFilterOn['keywords'] || $my['options']['ignoreInactiveTestCases'] || $my['options']['ignoreActiveTestCases'];
}
$tcase_counters['testcase_count'] = 0;
$node_type = isset($node['node_type_id']) ? $decoding_info['node_id_descr'][$node['node_type_id']] : null;
if ($node_type == 'testcase') {
$remove_node = false;
if ($my['options']['ignoreInactiveTestCases']) {
$sql = " SELECT COUNT(TCV.id) AS count_active_versions " . " FROM {$tables['tcversions']} TCV, {$tables['nodes_hierarchy']} NH " . " WHERE NH.parent_id=" . $node['id'] . " AND NH.id = TCV.id AND TCV.active=1";
$result = $db->exec_query($sql);
$row = $db->fetch_array($result);
if ($row['count_active_versions'] == 0) {
$remove_node = true;
}
} else {
if ($my['options']['ignoreActiveTestCases']) {
$sql = " SELECT COUNT(TCV.id) AS count_active_versions " . " FROM {$tables['tcversions']} TCV, {$tables['nodes_hierarchy']} NH " . " WHERE NH.parent_id=" . $node['id'] . " AND NH.id = TCV.id AND TCV.active=1";
$result = $db->exec_query($sql);
$row = $db->fetch_array($result);
if ($row['count_active_versions'] != 0) {
$remove_node = true;
}
}
}
if ($my['options']['hideTestCases'] || $remove_node || $doFilterOn['keywords'] && !isset($tcFilterByKeywords[$node['id']])) {
$node = null;
} else {
// needed to avoid problems when using json_encode with EXTJS
unset($node['childNodes']);
$node['leaf'] = true;
$tcase_counters['testcase_count'] = 1;
}
}
// if($node_type == 'testcase')
// ================================================================================
if (!is_null($node) && isset($node['childNodes']) && is_array($node['childNodes'])) {
// node has to be a Test Suite ?
$childNodes =& $node['childNodes'];
$childNodesQty = count($childNodes);
//$pos2unset = array();
for ($idx = 0; $idx < $childNodesQty; $idx++) {
$current =& $childNodes[$idx];
// I use set an element to null to filter out leaf menu items
if (is_null($current)) {
continue;
}
$counters_map = prepareTestSpecNode($db, $tprojectMgr, $tprojectID, $current, $map_node_tccount);
// 20120831 - to be analized carefully, because this can be solution
// to null issue with json and ext-js
// if( is_null($current) )
// {
// echo 'TO NULX';
// unset($childNodes[$idx]);
// }
$tcase_counters['testcase_count'] += $counters_map['testcase_count'];
}
//new dBug($pos2unset);
$node['testcase_count'] = $tcase_counters['testcase_count'];
if (isset($node['id'])) {
$map_node_tccount[$node['id']] = array('testcount' => $node['testcase_count'], 'name' => $node['name']);
}
// node must be destroyed if empty had we have using filtering conditions
if ($filtersApplied && !$tcase_counters['testcase_count'] && $node_type != 'testproject') {
$node = null;
}
} else {
if ($node_type == 'testsuite') {
//.........这里部分代码省略.........
示例10: req_link_replace
/**
* replace BBCode-link tagged links in req/reqspec scope with actual links
*
* @internal revisions:
* 20110525 - Julian - BUGID 4487 - allow to specify requirement version for internal links
* 20100301 - asimon - added anchor and tproj parameters to tags
*
* @param resource $dbHandler database handle
* @param string $scope text in which to replace tags with links
* @param integer $tprojectID ID of testproject to which req/reqspec belongs
* @return string $scope text with generated links
*/
function req_link_replace($dbHandler, $scope, $tprojectID)
{
// Use this to improve performance when is called in loops
static $tree_mgr;
static $tproject_mgr;
static $req_mgr;
static $cfg;
static $l18n;
static $title;
static $tables;
if (!$tproject_mgr) {
$tproject_mgr = new testproject($dbHandler);
$tree_mgr = new tree($dbHandler);
$req_mgr = new requirement_mgr($dbHandler);
$tables = tlObjectWithDB::getDBTables(array('requirements', 'req_specs'));
$cfg = config_get('internal_links');
$l18n['version'] = lang_get('tcversion_indicator');
$prop2loop = array('req' => array('prop' => 'req_link_title', 'default_lbl' => 'requirement'), 'req_spec' => array('prop' => 'req_spec_link_title', 'default_lbl' => 'req_spec_short'));
// configure link title (first part of the generated link)
$title = array();
foreach ($prop2loop as $key => $elem) {
$prop = $elem['prop'];
if ($cfg->{$prop}->type == 'string' && $cfg->{$prop}->value != '') {
$title[$key] = lang_get($cfg->{$prop}->value);
} else {
if ($cfg->{$prop}->type == 'none') {
$title[$key] = '';
} else {
$title[$key] = lang_get($elem['default_lbl']) . ": ";
}
}
}
}
$prefix = $tproject_mgr->getTestCasePrefix($tprojectID);
$string2replace = array();
// configure target in which link shall open
// use a reasonable default value if nothing is set in config
$cfg->target = isset($cfg->target) ? $cfg->target : 'popup';
switch ($cfg->target) {
case 'popup':
// use javascript to open popup window
$string2replace['req'] = '<a href="javascript:openLinkedReqVersionWindow(%s,%s,\'%s\')">%s%s%s</a>';
$string2replace['req_spec'] = '<a href="javascript:openLinkedReqSpecWindow(%s,\'%s\')">%s%s</a>';
break;
case 'window':
case 'frame':
// open in same frame
$target = $cfg->target == 'window' ? 'target="_blank"' : 'target="_self"';
$string2replace['req'] = '<a ' . $target . ' href="lib/requirements/reqView.php?' . 'item=requirement&requirement_id=%s&req_version_id=%s#%s">%s%s%s</a>';
$string2replace['req_spec'] = '<a ' . $target . ' href="lib/requirements/reqSpecView.php?' . 'item=req_spec&req_spec_id=%s#%s">%s%s</a>';
break;
}
// now the actual replacing
$patterns2search = array();
$patterns2search['req'] = "#\\[req(.*)\\](.*)\\[/req\\]#iU";
$patterns2search['req_spec'] = "#\\[req_spec(.*)\\](.*)\\[/req_spec\\]#iU";
$patternPositions = array('complete_string' => 0, 'attributes' => 1, 'doc_id' => 2);
$items2search['req'] = array('tproj', 'anchor', 'version');
$items2search['req_spec'] = array('tproj', 'anchor');
$itemPositions = array('item' => 0, 'item_value' => 1);
$sql2exec = array();
$sql2exec['req'] = " SELECT id, req_doc_id AS doc_id " . " FROM {$tables['requirements']} WHERE req_doc_id=";
$sql2exec['req_spec'] = " SELECT id, doc_id FROM {$tables['req_specs']} " . " WHERE doc_id=";
foreach ($patterns2search as $accessKey => $pattern) {
$matches = array();
preg_match_all($pattern, $scope, $matches);
// if no req_doc_id is set skip loop
if (count($matches[$patternPositions['doc_id']]) == 0) {
continue;
}
foreach ($matches[$patternPositions['complete_string']] as $key => $matched_string) {
$matched = array();
$matched['tproj'] = '';
$matched['anchor'] = '';
$matched['version'] = '';
// only look for attributes if any found
if ($matches[$patternPositions['attributes']][$key] != '') {
foreach ($items2search[$accessKey] as $item) {
$matched_item = array();
preg_match('/' . $item . '=([\\w]+)/', $matched_string, $matched_item);
$matched[$item] = isset($matched_item[$itemPositions['item_value']]) ? $matched_item[$itemPositions['item_value']] : '';
}
}
// set tproj to current project if tproj is not specified in attributes
if (!isset($matched['tproj']) || $matched['tproj'] == '') {
$matched['tproj'] = $prefix;
}
// get all reqs / req specs with the specified doc_id
//.........这里部分代码省略.........
示例11: __construct
/**
*
* @param database $dbHandler reference to database object
*/
public function __construct(&$dbHandler)
{
// call to constructor of parent class tlObjectWithDB
parent::__construct($dbHandler);
// Here comes all initializing work: First read the config, then user input.
// According to these inputs all filters which are not needed will not be used.
// Then initialize and use only the remaining filters.
$this->read_config();
$this->init_args();
// set filter mode to advanced or simple
$this->advanced_filter_mode = $this->filter_mode_choice_enabled && $this->args->advanced_filter_mode && !$this->args->simple_filter_mode;
// init button labels
if ($this->advanced_filter_mode) {
$label = self::SIMPLE_FILTER_BUTTON_LABEL;
$qty = self::ADVANCED_FILTER_ITEM_QUANTITY;
} else {
$label = self::ADVANCED_FILTER_BUTTON_LABEL;
$qty = self::SIMPLE_FILTER_ITEM_QUANTITY;
}
$this->filter_mode_button_label = lang_get($label);
$this->filter_mode_button_name = $label;
$this->filter_item_quantity = $qty;
$this->init_settings();
$this->init_filters();
}
示例12: templateConfiguration
$templateCfg = templateConfiguration();
$smarty = new TLSmarty();
$tpl = 'tcSearchResults.tpl';
$tproject_mgr = new testproject($db);
$tcase_mgr = new testcase($db);
$tcase_cfg = config_get('testcase_cfg');
$charset = config_get('charset');
$filter = null;
list($args, $filter) = init_args($tproject_mgr);
$ga = initializeGui($args, $tproject_mgr);
$gx = $tcase_mgr->getTcSearchSkeleton($args);
$gui = (object) array_merge((array) $ga, (array) $gx);
initSearch($gui, $args, $tproject_mgr);
$map = null;
if ($args->tprojectID && $args->doAction == 'doSearch') {
$tables = tlObjectWithDB::getDBTables(array('cfield_design_values', 'nodes_hierarchy', 'requirements', 'req_coverage', 'tcsteps', 'testcase_keywords', 'tcversions', 'users'));
$gui->tcasePrefix = $tproject_mgr->getTestCasePrefix($args->tprojectID);
$gui->tcasePrefix .= $tcase_cfg->glue_character;
$from = array('by_keyword_id' => ' ', 'by_custom_field' => ' ', 'by_requirement_doc_id' => '', 'users' => '');
$tcaseID = null;
$emptyTestProject = false;
if ($args->targetTestCase != "" && strcmp($args->targetTestCase, $gui->tcasePrefix) != 0) {
if (strpos($args->targetTestCase, $tcase_cfg->glue_character) === false) {
$args->targetTestCase = $gui->tcasePrefix . $args->targetTestCase;
}
$tcaseID = $tcase_mgr->getInternalID($args->targetTestCase);
$filter['by_tc_id'] = " AND NH_TCV.parent_id = " . intval($tcaseID);
} else {
$tproject_mgr->get_all_testcases_id($args->tprojectID, $a_tcid);
if (!is_null($a_tcid)) {
$filter['by_tc_id'] = " AND NH_TCV.parent_id IN (" . implode(",", $a_tcid) . ") ";
示例13: testlinkInitPage
*/
require_once "../../config.inc.php";
require_once "common.php";
testlinkInitPage($db);
$templateCfg = templateConfiguration();
$tproject_mgr = new testproject($db);
$req_cfg = config_get('req_cfg');
$gui = new stdClass();
$gui->main_descr = lang_get('caption_search_form_req_spec');
$gui->warning_msg = '';
$gui->path_info = null;
$gui->resultSet = null;
$map = null;
$args = init_args();
if ($args->tprojectID) {
$tables = tlObjectWithDB::getDBTables(array("cfield_design_values", 'nodes_hierarchy', 'req_specs'));
$filter = null;
$from = null;
if ($args->requirement_document_id) {
//search by id
$id = $db->prepare_string($args->requirement_document_id);
$filter['by_id'] = " AND RS.doc_id like '%{$id}%' ";
}
if ($args->name) {
//search by name/title
$title = $db->prepare_string($args->name);
$filter['by_name'] = " AND NH.name like '%{$title}%' ";
}
if ($args->reqSpecType != "notype") {
//search by type
$type = $db->prepare_string($args->reqSpecType);
示例14: doesKeywordExist
/**
* checks if a keyword for a certain testproject already exists in the database
*
* @param resource $db [ref] the database connection
* @param string $name the name of the keyword
* @param integer $tprojectID the testprojectID
* @param integer $kwID an additional keyword id which is excluded in the search
* @return integer return tl::OK if the keyword is found, else tlKeyword::E_NAMEALREADYEXISTS
*/
public static function doesKeywordExist(&$db, $name, $tprojectID, $kwID = null)
{
$result = tl::OK;
$tables = tlObjectWithDB::getDBTables("keywords");
$name = $db->prepare_string(strtoupper($name));
$query = " SELECT id FROM {$tables['keywords']} " . " WHERE UPPER(keyword) ='" . $name . "' AND testproject_id = " . $tprojectID;
if ($kwID) {
$query .= " AND id <> " . $kwID;
}
if ($db->fetchFirstRow($query)) {
$result = self::E_NAMEALREADYEXISTS;
}
return $result;
}
示例15: display_children
function display_children($dbHandler, $root_node, $parent, $filter_node, $show_children = ON, $operation = 'manage', $mode = 'reqspec')
{
$tables = tlObjectWithDB::getDBTables(array('requirements', 'nodes_hierarchy', 'node_types', 'req_specs'));
$cfg = config_get('req_cfg');
$forbidden_parent['testproject'] = 'none';
$forbidden_parent['requirement'] = 'testproject';
$forbidden_parent['requirement_spec'] = 'requirement_spec';
if ($cfg->child_requirements_mgmt) {
$forbidden_parent['requirement_spec'] = 'none';
}
$fn = array();
$fn['print']['reqspec'] = array('testproject' => 'TPROJECT_PTP_RS', 'requirement_spec' => 'TPROJECT_PRS', 'requirement' => 'openLinkedReqWindow');
$fn['manage']['reqspec'] = array('testproject' => 'TPROJECT_REQ_SPEC_MGMT', 'requirement_spec' => 'REQ_SPEC_MGMT', 'requirement' => 'REQ_MGMT');
$fn['print']['addtc'] = array('testproject' => 'TPROJECT_PTP', 'requirement_spec' => 'TPROJECT_PRS', 'requirement' => 'TPROJECT_PRS');
$fn['manage']['addtc'] = array('testproject' => 'EP', 'requirement_spec' => 'ERS', 'requirement' => 'ER');
switch ($operation) {
case 'print':
case 'manage':
$js_function = $fn[$operation][$mode];
break;
default:
$js_function = $fn['manage'][$mode];
break;
}
$nodes = null;
$filter_node_type = $show_children ? '' : ",'requirement'";
$sql = " SELECT NHA.*, NT.description AS node_type, RSPEC.doc_id " . " FROM {$tables['nodes_hierarchy']} NHA JOIN {$tables['node_types']} NT " . " ON NHA.node_type_id=NT.id " . " AND NT.description NOT IN " . " ('testcase','testsuite','testcase_version','testplan','requirement_spec_revision' {$filter_node_type}) " . " LEFT OUTER JOIN {$tables['req_specs']} RSPEC " . " ON RSPEC.id = NHA.id " . " WHERE NHA.parent_id = " . intval($parent);
if (!is_null($filter_node) && $filter_node > 0 && $parent == $root_node) {
$sql .= " AND NHA.id = " . intval($filter_node);
}
$sql .= " ORDER BY NHA.node_order ";
$nodeSet = $dbHandler->get_recordset($sql);
if (!is_null($nodeSet)) {
$sql = " SELECT DISTINCT req_doc_id AS doc_id,NHA.id" . " FROM {$tables['requirements']} REQ JOIN {$tables['nodes_hierarchy']} NHA ON NHA.id = REQ.id " . " JOIN {$tables['nodes_hierarchy']} NHB ON NHA.parent_id = NHB.id " . " JOIN {$tables['node_types']} NT ON NT.id = NHA.node_type_id " . " WHERE NHB.id = " . intval($parent) . " AND NT.description = 'requirement'";
$requirements = $dbHandler->fetchRowsIntoMap($sql, 'id');
$treeMgr = new tree($dbHandler);
$ntypes = $treeMgr->get_available_node_types();
$peerTypes = array('target' => $ntypes['requirement'], 'container' => $ntypes['requirement_spec']);
foreach ($nodeSet as $key => $row) {
$path['text'] = htmlspecialchars($row['name']);
$path['id'] = $row['id'];
// this attribute/property is used on custom code on drag and drop
$path['position'] = $row['node_order'];
$path['leaf'] = false;
$path['cls'] = 'folder';
// Important:
// We can add custom keys, and will be able to access it using
// public property 'attributes' of object of Class Ext.tree.TreeNode
//
$path['testlink_node_type'] = $row['node_type'];
$path['testlink_node_name'] = $path['text'];
// already htmlspecialchars() done
$path['forbidden_parent'] = 'none';
switch ($row['node_type']) {
case 'testproject':
$path['href'] = "javascript:EP({$path['id']})";
$path['forbidden_parent'] = $forbidden_parent[$row['node_type']];
break;
case 'requirement_spec':
$req_list = array();
$treeMgr->getAllItemsID($row['id'], $req_list, $peerTypes);
$path['href'] = "javascript:" . $js_function[$row['node_type']] . "({$path['id']})";
$path['text'] = htmlspecialchars($row['doc_id'] . ":") . $path['text'];
$path['forbidden_parent'] = $forbidden_parent[$row['node_type']];
if (!is_null($req_list)) {
$item_qty = count($req_list);
$path['text'] .= " ({$item_qty})";
}
break;
case 'requirement':
$path['href'] = "javascript:" . $js_function[$row['node_type']] . "({$path['id']})";
$path['text'] = htmlspecialchars($requirements[$row['id']]['doc_id'] . ":") . $path['text'];
$path['leaf'] = true;
$path['forbidden_parent'] = $forbidden_parent[$row['node_type']];
break;
}
$nodes[] = $path;
}
// foreach
}
return $nodes;
}