From 210091ad9bef58c5644ebd1e94e9e5f6f28c0c6e Mon Sep 17 00:00:00 2001 From: "o.pinke" Date: Tue, 18 Jul 2023 22:07:14 +0200 Subject: [PATCH] add new genericdb optimized for PHP8+ --- .../GenericDb/Driver/GenericDbDriver.php | 29 + .../Driver/MySql/GenericDbDriverMySql.php | 166 ++ conlite/classes/GenericDb/Item.php | 515 +++++ .../classes/GenericDb/ItemBaseAbstract.php | 166 ++ conlite/classes/GenericDb/ItemCache.php | 187 ++ conlite/classes/GenericDb/ItemCollection.php | 1231 ++++++++++++ conlite/classes/GenericDb/ItemException.php | 9 + conlite/classes/class.genericdb.php | 1719 +---------------- conlite/includes/startup.php | 2 +- vendor/composer/installed.php | 4 +- 10 files changed, 2308 insertions(+), 1720 deletions(-) create mode 100644 conlite/classes/GenericDb/Driver/GenericDbDriver.php create mode 100644 conlite/classes/GenericDb/Driver/MySql/GenericDbDriverMySql.php create mode 100644 conlite/classes/GenericDb/Item.php create mode 100644 conlite/classes/GenericDb/ItemBaseAbstract.php create mode 100644 conlite/classes/GenericDb/ItemCache.php create mode 100644 conlite/classes/GenericDb/ItemCollection.php create mode 100644 conlite/classes/GenericDb/ItemException.php diff --git a/conlite/classes/GenericDb/Driver/GenericDbDriver.php b/conlite/classes/GenericDb/Driver/GenericDbDriver.php new file mode 100644 index 0000000..9beae65 --- /dev/null +++ b/conlite/classes/GenericDb/Driver/GenericDbDriver.php @@ -0,0 +1,29 @@ +_sEncoding = $sEncoding; + } + + public function setItemClassInstance($oInstance) + { + $this->_oItemClassInstance = $oInstance; + } + + public function buildJoinQuery($destinationTable, $destinationClass, $destinationPrimaryKey, $sourceClass, $primaryKey) + { + + } + + public function buildOperator($sField, $sOperator, $sRestriction) + { + + } +} \ No newline at end of file diff --git a/conlite/classes/GenericDb/Driver/MySql/GenericDbDriverMySql.php b/conlite/classes/GenericDb/Driver/MySql/GenericDbDriverMySql.php new file mode 100644 index 0000000..875839b --- /dev/null +++ b/conlite/classes/GenericDb/Driver/MySql/GenericDbDriverMySql.php @@ -0,0 +1,166 @@ + $field, "table" => $tables, "join" => $join, "where" => $where]; + } + + function buildOperator($sField, $sOperator, $sRestriction) + { + $sOperator = strtolower($sOperator); + + $sWhereStatement = ""; + + switch ($sOperator) { + case "matchbool": + $sqlStatement = "MATCH (%s) AGAINST ('%s' IN BOOLEAN MODE)"; + $sWhereStatement = sprintf($sqlStatement, $sField, $this->_oItemClassInstance->_inFilter($sRestriction)); + break; + case "match": + $sqlStatement = "MATCH (%s) AGAINST ('%s')"; + $sWhereStatement = sprintf($sqlStatement, $sField, $this->_oItemClassInstance->_inFilter($sRestriction)); + break; + case "like": + $sqlStatement = "%s LIKE '%%%s%%'"; + $sWhereStatement = sprintf($sqlStatement, Contenido_Security::toString($sField), $this->_oItemClassInstance->_inFilter($sRestriction)); + break; + case "likeleft": + $sqlStatement = "%s LIKE '%s%%'"; + $sWhereStatement = sprintf($sqlStatement, Contenido_Security::toString($sField), $this->_oItemClassInstance->_inFilter($sRestriction)); + break; + case "likeright": + $sqlStatement = "%s LIKE '%%%s'"; + $sWhereStatement = sprintf($sqlStatement, Contenido_Security::toString($sField), $this->_oItemClassInstance->_inFilter($sRestriction)); + break; + case "notlike": + $sqlStatement = "%s NOT LIKE '%%%s%%'"; + $sWhereStatement = sprintf($sqlStatement, Contenido_Security::toString($sField), $this->_oItemClassInstance->_inFilter($sRestriction)); + break; + case "notlikeleft": + $sqlStatement = "%s NOT LIKE '%s%%'"; + $sWhereStatement = sprintf($sqlStatement, Contenido_Security::toString($sField), $this->_oItemClassInstance->_inFilter($sRestriction)); + break; + case "notlikeright": + $sqlStatement = "%s NOT LIKE '%%%s'"; + $sWhereStatement = sprintf($sqlStatement, Contenido_Security::toString($sField), $this->_oItemClassInstance->_inFilter($sRestriction)); + break; + case "diacritics": + if (!is_object($GLOBALS["_cCharTable"])) { + $GLOBALS["_cCharTable"] = new cCharacterConverter; + } + + $aliasSearch = []; + + $metaCharacters = ["*", "[", "]", "^", '$', "\\", "*", "'", '"', '+']; + + for ($i = 0; $i < strlen($sRestriction); $i++) { + $char = substr($sRestriction, $i, 1); + + $aliases = []; + + $aliases = array_merge($aliases, $GLOBALS["_cCharTable"]->fetchDiacriticCharactersForNormalizedChar($this->_sEncoding, $char)); + $normalizedChars = $GLOBALS["_cCharTable"]->fetchNormalizedCharsForDiacriticCharacter($this->_sEncoding, $char); + + foreach ($normalizedChars as $normalizedChar) { + $aliases = array_merge($aliases, $GLOBALS["_cCharTable"]->fetchDiacriticCharactersForNormalizedChar($this->_sEncoding, $normalizedChar)); + } + + $aliases = array_merge($aliases, $normalizedChars); + + if ($aliases !== []) { + $aliases[] = $char; + $allAliases = []; + + foreach ($aliases as $alias) { + $alias1 = $this->_oItemClassInstance->_inFilter($alias); + $allAliases[] = $alias1; + $allAliases[] = $alias; + } + + $allAliases = array_unique($allAliases); + $aliasSearch[] = "(" . implode("|", $allAliases) . ")"; + } else { + $addChars = []; + + + if (in_array($char, $metaCharacters)) { + $addChars[] = "\\\\" . $char; + } else { + $addChars[] = $char; + + $vChar = $this->_oItemClassInstance->_inFilter($char); + + if ($char != $vChar) { + $addChars[] = in_array($vChar, $metaCharacters) ? "\\\\" . $vChar : $vChar; + } + } + + $aliasSearch[] = "(" . implode("|", $addChars) . ")"; + } + } + + $restriction = "'" . implode("", $aliasSearch) . "'"; + $sWhereStatement = implode(" ", [$sField, "REGEXP", $restriction]); + + break; + case "fulltext": + + break; + case "in": + if (is_array($sRestriction)) { + $items = []; + + foreach ($sRestriction as $sRestrictionItem) { + $items[] = "'" . $this->_oItemClassInstance->_inFilter($sRestrictionItem) . "'"; + } + + $sRestriction = implode(", ", $items); + } else { + $sRestriction = "'" . $sRestriction . "'"; + } + + $sWhereStatement = implode(" ", [$sField, "IN (", $sRestriction, ")"]); + break; + case "notin": + if (is_array($sRestriction)) { + $items = []; + + foreach ($sRestriction as $Restriction) { + $items[] = "'" . $this->_oItemClassInstance->_inFilter($Restriction) . "'"; + } + + $sRestriction = implode(", ", $items); + } else { + $sRestriction = "'" . $sRestriction . "'"; + } + + $sWhereStatement = implode(" ", [$sField, "NOT IN (", $sRestriction, ")"]); + break; + default : + $sRestriction = "'" . $this->_oItemClassInstance->_inFilter($sRestriction) . "'"; + + $sWhereStatement = implode(" ", [$sField, $sOperator, $sRestriction]); + } + + return $sWhereStatement; + } + +} \ No newline at end of file diff --git a/conlite/classes/GenericDb/Item.php b/conlite/classes/GenericDb/Item.php new file mode 100644 index 0000000..c111998 --- /dev/null +++ b/conlite/classes/GenericDb/Item.php @@ -0,0 +1,515 @@ +_inFilter($mValue); + } + if ($sField === $this->primaryKey) { + $aRecordSet = self::$_oCache->getItem($this->table . "_" . $mValue); + } else { + $aRecordSet = self::$_oCache->getItemByProperty($this->table . "_" . $sField, $mValue); + } + + if ($aRecordSet) { + // entry in cache found, load entry from cache + $this->loadByRecordSet($aRecordSet); + return true; + } + + // SQL-Statement to select by field + $sql = sprintf("SELECT * FROM `%s` WHERE %s = '%s'", $this->table, $sField, $mValue); + //$sql = $this->db->prepare($sql, $this->table, $sField, $mValue); + // Query the database + $this->db->query($sql); + + $this->_lastSQL = $sql; + + if ($this->db->num_rows() > 1) { + $sMsg = "Tried to load a single line with field $sField and value $mValue from " + . $this->table . " but found more than one row"; + cWarning(__FILE__, __LINE__, $sMsg); + } + + // Advance to the next record, return false if nothing found + if (!$this->db->next_record()) { + return false; + } + + $this->loadByRecordSet($this->db->toArray()); + return true; + } + + /** + * Loads an item by passed where clause from the database. + * This function is expensive, since it executes allways a query to the database + * to retrieve the primary key, even if the record set is aleady cached. + * NOTE: Passed value has to be escaped before. This will not be done by this function. + * + * @param string $sWhere The where clause like 'idart = 123 AND idlang = 1' + * @return bool True if the load was successful + */ + protected function _loadByWhereClause($sWhere) + { + // SQL-Statement to select by whee clause + $sql = sprintf("SELECT %s AS pk FROM `%s` WHERE ", $this->primaryKey, $this->table) . $sWhere; + //$sql = $this->db->prepare($sql, $this->primaryKey, $this->table); + // Query the database + $this->db->query($sql); + + $this->_lastSQL = $sql; + + if ($this->db->num_rows() > 1) { + $sMsg = "Tried to load a single line with where clause '" . $sWhere . "' from " + . $this->table . " but found more than one row"; + cWarning(__FILE__, __LINE__, $sMsg); + } + + // Advance to the next record, return false if nothing found + if (!$this->db->next_record()) { + return false; + } + + $id = $this->db->f('pk'); + return $this->loadByPrimaryKey($id); + } + + /** + * Loads an item by ID from the database. + * + * @param string $mValue Specifies the primary key value + * @return bool True if the load was successful + */ + public function loadByPrimaryKey($mValue) + { + $bSuccess = $this->loadBy($this->primaryKey, $mValue); + + if (($bSuccess == true) && method_exists($this, '_onLoad')) { + $this->_onLoad(); + } + return $bSuccess; + } + + /** + * Loads an item by it's recordset. + * + * @param array $aRecordSet The recordset of the item + */ + public function loadByRecordSet(array $aRecordSet) + { + $this->values = $aRecordSet; + $this->oldPrimaryKey = $this->values[$this->primaryKey]; + $this->virgin = false; + self::$_oCache->addItem($this->table . "_" . $this->oldPrimaryKey, $this->values); + } + + /** + * Checks if a the item is already loaded. + * @return boolean + */ + public function isLoaded() + { + return !$this->virgin; + } + + /** + * Function which is called whenever an item is loaded. + * Inherited classes should override this function if desired. + * + * @return void + */ + protected function _onLoad() + { + + } + + /** + * Gets the value of a specific field. + * + * @param string $sField Specifies the field to retrieve + * @return mixed Value of the field + */ + public function getField($sField) + { + if ($this->virgin == true) { + $this->lasterror = 'No item loaded'; + return false; + } + return $this->_outFilter($this->values[$sField]); + } + + /** + * Wrapper for getField (less to type). + * + * @param string $sField Specifies the field to retrieve + * @return mixed Value of the field + */ + public function get($sField) + { + return $this->getField($sField); + } + + /** + * Sets the value of a specific field. + * + * @param string $sField Field name + * @param string $mValue Value to set + * @param bool $bSafe Flag to run defined inFilter on passed value + */ + public function setField($sField, $mValue, $bSafe = true): bool + { + if ($this->virgin == true) { + $this->lasterror = 'No item loaded'; + return false; + } + + $this->modifiedValues[$sField] = true; + + if ($sField == $this->primaryKey) { + $this->oldPrimaryKey = $this->values[$sField]; + } + + $this->values[$sField] = $bSafe == true ? $this->_inFilter($mValue) : $mValue; + return true; + } + + /** + * Shortcut to setField. + * + * @param string $sField Field name + * @param string $mValue Value to set + * @param bool $bSafe Flag to run defined inFilter on passed value + */ + public function set($sField, $mValue, $bSafe = true) + { + return $this->setField($sField, $mValue, $bSafe); + } + + /** + * Stores the loaded and modified item to the database. + * + * @return bool + */ + public function store() + { + if (!$this->isLoaded()) { + $this->lasterror = 'No item loaded'; + return false; + } + + $sql = 'UPDATE `' . $this->table . '` SET '; + $first = true; + + if (!is_array($this->modifiedValues)) { + return true; + } + + foreach (array_keys($this->modifiedValues) as $key) { + if ($first == true) { + $sql .= "`$key` = '" . $this->values[$key] . "'"; + $first = false; + } else { + $sql .= ", `$key` = '" . $this->values[$key] . "'"; + } + } + + $sql .= " WHERE " . $this->primaryKey . " = '" . $this->oldPrimaryKey . "'"; + + $this->db->query($sql); + + $this->_lastSQL = $sql; + + if ($this->db->affected_rows() > 0) { + self::$_oCache->addItem($this->table . "_" . $this->oldPrimaryKey, $this->values); + } + + return $this->db->affected_rows() >= 1; + } + + /** + * Returns current item data as an assoziative array. + */ + public function toArray(): array|false + { + if ($this->virgin == true) { + $this->lasterror = 'No item loaded'; + return false; + } + + $aReturn = []; + foreach (array_keys($this->values) as $field) { + $aReturn[$field] = $this->getField($field); + } + return $aReturn; + } + + /** + * Returns current item data as an object. + */ + public function toObject(): stdClass|false + { + $return = $this->toArray(); + return (false !== $return) ? (object)$return : $return; + } + + /** + * Sets a custom property. + * + * @param string $sType Specifies the type + * @param string $sName Specifies the name + * @param mixed $mValue Specifies the value + * @return bool + */ + public function setProperty($sType, $sName, mixed $mValue) + { + // If this object wasn't loaded before, return false + if ($this->virgin == true) { + $this->lasterror = 'No item loaded'; + return false; + } + + // Set the value + $oProperties = $this->_getPropertiesCollectionInstance(); + return $oProperties->setValue( + $this->primaryKey, $this->get($this->primaryKey), $sType, $sName, $mValue + ); + } + + /** + * Returns a custom property. + * + * @param string $sType Specifies the type + * @param string $sName Specifies the name + * @return mixed Value of the given property or false + */ + public function getProperty($sType, $sName) + { + // If this object wasn't loaded before, return false + if ($this->virgin == true) { + $this->lasterror = 'No item loaded'; + return false; + } + + // Return the value + $oProperties = $this->_getPropertiesCollectionInstance(); + return $oProperties->getValue( + $this->primaryKey, $this->get($this->primaryKey), $sType, $sName + ); + } + + /** + * Deletes a custom property. + * + * @param string $sType Specifies the type + * @param string $sName Specifies the name + * @return bool + */ + public function deleteProperty($sType, $sName) + { + // If this object wasn't loaded before, return false + if ($this->virgin == true) { + $this->lasterror = 'No item loaded'; + return false; + } + + // Delete the value + $oProperties = $this->_getPropertiesCollectionInstance(); + return $oProperties->deleteValue( + $this->primaryKey, $this->get($this->primaryKey), $sType, $sName + ); + } + + /** + * Deletes a custom property by its id. + * + * @param int $idprop Id of property + * @return bool + */ + public function deletePropertyById($idprop) + { + $oProperties = $this->_getPropertiesCollectionInstance(); + return $oProperties->delete($idprop); + } + + /** + * Deletes the current item + * + * @return void + */ + // Method doesn't work, remove in future versions + // function delete() + // { + // $this->_collectionInstance->delete($item->get($this->primaryKey)); + //} + + /** + * Define the filter functions used when data is being stored or retrieved + * from the database. + * + * Examples: + *
+     * $obj->setFilters(array('addslashes'), array('stripslashes'));
+     * $obj->setFilters(array('htmlencode', 'addslashes'), array('stripslashes', 'htmlencode'));
+     * 
+ * + * @param array $aInFilters Array with function names + * @param array $aOutFilters Array with function names + * + * @return void + */ + public function setFilters($aInFilters = [], $aOutFilters = []) + { + $this->_arrInFilters = $aInFilters; + $this->_arrOutFilters = $aOutFilters; + } + + /** + * Filters the passed data using the functions defines in the _arrInFilters array. + * + * @param mixed $mData Data to filter + * @return mixed Filtered data + * @see setFilters + * + * @todo This method is used from public scope, but it should be protected + * + */ + public function _inFilter(mixed $mData) + { + if (is_numeric($mData) || is_array($mData)) { + return $mData; + } + + if (is_null($mData)) { + $mData = ''; + } + + foreach ($this->_arrInFilters as $_arrInFilter) { + if (function_exists($_arrInFilter)) { + $mData = $_arrInFilter($mData); + } + } + return $mData; + } + + /** + * Filters the passed data using the functions defines in the _arrOutFilters array. + * + * @param mixed $mData Data to filter + * @return mixed Filtered data + * @see setFilters + * + */ + protected function _outFilter(mixed $mData) + { + if (is_numeric($mData)) + return $mData; + + foreach ($this->_arrOutFilters as $_arrOutFilter) { + if (function_exists($_arrOutFilter)) { + $mData = $_arrOutFilter($mData); + } + } + return $mData; + } + + protected function _setMetaObject($sObjectName) + { + $this->_metaObject = $sObjectName; + } + + public function getMetaObject() + { + global $_metaObjectCache; + + if (!is_array($_metaObjectCache)) { + $_metaObjectCache = []; + } + + $sClassName = $this->_metaObject; + $qclassname = strtolower($sClassName); + + if (array_key_exists($qclassname, $_metaObjectCache) && is_object($_metaObjectCache[$qclassname])) { + if (strtolower($_metaObjectCache[$qclassname]::class) === $qclassname) { + $_metaObjectCache[$qclassname]->setPayloadObject($this); + return $_metaObjectCache[$qclassname]; + } + } + + if (class_exists($sClassName)) { + $_metaObjectCache[$qclassname] = new $sClassName($this); + return $_metaObjectCache[$qclassname]; + } + } + +} \ No newline at end of file diff --git a/conlite/classes/GenericDb/ItemBaseAbstract.php b/conlite/classes/GenericDb/ItemBaseAbstract.php new file mode 100644 index 0000000..9230bfd --- /dev/null +++ b/conlite/classes/GenericDb/ItemBaseAbstract.php @@ -0,0 +1,166 @@ +db = new DB_ConLite(); + + if ($sTable == '') { + $sMsg = "$sClassName: No table specified. Inherited classes *need* to set a table"; + throw new ItemException($sMsg); + } elseif ($sPrimaryKey == '') { + $sMsg = "No primary key specified. Inherited classes *need* to set a primary key"; + throw new ItemException($sMsg); + } + + $this->_settings = $cfg['sql']; + + // instanciate caching + $aCacheOpt = (isset($this->_settings['cache'])) ? $this->_settings['cache'] : array(); + self::$_oCache = ItemCache::getInstance($sTable, $aCacheOpt); + + $this->table = $sTable; + $this->primaryKey = $sPrimaryKey; + $this->virgin = true; + $this->lifetime = $iLifetime; + $this->_className = $sClassName; + } + + /** + * Escape string for using in SQL-Statement. + * + * @param string $sString The string to escape + * @return string Escaped string + */ + public function escape($sString) { + return $this->db->escape($sString); + } + + /** + * Returns the second database instance, usable to run additional statements + * without losing current query results. + * + * @return DB_ConLite + */ + protected function _getSecondDBInstance() { + if (!isset($this->secondDb) || !($this->secondDb instanceof DB_ConLite)) { + $this->secondDb = new DB_ConLite(); + } + return $this->secondDb; + } + + /** + * Returns properties instance, instantiates it if not done before. + * + * @return PropertyCollection + */ + protected function _getPropertiesCollectionInstance() { + // Runtime on-demand allocation of the properties object + if (!isset($this->properties) || !($this->properties instanceof PropertyCollection)) { + $this->properties = new PropertyCollection(); + } + return $this->properties; + } + +} \ No newline at end of file diff --git a/conlite/classes/GenericDb/ItemCache.php b/conlite/classes/GenericDb/ItemCache.php new file mode 100644 index 0000000..4a59f39 --- /dev/null +++ b/conlite/classes/GenericDb/ItemCache.php @@ -0,0 +1,187 @@ + 0) { + $this->_iMaxItemsToCache = (int) $aOptions['max_items_to_cache']; + } + if (isset($aOptions['enable']) && is_bool($aOptions['enable'])) { + $this->_bEnable = $aOptions['enable']; + } + + if (isset($_GET['frame']) && is_numeric($_GET['frame'])) { + $this->_iFrame = (int) $_GET['frame']; + } else { + $this->_bEnable = false; + } + } + + /** + * Returns item cache instance, creates it, if not done before. + * Works as a singleton for one specific table. + * + * @param string $sTable Table name + * @param array $aOptions Options array as follows: + * - $aOptions['max_items_to_cache'] = (int) Number of items to cache + * - $aOptions['enable'] = (bool) Flag to enable caching + */ + public static function getInstance($sTable, array $aOptions = []) { + if (!isset(self::$_oInstances[$sTable])) { + self::$_oInstances[$sTable] = new self($sTable, $aOptions); + } + return self::$_oInstances[$sTable]; + } + + /** + * Returns items cache list. + * + * @return array + */ + public function getItemsCache() { + return $this->_aItemsCache[$this->_iFrame]; + } + + /** + * Returns existing entry from cache by it's id. + */ + public function getItem(mixed $mId): ?array { + if (!$this->_bEnable) { + return null; + } + + if (isset($this->_aItemsCache[$this->_iFrame][$mId])) { + return $this->_aItemsCache[$this->_iFrame][$mId]; + } else { + return null; + } + } + + /** + * Returns existing entry from cache by matching propery value. + */ + public function getItemByProperty(mixed $mProperty, mixed $mValue): ?array { + if (!$this->_bEnable) { + return null; + } + + // loop thru all cached entries and try to find a entry by it's property + if (is_array($this->_aItemsCache[$this->_iFrame]) && $this->_aItemsCache[$this->_iFrame] !== []) { + foreach ($this->_aItemsCache[$this->_iFrame] as $aEntry) { + if (isset($aEntry[$mProperty]) && $aEntry[$mProperty] == $mValue) { + return $aEntry; + } + } + } + return null; + } + + /** + * Returns existing entry from cache by matching properties and their values. + * + * @param array $aProperties Assoziative key value pairs + */ + public function getItemByProperties(array $aProperties): ?array { + if (!$this->_bEnable) { + return null; + } + + // loop thru all cached entries and try to find a entry by it's property + foreach ($this->_aItemsCache as $_aItemCache) { + $mFound = null; + foreach ($aProperties as $key => $value) { + if (isset($_aItemCache[$key]) && $_aItemCache[$key] == $value) { + $mFound = true; + } else { + $mFound = false; + break; + } + return $_aItemCache; + } + } + return null; + } + + /** + * Adds passed item data to internal cache + * + * @param array $aData Usually the recordset + * @return void + */ + public function addItem(mixed $mId, array $aData) { + if (!$this->_bEnable) { + return null; + } + + if (isset($this->_aItemsCache[$this->_iFrame])) { + $aTmpItemsArray = $this->_aItemsCache[$this->_iFrame]; + + if ($this->_iMaxItemsToCache == (is_countable($aTmpItemsArray) ? count($aTmpItemsArray) : 0)) { + // we have reached the maximum number of cached items, remove first entry + $firstEntryKey = array_shift($aTmpItemsArray); + if (is_array($firstEntryKey)) + return null; + unset($this->_aItemsCache[$this->_iFrame][$firstEntryKey]); + } + } + + // add entry + $this->_aItemsCache[$this->_iFrame][$mId] = $aData; + } + + /** + * Removes existing cache entry by it's key + * + * @return void + */ + public function removeItem(mixed $mId) { + if (!$this->_bEnable) { + return null; + } + + // remove entry + if (isset($this->_aItemsCache[$this->_iFrame][$mId])) { + unset($this->_aItemsCache[$this->_iFrame][$mId]); + } + } + +} \ No newline at end of file diff --git a/conlite/classes/GenericDb/ItemCollection.php b/conlite/classes/GenericDb/ItemCollection.php new file mode 100644 index 0000000..4dca522 --- /dev/null +++ b/conlite/classes/GenericDb/ItemCollection.php @@ -0,0 +1,1231 @@ +resetQuery(); + + // Try to load driver + $this->_initializeDriver(); + + // Try to find out the current encoding + if (isset($GLOBALS['lang']) && isset($GLOBALS['aLanguageEncodings'])) { + $this->setEncoding($GLOBALS['aLanguageEncodings'][$GLOBALS['lang']]); + } + + $this->_aOperators = array( + '=', '!=', '<>', '<', '>', '<=', '>=', 'LIKE', 'DIACRITICS' + ); + } + + /** + * Defines the reverse links for this table. + * + * Important: The class specified by $sForeignCollectionClass needs to be a + * collection class and has to exist. + * Define all links in the constructor of your object. + * + * @param string $sForeignCollectionClass Specifies the foreign class to use + * @return void + */ + protected function _setJoinPartner($sForeignCollectionClass) { + if (class_exists($sForeignCollectionClass)) { + // Add class + if (!in_array($sForeignCollectionClass, $this->_JoinPartners)) { + $this->_JoinPartners[] = strtolower($sForeignCollectionClass); + } + } else { + $sMsg = "Could not instanciate class [$sForeignCollectionClass] for use " + . "with _setJoinPartner in class " . get_class($this); + cWarning(__FILE__, __LINE__, $sMsg); + } + } + + /** + * Method to set the accompanying item object. + * + * @param string $sClassName Specifies the classname of item + * @return void + */ + protected function _setItemClass($sClassName) { + if (class_exists($sClassName)) { + $this->_itemClass = $sClassName; + $this->_itemClassInstance = new $sClassName; + + // Initialize driver in case the developer does a setItemClass-Call + // before calling the parent constructor + $this->_initializeDriver(); + $this->_driver->setItemClassInstance($this->_itemClassInstance); + } else { + $sMsg = "Could not instanciate class [$sClassName] for use with " + . "_setItemClass in class " . get_class($this); + cWarning(__FILE__, __LINE__, $sMsg); + } + } + + /** + * Initializes the driver to use with GenericDB. + * + * @param $bForceInit boolean If true, forces the driver to initialize, even if it already exists. + */ + protected function _initializeDriver($bForceInit = false) { + if (!is_object($this->_driver) || $bForceInit == true) { + $this->_driver = new GenericDbDriverMySql(); + } + } + + /** + * Sets the encoding. + * @param string $sEncoding + */ + public function setEncoding($sEncoding) { + $this->_encoding = $sEncoding; + $this->_driver->setEncoding($sEncoding); + } + + /** + * Sets the query to use foreign tables in the resultset + * @param string $sForeignClass The class of foreign table to use + */ + public function link($sForeignClass) { + if (class_exists($sForeignClass)) { + $this->_links[$sForeignClass] = new $sForeignClass; + } else { + $sMsg = "Could not find class [$sForeignClass] for use with link in class " + . get_class($this); + cWarning(__FILE__, __LINE__, $sMsg); + } + } + + /** + * Sets the limit for results + * @param int $iRowStart + * @param int $iRowCount + */ + public function setLimit($iRowStart, $iRowCount) { + $this->_limitStart = $iRowStart; + $this->_limitCount = $iRowCount; + } + + /** + * Restricts a query with a where clause + * @param string $sField + * @param mixed $mRestriction + * @param string $sOperator + */ + public function setWhere($sField, $mRestriction, $sOperator = '=') { + $sField = strtolower($sField); + $this->_where['global'][$sField]['operator'] = $sOperator; + $this->_where['global'][$sField]['restriction'] = $mRestriction; + } + + /** + * Removes a previous set where clause (@see ItemCollection::setWhere). + * @param string $sField + * @param mixed $mRestriction + * @param string $sOperator + */ + public function deleteWhere($sField, $mRestriction, $sOperator = '=') { + $sField = strtolower($sField); + if (isset($this->_where['global'][$sField]) && is_array($this->_where['global'][$sField])) { + if ($this->_where['global'][$sField]['operator'] == $sOperator && $this->_where['global'][$sField]['restriction'] == $mRestriction) { + unset($this->_where['global'][$sField]); + } + } + } + + /** + * Restricts a query with a where clause, groupable + * @param string $sGroup + * @param string $sField + * @param mixed $mRestriction + * @param string $sOperator + */ + public function setWhereGroup($sGroup, $sField, $mRestriction, $sOperator = '=') { + $sField = strtolower($sField); + $this->_where['groups'][$sGroup][$sField]['operator'] = $sOperator; + $this->_where['groups'][$sGroup][$sField]['restriction'] = $mRestriction; + } + + /** + * Removes a previous set groupable where clause (@see ItemCollection::setWhereGroup). + * @param string $sGroup + * @param string $sField + * @param mixed $mRestriction + * @param string $sOperator + */ + public function deleteWhereGroup($sGroup, $sField, $mRestriction, $sOperator = '=') { + $sField = strtolower($sField); + if (is_array($this->_where['groups'][$sGroup]) && isset($this->_where['groups'][$sGroup][$sField]) && is_array($this->_where['groups'][$sGroup][$sField])) { + if ($this->_where['groups'][$sGroup][$sField]['operator'] == $sOperator && $this->_where['groups'][$sGroup][$sField]['restriction'] == $mRestriction) { + unset($this->_where['groups'][$sGroup][$sField]); + } + } + } + + /** + * Defines how relations in one group are linked each together + * @param string $sGroup + * @param string $sCondition + */ + public function setInnerGroupCondition($sGroup, $sCondition = 'AND') { + $this->_innerGroupConditions[$sGroup] = $sCondition; + } + + /** + * Defines how groups are linked to each other + * @param string $sGroup1 + * @param string $sGroup2 + * @param string $sCondition + */ + public function setGroupCondition($sGroup1, $sGroup2, $sCondition = 'AND') { + $this->_groupConditions[$sGroup1][$sGroup2] = $sCondition; + } + + /** + * Builds a where statement out of the setGroupWhere calls + * + * @return array With all where statements + */ + protected function _buildGroupWhereStatements() { + $aWheres = array(); + $aGroupWhere = array(); + + $mLastGroup = false; + $sGroupWhereStatement = ''; + + // Find out if there are any defined groups + if (count($this->_where['groups']) > 0) { + // Step trough all groups + foreach ($this->_where['groups'] as $groupname => $group) { + $aWheres = array(); + + // Fetch restriction, fields and operators and build single group + // where statements + foreach ($group as $field => $item) { + $aWheres[] = $this->_driver->buildOperator($field, $item['operator'], $item['restriction']); + } + + // Add completed substatements + $sOperator = 'AND'; + if (isset($this->_innerGroupConditions[$groupname])) { + $sOperator = $this->_innerGroupConditions[$groupname]; + } + + $aGroupWhere[$groupname] = implode(' ' . $sOperator . ' ', $aWheres); + } + } + + // Combine groups + foreach ($aGroupWhere as $groupname => $group) { + if ($mLastGroup != false) { + $sOperator = 'AND'; + // Check if there's a group condition + if (isset($this->_groupConditions[$groupname])) { + if (isset($this->_groupConditions[$groupname][$mLastGroup])) { + $sOperator = $this->_groupConditions[$groupname][$mLastGroup]; + } + } + + // Reverse check + if (isset($this->_groupConditions[$mLastGroup])) { + if (isset($this->_groupConditions[$mLastGroup][$groupname])) { + $sOperator = $this->_groupConditions[$mLastGroup][$groupname]; + } + } + + $sGroupWhereStatement .= ' ' . $sOperator . ' (' . $group . ')'; + } else { + $sGroupWhereStatement .= '(' . $group . ')'; + } + + $mLastGroup = $groupname; + } + + return $sGroupWhereStatement; + } + + /** + * Builds a where statement out of the setWhere calls + * + * @return array With all where statements + */ + protected function _buildWhereStatements() { + $aWheres = array(); + + // Build global where condition + foreach ($this->_where['global'] as $field => $item) { + $aWheres[] = $this->_driver->buildOperator($field, $item['operator'], $item['restriction']); + } + + return (implode(' AND ', $aWheres)); + } + + /** + * Fetches all tables which will be joined later on. + * + * The returned array has the following format: + *
+     * array(
+     *     array(fields),
+     *     array(tables),
+     *     array(joins),
+     *     array(wheres)
+     * );
+     * 
+ * + * Notes: + * The table is the table name which needs to be added to the FROM clause + * The join statement which is inserted after the master table + * The where statement is combined with all other where statements + * The fields to select from + * + * @todo Reduce complexity of this function, to much code... + * + * @param ??? $ignoreRoot + * @return array Array structure, see above + */ + protected function _fetchJoinTables($ignoreRoot) { + $aParameters = array(); + $aFields = array(); + $aTables = array(); + $aJoins = array(); + $aWheres = array(); + + // Fetch linked tables + foreach ($this->_links as $link => $object) { + $matches = $this->_findReverseJoinPartner(strtolower(get_class($this)), $link); + + if ($matches !== false) { + if (isset($matches['desttable'])) { + // Driver function: Build query parts + $aParameters[] = $this->_driver->buildJoinQuery( + $matches['desttable'], + strtolower($matches['destclass']), + $matches['key'], + strtolower($matches['sourceclass']), + $matches['key'] + ); + } else { + foreach ($matches as $match) { + $aParameters[] = $this->_driver->buildJoinQuery( + $match['desttable'], + strtolower($match['destclass']), + $match['key'], + strtolower($match['sourceclass']), + $match['key'] + ); + } + } + } else { + // Try forward search + $mobject = new $link; + + $matches = $mobject->_findReverseJoinPartner($link, strtolower(get_class($this))); + + if ($matches !== false) { + if (isset($matches['desttable'])) { + $i = $this->_driver->buildJoinQuery( + $mobject->table, + strtolower($link), + $mobject->primaryKey, + strtolower($matches['destclass']), + $matches['key'] + ); + + if ($i['field'] == ($link . '.' . $mobject->primaryKey) && $link == $ignoreRoot) { + unset($i['join']); + } + $aParameters[] = $i; + } else { + foreach ($matches as $match) { + $xobject = new $match['sourceclass']; + + $i = $this->_driver->buildJoinQuery( + $xobject->table, + strtolower($match['sourceclass']), + $xobject->primaryKey, + strtolower($match['destclass']), + $match['key'] + ); + + if ($i['field'] == ($match['sourceclass'] . '.' . $xobject->primaryKey) && $match['sourceclass'] == $ignoreRoot) { + unset($i['join']); + } + array_unshift($aParameters, $i); + } + } + } else { + $bDualSearch = true; + // Check first if we are a instance of another class + foreach ($mobject->_JoinPartners as $sJoinPartner) { + if (class_exists($sJoinPartner)) { + if (is_subclass_of($this, $sJoinPartner)) { + $matches = $mobject->_findReverseJoinPartner($link, strtolower($sJoinPartner)); + + if ($matches !== false) { + if ($matches['destclass'] == strtolower($sJoinPartner)) { + $matches['destclass'] = get_class($this); + + if (isset($matches['desttable'])) { + $i = $this->_driver->buildJoinQuery( + $mobject->table, + strtolower($link), + $mobject->primaryKey, + strtolower($matches['destclass']), + $matches['key'] + ); + + if ($i['field'] == ($link . '.' . $mobject->primaryKey) && $link == $ignoreRoot) { + unset($i['join']); + } + $aParameters[] = $i; + } else { + foreach ($matches as $match) { + $xobject = new $match['sourceclass']; + + $i = $this->_driver->buildJoinQuery( + $xobject->table, + strtolower($match['sourceclass']), + $xobject->primaryKey, + strtolower($match['destclass']), + $match['key'] + ); + + if ($i['field'] == ($match['sourceclass'] . '.' . $xobject->primaryKey) && $match['sourceclass'] == $ignoreRoot) { + unset($i['join']); + } + array_unshift($aParameters, $i); + } + } + $bDualSearch = false; + } + } + } + } + } + + if ($bDualSearch) { + // Try dual-side search + $forward = $this->_resolveLinks(); + $reverse = $mobject->_resolveLinks(); + + $result = array_intersect($forward, $reverse); + + if (count($result) > 0) { + // Found an intersection, build references to it + foreach ($result as $value) { + $oIntersect = new $value; + $oIntersect->link(strtolower(get_class($this))); + $oIntersect->link(strtolower(get_class($mobject))); + + $aIntersectParameters = $oIntersect->_fetchJoinTables($ignoreRoot); + + $aFields = array_merge($aIntersectParameters['fields'], $aFields); + $aTables = array_merge($aIntersectParameters['tables'], $aTables); + $aJoins = array_merge($aIntersectParameters['joins'], $aJoins); + $aWheres = array_merge($aIntersectParameters['wheres'], $aWheres); + } + } else { + $sMsg = "Could not find join partner for class [$link] in class " + . get_class($this) . " in neither forward nor reverse direction."; + cWarning(__FILE__, __LINE__, $sMsg); + } + } + } + } + } + + // Add this class + $aFields[] = strtolower(strtolower(get_class($this))) . '.' . $this->primaryKey; + + // Make the parameters unique + foreach ($aParameters as $parameter) { + array_unshift($aFields, $parameter['field']); + array_unshift($aTables, $parameter['table']); + array_unshift($aJoins, $parameter['join']); + array_unshift($aWheres, $parameter['where']); + } + + $aFields = array_filter(array_unique($aFields)); + $aTables = array_filter(array_unique($aTables)); + $aJoins = array_filter(array_unique($aJoins)); + $aWheres = array_filter(array_unique($aWheres)); + + return array( + 'fields' => $aFields, 'tables' => $aTables, 'joins' => $aJoins, 'wheres' => $aWheres + ); + } + + /** + * Resolves links (class names of joined partners) + * + * @return array + */ + protected function _resolveLinks() { + $aResolvedLinks = array(); + $aResolvedLinks[] = strtolower(get_class($this)); + + foreach ($this->_JoinPartners as $link) { + $class = new $link; + $aResolvedLinks = array_merge($class->_resolveLinks(), $aResolvedLinks); + } + return $aResolvedLinks; + } + + /** + * Resets the properties + */ + public function resetQuery() { + $this->setLimit(0, 0); + $this->_JoinPartners = array(); + $this->_forwardJoinPartners = array(); + $this->_links = array(); + $this->_where['global'] = array(); + $this->_where['groups'] = array(); + $this->_groupConditions = array(); + $this->_resultFields = array(); + $this->_aTableColums = array(); + } + + /** + * Builds and runs the query + * + * @return bool + */ + public function query() { + if (!isset($this->_itemClassInstance)) { + $sMsg = "GenericDB can't use query() if no item class is set via setItemClass"; + cWarning(__FILE__, __LINE__, $sMsg); + return false; + } + + $aGroupWhereStatements = $this->_buildGroupWhereStatements(); + $sWhereStatements = $this->_buildWhereStatements(); + $aParameters = $this->_fetchJoinTables(strtolower(get_class($this))); + + $aStatement = array( + 'SELECT', + implode(', ', (array_merge($aParameters['fields'], $this->_resultFields))), + 'FROM', + '`' . $this->table . '` AS ' . strtolower(get_class($this)) + ); + + if (count($aParameters['tables']) > 0) { + $aStatement[] = implode(', ', $aParameters['tables']); + } + + if (count($aParameters['joins']) > 0) { + $aStatement[] = implode(' ', $aParameters['joins']); + } + + $aWheres = array(); + + if (count($aParameters['wheres']) > 0) { + $aWheres[] = implode(', ', $aParameters['wheres']); + } + + if ($aGroupWhereStatements != '') { + $aWheres[] = $aGroupWhereStatements; + } + + if ($sWhereStatements != '') { + $aWheres[] = $sWhereStatements; + } + + if (count($aWheres) > 0) { + $aStatement[] = 'WHERE ' . implode(' AND ', $aWheres); + } + + if ($this->_order != '') { + $aStatement[] = 'ORDER BY ' . $this->_order; + } + + if ($this->_limitStart > 0 || $this->_limitCount > 0) { + $iRowStart = intval($this->_limitStart); + $iRowCount = intval($this->_limitCount); + $aStatement[] = "LIMIT $iRowStart, $iRowCount"; + } + + $sql = implode(' ', $aStatement); + + $result = $this->db->query($sql); + $this->_lastSQL = $sql; + // @todo disable all mode in this method for the moment. It has to be verified, + // if enabling will result in negative side effects. + $this->_bAllMode = false; + return ($result) ? true : false; + } + + /** + * Sets the result order part of the query + * (e. g. "fieldname", "fieldname DESC", "fieldname DESC, field2name ASC") + * @param string $order + */ + public function setOrder($order) { + $this->_order = strtolower($order); + } + + /** + * Adds a result field + * @param string|array $mField + */ + public function addResultField($mField, $bAll = false) { + if (!empty($mField) && !is_array($mField)) { + $mField = array($mField); + } else if($bAll && empty($this->_aTableColums)) { + $aTemp = $this->db->metadata($this->table); + foreach ($aTemp as $aMeta) { + $this->_aTableColums[] = $aMeta['name']; + } + $mField = $this->_aTableColums; + } + foreach ($mField as $sField) { + $sField = strtolower($sField); + if (!in_array($sField, $this->_resultFields)) { + $this->_resultFields[] = $sField; + } + } + } + + /** + * Removes existing result field + * @param string|array $mField + */ + public function removeResultField($mField) { + if (!is_array($mField)) { + $mField = array($mField); + } + + foreach ($mField as $sField) { + $sField = strtolower($sField); + $key = array_search($sField, $this->_resultFields); + if ($key !== false) { + unset($this->_resultFields[$key]); + } + } + } + + /** + * Returns reverse join partner. + * + * @param string $sParentClass + * @param string $sClassName + * @param array|bool + */ + protected function _findReverseJoinPartner($sParentClass, $sClassName) { + // Make the parameters lowercase, as get_class is buggy + $sClassName = strtolower($sClassName); + $sParentClass = strtolower($sParentClass); + + // Check if we found a direct link + if (in_array($sClassName, $this->_JoinPartners)) { + $obj = new $sClassName; + return array( + 'desttable' => $obj->table, 'destclass' => $sClassName, + 'sourceclass' => $sParentClass, 'key' => $obj->primaryKey + ); + } else { + // Recurse all items + foreach ($this->_JoinPartners as $join => $tmpClassname) { + $obj = new $tmpClassname; + $status = $obj->_findReverseJoinPartner($tmpClassname, $sClassName); + + if (is_array($status)) { + $returns = array(); + + if (!isset($status['desttable'])) { + foreach ($status as $subitem) { + $returns[] = $subitem; + } + } else { + $returns[] = $status; + } + + $obj = new $tmpClassname; + + $returns[] = array( + 'desttable' => $obj->table, 'destclass' => $tmpClassname, + 'sourceclass' => $sParentClass, 'key' => $obj->primaryKey + ); + return ($returns); + } + } + } + + return false; + } + + /** + * Selects all entries from the database. Objects are loaded using their primary key. + * + * @param string $sWhere Specifies the where clause. + * @param string $sGroupBy Specifies the group by clause. + * @param string $sOrderBy Specifies the order by clause. + * @param string $sLimit Specifies the limit by clause. + * @return bool True on success, otherwhise false + */ + public function select($sWhere = '', $sGroupBy = '', $sOrderBy = '', $sLimit = '') { + unset($this->objects); + + if ($sWhere == '') { + $sWhere = ''; + } else { + $sWhere = ' WHERE ' . $sWhere; + } + + if ($sGroupBy != '') { + $sGroupBy = ' GROUP BY ' . $sGroupBy; + } + + if ($sOrderBy != '') { + $sOrderBy = ' ORDER BY ' . $sOrderBy; + } + + if ($sLimit != '') { + $sLimit = ' LIMIT ' . $sLimit; + } + + $sFields = ($this->_settings['select_all_mode']) ? '*' : $this->primaryKey; + $sql = 'SELECT ' . $sFields . ' FROM `' . $this->table . '`' . $sWhere + . $sGroupBy . $sOrderBy . $sLimit; + $this->db->query($sql); + $this->_lastSQL = $sql; + $this->_bAllMode = $this->_settings['select_all_mode']; + + if ($this->db->num_rows() == 0) { + return false; + } else { + return true; + } + } + + /** + * Selects all entries from the database. Objects are loaded using their primary key. + * + * @param string $sDistinct Specifies if distinct will be added to the SQL + * statement ($sDistinct !== '' -> DISTINCT) + * @param string $sFrom Specifies the additional from clause (e.g. + * 'con_news_groups AS groups, con_news_groupmembers AS groupmembers'). + * @param string $sWhere Specifies the where clause. + * @param string $sGroupBy Specifies the group by clause. + * @param string $sOrderBy Specifies the order by clause. + * @param string $sLimit Specifies the limit by clause. + * @return bool True on success, otherwhise false + * @author HerrB + */ + public function flexSelect($sDistinct = '', $sFrom = '', $sWhere = '', $sGroupBy = '', $sOrderBy = '', $sLimit = '') { + unset($this->objects); + + if ($sDistinct != '') { + $sDistinct = 'DISTINCT '; + } + + if ($sFrom != '') { + $sFrom = ', ' . $sFrom; + } + + if ($sWhere != '') { + $sWhere = ' WHERE ' . $sWhere; + } + + if ($sGroupBy != '') { + $sGroupBy = ' GROUP BY ' . $sGroupBy; + } + + if ($sOrderBy != '') { + $sOrderBy = ' ORDER BY ' . $sOrderBy; + } + + if ($sLimit != '') { + $sLimit = ' LIMIT ' . $sLimit; + } + + $sql = 'SELECT ' . $sDistinct . strtolower(get_class($this)) . '.' . $this->primaryKey + . ' AS ' . $this->primaryKey . ' FROM `' . $this->table . '` AS ' . strtolower(get_class($this)) + . $sFrom . $sWhere . $sGroupBy . $sOrderBy . $sLimit; + + $this->db->query($sql); + $this->_lastSQL = $sql; + // @todo disable all mode in this method + $this->_bAllMode = false; + + if ($this->db->num_rows() == 0) { + return false; + } else { + return true; + } + } + + /** + * Checks if a specific entry exists. + * + * @param mixed $mId The id to check for (could be numeric or string) + * @return bool True if object exists, false if not + */ + public function exists($mId) { + $oDb = $this->_getSecondDBInstance(); + $sql = "SELECT `%s` FROM %s WHERE %s='%s'"; + $oDb->query($sql, $this->primaryKey, $this->table, $this->primaryKey, $mId); + return ($oDb->next_record()) ? true : false; + } + + /** + * Advances to the next item in the database. + * + * @return Item|bool The next object, or false if no more objects + */ + public function next() { + if ($this->db->next_record()) { + if ($this->_bAllMode) { + $aRs = $this->db->toArray(DB_ConLite::FETCH_BOTH); + return $this->loadItem($aRs); + } else { + return $this->loadItem($this->db->f($this->primaryKey)); + } + } else { + return false; + } + } + + /** + * Fetches the resultset related to current loaded primary key as a object + * + * @param Item + */ + public function fetchObject($sClassName) { + $sKey = strtolower($sClassName); + + if (!is_object($this->_collectionCache[$sKey])) { + $this->_collectionCache[$sKey] = new $sClassName; + } + $obj = $this->_collectionCache[$sKey]; + return $obj->loadItem($this->db->f($obj->primaryKey)); + } + + /** + * Both arrays are optional. If both empty you will get an result using field stored in primaryKey + * + * $aFields = array with the fields to fetch. Notes: + * If the array contains keys, the key will be used as alias for the field. Example: + * array('id' => 'idcat') will put 'idcat' into field 'id' + * + * $aObjects = array with the objects to fetch. Notes: + * If the array contains keys, the key will be used as alias for the object. If you specify + * more than one object with the same key, the array will be multi-dimensional. + * + * @param array $aFields + * @param array $aObjects + * @return array + */ + public function fetchTable(array $aFields = array(), array $aObjects = array()) { + $row = 1; + $aTable = array(); + + if(!empty($this->_aTableColums)) { + $aFields = $this->_aTableColums; + } + + if (empty($aFields) && empty($aObjects)) { + $aFields = array($this->primaryKey); + } + + $this->db->seek(0); + + while ($this->db->next_record()) { + foreach ($aFields as $alias => $field) { + //if ($alias != '') { + if (is_string($alias)) { + $aTable[$row][$alias] = $this->db->f($field); + } else { + $aTable[$row][$field] = $this->db->f($field); + } + } + + // Fetch objects + if (!empty($aObjects)) { + foreach ($aObjects as $alias => $object) { + if ($alias != '') { + if (isset($aTable[$row][$alias])) { + // Is set, check for array. If no array, create one + if (is_array($aTable[$row][$alias])) { + $aTable[$row][$alias][] = $this->fetchObject($object); + } else { + // $tmpObj = $aTable[$row][$alias]; + $aTable[$row][$alias] = array(); + $aTable[$row][$alias][] = $this->fetchObject($object); + } + } else { + $aTable[$row][$alias] = $this->fetchObject($object); + } + } else { + $aTable[$row][$object] = $this->fetchObject($object); + } + } + } + $row++; + } + + $this->db->seek(0); + + return $aTable; + } + + /** + * Returns an array of arrays + * @param array $aObjects With the correct order of the objects + * @return array Result + */ + public function queryAndFetchStructured(array $aObjects) { + $aOrder = array(); + $aFetchObjects = array(); + $aResult = array(); + + foreach ($aObjects as $object) { + $x = new $object; + $object = strtolower($object); + $aOrder[] = $object . '.' . $x->primaryKey . ' ASC'; + $aFetchObjects[] = $x; + } + + $this->setOrder(implode(', ', $aOrder)); + $this->query(); + + $this->db->seek(0); + + while ($this->db->next_record()) { + $aResult = $this->_recursiveStructuredFetch($aFetchObjects, $aResult); + } + + return $aResult; + } + + protected function _recursiveStructuredFetch(array $aObjects, array $aResult) { + $i = array_shift($aObjects); + + $value = $this->db->f($i->primaryKey); + + if (!is_null($value)) { + $aResult[$value]['class'] = strtolower(get_class($i)); + $aResult[$value]['object'] = $i->loadItem($value); + + if (count($aObjects) > 0) { + $aResult[$value]['items'] = $this->_recursiveStructuredFetch($aObjects, $aResult[$value]['items']); + } + } + + return $aResult; + } + + /** + * Returns the amount of returned items + * @return int Number of rows + */ + public function count() { + return ($this->db->num_rows()); + } + + /** + * Loads a single entry by it's id. + * + * @param string|int $id The primary key of the item to load. + * @return Item The loaded item + */ + public function fetchById($id) { + if (is_numeric($id)) { + $id = (int) $id; + } elseif (is_string($id)) { + $id = $this->escape($id); + } + return $this->loadItem($id); + } + + /** + * Loads a single object from the database. + * + * @param mixed $mItem The primary key of the item to load or a recordset + * with itemdata (array) to inject to the item object. + * @return Item The newly created object + * @throws Contenido_ItemException If item class is not set + */ + public function loadItem($mItem) { + if (empty($this->_itemClass)) { + $sMsg = "ItemClass has to be set in the constructor of class " + . get_class($this) . ")"; + throw new Contenido_ItemException($sMsg); + } + + if (!is_object($this->_iteratorItem)) { + $this->_iteratorItem = new $this->_itemClass(); + } + + if (is_array($mItem)) { + $this->_iteratorItem->loadByRecordSet($mItem); + } else { + $this->_iteratorItem->loadByPrimaryKey($mItem); + } + + return $this->_iteratorItem; + } + + /** + * Creates a new item in the table and loads it afterwards. + * + * @param string $primaryKeyValue Optional parameter for direct input of primary key value + * @return Item The newly created object + */ + public function createNewItem($aData = NULL) { /* @var $oDb DB_ConLite */ + $oDb = $this->_getSecondDBInstance(); + if (is_null($aData) || empty($aData)) { + $iNextId = $oDb->nextid($this->table); + } else if (is_array($aData) && key_exists($this->primaryKey, $aData)) { + $iNextId = (int) $aData[$this->primaryKey]; + } else { + $iNextId = (int) $aData; + } + + $sql = 'INSERT INTO `%s` (%s) VALUES (%d)'; + $oDb->query($sql, $this->table, $this->primaryKey, $iNextId); + return $this->loadItem($iNextId); + } + + /** + * Deletes an item in the table. + * Deletes also cached e entry and any existing properties. + * + * @param mixed $mId Id of entry to delete + * @return bool + */ + public function delete($mId) { + $result = $this->_delete($mId); + + return $result; + } + + /** + * Deletes all found items in the table matching the rules in the passed where clause. + * Deletes also cached e entries and any existing properties. + * + * @param string $sWhere The where clause of the SQL statement + * @return int Number of deleted entries + */ + public function deleteByWhereClause($sWhere) { + $oDb = $this->_getSecondDBInstance(); + + $aIds = array(); + $numDeleted = 0; + + // get all ids + $sql = 'SELECT ' . $this->primaryKey . ' AS pk FROM `' . $this->table . '` WHERE ' . $sWhere; + $oDb->query($sql); + while ($oDb->next_record()) { + $aIds[] = $oDb->f('pk'); + } + + // delete entries by their ids + foreach ($aIds as $id) { + if ($this->_delete($id)) { + $numDeleted++; + } + } + + return $numDeleted; + } + + /** + * Deletes all found items in the table matching the passed field and it's value. + * Deletes also cached e entries and any existing properties. + * + * @param string $sField The field name + * @param mixed $mValue The value of the field + * @return int Number of deleted entries + */ + public function deleteBy($sField, $mValue) { + $oDb = $this->_getSecondDBInstance(); + + $aIds = array(); + $numDeleted = 0; + + // get all ids + if (is_string($mValue)) { + $sql = "SELECT %s AS pk FROM `%s` WHERE `%s` = '%s'"; + } else { + $sql = "SELECT %s AS pk FROM `%s` WHERE `%s` = %d"; + } + + $oDb->query($sql, $this->primaryKey, $this->table, $sField, $mValue); + while ($oDb->next_record()) { + $aIds[] = $oDb->f('pk'); + } + + // delete entries by their ids + foreach ($aIds as $id) { + if ($this->_delete($id)) { + $numDeleted++; + } + } + + return $numDeleted; + } + + /** + * Deletes an item in the table, deletes also existing cache entries and + * properties of the item. + * + * @param mixed $mId Id of entry to delete + * @return bool + */ + protected function _delete($mId) { + + // delete cache entry + self::$_oCache->removeItem($mId); + + // delete the property values + $oProperties = $this->_getPropertiesCollectionInstance(); + $oProperties->deleteProperties($this->primaryKey, $mId); + + $oDb = $this->_getSecondDBInstance(); + + // delete db entry + $sql = "DELETE FROM `%s` WHERE %s = '%s'"; + $oDb->query($sql, $this->table, $this->primaryKey, $mId); + + return (($oDb->affected_rows() > 0) ? true : false); + } + + /** + * Fetches an array of fields from the database. + * + * Example: + * $i = $object->fetchArray('idartlang', array('idlang', 'name')); + * + * could result in: + * $i[5] = array('idlang' => 5, 'name' => 'My Article'); + * + * Important: If you don't pass an array for fields, the function + * doesn't create an array. + * @param string $sKey Name of the field to use for the key + * @param mixed $mFields String or array + * @return array Resulting array + */ + public function fetchArray($sKey, $mFields) { + $aResult = array(); + + while ($item = $this->next()) { + if (is_array($mFields)) { + foreach ($mFields as $value) { + $aResult[$item->get($sKey)][$value] = $item->get($value); + } + } else { + $aResult[$item->get($sKey)] = $item->get($mFields); + } + } + + return $aResult; + } +} \ No newline at end of file diff --git a/conlite/classes/GenericDb/ItemException.php b/conlite/classes/GenericDb/ItemException.php new file mode 100644 index 0000000..89f21b0 --- /dev/null +++ b/conlite/classes/GenericDb/ItemException.php @@ -0,0 +1,9 @@ +resetQuery(); - - // Try to load driver - $this->_initializeDriver(); - - // Try to find out the current encoding - if (isset($GLOBALS['lang']) && isset($GLOBALS['aLanguageEncodings'])) { - $this->setEncoding($GLOBALS['aLanguageEncodings'][$GLOBALS['lang']]); - } - - $this->_aOperators = array( - '=', '!=', '<>', '<', '>', '<=', '>=', 'LIKE', 'DIACRITICS' - ); - } - - /** - * Defines the reverse links for this table. - * - * Important: The class specified by $sForeignCollectionClass needs to be a - * collection class and has to exist. - * Define all links in the constructor of your object. - * - * @param string $sForeignCollectionClass Specifies the foreign class to use - * @return void - */ - protected function _setJoinPartner($sForeignCollectionClass) { - if (class_exists($sForeignCollectionClass)) { - // Add class - if (!in_array($sForeignCollectionClass, $this->_JoinPartners)) { - $this->_JoinPartners[] = strtolower($sForeignCollectionClass); - } - } else { - $sMsg = "Could not instanciate class [$sForeignCollectionClass] for use " - . "with _setJoinPartner in class " . get_class($this); - cWarning(__FILE__, __LINE__, $sMsg); - } - } - - /** - * Method to set the accompanying item object. - * - * @param string $sClassName Specifies the classname of item - * @return void - */ - protected function _setItemClass($sClassName) { - if (class_exists($sClassName)) { - $this->_itemClass = $sClassName; - $this->_itemClassInstance = new $sClassName; - - // Initialize driver in case the developer does a setItemClass-Call - // before calling the parent constructor - $this->_initializeDriver(); - $this->_driver->setItemClassInstance($this->_itemClassInstance); - } else { - $sMsg = "Could not instanciate class [$sClassName] for use with " - . "_setItemClass in class " . get_class($this); - cWarning(__FILE__, __LINE__, $sMsg); - } - } - - /** - * Initializes the driver to use with GenericDB. - * - * @param $bForceInit boolean If true, forces the driver to initialize, even if it already exists. - */ - protected function _initializeDriver($bForceInit = false) { - if (!is_object($this->_driver) || $bForceInit == true) { - $this->_driver = new gdbMySQL(); - } - } - - /** - * Sets the encoding. - * @param string $sEncoding - */ - public function setEncoding($sEncoding) { - $this->_encoding = $sEncoding; - $this->_driver->setEncoding($sEncoding); - } - - /** - * Sets the query to use foreign tables in the resultset - * @param string $sForeignClass The class of foreign table to use - */ - public function link($sForeignClass) { - if (class_exists($sForeignClass)) { - $this->_links[$sForeignClass] = new $sForeignClass; - } else { - $sMsg = "Could not find class [$sForeignClass] for use with link in class " - . get_class($this); - cWarning(__FILE__, __LINE__, $sMsg); - } - } - - /** - * Sets the limit for results - * @param int $iRowStart - * @param int $iRowCount - */ - public function setLimit($iRowStart, $iRowCount) { - $this->_limitStart = $iRowStart; - $this->_limitCount = $iRowCount; - } - - /** - * Restricts a query with a where clause - * @param string $sField - * @param mixed $mRestriction - * @param string $sOperator - */ - public function setWhere($sField, $mRestriction, $sOperator = '=') { - $sField = strtolower($sField); - $this->_where['global'][$sField]['operator'] = $sOperator; - $this->_where['global'][$sField]['restriction'] = $mRestriction; - } - - /** - * Removes a previous set where clause (@see ItemCollection::setWhere). - * @param string $sField - * @param mixed $mRestriction - * @param string $sOperator - */ - public function deleteWhere($sField, $mRestriction, $sOperator = '=') { - $sField = strtolower($sField); - if (isset($this->_where['global'][$sField]) && is_array($this->_where['global'][$sField])) { - if ($this->_where['global'][$sField]['operator'] == $sOperator && $this->_where['global'][$sField]['restriction'] == $mRestriction) { - unset($this->_where['global'][$sField]); - } - } - } - - /** - * Restricts a query with a where clause, groupable - * @param string $sGroup - * @param string $sField - * @param mixed $mRestriction - * @param string $sOperator - */ - public function setWhereGroup($sGroup, $sField, $mRestriction, $sOperator = '=') { - $sField = strtolower($sField); - $this->_where['groups'][$sGroup][$sField]['operator'] = $sOperator; - $this->_where['groups'][$sGroup][$sField]['restriction'] = $mRestriction; - } - - /** - * Removes a previous set groupable where clause (@see ItemCollection::setWhereGroup). - * @param string $sGroup - * @param string $sField - * @param mixed $mRestriction - * @param string $sOperator - */ - public function deleteWhereGroup($sGroup, $sField, $mRestriction, $sOperator = '=') { - $sField = strtolower($sField); - if (is_array($this->_where['groups'][$sGroup]) && isset($this->_where['groups'][$sGroup][$sField]) && is_array($this->_where['groups'][$sGroup][$sField])) { - if ($this->_where['groups'][$sGroup][$sField]['operator'] == $sOperator && $this->_where['groups'][$sGroup][$sField]['restriction'] == $mRestriction) { - unset($this->_where['groups'][$sGroup][$sField]); - } - } - } - - /** - * Defines how relations in one group are linked each together - * @param string $sGroup - * @param string $sCondition - */ - public function setInnerGroupCondition($sGroup, $sCondition = 'AND') { - $this->_innerGroupConditions[$sGroup] = $sCondition; - } - - /** - * Defines how groups are linked to each other - * @param string $sGroup1 - * @param string $sGroup2 - * @param string $sCondition - */ - public function setGroupCondition($sGroup1, $sGroup2, $sCondition = 'AND') { - $this->_groupConditions[$sGroup1][$sGroup2] = $sCondition; - } - - /** - * Builds a where statement out of the setGroupWhere calls - * - * @return array With all where statements - */ - protected function _buildGroupWhereStatements() { - $aWheres = array(); - $aGroupWhere = array(); - - $mLastGroup = false; - $sGroupWhereStatement = ''; - - // Find out if there are any defined groups - if (count($this->_where['groups']) > 0) { - // Step trough all groups - foreach ($this->_where['groups'] as $groupname => $group) { - $aWheres = array(); - - // Fetch restriction, fields and operators and build single group - // where statements - foreach ($group as $field => $item) { - $aWheres[] = $this->_driver->buildOperator($field, $item['operator'], $item['restriction']); - } - - // Add completed substatements - $sOperator = 'AND'; - if (isset($this->_innerGroupConditions[$groupname])) { - $sOperator = $this->_innerGroupConditions[$groupname]; - } - - $aGroupWhere[$groupname] = implode(' ' . $sOperator . ' ', $aWheres); - } - } - - // Combine groups - foreach ($aGroupWhere as $groupname => $group) { - if ($mLastGroup != false) { - $sOperator = 'AND'; - // Check if there's a group condition - if (isset($this->_groupConditions[$groupname])) { - if (isset($this->_groupConditions[$groupname][$mLastGroup])) { - $sOperator = $this->_groupConditions[$groupname][$mLastGroup]; - } - } - - // Reverse check - if (isset($this->_groupConditions[$mLastGroup])) { - if (isset($this->_groupConditions[$mLastGroup][$groupname])) { - $sOperator = $this->_groupConditions[$mLastGroup][$groupname]; - } - } - - $sGroupWhereStatement .= ' ' . $sOperator . ' (' . $group . ')'; - } else { - $sGroupWhereStatement .= '(' . $group . ')'; - } - - $mLastGroup = $groupname; - } - - return $sGroupWhereStatement; - } - - /** - * Builds a where statement out of the setWhere calls - * - * @return array With all where statements - */ - protected function _buildWhereStatements() { - $aWheres = array(); - - // Build global where condition - foreach ($this->_where['global'] as $field => $item) { - $aWheres[] = $this->_driver->buildOperator($field, $item['operator'], $item['restriction']); - } - - return (implode(' AND ', $aWheres)); - } - - /** - * Fetches all tables which will be joined later on. - * - * The returned array has the following format: - *
-     * array(
-     *     array(fields),
-     *     array(tables),
-     *     array(joins),
-     *     array(wheres)
-     * );
-     * 
- * - * Notes: - * The table is the table name which needs to be added to the FROM clause - * The join statement which is inserted after the master table - * The where statement is combined with all other where statements - * The fields to select from - * - * @todo Reduce complexity of this function, to much code... - * - * @param ??? $ignoreRoot - * @return array Array structure, see above - */ - protected function _fetchJoinTables($ignoreRoot) { - $aParameters = array(); - $aFields = array(); - $aTables = array(); - $aJoins = array(); - $aWheres = array(); - - // Fetch linked tables - foreach ($this->_links as $link => $object) { - $matches = $this->_findReverseJoinPartner(strtolower(get_class($this)), $link); - - if ($matches !== false) { - if (isset($matches['desttable'])) { - // Driver function: Build query parts - $aParameters[] = $this->_driver->buildJoinQuery( - $matches['desttable'], - strtolower($matches['destclass']), - $matches['key'], - strtolower($matches['sourceclass']), - $matches['key'] - ); - } else { - foreach ($matches as $match) { - $aParameters[] = $this->_driver->buildJoinQuery( - $match['desttable'], - strtolower($match['destclass']), - $match['key'], - strtolower($match['sourceclass']), - $match['key'] - ); - } - } - } else { - // Try forward search - $mobject = new $link; - - $matches = $mobject->_findReverseJoinPartner($link, strtolower(get_class($this))); - - if ($matches !== false) { - if (isset($matches['desttable'])) { - $i = $this->_driver->buildJoinQuery( - $mobject->table, - strtolower($link), - $mobject->primaryKey, - strtolower($matches['destclass']), - $matches['key'] - ); - - if ($i['field'] == ($link . '.' . $mobject->primaryKey) && $link == $ignoreRoot) { - unset($i['join']); - } - $aParameters[] = $i; - } else { - foreach ($matches as $match) { - $xobject = new $match['sourceclass']; - - $i = $this->_driver->buildJoinQuery( - $xobject->table, - strtolower($match['sourceclass']), - $xobject->primaryKey, - strtolower($match['destclass']), - $match['key'] - ); - - if ($i['field'] == ($match['sourceclass'] . '.' . $xobject->primaryKey) && $match['sourceclass'] == $ignoreRoot) { - unset($i['join']); - } - array_unshift($aParameters, $i); - } - } - } else { - $bDualSearch = true; - // Check first if we are a instance of another class - foreach ($mobject->_JoinPartners as $sJoinPartner) { - if (class_exists($sJoinPartner)) { - if (is_subclass_of($this, $sJoinPartner)) { - $matches = $mobject->_findReverseJoinPartner($link, strtolower($sJoinPartner)); - - if ($matches !== false) { - if ($matches['destclass'] == strtolower($sJoinPartner)) { - $matches['destclass'] = get_class($this); - - if (isset($matches['desttable'])) { - $i = $this->_driver->buildJoinQuery( - $mobject->table, - strtolower($link), - $mobject->primaryKey, - strtolower($matches['destclass']), - $matches['key'] - ); - - if ($i['field'] == ($link . '.' . $mobject->primaryKey) && $link == $ignoreRoot) { - unset($i['join']); - } - $aParameters[] = $i; - } else { - foreach ($matches as $match) { - $xobject = new $match['sourceclass']; - - $i = $this->_driver->buildJoinQuery( - $xobject->table, - strtolower($match['sourceclass']), - $xobject->primaryKey, - strtolower($match['destclass']), - $match['key'] - ); - - if ($i['field'] == ($match['sourceclass'] . '.' . $xobject->primaryKey) && $match['sourceclass'] == $ignoreRoot) { - unset($i['join']); - } - array_unshift($aParameters, $i); - } - } - $bDualSearch = false; - } - } - } - } - } - - if ($bDualSearch) { - // Try dual-side search - $forward = $this->_resolveLinks(); - $reverse = $mobject->_resolveLinks(); - - $result = array_intersect($forward, $reverse); - - if (count($result) > 0) { - // Found an intersection, build references to it - foreach ($result as $value) { - $oIntersect = new $value; - $oIntersect->link(strtolower(get_class($this))); - $oIntersect->link(strtolower(get_class($mobject))); - - $aIntersectParameters = $oIntersect->_fetchJoinTables($ignoreRoot); - - $aFields = array_merge($aIntersectParameters['fields'], $aFields); - $aTables = array_merge($aIntersectParameters['tables'], $aTables); - $aJoins = array_merge($aIntersectParameters['joins'], $aJoins); - $aWheres = array_merge($aIntersectParameters['wheres'], $aWheres); - } - } else { - $sMsg = "Could not find join partner for class [$link] in class " - . get_class($this) . " in neither forward nor reverse direction."; - cWarning(__FILE__, __LINE__, $sMsg); - } - } - } - } - } - - // Add this class - $aFields[] = strtolower(strtolower(get_class($this))) . '.' . $this->primaryKey; - - // Make the parameters unique - foreach ($aParameters as $parameter) { - array_unshift($aFields, $parameter['field']); - array_unshift($aTables, $parameter['table']); - array_unshift($aJoins, $parameter['join']); - array_unshift($aWheres, $parameter['where']); - } - - $aFields = array_filter(array_unique($aFields)); - $aTables = array_filter(array_unique($aTables)); - $aJoins = array_filter(array_unique($aJoins)); - $aWheres = array_filter(array_unique($aWheres)); - - return array( - 'fields' => $aFields, 'tables' => $aTables, 'joins' => $aJoins, 'wheres' => $aWheres - ); - } - - /** - * Resolves links (class names of joined partners) - * - * @return array - */ - protected function _resolveLinks() { - $aResolvedLinks = array(); - $aResolvedLinks[] = strtolower(get_class($this)); - - foreach ($this->_JoinPartners as $link) { - $class = new $link; - $aResolvedLinks = array_merge($class->_resolveLinks(), $aResolvedLinks); - } - return $aResolvedLinks; - } - - /** - * Resets the properties - */ - public function resetQuery() { - $this->setLimit(0, 0); - $this->_JoinPartners = array(); - $this->_forwardJoinPartners = array(); - $this->_links = array(); - $this->_where['global'] = array(); - $this->_where['groups'] = array(); - $this->_groupConditions = array(); - $this->_resultFields = array(); - $this->_aTableColums = array(); - } - - /** - * Builds and runs the query - * - * @return bool - */ - public function query() { - if (!isset($this->_itemClassInstance)) { - $sMsg = "GenericDB can't use query() if no item class is set via setItemClass"; - cWarning(__FILE__, __LINE__, $sMsg); - return false; - } - - $aGroupWhereStatements = $this->_buildGroupWhereStatements(); - $sWhereStatements = $this->_buildWhereStatements(); - $aParameters = $this->_fetchJoinTables(strtolower(get_class($this))); - - $aStatement = array( - 'SELECT', - implode(', ', (array_merge($aParameters['fields'], $this->_resultFields))), - 'FROM', - '`' . $this->table . '` AS ' . strtolower(get_class($this)) - ); - - if (count($aParameters['tables']) > 0) { - $aStatement[] = implode(', ', $aParameters['tables']); - } - - if (count($aParameters['joins']) > 0) { - $aStatement[] = implode(' ', $aParameters['joins']); - } - - $aWheres = array(); - - if (count($aParameters['wheres']) > 0) { - $aWheres[] = implode(', ', $aParameters['wheres']); - } - - if ($aGroupWhereStatements != '') { - $aWheres[] = $aGroupWhereStatements; - } - - if ($sWhereStatements != '') { - $aWheres[] = $sWhereStatements; - } - - if (count($aWheres) > 0) { - $aStatement[] = 'WHERE ' . implode(' AND ', $aWheres); - } - - if ($this->_order != '') { - $aStatement[] = 'ORDER BY ' . $this->_order; - } - - if ($this->_limitStart > 0 || $this->_limitCount > 0) { - $iRowStart = intval($this->_limitStart); - $iRowCount = intval($this->_limitCount); - $aStatement[] = "LIMIT $iRowStart, $iRowCount"; - } - - $sql = implode(' ', $aStatement); - - $result = $this->db->query($sql); - $this->_lastSQL = $sql; - // @todo disable all mode in this method for the moment. It has to be verified, - // if enabling will result in negative side effects. - $this->_bAllMode = false; - return ($result) ? true : false; - } - - /** - * Sets the result order part of the query - * (e. g. "fieldname", "fieldname DESC", "fieldname DESC, field2name ASC") - * @param string $order - */ - public function setOrder($order) { - $this->_order = strtolower($order); - } - - /** - * Adds a result field - * @param string|array $mField - */ - public function addResultField($mField, $bAll = false) { - if (!empty($mField) && !is_array($mField)) { - $mField = array($mField); - } else if($bAll && empty($this->_aTableColums)) { - $aTemp = $this->db->metadata($this->table); - foreach ($aTemp as $aMeta) { - $this->_aTableColums[] = $aMeta['name']; - } - $mField = $this->_aTableColums; - } - foreach ($mField as $sField) { - $sField = strtolower($sField); - if (!in_array($sField, $this->_resultFields)) { - $this->_resultFields[] = $sField; - } - } - } - - /** - * Removes existing result field - * @param string|array $mField - */ - public function removeResultField($mField) { - if (!is_array($mField)) { - $mField = array($mField); - } - - foreach ($mField as $sField) { - $sField = strtolower($sField); - $key = array_search($sField, $this->_resultFields); - if ($key !== false) { - unset($this->_resultFields[$key]); - } - } - } - - /** - * Returns reverse join partner. - * - * @param string $sParentClass - * @param string $sClassName - * @param array|bool - */ - protected function _findReverseJoinPartner($sParentClass, $sClassName) { - // Make the parameters lowercase, as get_class is buggy - $sClassName = strtolower($sClassName); - $sParentClass = strtolower($sParentClass); - - // Check if we found a direct link - if (in_array($sClassName, $this->_JoinPartners)) { - $obj = new $sClassName; - return array( - 'desttable' => $obj->table, 'destclass' => $sClassName, - 'sourceclass' => $sParentClass, 'key' => $obj->primaryKey - ); - } else { - // Recurse all items - foreach ($this->_JoinPartners as $join => $tmpClassname) { - $obj = new $tmpClassname; - $status = $obj->_findReverseJoinPartner($tmpClassname, $sClassName); - - if (is_array($status)) { - $returns = array(); - - if (!isset($status['desttable'])) { - foreach ($status as $subitem) { - $returns[] = $subitem; - } - } else { - $returns[] = $status; - } - - $obj = new $tmpClassname; - - $returns[] = array( - 'desttable' => $obj->table, 'destclass' => $tmpClassname, - 'sourceclass' => $sParentClass, 'key' => $obj->primaryKey - ); - return ($returns); - } - } - } - - return false; - } - - /** - * Selects all entries from the database. Objects are loaded using their primary key. - * - * @param string $sWhere Specifies the where clause. - * @param string $sGroupBy Specifies the group by clause. - * @param string $sOrderBy Specifies the order by clause. - * @param string $sLimit Specifies the limit by clause. - * @return bool True on success, otherwhise false - */ - public function select($sWhere = '', $sGroupBy = '', $sOrderBy = '', $sLimit = '') { - unset($this->objects); - - if ($sWhere == '') { - $sWhere = ''; - } else { - $sWhere = ' WHERE ' . $sWhere; - } - - if ($sGroupBy != '') { - $sGroupBy = ' GROUP BY ' . $sGroupBy; - } - - if ($sOrderBy != '') { - $sOrderBy = ' ORDER BY ' . $sOrderBy; - } - - if ($sLimit != '') { - $sLimit = ' LIMIT ' . $sLimit; - } - - $sFields = ($this->_settings['select_all_mode']) ? '*' : $this->primaryKey; - $sql = 'SELECT ' . $sFields . ' FROM `' . $this->table . '`' . $sWhere - . $sGroupBy . $sOrderBy . $sLimit; - $this->db->query($sql); - $this->_lastSQL = $sql; - $this->_bAllMode = $this->_settings['select_all_mode']; - - if ($this->db->num_rows() == 0) { - return false; - } else { - return true; - } - } - - /** - * Selects all entries from the database. Objects are loaded using their primary key. - * - * @param string $sDistinct Specifies if distinct will be added to the SQL - * statement ($sDistinct !== '' -> DISTINCT) - * @param string $sFrom Specifies the additional from clause (e.g. - * 'con_news_groups AS groups, con_news_groupmembers AS groupmembers'). - * @param string $sWhere Specifies the where clause. - * @param string $sGroupBy Specifies the group by clause. - * @param string $sOrderBy Specifies the order by clause. - * @param string $sLimit Specifies the limit by clause. - * @return bool True on success, otherwhise false - * @author HerrB - */ - public function flexSelect($sDistinct = '', $sFrom = '', $sWhere = '', $sGroupBy = '', $sOrderBy = '', $sLimit = '') { - unset($this->objects); - - if ($sDistinct != '') { - $sDistinct = 'DISTINCT '; - } - - if ($sFrom != '') { - $sFrom = ', ' . $sFrom; - } - - if ($sWhere != '') { - $sWhere = ' WHERE ' . $sWhere; - } - - if ($sGroupBy != '') { - $sGroupBy = ' GROUP BY ' . $sGroupBy; - } - - if ($sOrderBy != '') { - $sOrderBy = ' ORDER BY ' . $sOrderBy; - } - - if ($sLimit != '') { - $sLimit = ' LIMIT ' . $sLimit; - } - - $sql = 'SELECT ' . $sDistinct . strtolower(get_class($this)) . '.' . $this->primaryKey - . ' AS ' . $this->primaryKey . ' FROM `' . $this->table . '` AS ' . strtolower(get_class($this)) - . $sFrom . $sWhere . $sGroupBy . $sOrderBy . $sLimit; - - $this->db->query($sql); - $this->_lastSQL = $sql; - // @todo disable all mode in this method - $this->_bAllMode = false; - - if ($this->db->num_rows() == 0) { - return false; - } else { - return true; - } - } - - /** - * Checks if a specific entry exists. - * - * @param mixed $mId The id to check for (could be numeric or string) - * @return bool True if object exists, false if not - */ - public function exists($mId) { - $oDb = $this->_getSecondDBInstance(); - $sql = "SELECT `%s` FROM %s WHERE %s='%s'"; - $oDb->query($sql, $this->primaryKey, $this->table, $this->primaryKey, $mId); - return ($oDb->next_record()) ? true : false; - } - - /** - * Advances to the next item in the database. - * - * @return Item|bool The next object, or false if no more objects - */ - public function next() { - if ($this->db->next_record()) { - if ($this->_bAllMode) { - $aRs = $this->db->toArray(DB_ConLite::FETCH_BOTH); - return $this->loadItem($aRs); - } else { - return $this->loadItem($this->db->f($this->primaryKey)); - } - } else { - return false; - } - } - - /** - * Fetches the resultset related to current loaded primary key as a object - * - * @param Item - */ - public function fetchObject($sClassName) { - $sKey = strtolower($sClassName); - - if (!is_object($this->_collectionCache[$sKey])) { - $this->_collectionCache[$sKey] = new $sClassName; - } - $obj = $this->_collectionCache[$sKey]; - return $obj->loadItem($this->db->f($obj->primaryKey)); - } - - /** - * Both arrays are optional. If both empty you will get an result using field stored in primaryKey - * - * $aFields = array with the fields to fetch. Notes: - * If the array contains keys, the key will be used as alias for the field. Example: - * array('id' => 'idcat') will put 'idcat' into field 'id' - * - * $aObjects = array with the objects to fetch. Notes: - * If the array contains keys, the key will be used as alias for the object. If you specify - * more than one object with the same key, the array will be multi-dimensional. - * - * @param array $aFields - * @param array $aObjects - * @return array - */ - public function fetchTable(array $aFields = array(), array $aObjects = array()) { - $row = 1; - $aTable = array(); - - if(!empty($this->_aTableColums)) { - $aFields = $this->_aTableColums; - } - - if (empty($aFields) && empty($aObjects)) { - $aFields = array($this->primaryKey); - } - - $this->db->seek(0); - - while ($this->db->next_record()) { - foreach ($aFields as $alias => $field) { - //if ($alias != '') { - if (is_string($alias)) { - $aTable[$row][$alias] = $this->db->f($field); - } else { - $aTable[$row][$field] = $this->db->f($field); - } - } - - // Fetch objects - if (!empty($aObjects)) { - foreach ($aObjects as $alias => $object) { - if ($alias != '') { - if (isset($aTable[$row][$alias])) { - // Is set, check for array. If no array, create one - if (is_array($aTable[$row][$alias])) { - $aTable[$row][$alias][] = $this->fetchObject($object); - } else { - // $tmpObj = $aTable[$row][$alias]; - $aTable[$row][$alias] = array(); - $aTable[$row][$alias][] = $this->fetchObject($object); - } - } else { - $aTable[$row][$alias] = $this->fetchObject($object); - } - } else { - $aTable[$row][$object] = $this->fetchObject($object); - } - } - } - $row++; - } - - $this->db->seek(0); - - return $aTable; - } - - /** - * Returns an array of arrays - * @param array $aObjects With the correct order of the objects - * @return array Result - */ - public function queryAndFetchStructured(array $aObjects) { - $aOrder = array(); - $aFetchObjects = array(); - $aResult = array(); - - foreach ($aObjects as $object) { - $x = new $object; - $object = strtolower($object); - $aOrder[] = $object . '.' . $x->primaryKey . ' ASC'; - $aFetchObjects[] = $x; - } - - $this->setOrder(implode(', ', $aOrder)); - $this->query(); - - $this->db->seek(0); - - while ($this->db->next_record()) { - $aResult = $this->_recursiveStructuredFetch($aFetchObjects, $aResult); - } - - return $aResult; - } - - protected function _recursiveStructuredFetch(array $aObjects, array $aResult) { - $i = array_shift($aObjects); - - $value = $this->db->f($i->primaryKey); - - if (!is_null($value)) { - $aResult[$value]['class'] = strtolower(get_class($i)); - $aResult[$value]['object'] = $i->loadItem($value); - - if (count($aObjects) > 0) { - $aResult[$value]['items'] = $this->_recursiveStructuredFetch($aObjects, $aResult[$value]['items']); - } - } - - return $aResult; - } - - /** - * Returns the amount of returned items - * @return int Number of rows - */ - public function count() { - return ($this->db->num_rows()); - } - - /** - * Loads a single entry by it's id. - * - * @param string|int $id The primary key of the item to load. - * @return Item The loaded item - */ - public function fetchById($id) { - if (is_numeric($id)) { - $id = (int) $id; - } elseif (is_string($id)) { - $id = $this->escape($id); - } - return $this->loadItem($id); - } - - /** - * Loads a single object from the database. - * - * @param mixed $mItem The primary key of the item to load or a recordset - * with itemdata (array) to inject to the item object. - * @return Item The newly created object - * @throws Contenido_ItemException If item class is not set - */ - public function loadItem($mItem) { - if (empty($this->_itemClass)) { - $sMsg = "ItemClass has to be set in the constructor of class " - . get_class($this) . ")"; - throw new Contenido_ItemException($sMsg); - } - - if (!is_object($this->_iteratorItem)) { - $this->_iteratorItem = new $this->_itemClass(); - } - - if (is_array($mItem)) { - $this->_iteratorItem->loadByRecordSet($mItem); - } else { - $this->_iteratorItem->loadByPrimaryKey($mItem); - } - - return $this->_iteratorItem; - } - - /** - * Creates a new item in the table and loads it afterwards. - * - * @param string $primaryKeyValue Optional parameter for direct input of primary key value - * @return Item The newly created object - */ - public function createNewItem($aData = NULL) { /* @var $oDb DB_ConLite */ - $oDb = $this->_getSecondDBInstance(); - if (is_null($aData) || empty($aData)) { - $iNextId = $oDb->nextid($this->table); - } else if (is_array($aData) && key_exists($this->primaryKey, $aData)) { - $iNextId = (int) $aData[$this->primaryKey]; - } else { - $iNextId = (int) $aData; - } - - $sql = 'INSERT INTO `%s` (%s) VALUES (%d)'; - $oDb->query($sql, $this->table, $this->primaryKey, $iNextId); - return $this->loadItem($iNextId); - } - - /** - * Deletes an item in the table. - * Deletes also cached e entry and any existing properties. - * - * @param mixed $mId Id of entry to delete - * @return bool - */ - public function delete($mId) { - $result = $this->_delete($mId); - - return $result; - } - - /** - * Deletes all found items in the table matching the rules in the passed where clause. - * Deletes also cached e entries and any existing properties. - * - * @param string $sWhere The where clause of the SQL statement - * @return int Number of deleted entries - */ - public function deleteByWhereClause($sWhere) { - $oDb = $this->_getSecondDBInstance(); - - $aIds = array(); - $numDeleted = 0; - - // get all ids - $sql = 'SELECT ' . $this->primaryKey . ' AS pk FROM `' . $this->table . '` WHERE ' . $sWhere; - $oDb->query($sql); - while ($oDb->next_record()) { - $aIds[] = $oDb->f('pk'); - } - - // delete entries by their ids - foreach ($aIds as $id) { - if ($this->_delete($id)) { - $numDeleted++; - } - } - - return $numDeleted; - } - - /** - * Deletes all found items in the table matching the passed field and it's value. - * Deletes also cached e entries and any existing properties. - * - * @param string $sField The field name - * @param mixed $mValue The value of the field - * @return int Number of deleted entries - */ - public function deleteBy($sField, $mValue) { - $oDb = $this->_getSecondDBInstance(); - - $aIds = array(); - $numDeleted = 0; - - // get all ids - if (is_string($mValue)) { - $sql = "SELECT %s AS pk FROM `%s` WHERE `%s` = '%s'"; - } else { - $sql = "SELECT %s AS pk FROM `%s` WHERE `%s` = %d"; - } - - $oDb->query($sql, $this->primaryKey, $this->table, $sField, $mValue); - while ($oDb->next_record()) { - $aIds[] = $oDb->f('pk'); - } - - // delete entries by their ids - foreach ($aIds as $id) { - if ($this->_delete($id)) { - $numDeleted++; - } - } - - return $numDeleted; - } - - /** - * Deletes an item in the table, deletes also existing cache entries and - * properties of the item. - * - * @param mixed $mId Id of entry to delete - * @return bool - */ - protected function _delete($mId) { - - // delete cache entry - self::$_oCache->removeItem($mId); - - // delete the property values - $oProperties = $this->_getPropertiesCollectionInstance(); - $oProperties->deleteProperties($this->primaryKey, $mId); - - $oDb = $this->_getSecondDBInstance(); - - // delete db entry - $sql = "DELETE FROM `%s` WHERE %s = '%s'"; - $oDb->query($sql, $this->table, $this->primaryKey, $mId); - - return (($oDb->affected_rows() > 0) ? true : false); - } - - /** - * Fetches an array of fields from the database. - * - * Example: - * $i = $object->fetchArray('idartlang', array('idlang', 'name')); - * - * could result in: - * $i[5] = array('idlang' => 5, 'name' => 'My Article'); - * - * Important: If you don't pass an array for fields, the function - * doesn't create an array. - * @param string $sKey Name of the field to use for the key - * @param mixed $mFields String or array - * @return array Resulting array - */ - public function fetchArray($sKey, $mFields) { - $aResult = array(); - - while ($item = $this->next()) { - if (is_array($mFields)) { - foreach ($mFields as $value) { - $aResult[$item->get($sKey)][$value] = $item->get($value); - } - } else { - $aResult[$item->get($sKey)] = $item->get($mFields); - } - } - - return $aResult; - } +abstract class ItemCollection extends \ConLite\GenericDb\ItemCollection { } @@ -1284,501 +64,6 @@ abstract class ItemCollection extends cItemBaseAbstract { * @version 0.3 * @copyright four for business 2003 */ -abstract class Item extends cItemBaseAbstract { - - /** - * Storage of the source table to use for the user informations - * @var array - */ - public $values; - - /** - * Storage of the fields which were modified, where the keys are the - * fieldnames and the values just simple booleans. - * @var array - */ - protected $modifiedValues; - - /** - * Stores the old primary key, just in case somebody wants to change it - * @var string - */ - protected $oldPrimaryKey; - - /** - * List of funcion names of the filters used when data is stored to the db. - * @var array - */ - protected $_arrInFilters = array('urlencode', 'clHtmlSpecialChars', 'addslashes'); - - /** - * List of funcion names of the filtersused when data is retrieved from the db - * @var array - */ - protected $_arrOutFilters = array('stripslashes', 'htmldecode','urldecode'); - - /** - * Class name of meta object - * @var string - */ - protected $_metaObject; - - /** - * Constructor function - * - * @param string $sTable The table to use as information source - * @param string $sPrimaryKey The primary key to use - * @param int $iLifetime - */ - public function __construct($sTable = '', $sPrimaryKey = '', $iLifetime = 10) { - parent::__construct($sTable, $sPrimaryKey, get_parent_class($this), $iLifetime); - } - - function __destruct() { - //print_r(self::$_oCache); - } - - /** - * Loads an item by colum/field from the database. - * - * @param string $sField Specifies the field - * @param mixed $mValue Specifies the value - * @param bool $bSafe Use inFilter or not - * @return bool True if the load was successful - */ - public function loadBy($sField, $mValue, $bSafe = true) { - if ($bSafe) { - $mValue = $this->_inFilter($mValue); - } - - // check, if cache contains a matching entry - $aRecordSet = null; - if ($sField === $this->primaryKey) { - $aRecordSet = self::$_oCache->getItem($this->table . "_" . $mValue); - } else { - $aRecordSet = self::$_oCache->getItemByProperty($this->table . "_" . $sField, $mValue); - } - - if ($aRecordSet) { - // entry in cache found, load entry from cache - $this->loadByRecordSet($aRecordSet); - return true; - } - - // SQL-Statement to select by field - $sql = sprintf("SELECT * FROM `%s` WHERE %s = '%s'", $this->table, $sField, $mValue); - //$sql = $this->db->prepare($sql, $this->table, $sField, $mValue); - // Query the database - $this->db->query($sql); - - $this->_lastSQL = $sql; - - if ($this->db->num_rows() > 1) { - $sMsg = "Tried to load a single line with field $sField and value $mValue from " - . $this->table . " but found more than one row"; - cWarning(__FILE__, __LINE__, $sMsg); - } - - // Advance to the next record, return false if nothing found - if (!$this->db->next_record()) { - return false; - } - - $this->loadByRecordSet($this->db->toArray()); - return true; - } - - /** - * Loads an item by passed where clause from the database. - * This function is expensive, since it executes allways a query to the database - * to retrieve the primary key, even if the record set is aleady cached. - * NOTE: Passed value has to be escaped before. This will not be done by this function. - * - * @param string $sWhere The where clause like 'idart = 123 AND idlang = 1' - * @return bool True if the load was successful - */ - protected function _loadByWhereClause($sWhere) { - // SQL-Statement to select by whee clause - $sql = sprintf("SELECT %s AS pk FROM `%s` WHERE ", $this->primaryKey, $this->table) . (string) $sWhere; - //$sql = $this->db->prepare($sql, $this->primaryKey, $this->table); - // Query the database - $this->db->query($sql); - - $this->_lastSQL = $sql; - - if ($this->db->num_rows() > 1) { - $sMsg = "Tried to load a single line with where clause '" . $sWhere . "' from " - . $this->table . " but found more than one row"; - cWarning(__FILE__, __LINE__, $sMsg); - } - - // Advance to the next record, return false if nothing found - if (!$this->db->next_record()) { - return false; - } - - $id = $this->db->f('pk'); - return $this->loadByPrimaryKey($id); - } - - /** - * Loads an item by ID from the database. - * - * @param string $mValue Specifies the primary key value - * @return bool True if the load was successful - */ - public function loadByPrimaryKey($mValue) { - $bSuccess = $this->loadBy($this->primaryKey, $mValue); - - if (($bSuccess == true) && method_exists($this, '_onLoad')) { - $this->_onLoad(); - } - return $bSuccess; - } - - /** - * Loads an item by it's recordset. - * - * @param array $aRecordSet The recordset of the item - */ - public function loadByRecordSet(array $aRecordSet) { - $this->values = $aRecordSet; - $this->oldPrimaryKey = $this->values[$this->primaryKey]; - $this->virgin = false; - self::$_oCache->addItem($this->table . "_" . $this->oldPrimaryKey, $this->values); - } - - /** - * Checks if a the item is already loaded. - * @return boolean - */ - public function isLoaded() { - return ($this->virgin) ? FALSE : TRUE; - } - - /** - * Function which is called whenever an item is loaded. - * Inherited classes should override this function if desired. - * - * @return void - */ - protected function _onLoad() { - - } - - /** - * Gets the value of a specific field. - * - * @param string $sField Specifies the field to retrieve - * @return mixed Value of the field - */ - public function getField($sField) { - if ($this->virgin == true) { - $this->lasterror = 'No item loaded'; - return false; - } - return $this->_outFilter($this->values[$sField]); - } - - /** - * Wrapper for getField (less to type). - * - * @param string $sField Specifies the field to retrieve - * @return mixed Value of the field - */ - public function get($sField) { - return $this->getField($sField); - } - - /** - * Sets the value of a specific field. - * - * @param string $sField Field name - * @param string $mValue Value to set - * @param bool $bSafe Flag to run defined inFilter on passed value - */ - public function setField($sField, $mValue, $bSafe = true) { - if ($this->virgin == true) { - $this->lasterror = 'No item loaded'; - return false; - } - - $this->modifiedValues[$sField] = true; - - if ($sField == $this->primaryKey) { - $this->oldPrimaryKey = $this->values[$sField]; - } - - if ($bSafe == true) { - $this->values[$sField] = $this->_inFilter($mValue); - } else { - $this->values[$sField] = $mValue; - } - return true; - } - - /** - * Shortcut to setField. - * - * @param string $sField Field name - * @param string $mValue Value to set - * @param bool $bSafe Flag to run defined inFilter on passed value - */ - public function set($sField, $mValue, $bSafe = true) { - return $this->setField($sField, $mValue, $bSafe); - } - - /** - * Stores the loaded and modified item to the database. - * - * @return bool - */ - public function store() { - if (!$this->isLoaded()) { - $this->lasterror = 'No item loaded'; - return false; - } - - $sql = 'UPDATE `' . $this->table . '` SET '; - $first = true; - - if (!is_array($this->modifiedValues)) { - return true; - } - - foreach ($this->modifiedValues as $key => $bValue) { - if ($first == true) { - $sql .= "`$key` = '" . $this->values[$key] . "'"; - $first = false; - } else { - $sql .= ", `$key` = '" . $this->values[$key] . "'"; - } - } - - $sql .= " WHERE " . $this->primaryKey . " = '" . $this->oldPrimaryKey . "'"; - - $this->db->query($sql); - - $this->_lastSQL = $sql; - - if ($this->db->affected_rows() > 0) { - self::$_oCache->addItem($this->table . "_" . $this->oldPrimaryKey, $this->values); - } - - return ($this->db->affected_rows() < 1) ? false : true; - } - - /** - * Returns current item data as an assoziative array. - * - * @return array|false - */ - public function toArray() { - if ($this->virgin == true) { - $this->lasterror = 'No item loaded'; - return false; - } - - $aReturn = array(); - foreach ($this->values as $field => $value) { - $aReturn[$field] = $this->getField($field); - } - return $aReturn; - } - - /** - * Returns current item data as an object. - * - * @return stdClass|false - */ - public function toObject() { - $return = $this->toArray(); - return (false !== $return) ? (object) $return : $return; - } - - /** - * Sets a custom property. - * - * @param string $sType Specifies the type - * @param string $sName Specifies the name - * @param mixed $mValue Specifies the value - * @return bool - */ - public function setProperty($sType, $sName, $mValue) { - // If this object wasn't loaded before, return false - if ($this->virgin == true) { - $this->lasterror = 'No item loaded'; - return false; - } - - // Set the value - $oProperties = $this->_getPropertiesCollectionInstance(); - $bResult = $oProperties->setValue( - $this->primaryKey, $this->get($this->primaryKey), $sType, $sName, $mValue - ); - return $bResult; - } - - /** - * Returns a custom property. - * - * @param string $sType Specifies the type - * @param string $sName Specifies the name - * @return mixed Value of the given property or false - */ - public function getProperty($sType, $sName) { - // If this object wasn't loaded before, return false - if ($this->virgin == true) { - $this->lasterror = 'No item loaded'; - return false; - } - - // Return the value - $oProperties = $this->_getPropertiesCollectionInstance(); - $mValue = $oProperties->getValue( - $this->primaryKey, $this->get($this->primaryKey), $sType, $sName - ); - return $mValue; - } - - /** - * Deletes a custom property. - * - * @param string $sType Specifies the type - * @param string $sName Specifies the name - * @return bool - */ - public function deleteProperty($sType, $sName) { - // If this object wasn't loaded before, return false - if ($this->virgin == true) { - $this->lasterror = 'No item loaded'; - return false; - } - - // Delete the value - $oProperties = $this->_getPropertiesCollectionInstance(); - $bResult = $oProperties->deleteValue( - $this->primaryKey, $this->get($this->primaryKey), $sType, $sName - ); - return $bResult; - } - - /** - * Deletes a custom property by its id. - * - * @param int $idprop Id of property - * @return bool - */ - public function deletePropertyById($idprop) { - $oProperties = $this->_getPropertiesCollectionInstance(); - return $oProperties->delete($idprop); - } - - /** - * Deletes the current item - * - * @return void - */ - // Method doesn't work, remove in future versions - // function delete() - // { - // $this->_collectionInstance->delete($item->get($this->primaryKey)); - //} - - /** - * Define the filter functions used when data is being stored or retrieved - * from the database. - * - * Examples: - *
-     * $obj->setFilters(array('addslashes'), array('stripslashes'));
-     * $obj->setFilters(array('htmlencode', 'addslashes'), array('stripslashes', 'htmlencode'));
-     * 
- * - * @param array $aInFilters Array with function names - * @param array $aOutFilters Array with function names - * - * @return void - */ - public function setFilters($aInFilters = array(), $aOutFilters = array()) { - $this->_arrInFilters = $aInFilters; - $this->_arrOutFilters = $aOutFilters; - } - - /** - * Filters the passed data using the functions defines in the _arrInFilters array. - * - * @see setFilters - * - * @todo This method is used from public scope, but it should be protected - * - * @param mixed $mData Data to filter - * @return mixed Filtered data - */ - public function _inFilter($mData) { - if (is_numeric($mData) || is_array($mData)) { - return $mData; - } - - if(is_null($mData)) { - $mData = ''; - } - - foreach ($this->_arrInFilters as $_function) { - if (function_exists($_function)) { - $mData = $_function($mData); - } - } - return $mData; - } - - /** - * Filters the passed data using the functions defines in the _arrOutFilters array. - * - * @see setFilters - * - * @param mixed $mData Data to filter - * @return mixed Filtered data - */ - protected function _outFilter($mData) { - if (is_numeric($mData)) - return $mData; - - foreach ($this->_arrOutFilters as $_function) { - if (function_exists($_function)) { - $mData = $_function($mData); - } - } - return $mData; - } - - protected function _setMetaObject($sObjectName) { - $this->_metaObject = $sObjectName; - } - - public function getMetaObject() { - global $_metaObjectCache; - - if (!is_array($_metaObjectCache)) { - $_metaObjectCache = array(); - } - - $sClassName = $this->_metaObject; - $qclassname = strtolower($sClassName); - - if (array_key_exists($qclassname, $_metaObjectCache)) { - if (is_object($_metaObjectCache[$qclassname])) { - if (strtolower(get_class($_metaObjectCache[$qclassname])) == $qclassname) { - $_metaObjectCache[$qclassname]->setPayloadObject($this); - return $_metaObjectCache[$qclassname]; - } - } - } - - if (class_exists($sClassName)) { - $_metaObjectCache[$qclassname] = new $sClassName($this); - return $_metaObjectCache[$qclassname]; - } - } +abstract class Item extends \ConLite\GenericDb\Item { } diff --git a/conlite/includes/startup.php b/conlite/includes/startup.php index 6b0588d..de028cc 100644 --- a/conlite/includes/startup.php +++ b/conlite/includes/startup.php @@ -142,7 +142,7 @@ require_once($cfg['path']['conlite'] . $cfg['path']['includes'] . '/api/function include_once($cfg['path']['conlite'] . $cfg['path']['classes'] . 'class.autoload.php'); cAutoload::initialize($cfg); // init composer autoload -include_once($cfg['path']['conlite'] . 'vendor/autoload.php'); +include_once(dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'vendor/autoload.php'); // 2. security check: Check HTTP parameters, if requested diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index f14fb1a..987950e 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -5,7 +5,7 @@ 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), - 'reference' => '727cad0e1e2ad00ac92dac6aa02e5ea0b4ca1dfb', + 'reference' => '680b5bad712adbaf56c58c3d71ff53edac53c924', 'name' => 'org.conlite/conlite', 'dev' => false, ), @@ -16,7 +16,7 @@ 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), - 'reference' => '727cad0e1e2ad00ac92dac6aa02e5ea0b4ca1dfb', + 'reference' => '680b5bad712adbaf56c58c3d71ff53edac53c924', 'dev_requirement' => false, ), 'phpmailer/phpmailer' => array(