Application =& kApplication::Instance(); } /** * Create new instance of object * * @return kBase */ function &makeClass() { $object = new kBase(); return $object; } /** * Set's prefix and special * * @param string $prefix * @param string $special * @access public */ function Init($prefix,$special,$event_params=null) { $prefix=explode('_',$prefix,2); $this->Prefix=$prefix[0]; $this->Special=$special; $this->OriginalParams = $event_params; } /** * Returns joined prefix * and special if any * * @param bool $from_submit if true, then joins prefix & special by "_", uses "." otherwise * @return string * @access protected */ function getPrefixSpecial($from_submit = false) { $separator = !$from_submit ? '.' : '_'; $ret = $this->Prefix.$separator.$this->Special; return rtrim($ret, $separator); } function &getProperty($property_name) { return $this->$property_name; } function setProperty($property_name, &$property_value) { $this->$property_name =& $property_value; } } class kHelper extends kBase { /** * Connection to database * * @var kDBConnection * @access public */ var $Conn; function kHelper() { parent::kBase(); $this->Conn =& $this->Application->GetADODBConnection(); } function InitHelper() { } /** * Append prefix and special to tag * params (get them from tagname) like * they were really passed as params * * @param string $prefix_special * @param Array $tag_params * @return Array * @access protected */ function prepareTagParams($prefix_special, $tag_params = Array()) { $parts = explode('.', $prefix_special); $ret = $tag_params; $ret['Prefix'] = $parts[0]; $ret['Special'] = count($parts) > 1 ? $parts[1] : ''; $ret['PrefixSpecial'] = $prefix_special; return $ret; } } class kDBBase extends kBase { /** * Connection to database * * @var kDBConnection * @access public */ var $Conn; /** * Description * * @var string Name of primary key field for the item * @access public */ var $IDField; /** * Holds SELECT, FROM, JOIN parts of SELECT query * * @var string * @access public */ var $SelectClause; /** * Fields allowed to be set (from table + virtual) * * @var Array * @access private */ var $Fields = Array(); /** * Holds custom field names for item * * @var Array */ var $customFields = Array(); /** * All virtual field names * * @var Array * @access private */ var $VirtualFields = Array(); /** * Fields that need to be queried using custom expression, e.g. IF(...) AS value * * @var Array * @access private */ var $CalculatedFields = Array(); /** * Calculated fields, that contain aggregated functions, e.g. COUNT, SUM, etc. * * @var Array */ var $AggregatedCalculatedFields = Array(); /** * Description * * @var string Item' database table name, without prefix * @access public */ var $TableName; /** * Allows to determine object's table status ('temp' - temp table, '' - live table) * * @var string * @access public */ var $mode=''; function kDBBase() { parent::kBase(); $this->Conn =& $this->Application->GetADODBConnection(); } /** * Set current item' database table name * * @access public * @param string $table_name * @return void */ function setTableName($table_name) { $this->TableName = $table_name; } /** * Set object' TableName to Live table from config * * @access public */ function SwitchToLive() { $this->TableName = $this->Application->getUnitOption($this->Prefix, 'TableName'); $this->mode = ''; } /** * Set object' TableName to Temp table from config * * @access public */ function SwitchToTemp() { $this->TableName = $this->Application->getUnitOption($this->Prefix, 'TableName'); $this->SetTableName( $this->Application->GetTempName($this->TableName, 'prefix:'.$this->Prefix) ); $this->mode = 't'; } /** * Checks if object uses temp table * * @return bool */ function IsTempTable() { return $this->Application->IsTempTable($this->TableName); } /** * Sets SELECT part of list' query * * @access public * @param string $sql SELECT and FROM [JOIN] part of the query up to WHERE * @return void */ function SetSelectSQL($sql) { $this->SelectClause = $sql; } function GetSelectSQL($base_query = null) { if (!isset($base_query)) { $base_query = $this->SelectClause; } $query = str_replace( Array('%1$s','%s'), $this->TableName, $base_query); $query = $this->replaceModePrefix($query); return $query; } /** * Returns required mixing of aggregated & non-aggregated calculated fields * * @param int $aggregated 0 - having + aggregated, 1 - having only, 2 - aggregated only * @return Array */ function getCalculatedFields($aggregated = 0) { switch ($aggregated) { case 0: $fields = array_merge($this->CalculatedFields, $this->AggregatedCalculatedFields); break; case 1: $fields = $this->CalculatedFields; break; case 2: $fields = $this->AggregatedCalculatedFields; break; default: $fields = Array(); break; } return $fields; } /** * Insert calculated fields sql into query in place of %2$s, * return processed query. * * @param string $query * @param int $aggregated 0 - having + aggregated, 1 - having only, 2 - aggregated only * @return string */ function addCalculatedFields($query, $aggregated = 1) { $fields = $this->getCalculatedFields($aggregated); if ($fields) { $sql = Array (); $fields = str_replace('%2$s', $this->Application->GetVar('m_lang'), $fields); foreach ($fields as $field_name => $field_expression) { $sql[] = '('.$field_expression.') AS `'.$field_name.'`'; } $sql = implode(',',$sql); return $this->Application->ReplaceLanguageTags( str_replace('%2$s', ','.$sql, $query) ); } else { return str_replace('%2$s', '', $query); } } /** * Allows substables to be in same mode as main item (e.g. LEFT JOINED ones) * * @param string $query * @return string */ function replaceModePrefix($query) { $live_table = substr($this->Application->GetLiveName($this->TableName), strlen(TABLE_PREFIX)); if (preg_match('/'.preg_quote(TABLE_PREFIX, '/').'(.*)'.preg_quote($live_table, '/').'/', $this->TableName, $rets)) { // will only happen, when table has a prefix (like in K4) return str_replace('%3$s', $rets[1], $query); } // will happen, when K3 table without prefix is used return $query; } /** * Adds calculated field declaration to object. * * @param string $name * @param string $sql_clause */ function addCalculatedField($name, $sql_clause) { $this->CalculatedFields[$name] = $sql_clause; } /** * Sets ID Field name used as primary key for loading items * * @access public * @param string $field_name * @return void * @see kDBBase::IDField */ function setIDField($field_name) { $this->IDField = $field_name; } /** * Performs initial object configuration * * @param bool $populate_ml_fields create all ml fields from db in config or not */ function Configure($populate_ml_fields = false) { $this->setTableName( $this->Application->getUnitOption($this->Prefix, 'TableName') ); $this->setIDField( $this->Application->getUnitOption($this->Prefix, 'IDField') ); $this->defineFields(); $this->ApplyFieldModifiers(); // should be called only after all fields definitions been set $this->prepareConfigOptions(); // this should go last, but before setDefaultValues, order is significant! $this->SetDefaultValues($populate_ml_fields); } /** * Add field definitions from all possible sources (DB Fields, Virtual Fields, Calcualted Fields, e.t.c.) * */ function defineFields() { $this->setConfigFields( $this->Application->getUnitOption($this->Prefix, 'Fields') ); $this->setCustomFields( $this->Application->getUnitOption($this->Prefix, 'CustomFields', Array()) ); $this->setVirtualFields( $this->Application->getUnitOption($this->Prefix, 'VirtualFields') ); $this->setCalculatedFields( $this->Application->getUnitOption($this->Prefix, 'CalculatedFields', Array()) ); $this->setAggragatedCalculatedFields( $this->Application->getUnitOption($this->Prefix, 'AggregatedCalculatedFields', Array()) ); } function setCalculatedFields($fields) { $this->CalculatedFields = isset($fields[$this->Special]) ? $fields[$this->Special] : (isset($fields['']) ? $fields[''] : Array()); } function setAggragatedCalculatedFields($fields) { $this->AggregatedCalculatedFields = isset($fields[$this->Special]) ? $fields[$this->Special] : (isset($fields['']) ? $fields[''] : Array()); } /** * Set's field names from table * from config * * @param Array $fields * @access public */ function setCustomFields($fields) { $this->customFields = $fields; } /** * Set's field names from table * from config * * @param Array $fields * @access public */ function setConfigFields($fields) { $this->Fields = $fields; } /** * Override field options with ones defined in submit via "field_modfiers" array (common for all prefixes) * * @access private * @author Alex */ function ApplyFieldModifiers($field_modifiers = null) { $allowed_modifiers = Array('required', 'multiple'); if ($this->Application->isAdminUser) { // can change upload dir on the fly (admin only!) $allowed_modifiers[] = 'upload_dir'; } if (!isset($field_modifiers)) { $field_modifiers = $this->Application->GetVar('field_modifiers'); if (!$field_modifiers) { // no field modifiers return false; } $field_modifiers = getArrayValue($field_modifiers, $this->getPrefixSpecial()); } if (!$field_modifiers) { // no field modifiers for current prefix_special return false; } foreach ($field_modifiers as $field => $field_options) { foreach ($field_options as $option_name => $option_value) { if ( !in_array(strtolower($option_name), $allowed_modifiers) ) continue; $this->Fields[$field][$option_name] = $option_value; } } } /** * Set fields (+options) for fields that physically doesn't exist in database * * @param Array $fields * @access public */ function setVirtualFields($fields) { if($fields) { $this->VirtualFields = $fields; $this->Fields = array_merge($this->VirtualFields, $this->Fields); // $this->Fields = array_merge_recursive2($this->VirtualFields, $this->Fields); } } function SetDefaultValues($populate_ml_fields = false) { foreach($this->Fields as $field => $options) { if( isset($options['default']) && $options['default'] === '#NOW#') { $this->Fields[$field]['default'] = adodb_mktime(); } } } function SetFieldOptions($field, $options) { $this->Fields[$field] = $options; } function GetFieldOptions($field) { if (isset($this->Fields[$field])) { $options_prepared = array_key_exists('options_prepared', $this->Fields[$field]) ? $this->Fields[$field]['options_prepared'] : false; if (!$options_prepared) { $this->PrepareFieldOptions($field); $this->Fields[$field]['options_prepared'] = true; } return $this->Fields[$field]; } else { return Array(); } } /** * Returns formatted field value * * @param string $name * @param string $format * * @return string * @access public */ function GetField($name, $format = null) { $options = $this->GetFieldOptions($name); if (array_key_exists('formatter', $options)) { $formatter_class = $options['formatter']; $value = ($formatter_class == 'kMultiLanguage') && !preg_match('/^l[0-9]+_/', $name) ? '' : $this->GetDBField($name); $formatter =& $this->Application->recallObject($formatter_class); return $formatter->Format($value, $name, $this, $format); } return $this->GetDBField($name); } function HasField($name) { } function GetFieldValues() { } function UpdateFormattersSubFields($fields=null) { if (!is_array($fields)) { $fields = array_keys($this->Fields); } foreach ($fields as $field) { if ( isset($this->Fields[$field]['formatter']) ) { $formatter =& $this->Application->recallObject($this->Fields[$field]['formatter']); $formatter->UpdateSubFields($field, $this->GetDBField($field), $this->Fields[$field], $this); } } } function prepareConfigOptions() { foreach (array_keys($this->Fields) as $field_name) { // $this->PrepareFieldOptions($field_name); $this->PrepareOptions($field_name); } } /** * Escapes fields only, not expressions * * @param string $field_expr * @return string */ function escapeField($field_expr) { return preg_match('/[.(]/', $field_expr) ? $field_expr : '`'.$field_expr.'`'; } /** * Replaces current language id in given field options * * @param string $field_name * @param Array $field_option_names */ function _replaceLanguageId($field_name, $field_option_names) { // don't use GetVar('m_lang') since it's always equals to default language on editing form in admin $current_language_id = $this->Application->Phrases->LanguageId; $primary_language_id = $this->Application->GetDefaultLanguageId(); $field_options =& $this->Fields[$field_name]; foreach ($field_option_names as $option_name) { $field_options[$option_name] = str_replace('%2$s', $current_language_id, $field_options[$option_name]); $field_options[$option_name] = str_replace('%3$s', $primary_language_id, $field_options[$option_name]); } } function PrepareFieldOptions($field_name) { $field_options =& $this->Fields[$field_name]; if (array_key_exists('options_sql', $field_options) ) { // get options based on given sql $replace_options = Array ('option_title_field', 'option_key_field', 'options_sql'); $this->_replaceLanguageId($field_name, $replace_options); $select_clause = $this->escapeField($field_options['option_title_field']) . ',' . $this->escapeField($field_options['option_key_field']); $sql = sprintf($field_options['options_sql'], $select_clause); if (array_key_exists('serial_name', $field_options)) { // try to cache option sql on serial basis $cache_key = 'sql_' . crc32($sql) . '[%' . $field_options['serial_name'] . '%]'; $dynamic_options = $this->Application->getCache($cache_key); if ($dynamic_options === false) { $this->Conn->nextQueryCachable = true; $dynamic_options = $this->Conn->GetCol($sql, preg_replace('/^.*?\./', '', $field_options['option_key_field'])); $this->Application->setCache($cache_key, $dynamic_options); } } else { // don't cache options sql $dynamic_options = $this->Conn->GetCol($sql, preg_replace('/^.*?\./', '', $field_options['option_key_field'])); } $options_hash = array_key_exists('options', $field_options) ? $field_options['options'] : Array (); $field_options['options'] = array_merge_recursive2($options_hash, $dynamic_options); } } function PrepareOptions($field_name) { if ( isset($this->Fields[$field_name]['formatter']) ) { $formatter =& $this->Application->recallObject( $this->Fields[$field_name]['formatter'] ); $formatter->PrepareOptions($field_name, $this->Fields[$field_name], $this); } } /** * Returns unformatted field value * * @param string $field * @return string * @access public */ function GetDBField($field) { } /** * Returns ID of currently processed record * * @return int * @access public */ function GetID() { return $this->GetDBField($this->IDField); } /** * Allows kDBTagProcessor.SectionTitle to detect if it's editing or new item creation * * @return bool */ function IsNewItem() { return $this->GetID() ? false : true; } /** * Returns parent table information * * @param bool $from_temp load parent item from temp table * @param string $special special of main item * @param bool $guess_special if object retrieved with specified special is not loaded, then try not to use special * @return Array */ function getLinkedInfo($special = '', $guess_special = false) { $parent_prefix = $this->Application->getUnitOption($this->Prefix, 'ParentPrefix'); if ($parent_prefix) { // if this is linked table, then set id from main table $table_info = Array ( 'TableName' => $this->Application->getUnitOption($this->Prefix,'TableName'), 'IdField' => $this->Application->getUnitOption($this->Prefix,'IDField'), 'ForeignKey' => $this->Application->getUnitOption($this->Prefix,'ForeignKey'), 'ParentTableKey' => $this->Application->getUnitOption($this->Prefix,'ParentTableKey'), 'ParentPrefix' => $parent_prefix ); if (is_array($table_info['ForeignKey'])) { $table_info['ForeignKey'] = getArrayValue($table_info, 'ForeignKey', $parent_prefix); } if (is_array($table_info['ParentTableKey'])) { $table_info['ParentTableKey'] = getArrayValue($table_info, 'ParentTableKey', $parent_prefix); } $main_object =& $this->Application->recallObject($parent_prefix.'.'.$special, null, Array ('raise_warnings' => 0)); /* @var $main_object kDBItem */ if (!$main_object->isLoaded() && $guess_special) { $main_object =& $this->Application->recallObject($parent_prefix); } return array_merge($table_info, Array('ParentId'=> $main_object->GetDBField( $table_info['ParentTableKey'] ) ) ); } return false; } /** * Returns true if item was queried/loaded * * @return bool */ function isLoaded() { return false; } /** * Returns specified field value from all selected rows. * Don't affect current record index * * @param string $field * @return Array */ function GetCol($field) { return Array (); } }