private function cbk_anwloop($asMatches) { $sLoopParams = $asMatches[1]; $sLoopContent = $asMatches[2]; self::debug("Starting loop: " . $sLoopParams); //read loop parameters //loop/type - REQUIRED try { $sLoopLoop = self::getTagSetting($sLoopParams, "loop", $this->regexpVariable()); $bIsFetchLoop = false; // it's a normal loop : <anwloop item="$tag" loop="$item.tags" limit="5"> } catch (AnwUnexpectedException $e) { $bIsFetchLoop = true; // it's a fetch loop : <anwloop item="$menu" class="menu" match="*" limit="5" sort="myname" order="asc"> } //only Fetching loop can be cached (to avoid unsync problems between parent/childs loops) $nLoopCacheTime = -1; $bCacheEnabled = false; $bCacheBlockEnabled = false; $bDoCaching = false; if ($bIsFetchLoop) { //cachetime - OPTIONAL try { $nLoopCacheTime = (int) self::getTagSetting($sLoopParams, "cachetime", '!^([0-9]*?)$!si'); } catch (AnwUnexpectedException $e) { //cachetime setting not found, keep default values $nLoopCacheTime = AnwComponent::globalCfgLoopsAutoCacheTime(); } if ($nLoopCacheTime > 0) { $bCacheEnabled = true; //if we have specified a cachetime, look for cacheblock setting try { $sTmpCacheBlock = self::getTagSetting($sLoopParams, "cacheblock", '!^(true|false|yes|no|0|1)$!si'); $bCacheBlockEnabled = in_array($sTmpCacheBlock, array('true', 'yes', '1')); unset($sTmpCacheBlock); } catch (AnwUnexpectedException $e) { //should we implicitely enable cacheblock by default? $bCacheBlockEnabled = AnwComponent::globalCfgLoopsAutoCacheblock(); } self::debug("cacheBlockEnabled: " . $bCacheBlockEnabled); } //can we really use cache for this loop? $bDoCaching = $bCacheEnabled && $this->bCachingEnabled && AnwComponent::globalCfgCacheLoopsEnabled(); //simulate a cacheblock if enabled if ($bDoCaching && $bCacheBlockEnabled) { self::debug("cacheblock enabled for loop"); $this->nTmpCacheBlockId++; $nCurrentCacheBlockId = $this->nTmpCacheBlockId; //we need to keep this value unchanged for caching under the same key, at the end of the function try { $sReturn = AnwCache_cacheBlock::getCacheBlock($this->oPage, $nCurrentCacheBlockId, $nLoopCacheTime); self::debug("AnwLoop found in cacheblock, returning cached result."); return $sReturn; //return directly } catch (AnwCacheNotFoundException $e) { } } else { self::debug("cacheblock disabled for loop"); } } //item - REQUIRED $sLoopItem = self::getTagSetting($sLoopParams, "item", '!^\\$([a-z]*?)$!si'); //required $sLoopItem = substr($sLoopItem, 1); //remove starting '$' if (isset($this->asTmpLoopItemsInUse[$sLoopItem])) { throw new AnwUnexpectedException("Loop item already used : " . $sLoopItem); } $this->asTmpLoopItemsInUse[$sLoopItem] = 1; //limit - OPTIONAL try { $nLoopLimit = (int) self::getTagSetting($sLoopParams, "limit", '!^([0-9]*?)$!si'); } catch (AnwUnexpectedException $e) { $nLoopLimit = 999999; //TODO } if ($bIsFetchLoop) { //class - REQUIRED $sLoopClass = self::getTagSetting($sLoopParams, "class", '!^([a-z]*?)$!si'); //match - OPTIONAL try { $sLoopMatch = self::getTagSetting($sLoopParams, "match", '!^([^"]*?)$!si'); } catch (AnwUnexpectedException $e) { $sLoopMatch = '*'; } //morelangs - OPTIONAL $asLoopLangs = array($this->oPage->getLang()); try { $sTmp = self::getTagSetting($sLoopParams, "morelangs", '!^([a-z,]*?)$!si'); $asTmpLangs = explode(',', $sTmp); foreach ($asTmpLangs as $sTmpLang) { $sTmpLang = trim($sTmpLang); if (Anwi18n::langExists($sTmpLang) && !in_array($sTmpLang, $asLoopLangs)) { $asLoopLangs[] = $sTmpLang; } } } catch (AnwUnexpectedException $e) { } //sort - OPTIONAL try { $sLoopSort = self::getTagSetting($sLoopParams, "sort", '!^([a-z]*?)$!si'); } catch (AnwUnexpectedException $e) { $sLoopSort = AnwUtils::SORT_BY_NAME; //TODO secure pattern } //order - OPTIONAL try { $sLoopOrder = self::getTagSetting($sLoopParams, "order", '!^(' . AnwUtils::SORTORDER_ASC . '|' . AnwUtils::SORTORDER_DESC . ')$!si'); } catch (AnwUnexpectedException $e) { $sLoopOrder = AnwUtils::SORTORDER_ASC; } //filter - OPTIONAL //filter="required=true,name:test*" $asLoopFilters = array(); try { $asFILTERS_OPERATORS = array(AnwUtils::FILTER_OP_EQUALS, AnwUtils::FILTER_OP_LIKE, AnwUtils::FILTER_OP_LT, AnwUtils::FILTER_OP_GT, AnwUtils::FILTER_OP_LE, AnwUtils::FILTER_OP_GE); $sTmp = self::getTagSetting($sLoopParams, "filter", '!^([a-z0-9_\\-,#|' . implode('', $asFILTERS_OPERATORS) . '\\*]*?)$!si'); $asTmpFilters = explode(',', $sTmp); foreach ($asTmpFilters as $sTmpFilter) { $sTmpFilter = trim($sTmpFilter); try { list($sFilterOp1, $sFilterOperator, $sFilterOp2) = self::parseOperator($asFILTERS_OPERATORS, $sTmpFilter); $sFilterOp1 = $this->getOperandValue($sFilterOp1); $sFilterOp2 = $this->getOperandValue($sFilterOp2); $asLoopFilters[] = array('FIELD' => $sFilterOp1, 'OPERATOR' => $sFilterOperator, 'VALUE' => $sFilterOp2); } catch (AnwUnexpectedException $e) { } } } catch (AnwUnexpectedException $e) { } } //iterate over the loop $sReturn = ""; $aoLoopsItems = array(); try { if ($bIsFetchLoop) { self::debug("anwloop/fetch found"); $aoLoopsItems = $this->getAnwloopFetchItems($nLoopLimit, $sLoopClass, $sLoopMatch, $asLoopLangs, $sLoopSort, $sLoopOrder, $asLoopFilters, $bDoCaching, $nLoopCacheTime); } else { self::debug("anwloop/loop found"); $aoLoopsItems = $this->parseLoopVariable('{' . $sLoopLoop . '}'); //throws an exception if error } //run the loop! foreach ($aoLoopsItems as $oLoopItem) { self::debug("anwloop iteration"); $this->aoLoopsItems[$sLoopItem] = $oLoopItem; //we may need it during recursive calls $sReturn .= $this->runAnwloopIteration($sLoopContent, $sLoopItem); unset($this->aoLoopsItems[$sLoopItem]); } } catch (Exception $e) { self::debug("! LOOP ERROR!"); $sReturn = AnwComponent::g_("local_exec_loop_error"); } unset($this->asTmpLoopItemsInUse[$sLoopItem]); //put whole content in cache if cacheblock enabled if ($bDoCaching && $bCacheBlockEnabled) { AnwCache_cacheBlock::putCacheBlock($this->oPage, $nCurrentCacheBlockId, $sReturn); } return $sReturn; }