%PDF- %PDF-
Direktori : /home/bitrix/www/bitrix/modules/main/classes/general/ |
Current File : /home/bitrix/www/bitrix/modules/main/classes/general/database.php |
<?php /** * Bitrix Framework * @package bitrix * @subpackage main * @copyright 2001-2014 Bitrix */ use Bitrix\Main; use Bitrix\Main\Data\ConnectionPool; abstract class CAllDatabase { var $DBName; var $DBHost; var $DBLogin; var $DBPassword; var $bConnected; var $db_Conn; var $debug; var $DebugToFile; var $ShowSqlStat; var $db_Error; var $db_ErrorSQL; var $result; var $type; static $arNodes = array(); var $column_cache = array(); var $bModuleConnection; var $bNodeConnection; var $node_id; /** @var CDatabase */ var $obSlave = null; /** * @var integer * @deprecated Use \Bitrix\Main\Application::getConnection()->getTracker()->getCounter(); **/ var $cntQuery = 0; /** * @var float * @deprecated Use \Bitrix\Main\Application::getConnection()->getTracker()->getTime(); **/ var $timeQuery = 0.0; /** * @var \Bitrix\Main\Diag\SqlTrackerQuery[] * @deprecated Use \Bitrix\Main\Application::getConnection()->getTracker()->getQueries(); **/ var $arQueryDebug = array(); /** * @var \Bitrix\Main\Diag\SqlTracker */ public $sqlTracker = null; function StartUsingMasterOnly() { Main\Application::getInstance()->getConnectionPool()->useMasterOnly(true); } function StopUsingMasterOnly() { Main\Application::getInstance()->getConnectionPool()->useMasterOnly(false); } /** * @param string $node_id * @param boolean $bIgnoreErrors * @param boolean $bCheckStatus * * @return boolean|CDatabase */ function GetDBNodeConnection($node_id, $bIgnoreErrors = false, $bCheckStatus = true) { global $DB; if(!array_key_exists($node_id, self::$arNodes)) { if(CModule::IncludeModule('cluster')) self::$arNodes[$node_id] = CClusterDBNode::GetByID($node_id); else self::$arNodes[$node_id] = false; } $node = &self::$arNodes[$node_id]; if( is_array($node) && ( !$bCheckStatus || ( $node["ACTIVE"] == "Y" && ($node["STATUS"] == "ONLINE" || $node["STATUS"] == "READY") ) ) && !isset($node["ONHIT_ERROR"]) ) { if(!array_key_exists("DB", $node)) { $node_DB = new CDatabase; $node_DB->type = $DB->type; $node_DB->debug = $DB->debug; $node_DB->DebugToFile = $DB->DebugToFile; $node_DB->bNodeConnection = true; $node_DB->node_id = $node_id; if($node_DB->Connect($node["DB_HOST"], $node["DB_NAME"], $node["DB_LOGIN"], $node["DB_PASSWORD"], "node".$node_id)) { if(defined("DELAY_DB_CONNECT") && DELAY_DB_CONNECT===true) { if($node_DB->DoConnect("node".$node_id)) $node["DB"] = $node_DB; } else { $node["DB"] = $node_DB; } } } if(array_key_exists("DB", $node)) return $node["DB"]; } if($bIgnoreErrors) { return false; } else { if(file_exists($_SERVER["DOCUMENT_ROOT"].BX_PERSONAL_ROOT."/php_interface/dbconn_error.php")) include($_SERVER["DOCUMENT_ROOT"].BX_PERSONAL_ROOT."/php_interface/dbconn_error.php"); else include($_SERVER["DOCUMENT_ROOT"].BX_ROOT."/modules/main/include/dbconn_error.php"); die(); } } /** * Returns module database connection. * Can be used only if module supports sharding. * * @param string $module_id * @param bool $bModuleInclude * @return bool|CDatabase */ public static function GetModuleConnection($module_id, $bModuleInclude = false) { $node_id = COption::GetOptionString($module_id, "dbnode_id", "N"); if(is_numeric($node_id)) { if($bModuleInclude) { $status = COption::GetOptionString($module_id, "dbnode_status", "ok"); if($status === "move") return false; } $moduleDB = CDatabase::GetDBNodeConnection($node_id, $bModuleInclude); if(is_object($moduleDB)) { $moduleDB->bModuleConnection = true; return $moduleDB; } //There was an connection error if($bModuleInclude && CModule::IncludeModule('cluster')) CClusterDBNode::SetOffline($node_id); //TODO: unclear what to return when node went offline //in the middle of the hit. return false; } else { return $GLOBALS["DB"]; } } abstract function Connect($DBHost, $DBName, $DBLogin, $DBPassword); abstract function ConnectInternal(); function DoConnect($connectionName = "") { if($this->bConnected) return true; $app = Main\Application::getInstance(); if ($app != null) { $con = $app->getConnection($connectionName); if ( $con && $con->isConnected() && ($con instanceof Bitrix\Main\DB\Connection) && ($this->DBHost == $con->getHost()) && ($this->DBLogin == $con->getLogin()) && ($this->DBName == $con->getDatabase()) ) { $this->db_Conn = $con->getResource(); $this->bConnected = true; $this->sqlTracker = null; $this->cntQuery = 0; $this->timeQuery = 0; $this->arQueryDebug = array(); return true; } } if(!$this->ConnectInternal()) { return false; } $this->bConnected = true; $this->sqlTracker = null; $this->cntQuery = 0; $this->timeQuery = 0; $this->arQueryDebug = array(); /** @noinspection PhpUnusedLocalVariableInspection */ global $DB, $USER, $APPLICATION; if(file_exists($_SERVER["DOCUMENT_ROOT"].BX_PERSONAL_ROOT."/php_interface/after_connect.php")) include($_SERVER["DOCUMENT_ROOT"].BX_PERSONAL_ROOT."/php_interface/after_connect.php"); if ($app != null) { $con = $app->getConnection($connectionName); if(!$con && $this->bNodeConnection) { //create a node connection in the new kernel $pool = $app->getConnectionPool(); $parameters = array( 'host' => $this->DBHost, 'database' => $this->DBName, 'login' => $this->DBLogin, 'password' => $this->DBPassword, ); $con = $pool->cloneConnection(ConnectionPool::DEFAULT_CONNECTION_NAME, $connectionName, $parameters); $con->setNodeId($this->node_id); } if ( $con && !$con->isConnected() && ($con instanceof Bitrix\Main\DB\Connection) && ($this->DBHost == $con->getHost()) && ($this->DBLogin == $con->getLogin()) && ($this->DBName == $con->getDatabase()) ) { $con->setConnectionResourceNoDemand($this->db_Conn); } } return true; } function startSqlTracker() { if (!$this->sqlTracker) { $app = Main\Application::getInstance(); $this->sqlTracker = $app->getConnection()->startTracker(); } return $this->sqlTracker; } function GetNowFunction() { return CDatabase::CurrentTimeFunction(); } function GetNowDate() { return CDatabase::CurrentDateFunction(); } abstract function DateToCharFunction($strFieldName, $strType="FULL"); abstract function CharToDateFunction($strValue, $strType="FULL"); abstract function Concat(); function Substr($str, $from, $length = null) { // works for mysql and oracle, redefined for mssql $sql = 'SUBSTR('.$str.', '.$from; if (!is_null($length)) { $sql .= ', '.$length; } return $sql.')'; } abstract function IsNull($expression, $result); abstract function Length($field); function ToChar($expr, $len=0) { return "CAST(".$expr." AS CHAR".($len > 0? "(".$len.")":"").")"; } public static function DateFormatToPHP($format) { static $cache = array(); if (!isset($cache[$format])) { $cache[$format] = Main\Type\Date::convertFormatToPhp($format); } return $cache[$format]; } public static function FormatDate($strDate, $format="DD.MM.YYYY HH:MI:SS", $new_format="DD.MM.YYYY HH:MI:SS") { if (empty($strDate)) return false; if ($format===false && defined("FORMAT_DATETIME")) $format = FORMAT_DATETIME; $fromPhpFormat = Main\Type\Date::convertFormatToPhp($format); $time = false; try { $time = new Main\Type\DateTime($strDate, $fromPhpFormat); } catch(Main\ObjectException $e) { } if ($time !== false) { //Compatibility issue $fixed_format = preg_replace( array( "/(?<!Y)Y(?!Y)/i", "/(?<!M)M(?!M|I)/i", "/(?<!D)D(?!D)/i", "/(?<!H)H:I:S/i", ), array( "YYYY", "MM", "DD", "HH:MI:SS", ), strtoupper($new_format) ); $toPhpFormat = Main\Type\Date::convertFormatToPhp($fixed_format); return $time->format($toPhpFormat); } return false; } /** * @param string $strSql * @param bool $bIgnoreErrors * @param string $error_position * @param array $arOptions * @return CDBResult */ abstract function Query($strSql, $bIgnoreErrors=false, $error_position="", $arOptions=array()); //query with CLOB function QueryBind($strSql, $arBinds, $bIgnoreErrors=false) { return $this->Query($strSql, $bIgnoreErrors); } function QueryLong($strSql, $bIgnoreErrors = false) { return $this->Query($strSql, $bIgnoreErrors); } abstract function ForSql($strValue, $iMaxLength=0); abstract function PrepareInsert($strTableName, $arFields); abstract function PrepareUpdate($strTableName, $arFields); function ParseSqlBatch($strSql, $bIncremental = False) { if(strtolower($this->type)=="mysql") $delimiter = ";"; elseif(strtolower($this->type)=="mssql") $delimiter = "\nGO"; else $delimiter = "(?<!\\*)/(?!\\*)"; $strSql = trim($strSql); $ret = array(); $str = ""; do { if(preg_match("%^(.*?)(['\"`#]|--|".$delimiter.")%is", $strSql, $match)) { //Found string start if($match[2] == "\"" || $match[2] == "'" || $match[2] == "`") { $strSql = substr($strSql, strlen($match[0])); $str .= $match[0]; //find a qoute not preceeded by \ if(preg_match("%^(.*?)(?<!\\\\)".$match[2]."%s", $strSql, $string_match)) { $strSql = substr($strSql, strlen($string_match[0])); $str .= $string_match[0]; } else { //String falled beyong end of file $str .= $strSql; $strSql = ""; } } //Comment found elseif($match[2] == "#" || $match[2] == "--") { //Take that was before comment as part of sql $strSql = substr($strSql, strlen($match[1])); $str .= $match[1]; //And cut the rest $p = strpos($strSql, "\n"); if($p === false) { $p1 = strpos($strSql, "\r"); if($p1 === false) $strSql = ""; elseif($p < $p1) $strSql = substr($strSql, $p); else $strSql = substr($strSql, $p1); } else $strSql = substr($strSql, $p); } //Delimiter! else { //Take that was before delimiter as part of sql $strSql = substr($strSql, strlen($match[0])); $str .= $match[1]; //Delimiter must be followed by whitespace if(preg_match("%^[\n\r\t ]%", $strSql)) { $str = trim($str); if(strlen($str)) { if ($bIncremental) { $strSql1 = str_replace("\r\n", "\n", $str); if (!$this->QueryLong($strSql1, true)) $ret[] = $this->GetErrorMessage(); } else { $ret[] = $str; $str = ""; } } } //It was not delimiter! elseif(strlen($strSql)) { $str .= $match[2]; } } } else //End of file is our delimiter { $str .= $strSql; $strSql = ""; } } while (strlen($strSql)); $str = trim($str); if(strlen($str)) { if ($bIncremental) { $strSql1 = str_replace("\r\n", "\n", $str); if (!$this->QueryLong($strSql1, true)) $ret[] = $this->GetErrorMessage(); } else { $ret[] = $str; } } return $ret; } function RunSQLBatch($filepath, $bIncremental = False) { if(!file_exists($filepath) || !is_file($filepath)) return array("File $filepath is not found."); $arErr = array(); $contents = file_get_contents($filepath); $arSql = $this->ParseSqlBatch($contents, $bIncremental); foreach($arSql as $strSql) { if ($bIncremental) { $arErr[] = $strSql; } else { $strSql = str_replace("\r\n", "\n", $strSql); if(!$this->Query($strSql, true)) $arErr[] = "<hr><pre>Query:\n".$strSql."\n\nError:\n<font color=red>".$this->GetErrorMessage()."</font></pre>"; } } if(!empty($arErr)) return $arErr; return false; } function IsDate($value, $format=false, $lang=false, $format_type="SHORT") { if ($format===false) $format = CLang::GetDateFormat($format_type, $lang); return CheckDateTime($value, $format); } function GetErrorMessage() { if(is_object($this->obSlave) && strlen($this->obSlave->db_Error)) return $this->obSlave->db_Error; elseif(strlen($this->db_Error)) return $this->db_Error."!"; else return ''; } function GetErrorSQL() { if(is_object($this->obSlave) && strlen($this->obSlave->db_ErrorSQL)) return $this->obSlave->db_ErrorSQL; elseif(strlen($this->db_ErrorSQL)) return $this->db_ErrorSQL; else return ''; } function DDL($strSql, $bIgnoreErrors=false, $error_position="", $arOptions=array()) { $res = $this->Query($strSql, $bIgnoreErrors, $error_position, $arOptions); //Reset metadata cache $this->column_cache = array(); return $res; } function addDebugQuery($strSql, $exec_time, $node_id = 0) { $this->cntQuery++; $this->timeQuery += $exec_time; $this->arQueryDebug[] = $this->startSqlTracker()->getNewTrackerQuery() ->setSql($strSql) ->setTime($exec_time) ->setTrace(defined("BX_NO_SQL_BACKTRACE")? null: Main\Diag\Helper::getBackTrace(8, null, 2)) ->setState($GLOBALS["BX_STATE"]) ->setNode($node_id) ; } function addDebugTime($index, $exec_time) { if ($this->arQueryDebug[$index]) { $this->arQueryDebug[$index]->addTime($exec_time); } } abstract public function GetIndexName($tableName, $arColumns, $bStrict = false); public function IndexExists($tableName, $arColumns, $bStrict = false) { return $this->GetIndexName($tableName, $arColumns, $bStrict) !== ""; } } abstract class CAllDBResult { var $result; var $arResult; var $arReplacedAliases; // replace tech. aliases in Fetch to human aliases var $arResultAdd; var $bNavStart = false; var $bShowAll = false; var $NavNum, $NavPageCount, $NavPageNomer, $NavPageSize, $NavShowAll, $NavRecordCount; var $bFirstPrintNav = true; var $PAGEN, $SIZEN; var $SESS_SIZEN, $SESS_ALL, $SESS_PAGEN; var $add_anchor = ""; var $bPostNavigation = false; var $bFromArray = false; var $bFromLimited = false; var $sSessInitAdd = ""; var $nPageWindow = 5; var $nSelectedCount = false; var $arGetNextCache = false; var $bDescPageNumbering = false; /** @var array */ var $arUserFields = false; var $usedUserFields = false; /** @var array */ var $SqlTraceIndex = false; /** @var CDatabase */ var $DB; var $NavRecordCountChangeDisable = false; var $is_filtered = false; var $nStartPage = 0; var $nEndPage = 0; /** @var Main\DB\Result */ var $resultObject = null; /** @param CDBResult $res */ public function __construct($res = null) { $obj = is_object($res); if($obj && is_subclass_of($res, "CAllDBResult")) { $this->result = $res->result; $this->nSelectedCount = $res->nSelectedCount; $this->arResult = $res->arResult; $this->arResultAdd = $res->arResultAdd; $this->bNavStart = $res->bNavStart; $this->NavPageNomer = $res->NavPageNomer; $this->bShowAll = $res->bShowAll; $this->NavNum = $res->NavNum; $this->NavPageCount = $res->NavPageCount; $this->NavPageSize = $res->NavPageSize; $this->NavShowAll = $res->NavShowAll; $this->NavRecordCount = $res->NavRecordCount; $this->bFirstPrintNav = $res->bFirstPrintNav; $this->PAGEN = $res->PAGEN; $this->SIZEN = $res->SIZEN; $this->bFromArray = $res->bFromArray; $this->bFromLimited = $res->bFromLimited; $this->nPageWindow = $res->nPageWindow; $this->bDescPageNumbering = $res->bDescPageNumbering; $this->SqlTraceIndex = $res->SqlTraceIndex; $this->DB = $res->DB; $this->arUserFields = $res->arUserFields; } elseif($obj && $res instanceof Main\DB\ArrayResult) { $this->InitFromArray($res->getResource()); } elseif($obj && $res instanceof Main\DB\Result) { $this->result = $res->getResource(); $this->resultObject = $res; } elseif(is_array($res)) { $this->arResult = $res; } else { $this->result = $res; } } /** @deprecated */ public function CAllDBResult($res = null) { self::__construct($res); } public function __sleep() { return array( 'result', 'arResult', 'arReplacedAliases', 'arResultAdd', 'bNavStart', 'bShowAll', 'NavNum', 'NavPageCount', 'NavPageNomer', 'NavPageSize', 'NavShowAll', 'NavRecordCount', 'bFirstPrintNav', 'PAGEN', 'SIZEN', 'add_anchor', 'bPostNavigation', 'bFromArray', 'bFromLimited', 'sSessInitAdd', 'nPageWindow', 'nSelectedCount', 'arGetNextCache', 'bDescPageNumbering', 'arUserMultyFields', ); } /** * @return array */ abstract public function Fetch(); /** * @return array */ abstract protected function FetchInternal(); abstract public function SelectedRowsCount(); abstract public function AffectedRowsCount(); abstract public function FieldsCount(); abstract public function FieldName($iCol); public function NavContinue() { if (count($this->arResultAdd) > 0) { $this->arResult = $this->arResultAdd; return true; } else return false; } public function IsNavPrint() { if ($this->NavRecordCount == 0 || ($this->NavPageCount == 1 && $this->NavShowAll == false)) return false; return true; } public function NavPrint($title, $show_allways=false, $StyleText="text", $template_path=false) { echo $this->GetNavPrint($title, $show_allways, $StyleText, $template_path); } public function GetNavPrint($title, $show_allways=false, $StyleText="text", $template_path=false, $arDeleteParam=false) { $res = ''; $add_anchor = $this->add_anchor; $sBegin = GetMessage("nav_begin"); $sEnd = GetMessage("nav_end"); $sNext = GetMessage("nav_next"); $sPrev = GetMessage("nav_prev"); $sAll = GetMessage("nav_all"); $sPaged = GetMessage("nav_paged"); $nPageWindow = $this->nPageWindow; if(!$show_allways) { if ($this->NavRecordCount == 0 || ($this->NavPageCount == 1 && $this->NavShowAll == false)) return ''; } $sUrlPath = GetPagePath(); $arDel = array("PAGEN_".$this->NavNum, "SIZEN_".$this->NavNum, "SHOWALL_".$this->NavNum, "PHPSESSID"); if(is_array($arDeleteParam)) $arDel = array_merge($arDel, $arDeleteParam); $strNavQueryString = DeleteParam($arDel); if($strNavQueryString <> "") $strNavQueryString = htmlspecialcharsbx("&".$strNavQueryString); if($template_path!==false && !file_exists($template_path) && file_exists($_SERVER["DOCUMENT_ROOT"].$template_path)) $template_path = $_SERVER["DOCUMENT_ROOT"].$template_path; if($this->bDescPageNumbering === true) { if($this->NavPageNomer + floor($nPageWindow/2) >= $this->NavPageCount) $nStartPage = $this->NavPageCount; else { if($this->NavPageNomer + floor($nPageWindow/2) >= $nPageWindow) $nStartPage = $this->NavPageNomer + floor($nPageWindow/2); else { if($this->NavPageCount >= $nPageWindow) $nStartPage = $nPageWindow; else $nStartPage = $this->NavPageCount; } } if($nStartPage - $nPageWindow >= 0) $nEndPage = $nStartPage - $nPageWindow + 1; else $nEndPage = 1; //echo "nEndPage = $nEndPage; nStartPage = $nStartPage;"; } else { if($this->NavPageNomer > floor($nPageWindow/2) + 1 && $this->NavPageCount > $nPageWindow) $nStartPage = $this->NavPageNomer - floor($nPageWindow/2); else $nStartPage = 1; if($this->NavPageNomer <= $this->NavPageCount - floor($nPageWindow/2) && $nStartPage + $nPageWindow-1 <= $this->NavPageCount) $nEndPage = $nStartPage + $nPageWindow - 1; else { $nEndPage = $this->NavPageCount; if($nEndPage - $nPageWindow + 1 >= 1) $nStartPage = $nEndPage - $nPageWindow + 1; } } $this->nStartPage = $nStartPage; $this->nEndPage = $nEndPage; if($template_path!==false && file_exists($template_path)) { /* $this->bFirstPrintNav - is first tiem call $this->NavPageNomer - number of current page $this->NavPageCount - total page count $this->NavPageSize - page size $this->NavRecordCount - records count $this->bShowAll - show "all" link $this->NavShowAll - is all shown $this->NavNum - number of navigation $this->bDescPageNumbering - reverse paging $this->nStartPage - first page in chain $this->nEndPage - last page in chain $strNavQueryString - query string $sUrlPath - current url Url for link to the page #PAGE_NUMBER#: $sUrlPath.'?PAGEN_'.$this->NavNum.'='.#PAGE_NUMBER#.$strNavQueryString.'#nav_start"'.$add_anchor */ ob_start(); include($template_path); $res = ob_get_contents(); ob_end_clean(); $this->bFirstPrintNav = false; return $res; } if($this->bFirstPrintNav) { $res .= '<a name="nav_start'.$add_anchor.'"></a>'; $this->bFirstPrintNav = false; } $res .= '<font class="'.$StyleText.'">'.$title.' '; if($this->bDescPageNumbering === true) { $makeweight = ($this->NavRecordCount % $this->NavPageSize); $NavFirstRecordShow = 0; if($this->NavPageNomer != $this->NavPageCount) $NavFirstRecordShow += $makeweight; $NavFirstRecordShow += ($this->NavPageCount - $this->NavPageNomer) * $this->NavPageSize + 1; if ($this->NavPageCount == 1) $NavLastRecordShow = $this->NavRecordCount; else $NavLastRecordShow = $makeweight + ($this->NavPageCount - $this->NavPageNomer + 1) * $this->NavPageSize; $res .= $NavFirstRecordShow; $res .= ' - '.$NavLastRecordShow; $res .= ' '.GetMessage("nav_of").' '; $res .= $this->NavRecordCount; $res .= "\n<br>\n</font>"; $res .= '<font class="'.$StyleText.'">'; if($this->NavPageNomer < $this->NavPageCount) $res .= '<a href="'.$sUrlPath.'?PAGEN_'.$this->NavNum.'='.$this->NavPageCount.$strNavQueryString.'#nav_start'.$add_anchor.'">'.$sBegin.'</a> | <a href="'.$sUrlPath.'?PAGEN_'.$this->NavNum.'='.($this->NavPageNomer+1).$strNavQueryString.'#nav_start'.$add_anchor.'">'.$sPrev.'</a>'; else $res .= $sBegin.' | '.$sPrev; $res .= ' | '; $NavRecordGroup = $nStartPage; while($NavRecordGroup >= $nEndPage) { $NavRecordGroupPrint = $this->NavPageCount - $NavRecordGroup + 1; if($NavRecordGroup == $this->NavPageNomer) $res .= '<b>'.$NavRecordGroupPrint.'</b> '; else $res .= '<a href="'.$sUrlPath.'?PAGEN_'.$this->NavNum.'='.$NavRecordGroup.$strNavQueryString.'#nav_start'.$add_anchor.'">'.$NavRecordGroupPrint.'</a> '; $NavRecordGroup--; } $res .= '| '; if($this->NavPageNomer > 1) $res .= '<a href="'.$sUrlPath.'?PAGEN_'.$this->NavNum.'='.($this->NavPageNomer-1).$strNavQueryString.'#nav_start'.$add_anchor.'">'.$sNext.'</a> | <a href="'.$sUrlPath.'?PAGEN_'.$this->NavNum.'=1'.$strNavQueryString.'#nav_start'.$add_anchor.'">'.$sEnd.'</a> '; else $res .= $sNext.' | '.$sEnd.' '; } else { $res .= ($this->NavPageNomer-1)*$this->NavPageSize+1; $res .= ' - '; if($this->NavPageNomer != $this->NavPageCount) $res .= $this->NavPageNomer * $this->NavPageSize; else $res .= $this->NavRecordCount; $res .= ' '.GetMessage("nav_of").' '; $res .= $this->NavRecordCount; $res .= "\n<br>\n</font>"; $res .= '<font class="'.$StyleText.'">'; if($this->NavPageNomer > 1) $res .= '<a href="'.$sUrlPath.'?PAGEN_'.$this->NavNum.'=1'.$strNavQueryString.'#nav_start'.$add_anchor.'">'.$sBegin.'</a> | <a href="'.$sUrlPath.'?PAGEN_'.$this->NavNum.'='.($this->NavPageNomer-1).$strNavQueryString.'#nav_start'.$add_anchor.'">'.$sPrev.'</a>'; else $res .= $sBegin.' | '.$sPrev; $res .= ' | '; $NavRecordGroup = $nStartPage; while($NavRecordGroup <= $nEndPage) { if($NavRecordGroup == $this->NavPageNomer) $res .= '<b>'.$NavRecordGroup.'</b> '; else $res .= '<a href="'.$sUrlPath.'?PAGEN_'.$this->NavNum.'='.$NavRecordGroup.$strNavQueryString.'#nav_start'.$add_anchor.'">'.$NavRecordGroup.'</a> '; $NavRecordGroup++; } $res .= '| '; if($this->NavPageNomer < $this->NavPageCount) $res .= '<a href="'.$sUrlPath.'?PAGEN_'.$this->NavNum.'='.($this->NavPageNomer+1).$strNavQueryString.'#nav_start'.$add_anchor.'">'.$sNext.'</a> | <a href="'.$sUrlPath.'?PAGEN_'.$this->NavNum.'='.$this->NavPageCount.$strNavQueryString.'#nav_start'.$add_anchor.'">'.$sEnd.'</a> '; else $res .= $sNext.' | '.$sEnd.' '; } if($this->bShowAll) $res .= $this->NavShowAll? '| <a href="'.$sUrlPath.'?SHOWALL_'.$this->NavNum.'=0'.$strNavQueryString.'#nav_start'.$add_anchor.'">'.$sPaged.'</a> ' : '| <a href="'.$sUrlPath.'?SHOWALL_'.$this->NavNum.'=1'.$strNavQueryString.'#nav_start'.$add_anchor.'">'.$sAll.'</a> '; $res .= '</font>'; return $res; } public function ExtractFields($strPrefix="str_", $bDoEncode=true) { return $this->NavNext(true, $strPrefix, $bDoEncode); } public function ExtractEditFields($strPrefix="str_") { return $this->NavNext(true, $strPrefix, true, false); } public function GetNext($bTextHtmlAuto=true, $use_tilda=true) { if($arRes = $this->Fetch()) { if($this->arGetNextCache==false) { $this->arGetNextCache = array(); foreach($arRes as $FName=>$arFValue) $this->arGetNextCache[$FName] = array_key_exists($FName."_TYPE", $arRes); } if($use_tilda) { $arTilda = array(); foreach($arRes as $FName=>$arFValue) { if($this->arGetNextCache[$FName] && $bTextHtmlAuto) $arTilda[$FName] = FormatText($arFValue, $arRes[$FName."_TYPE"]); elseif(is_array($arFValue)) $arTilda[$FName] = htmlspecialcharsEx($arFValue); elseif(preg_match("/[;&<>\"]/", $arFValue)) $arTilda[$FName] = htmlspecialcharsEx($arFValue); else $arTilda[$FName] = $arFValue; $arTilda["~".$FName] = $arFValue; } return $arTilda; } else { foreach($arRes as $FName=>$arFValue) { if($this->arGetNextCache[$FName] && $bTextHtmlAuto) $arRes[$FName] = FormatText($arFValue, $arRes[$FName."_TYPE"]); elseif(is_array($arFValue)) $arRes[$FName] = htmlspecialcharsEx($arFValue); elseif(preg_match("/[;&<>\"]/", $arFValue)) $arRes[$FName] = htmlspecialcharsEx($arFValue); } } } return $arRes; } public static function NavStringForCache($nPageSize=0, $bShowAll=true, $iNumPage=false) { $NavParams = CDBResult::GetNavParams($nPageSize, $bShowAll, $iNumPage); return "|".($NavParams["SHOW_ALL"]?"":$NavParams["PAGEN"])."|".$NavParams["SHOW_ALL"]."|"; } public static function GetNavParams($nPageSize=0, $bShowAll=true, $iNumPage=false) { /** @global CMain $APPLICATION */ global $NavNum, $APPLICATION; $bDescPageNumbering = false; //it can be extracted from $nPageSize if(is_array($nPageSize)) { $params = $nPageSize; if(isset($params["iNumPage"])) $iNumPage = $params["iNumPage"]; if(isset($params["nPageSize"])) $nPageSize = $params["nPageSize"]; if(isset($params["bDescPageNumbering"])) $bDescPageNumbering = $params["bDescPageNumbering"]; if(isset($params["bShowAll"])) $bShowAll = $params["bShowAll"]; if(isset($params["NavShowAll"])) $NavShowAll = $params["NavShowAll"]; if(isset($params["sNavID"])) $sNavID = $params["sNavID"]; } $nPageSize = intval($nPageSize); $NavNum = intval($NavNum); $PAGEN_NAME = "PAGEN_".($NavNum+1); $SHOWALL_NAME = "SHOWALL_".($NavNum+1); global ${$PAGEN_NAME}, ${$SHOWALL_NAME}; $md5Path = md5((isset($sNavID)? $sNavID: $APPLICATION->GetCurPage())); if($iNumPage === false) $PAGEN = ${$PAGEN_NAME}; else $PAGEN = $iNumPage; $SHOWALL = ${$SHOWALL_NAME}; $SESS_PAGEN = $md5Path."SESS_PAGEN_".($NavNum+1); $SESS_ALL = $md5Path."SESS_ALL_".($NavNum+1); if(intval($PAGEN) <= 0) { if(CPageOption::GetOptionString("main", "nav_page_in_session", "Y")=="Y" && intval($_SESSION[$SESS_PAGEN])>0) $PAGEN = $_SESSION[$SESS_PAGEN]; elseif($bDescPageNumbering === true) $PAGEN = 0; else $PAGEN = 1; } //Number of records on a page $SIZEN = $nPageSize; if(intval($SIZEN) < 1) $SIZEN = 10; //Show all records $SHOW_ALL = ($bShowAll? (isset($SHOWALL) ? ($SHOWALL == 1) : (CPageOption::GetOptionString("main", "nav_page_in_session", "Y")=="Y" && $_SESSION[$SESS_ALL] == 1)) : false); //$NavShowAll comes from $nPageSize array $res = array( "PAGEN"=>$PAGEN, "SIZEN"=>$SIZEN, "SHOW_ALL"=>(isset($NavShowAll)? $NavShowAll : $SHOW_ALL), ); if(CPageOption::GetOptionString("main", "nav_page_in_session", "Y")=="Y") { $_SESSION[$SESS_PAGEN] = $PAGEN; $_SESSION[$SESS_ALL] = $SHOW_ALL; $res["SESS_PAGEN"] = $SESS_PAGEN; $res["SESS_ALL"] = $SESS_ALL; } return $res; } public function InitNavStartVars($nPageSize=0, $bShowAll=true, $iNumPage=false) { if(is_array($nPageSize) && isset($nPageSize["bShowAll"])) $this->bShowAll = $nPageSize["bShowAll"]; else $this->bShowAll = $bShowAll; $this->bNavStart = true; $arParams = self::GetNavParams($nPageSize, $bShowAll, $iNumPage); $this->PAGEN = $arParams["PAGEN"]; $this->SIZEN = $arParams["SIZEN"]; $this->NavShowAll = $arParams["SHOW_ALL"]; $this->NavPageSize = $arParams["SIZEN"]; $this->SESS_SIZEN = $arParams["SESS_SIZEN"]; $this->SESS_PAGEN = $arParams["SESS_PAGEN"]; $this->SESS_ALL = $arParams["SESS_ALL"]; global $NavNum; $NavNum++; $this->NavNum = $NavNum; if($this->NavNum>1) $add_anchor = "_".$this->NavNum; else $add_anchor = ""; $this->add_anchor = $add_anchor; } public function NavStart($nPageSize=0, $bShowAll=true, $iNumPage=false) { if($this->bFromLimited) return; if(is_array($nPageSize)) $this->InitNavStartVars($nPageSize); else $this->InitNavStartVars(intval($nPageSize), $bShowAll, $iNumPage); if($this->bFromArray) { $this->NavRecordCount = count($this->arResult); if($this->NavRecordCount < 1) return; if($this->NavShowAll) $this->NavPageSize = $this->NavRecordCount; $this->NavPageCount = floor($this->NavRecordCount/$this->NavPageSize); if($this->NavRecordCount % $this->NavPageSize > 0) $this->NavPageCount++; $this->NavPageNomer = ($this->PAGEN < 1 || $this->PAGEN > $this->NavPageCount ? (CPageOption::GetOptionString("main", "nav_page_in_session", "Y")!="Y" || $_SESSION[$this->SESS_PAGEN] < 1 || $_SESSION[$this->SESS_PAGEN] > $this->NavPageCount ? 1 : $_SESSION[$this->SESS_PAGEN] ) : $this->PAGEN ); $NavFirstRecordShow = $this->NavPageSize*($this->NavPageNomer-1); $NavLastRecordShow = $this->NavPageSize*$this->NavPageNomer; $this->arResult = array_slice($this->arResult, $NavFirstRecordShow, $NavLastRecordShow - $NavFirstRecordShow); } else { $this->DBNavStart(); } } abstract public function DBNavStart(); public function InitFromArray($arr) { if(is_array($arr)) reset($arr); $this->arResult = $arr; $this->nSelectedCount = count($arr); $this->bFromArray = true; } public function NavNext($bSetGlobalVars=true, $strPrefix="str_", $bDoEncode=true, $bSkipEntities=true) { $arr = $this->Fetch(); if($arr && $bSetGlobalVars) { foreach($arr as $key=>$val) { $varname = $strPrefix.$key; global $$varname; if($bDoEncode && !is_array($val) && !is_object($val)) { if($bSkipEntities) $$varname = htmlspecialcharsEx($val); else $$varname = htmlspecialcharsbx($val); } else { $$varname = $val; } } } return $arr; } public function GetPageNavString($navigationTitle, $templateName = "", $showAlways=false, $parentComponent=null) { return $this->GetPageNavStringEx($dummy, $navigationTitle, $templateName, $showAlways, $parentComponent); } public function GetPageNavStringEx(&$navComponentObject, $navigationTitle, $templateName = "", $showAlways=false, $parentComponent=null, $componentParams = array()) { /** @global CMain $APPLICATION */ global $APPLICATION; ob_start(); $params = array_merge( array( "NAV_TITLE"=> $navigationTitle, "NAV_RESULT" => $this, "SHOW_ALWAYS" => $showAlways ), $componentParams ); $navComponentObject = $APPLICATION->IncludeComponent( "bitrix:system.pagenavigation", $templateName, $params, $parentComponent, array( "HIDE_ICONS" => "Y" ) ); $result = ob_get_contents(); ob_end_clean(); return $result; } public function SetUserFields($arUserFields) { if (is_array($arUserFields)) { $this->arUserFields = $arUserFields; $this->usedUserFields = false; } else { $this->arUserFields = false; $this->usedUserFields = false; } } protected function AfterFetch(&$res) { global $USER_FIELD_MANAGER; if($this->arUserFields) { //Cache actual user fields on first fetch if ($this->usedUserFields === false) { $this->usedUserFields = array(); foreach($this->arUserFields as $userField) { if (array_key_exists($userField['FIELD_NAME'], $res)) $this->usedUserFields[] = $userField; } } // We need to call OnAfterFetch for each user field foreach($this->usedUserFields as $userField) { $name = $userField['FIELD_NAME']; if ($userField['MULTIPLE'] === 'Y') { if (substr($res[$name], 0, 1) !== 'a' && $res[$name] > 0) { $res[$name] = $USER_FIELD_MANAGER->LoadMultipleValues($userField, $res[$name]); } else { $res[$name] = unserialize($res[$name]); } $res[$name] = $USER_FIELD_MANAGER->OnAfterFetch($userField, $res[$name]); } else { $res[$name] = $USER_FIELD_MANAGER->OnAfterFetch($userField, $res[$name]); } } } if ($this->arReplacedAliases) { foreach($this->arReplacedAliases as $tech => $human) { $res[$human] = $res[$tech]; unset($res[$tech]); } } } }